diff --git a/bun.lock b/bun.lock index 525627816aee..dba7a1219dcc 100644 --- a/bun.lock +++ b/bun.lock @@ -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=="], diff --git a/package.json b/package.json index ab516e66e70a..05d82b27836d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/ai/example/tutorial.ts b/packages/ai/example/tutorial.ts index b97fbb212df0..eb7b75f39a94 100644 --- a/packages/ai/example/tutorial.ts +++ b/packages/ai/example/tutorial.ts @@ -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 diff --git a/packages/ai/script/setup-recording-env.ts b/packages/ai/script/setup-recording-env.ts index 94eac741d2c4..4b583076a890 100644 --- a/packages/ai/script/setup-recording-env.ts +++ b/packages/ai/script/setup-recording-env.ts @@ -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({ diff --git a/packages/ai/src/experimental/system-one.ts b/packages/ai/src/experimental/system-one.ts index 55a386b79ddd..3e924f2810e4 100644 --- a/packages/ai/src/experimental/system-one.ts +++ b/packages/ai/src/experimental/system-one.ts @@ -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, diff --git a/packages/ai/src/image.ts b/packages/ai/src/image.ts index b25efee811fc..4447535b798b 100644 --- a/packages/ai/src/image.ts +++ b/packages/ai/src/image.ts @@ -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"], diff --git a/packages/ai/src/media.ts b/packages/ai/src/media.ts index fca61a3cc2a3..91c0d832c9eb 100644 --- a/packages/ai/src/media.ts +++ b/packages/ai/src/media.ts @@ -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, } diff --git a/packages/ai/src/protocols/anthropic-messages.ts b/packages/ai/src/protocols/anthropic-messages.ts index f1646b1727c9..22eedc4d5f5a 100644 --- a/packages/ai/src/protocols/anthropic-messages.ts +++ b/packages/ai/src/protocols/anthropic-messages.ts @@ -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, diff --git a/packages/ai/src/protocols/assemblyai-transcription.ts b/packages/ai/src/protocols/assemblyai-transcription.ts index 46c07413225b..6446b04f4821 100644 --- a/packages/ai/src/protocols/assemblyai-transcription.ts +++ b/packages/ai/src/protocols/assemblyai-transcription.ts @@ -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" diff --git a/packages/ai/src/protocols/bedrock-converse.ts b/packages/ai/src/protocols/bedrock-converse.ts index 9e31442b03ef..9eabf8043b59 100644 --- a/packages/ai/src/protocols/bedrock-converse.ts +++ b/packages/ai/src/protocols/bedrock-converse.ts @@ -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> } -const encodeRedactedContent = (chunks: ReadonlyArray) => Encoding.encodeBase64(concatBytes(chunks)) +const encodeRedactedContent = (chunks: ReadonlyArray) => 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, diff --git a/packages/ai/src/protocols/bedrock-event-stream.ts b/packages/ai/src/protocols/bedrock-event-stream.ts index a29cc1c529dd..af81da859c2b 100644 --- a/packages/ai/src/protocols/bedrock-event-stream.ts +++ b/packages/ai/src/protocols/bedrock-event-stream.ts @@ -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, ), }) diff --git a/packages/ai/src/protocols/bfl-images.ts b/packages/ai/src/protocols/bfl-images.ts index b5f7b532bf0e..ca4e128f568e 100644 --- a/packages/ai/src/protocols/bfl-images.ts +++ b/packages/ai/src/protocols/bfl-images.ts @@ -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" diff --git a/packages/ai/src/protocols/deepgram-transcription.ts b/packages/ai/src/protocols/deepgram-transcription.ts index 1c6e8517c8cc..c3868c71cd6d 100644 --- a/packages/ai/src/protocols/deepgram-transcription.ts +++ b/packages/ai/src/protocols/deepgram-transcription.ts @@ -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" diff --git a/packages/ai/src/protocols/elevenlabs-transcription.ts b/packages/ai/src/protocols/elevenlabs-transcription.ts index 626df5e8e0a9..1f971231a8ce 100644 --- a/packages/ai/src/protocols/elevenlabs-transcription.ts +++ b/packages/ai/src/protocols/elevenlabs-transcription.ts @@ -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" diff --git a/packages/ai/src/protocols/fal-images.ts b/packages/ai/src/protocols/fal-images.ts index d3de229dc4ef..ce722a5e0784 100644 --- a/packages/ai/src/protocols/fal-images.ts +++ b/packages/ai/src/protocols/fal-images.ts @@ -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" diff --git a/packages/ai/src/protocols/fal-video.ts b/packages/ai/src/protocols/fal-video.ts index 02e77db373fe..dc5a0664d211 100644 --- a/packages/ai/src/protocols/fal-video.ts +++ b/packages/ai/src/protocols/fal-video.ts @@ -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" diff --git a/packages/ai/src/protocols/google-images.ts b/packages/ai/src/protocols/google-images.ts index b8f7ff1584cb..ed67d294bba5 100644 --- a/packages/ai/src/protocols/google-images.ts +++ b/packages/ai/src/protocols/google-images.ts @@ -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" diff --git a/packages/ai/src/protocols/google-video.ts b/packages/ai/src/protocols/google-video.ts index c3ff3a621fe7..af1adc31f4f9 100644 --- a/packages/ai/src/protocols/google-video.ts +++ b/packages/ai/src/protocols/google-video.ts @@ -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" diff --git a/packages/ai/src/protocols/meta-images.ts b/packages/ai/src/protocols/meta-images.ts index 4e83f8478012..e0efbe34ae1c 100644 --- a/packages/ai/src/protocols/meta-images.ts +++ b/packages/ai/src/protocols/meta-images.ts @@ -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" diff --git a/packages/ai/src/protocols/meta-responses.ts b/packages/ai/src/protocols/meta-responses.ts index 79827fa3178d..6b1d2e0263ce 100644 --- a/packages/ai/src/protocols/meta-responses.ts +++ b/packages/ai/src/protocols/meta-responses.ts @@ -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, diff --git a/packages/ai/src/protocols/open-responses-channel.ts b/packages/ai/src/protocols/open-responses-channel.ts index 15abd8a62c32..5ff0e956f7a8 100644 --- a/packages/ai/src/protocols/open-responses-channel.ts +++ b/packages/ai/src/protocols/open-responses-channel.ts @@ -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 { diff --git a/packages/ai/src/protocols/openai-responses.ts b/packages/ai/src/protocols/openai-responses.ts index 610a9883267b..7ff86f58792a 100644 --- a/packages/ai/src/protocols/openai-responses.ts +++ b/packages/ai/src/protocols/openai-responses.ts @@ -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), ), diff --git a/packages/ai/src/protocols/replicate-images.ts b/packages/ai/src/protocols/replicate-images.ts index 087bd57df9e7..f98815198660 100644 --- a/packages/ai/src/protocols/replicate-images.ts +++ b/packages/ai/src/protocols/replicate-images.ts @@ -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" diff --git a/packages/ai/src/protocols/runway-video.ts b/packages/ai/src/protocols/runway-video.ts index bc3a68f064f9..14a9ec8ab064 100644 --- a/packages/ai/src/protocols/runway-video.ts +++ b/packages/ai/src/protocols/runway-video.ts @@ -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" diff --git a/packages/ai/src/protocols/shared.ts b/packages/ai/src/protocols/shared.ts index bd8d2538d6a8..065b64841c19 100644 --- a/packages/ai/src/protocols/shared.ts +++ b/packages/ai/src/protocols/shared.ts @@ -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, diff --git a/packages/ai/src/protocols/stability-images.ts b/packages/ai/src/protocols/stability-images.ts index 2dcc538df8d1..b4979d598857 100644 --- a/packages/ai/src/protocols/stability-images.ts +++ b/packages/ai/src/protocols/stability-images.ts @@ -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" diff --git a/packages/ai/src/protocols/utils/bedrock-auth.ts b/packages/ai/src/protocols/utils/bedrock-auth.ts index 7be6c260063b..708a71fcc889 100644 --- a/packages/ai/src/protocols/utils/bedrock-auth.ts +++ b/packages/ai/src/protocols/utils/bedrock-auth.ts @@ -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" diff --git a/packages/ai/src/protocols/utils/bedrock-media.ts b/packages/ai/src/protocols/utils/bedrock-media.ts index 9cc5730b8dbb..efd1a884d3c0 100644 --- a/packages/ai/src/protocols/utils/bedrock-media.ts +++ b/packages/ai/src/protocols/utils/bedrock-media.ts @@ -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) { 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 diff --git a/packages/ai/src/protocols/utils/fal-queue.ts b/packages/ai/src/protocols/utils/fal-queue.ts index cd2dc5c526b2..02f5c5bb4646 100644 --- a/packages/ai/src/protocols/utils/fal-queue.ts +++ b/packages/ai/src/protocols/utils/fal-queue.ts @@ -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" diff --git a/packages/ai/src/protocols/utils/media-input.ts b/packages/ai/src/protocols/utils/media-input.ts index 2116b8cb542b..2120e35e040b 100644 --- a/packages/ai/src/protocols/utils/media-input.ts +++ b/packages/ai/src/protocols/utils/media-input.ts @@ -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 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)), ) diff --git a/packages/ai/src/protocols/utils/tool-schema.ts b/packages/ai/src/protocols/utils/tool-schema.ts index 013cd4d321ab..6766b6a0997e 100644 --- a/packages/ai/src/protocols/utils/tool-schema.ts +++ b/packages/ai/src/protocols/utils/tool-schema.ts @@ -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 } } diff --git a/packages/ai/src/protocols/xai-images.ts b/packages/ai/src/protocols/xai-images.ts index 01593ffcf373..438b93a701ef 100644 --- a/packages/ai/src/protocols/xai-images.ts +++ b/packages/ai/src/protocols/xai-images.ts @@ -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" diff --git a/packages/ai/src/protocols/xai-video.ts b/packages/ai/src/protocols/xai-video.ts index 45d1eac0b655..e23d92f7f81c 100644 --- a/packages/ai/src/protocols/xai-video.ts +++ b/packages/ai/src/protocols/xai-video.ts @@ -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" diff --git a/packages/ai/src/protocols/zai-images.ts b/packages/ai/src/protocols/zai-images.ts index 736e650361f9..375686a4a22c 100644 --- a/packages/ai/src/protocols/zai-images.ts +++ b/packages/ai/src/protocols/zai-images.ts @@ -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" diff --git a/packages/ai/src/providers/vercel-ai-gateway.ts b/packages/ai/src/providers/vercel-ai-gateway.ts index c435c8e1295c..7a65b0567b48 100644 --- a/packages/ai/src/providers/vercel-ai-gateway.ts +++ b/packages/ai/src/providers/vercel-ai-gateway.ts @@ -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, diff --git a/packages/ai/src/route/auth.ts b/packages/ai/src/route/auth.ts index 5494a86ebdcc..9a8a4d9a2178 100644 --- a/packages/ai/src/route/auth.ts +++ b/packages/ai/src/route/auth.ts @@ -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`)) }), diff --git a/packages/ai/src/route/executor-service.ts b/packages/ai/src/route/executor-service.ts index 5cd0c3fd24c1..8087867c9bdc 100644 --- a/packages/ai/src/route/executor-service.ts +++ b/packages/ai/src/route/executor-service.ts @@ -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 diff --git a/packages/ai/src/route/executor.ts b/packages/ai/src/route/executor.ts index 523769015269..b4cfdd079a3d 100644 --- a/packages/ai/src/route/executor.ts +++ b/packages/ai/src/route/executor.ts @@ -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" diff --git a/packages/ai/src/route/framing.ts b/packages/ai/src/route/framing.ts index c53f0a68eee0..cbe9c97675c2 100644 --- a/packages/ai/src/route/framing.ts +++ b/packages/ai/src/route/framing.ts @@ -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" /** diff --git a/packages/ai/src/route/media-protocol.ts b/packages/ai/src/route/media-protocol.ts index 27b8d6de5b29..47514a352c99 100644 --- a/packages/ai/src/route/media-protocol.ts +++ b/packages/ai/src/route/media-protocol.ts @@ -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" diff --git a/packages/ai/src/route/media.ts b/packages/ai/src/route/media.ts index 884fece763ea..5af63162d68d 100644 --- a/packages/ai/src/route/media.ts +++ b/packages/ai/src/route/media.ts @@ -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" diff --git a/packages/ai/src/route/transport/http.ts b/packages/ai/src/route/transport/http.ts index c8f94d1a7a1a..6d9d5a6e28c9 100644 --- a/packages/ai/src/route/transport/http.ts +++ b/packages/ai/src/route/transport/http.ts @@ -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" diff --git a/packages/ai/src/route/transport/websocket-channel.ts b/packages/ai/src/route/transport/websocket-channel.ts index f858c828585c..8c5c69ee2afc 100644 --- a/packages/ai/src/route/transport/websocket-channel.ts +++ b/packages/ai/src/route/transport/websocket-channel.ts @@ -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 { diff --git a/packages/ai/src/route/transport/websocket.ts b/packages/ai/src/route/transport/websocket.ts index 647c259008bc..f0f7740c0549 100644 --- a/packages/ai/src/route/transport/websocket.ts +++ b/packages/ai/src/route/transport/websocket.ts @@ -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, diff --git a/packages/ai/src/schema/events.ts b/packages/ai/src/schema/events.ts index 2d06eb9ae153..dc74aa291b3b 100644 --- a/packages/ai/src/schema/events.ts +++ b/packages/ai/src/schema/events.ts @@ -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.make({ ...input, id: contentBlockID(input.id) }), diff --git a/packages/ai/src/schema/messages.ts b/packages/ai/src/schema/messages.ts index 5787e3dcc683..447650a88766 100644 --- a/packages/ai/src/schema/messages.ts +++ b/packages/ai/src/schema/messages.ts @@ -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 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) => { if (input === undefined) return [] @@ -76,7 +77,7 @@ const toolResultValueSchema = Schema.Union([ export type ToolResultValue = Schema.Schema.Type 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 } -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 -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 & CompactionContent): CompactionPart => Schema.decodeUnknownSync(compactionPartSchema)({ type: "compaction", ...input }), }) @@ -326,7 +327,7 @@ export type ToolNamespaceEntryInput = ToolNamespaceInput & { readonly type: "nam export const ToolNamespace: Schema.Codec & { 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 & { readonly make: (input: ToolEntryInput) => ToolEntry -} = Object.assign( +} = extendSchema( Schema.Union([ToolDefinition, ToolNamespace]).pipe( Schema.toTaggedUnion("type"), Schema.annotate({ identifier: "LLM.ToolEntry" }), diff --git a/packages/ai/src/speech.ts b/packages/ai/src/speech.ts index 9c07febe72c0..cbeeb9737cf9 100644 --- a/packages/ai/src/speech.ts +++ b/packages/ai/src/speech.ts @@ -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"], diff --git a/packages/ai/src/tool.ts b/packages/ai/src/tool.ts index c04b666887c0..36347b0adb16 100644 --- a/packages/ai/src/tool.ts +++ b/packages/ai/src/tool.ts @@ -231,7 +231,8 @@ export const toDefinitions = (tools: Tools): ReadonlyArray ) 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 } } diff --git a/packages/ai/src/transcription.ts b/packages/ai/src/transcription.ts index 1302d72fccd6..8dbb8611fa75 100644 --- a/packages/ai/src/transcription.ts +++ b/packages/ai/src/transcription.ts @@ -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"], diff --git a/packages/ai/src/video.ts b/packages/ai/src/video.ts index c97ac08f43f6..f59ed9abd8c2 100644 --- a/packages/ai/src/video.ts +++ b/packages/ai/src/video.ts @@ -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"], diff --git a/packages/ai/test/auth-options.types.ts b/packages/ai/test/auth-options.types.ts index 7743047b721b..bbdcb3c58a0f 100644 --- a/packages/ai/test/auth-options.types.ts +++ b/packages/ai/test/auth-options.types.ts @@ -30,7 +30,7 @@ type LanguageModel = { declare const auth: Auth.Definition declare const optionalAuthModel: LanguageModelFactory declare const requiredAuthModel: LanguageModelFactory -const configApiKey = Config.redacted("OPENAI_API_KEY") +const configApiKey = Config.Redacted("OPENAI_API_KEY") OpenAIChat.route.model({ id: "gpt-4.1-mini" }) diff --git a/packages/ai/test/auth.test.ts b/packages/ai/test/auth.test.ts index cabf3013bbd6..d76d75b3ef5f 100644 --- a/packages/ai/test/auth.test.ts +++ b/packages/ai/test/auth.test.ts @@ -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" diff --git a/packages/ai/test/compaction-http.test.ts b/packages/ai/test/compaction-http.test.ts index 9472463762ec..8b235ab650b6 100644 --- a/packages/ai/test/compaction-http.test.ts +++ b/packages/ai/test/compaction-http.test.ts @@ -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" diff --git a/packages/ai/test/compile.test.ts b/packages/ai/test/compile.test.ts index e72bcf6fe178..2171993c57be 100644 --- a/packages/ai/test/compile.test.ts +++ b/packages/ai/test/compile.test.ts @@ -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, diff --git a/packages/ai/test/evaluation.test.ts b/packages/ai/test/evaluation.test.ts index 8f821e202ca6..d0f4245a8ce6 100644 --- a/packages/ai/test/evaluation.test.ts +++ b/packages/ai/test/evaluation.test.ts @@ -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" diff --git a/packages/ai/test/executor.test.ts b/packages/ai/test/executor.test.ts index 473b25a80fd7..f4a7b54e7fd7 100644 --- a/packages/ai/test/executor.test.ts +++ b/packages/ai/test/executor.test.ts @@ -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" diff --git a/packages/ai/test/image.test.ts b/packages/ai/test/image.test.ts index 9b6768a6cef6..7a6435e88d1a 100644 --- a/packages/ai/test/image.test.ts +++ b/packages/ai/test/image.test.ts @@ -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" diff --git a/packages/ai/test/lib/http.ts b/packages/ai/test/lib/http.ts index 11196323db1e..35e30fef94a8 100644 --- a/packages/ai/test/lib/http.ts +++ b/packages/ai/test/lib/http.ts @@ -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" diff --git a/packages/ai/test/media.test.ts b/packages/ai/test/media.test.ts index 32fc8f65560a..27245a8e08a4 100644 --- a/packages/ai/test/media.test.ts +++ b/packages/ai/test/media.test.ts @@ -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" diff --git a/packages/ai/test/promise.test.ts b/packages/ai/test/promise.test.ts index cc3ede886f0a..c3c53c6a23e9 100644 --- a/packages/ai/test/promise.test.ts +++ b/packages/ai/test/promise.test.ts @@ -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" diff --git a/packages/ai/test/provider/alibaba.test.ts b/packages/ai/test/provider/alibaba.test.ts index 92b955f1d5bc..908f939de6c1 100644 --- a/packages/ai/test/provider/alibaba.test.ts +++ b/packages/ai/test/provider/alibaba.test.ts @@ -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" diff --git a/packages/ai/test/provider/anthropic-messages.test.ts b/packages/ai/test/provider/anthropic-messages.test.ts index a2d03c884b5c..9dc8da01aea5 100644 --- a/packages/ai/test/provider/anthropic-messages.test.ts +++ b/packages/ai/test/provider/anthropic-messages.test.ts @@ -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, diff --git a/packages/ai/test/provider/bedrock-converse.test.ts b/packages/ai/test/provider/bedrock-converse.test.ts index 9a6471fa3786..035e4998da9b 100644 --- a/packages/ai/test/provider/bedrock-converse.test.ts +++ b/packages/ai/test/provider/bedrock-converse.test.ts @@ -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)) } }), ) diff --git a/packages/ai/test/provider/bedrock-mantle.test.ts b/packages/ai/test/provider/bedrock-mantle.test.ts index 9f4015120ed2..a785764e9545 100644 --- a/packages/ai/test/provider/bedrock-mantle.test.ts +++ b/packages/ai/test/provider/bedrock-mantle.test.ts @@ -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" diff --git a/packages/ai/test/provider/cloudflare.test.ts b/packages/ai/test/provider/cloudflare.test.ts index 6f77d902694b..1e0597e90e34 100644 --- a/packages/ai/test/provider/cloudflare.test.ts +++ b/packages/ai/test/provider/cloudflare.test.ts @@ -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" diff --git a/packages/ai/test/provider/google-vertex.test.ts b/packages/ai/test/provider/google-vertex.test.ts index eb0e22aebc77..e09aeac3d678 100644 --- a/packages/ai/test/provider/google-vertex.test.ts +++ b/packages/ai/test/provider/google-vertex.test.ts @@ -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" diff --git a/packages/ai/test/provider/meta-capabilities.test.ts b/packages/ai/test/provider/meta-capabilities.test.ts index 604e32b66938..ebc7e1afd16c 100644 --- a/packages/ai/test/provider/meta-capabilities.test.ts +++ b/packages/ai/test/provider/meta-capabilities.test.ts @@ -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" diff --git a/packages/ai/test/provider/meta.test.ts b/packages/ai/test/provider/meta.test.ts index 5cfa52ff886f..293ae904ddd2 100644 --- a/packages/ai/test/provider/meta.test.ts +++ b/packages/ai/test/provider/meta.test.ts @@ -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" diff --git a/packages/ai/test/provider/minimax.test.ts b/packages/ai/test/provider/minimax.test.ts index eb12815efad3..bc4c8112d9e7 100644 --- a/packages/ai/test/provider/minimax.test.ts +++ b/packages/ai/test/provider/minimax.test.ts @@ -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" diff --git a/packages/ai/test/provider/mistral-chat.test.ts b/packages/ai/test/provider/mistral-chat.test.ts index 263f5c7efb9f..2c1bc694f464 100644 --- a/packages/ai/test/provider/mistral-chat.test.ts +++ b/packages/ai/test/provider/mistral-chat.test.ts @@ -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" diff --git a/packages/ai/test/provider/moonshot.test.ts b/packages/ai/test/provider/moonshot.test.ts index 9bcf0aa5d7f0..cbc1a9a5b251 100644 --- a/packages/ai/test/provider/moonshot.test.ts +++ b/packages/ai/test/provider/moonshot.test.ts @@ -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" diff --git a/packages/ai/test/provider/native-providers.test.ts b/packages/ai/test/provider/native-providers.test.ts index 156dc99c3c99..1d46693b852e 100644 --- a/packages/ai/test/provider/native-providers.test.ts +++ b/packages/ai/test/provider/native-providers.test.ts @@ -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, diff --git a/packages/ai/test/provider/openai-chat.test.ts b/packages/ai/test/provider/openai-chat.test.ts index dac4350c3260..ab8aa5f15687 100644 --- a/packages/ai/test/provider/openai-chat.test.ts +++ b/packages/ai/test/provider/openai-chat.test.ts @@ -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, diff --git a/packages/ai/test/provider/openai-compatible-chat.test.ts b/packages/ai/test/provider/openai-compatible-chat.test.ts index 32cabda1f7ce..30675935f18a 100644 --- a/packages/ai/test/provider/openai-compatible-chat.test.ts +++ b/packages/ai/test/provider/openai-compatible-chat.test.ts @@ -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" diff --git a/packages/ai/test/provider/openai-responses-websocket.recorded.test.ts b/packages/ai/test/provider/openai-responses-websocket.recorded.test.ts index 38e62cbc3334..667248bdea2e 100644 --- a/packages/ai/test/provider/openai-responses-websocket.recorded.test.ts +++ b/packages/ai/test/provider/openai-responses-websocket.recorded.test.ts @@ -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, diff --git a/packages/ai/test/provider/openai-responses.test.ts b/packages/ai/test/provider/openai-responses.test.ts index 4e3cf3b91cba..a28e1944bf9e 100644 --- a/packages/ai/test/provider/openai-responses.test.ts +++ b/packages/ai/test/provider/openai-responses.test.ts @@ -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, diff --git a/packages/ai/test/provider/xai-images.test.ts b/packages/ai/test/provider/xai-images.test.ts index de7366e9ae2f..29a891ef9c55 100644 --- a/packages/ai/test/provider/xai-images.test.ts +++ b/packages/ai/test/provider/xai-images.test.ts @@ -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" diff --git a/packages/ai/test/provider/zai-images.test.ts b/packages/ai/test/provider/zai-images.test.ts index c33d3fe483d6..43187a7c034f 100644 --- a/packages/ai/test/provider/zai-images.test.ts +++ b/packages/ai/test/provider/zai-images.test.ts @@ -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" diff --git a/packages/ai/test/provider/zai.test.ts b/packages/ai/test/provider/zai.test.ts index b7986b7e36f4..ccbe8b9531f2 100644 --- a/packages/ai/test/provider/zai.test.ts +++ b/packages/ai/test/provider/zai.test.ts @@ -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" diff --git a/packages/ai/test/recorded-test.ts b/packages/ai/test/recorded-test.ts index 2c507f5a0ddd..005773a2a9a8 100644 --- a/packages/ai/test/recorded-test.ts +++ b/packages/ai/test/recorded-test.ts @@ -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" diff --git a/packages/ai/test/speech.test.ts b/packages/ai/test/speech.test.ts index 6d88a7aea22b..3d2810db65b2 100644 --- a/packages/ai/test/speech.test.ts +++ b/packages/ai/test/speech.test.ts @@ -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, 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], diff --git a/packages/ai/test/transcription.test.ts b/packages/ai/test/transcription.test.ts index 8a980afc92a2..b7dab85d2a2b 100644 --- a/packages/ai/test/transcription.test.ts +++ b/packages/ai/test/transcription.test.ts @@ -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" diff --git a/packages/app/e2e/utils/mock-api.ts b/packages/app/e2e/utils/mock-api.ts index cb559dacf343..23738625cac9 100644 --- a/packages/app/e2e/utils/mock-api.ts +++ b/packages/app/e2e/utils/mock-api.ts @@ -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" diff --git a/packages/app/e2e/utils/mock-server.ts b/packages/app/e2e/utils/mock-server.ts index eebde4b3f339..eb130245bdf6 100644 --- a/packages/app/e2e/utils/mock-server.ts +++ b/packages/app/e2e/utils/mock-server.ts @@ -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" diff --git a/packages/app/src/runtime/persistence/schema.ts b/packages/app/src/runtime/persistence/schema.ts index bab04ef3940b..4ee62a2717f9 100644 --- a/packages/app/src/runtime/persistence/schema.ts +++ b/packages/app/src/runtime/persistence/schema.ts @@ -23,14 +23,23 @@ export function withInitial>( initial: NoInfer, ) { const schema = isMigrated(definition) ? definition.current : definition - const read = isMigrated(definition) - ? SchemaParser.decodeUnknownResult(definition.read, { onExcessProperty: "preserve" }) - : Result.succeed + const read = isMigrated(definition) ? SchemaParser.decodeUnknownResult(definition.read) : Result.succeed const encode = Schema.encodeUnknownSync(schema) return Schema.Unknown.pipe( Schema.decode({ - 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)), }), diff --git a/packages/cli/src/commands/commands.ts b/packages/cli/src/commands/commands.ts index 6adc263a692d..b8d51a78bdad 100644 --- a/packages/cli/src/commands/commands.ts +++ b/packages/cli/src/commands/commands.ts @@ -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)), }, }), ], diff --git a/packages/cli/src/commands/handlers/session/list.ts b/packages/cli/src/commands/handlers/session/list.ts index 5589070c4dad..83f71782aaed 100644 --- a/packages/cli/src/commands/handlers/session/list.ts +++ b/packages/cli/src/commands/handlers/session/list.ts @@ -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 diff --git a/packages/cli/src/env.ts b/packages/cli/src/env.ts index 45340c1e0c29..8361bdb18520 100644 --- a/packages/cli/src/env.ts +++ b/packages/cli/src/env.ts @@ -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), ) diff --git a/packages/cli/src/framework/runtime.ts b/packages/cli/src/framework/runtime.ts index 76c99ab9df5e..3df1f074965a 100644 --- a/packages/cli/src/framework/runtime.ts +++ b/packages/cli/src/framework/runtime.ts @@ -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" diff --git a/packages/cli/src/framework/spec.ts b/packages/cli/src/framework/spec.ts index 587993299740..b57e46b849f5 100644 --- a/packages/cli/src/framework/spec.ts +++ b/packages/cli/src/framework/spec.ts @@ -1,4 +1,4 @@ -import { Command } from "effect/unstable/cli" +import { Command } from "effect/cli" type Options> = { readonly description?: string diff --git a/packages/cli/src/server-process.ts b/packages/cli/src/server-process.ts index cce3a2c53b99..70fd0fbe1089 100644 --- a/packages/cli/src/server-process.ts +++ b/packages/cli/src/server-process.ts @@ -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" diff --git a/packages/cli/src/services/service-registration.ts b/packages/cli/src/services/service-registration.ts index 68e3e307d458..9ca8451ae56b 100644 --- a/packages/cli/src/services/service-registration.ts +++ b/packages/cli/src/services/service-registration.ts @@ -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 diff --git a/packages/cli/src/services/standalone.ts b/packages/cli/src/services/standalone.ts index b69e13ea3ea8..275604038578 100644 --- a/packages/cli/src/services/standalone.ts +++ b/packages/cli/src/services/standalone.ts @@ -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" diff --git a/packages/cli/src/services/updater.ts b/packages/cli/src/services/updater.ts index daa95bf4dbc2..d662fadd5627 100644 --- a/packages/cli/src/services/updater.ts +++ b/packages/cli/src/services/updater.ts @@ -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" diff --git a/packages/cli/src/services/web-ui.ts b/packages/cli/src/services/web-ui.ts index 732e505f0b1e..6b4b414e75e2 100644 --- a/packages/cli/src/services/web-ui.ts +++ b/packages/cli/src/services/web-ui.ts @@ -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" diff --git a/packages/cli/src/ssh-askpass.ts b/packages/cli/src/ssh-askpass.ts index b8db12912074..be045d0946ab 100644 --- a/packages/cli/src/ssh-askpass.ts +++ b/packages/cli/src/ssh-askpass.ts @@ -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 diff --git a/packages/cli/test/cors.test.ts b/packages/cli/test/cors.test.ts index d87589ef9a6e..92e5de1fb8b3 100644 --- a/packages/cli/test/cors.test.ts +++ b/packages/cli/test/cors.test.ts @@ -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" diff --git a/packages/cli/test/fixture/upgrade.ts b/packages/cli/test/fixture/upgrade.ts index 2cf2d39f1637..42af629c045a 100644 --- a/packages/cli/test/fixture/upgrade.ts +++ b/packages/cli/test/fixture/upgrade.ts @@ -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" diff --git a/packages/cli/test/service.test.ts b/packages/cli/test/service.test.ts index e75719bef72f..f183b6ad0ddb 100644 --- a/packages/cli/test/service.test.ts +++ b/packages/cli/test/service.test.ts @@ -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, diff --git a/packages/cli/test/updater-install.test.ts b/packages/cli/test/updater-install.test.ts index 8ef9082aca73..579213bc4db4 100644 --- a/packages/cli/test/updater-install.test.ts +++ b/packages/cli/test/updater-install.test.ts @@ -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" diff --git a/packages/cli/test/web-ui.test.ts b/packages/cli/test/web-ui.test.ts index 4bc4b59b5eda..f463d3980e5a 100644 --- a/packages/cli/test/web-ui.test.ts +++ b/packages/cli/test/web-ui.test.ts @@ -2,7 +2,7 @@ import { NodeFileSystem, NodeHttpServer } from "@effect/platform-node" import { ServerProcess } from "@opencode/server/process" import { afterAll, describe, expect, test } from "bun:test" import { Effect } from "effect" -import { HttpServer, HttpServerError, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { HttpServer, HttpServerError, HttpServerRequest, HttpServerResponse } from "effect/http" import { createServer } from "node:http" import { mkdtemp, rm, writeFile } from "node:fs/promises" import { tmpdir } from "node:os" diff --git a/packages/client/package.json b/packages/client/package.json index 3f33615a1ec3..423d2224badd 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -37,7 +37,7 @@ "@opencode/protocol": "workspace:*" }, "peerDependencies": { - "effect": "4.0.0-rc.112", + "effect": "4.0.0", "solid-js": ">=1.9.0" }, "peerDependenciesMeta": { diff --git a/packages/client/src/effect/api/api.ts b/packages/client/src/effect/api/api.ts index 03b56ec7d8df..08075a197dc2 100644 --- a/packages/client/src/effect/api/api.ts +++ b/packages/client/src/effect/api/api.ts @@ -7,7 +7,6 @@ import type { Session } from "@opencode/schema/session" import type { AbsolutePath } from "@opencode/schema/schema" import type { Project } from "@opencode/schema/project" import type { RelativePath } from "@opencode/schema/schema" -import type { Brand } from "effect" import type { Model } from "@opencode/schema/model" import type { DateTime } from "effect" import type { Permission } from "@opencode/schema/permission" @@ -120,14 +119,11 @@ export type SessionListInput = { readonly directory?: AbsolutePath | undefined readonly project?: Project.ID | undefined readonly subpath?: RelativePath | undefined - readonly cursor?: (string & Brand.Brand<"SessionsCursor">) | undefined + readonly cursor?: string | undefined } export type SessionListOutput = { readonly data: ReadonlyArray - readonly cursor: { - readonly previous?: (string & Brand.Brand<"SessionsCursor">) | undefined - readonly next?: (string & Brand.Brand<"SessionsCursor">) | undefined - } + readonly cursor: { readonly previous?: string | undefined; readonly next?: string | undefined } } export type SessionListOperation = (input?: SessionListInput) => Effect.Effect @@ -150,7 +146,7 @@ export type SessionStatsOutput = { readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } } - readonly cost: number & Brand.Brand<"Money.USD"> + readonly cost: number readonly tools: | { readonly mode: "none" } | { @@ -191,7 +187,7 @@ export type SessionStatsOutput = { readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } } - readonly cost: number & Brand.Brand<"Money.USD"> + readonly cost: number }> } export type SessionStatsOperation = (input?: SessionStatsInput) => Effect.Effect @@ -432,18 +428,12 @@ export type SessionLogOutput = readonly type: "session.created" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID readonly projectID: Project.ID - readonly location: { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + readonly location: { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } readonly subpath?: RelativePath | undefined readonly parentID?: Session.ID | undefined readonly slug: string @@ -462,10 +452,7 @@ export type SessionLogOutput = readonly type: "session.agent.selected" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -480,10 +467,7 @@ export type SessionLogOutput = readonly type: "session.model.selected" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -498,17 +482,11 @@ export type SessionLogOutput = readonly type: "session.moved" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID - readonly location: { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + readonly location: { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } readonly projectID: Project.ID readonly subpath?: RelativePath | undefined } @@ -520,10 +498,7 @@ export type SessionLogOutput = readonly type: "session.renamed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly title: string } } @@ -534,10 +509,7 @@ export type SessionLogOutput = readonly type: "session.metadata.updated" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly metadata: Session.Metadata } } @@ -548,10 +520,7 @@ export type SessionLogOutput = readonly type: "session.permissions" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly permissions: Permission.Ruleset } } @@ -562,10 +531,7 @@ export type SessionLogOutput = readonly type: "session.viewed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly idle: number } } @@ -576,10 +542,7 @@ export type SessionLogOutput = readonly type: "session.deleted" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID } } @@ -590,18 +553,13 @@ export type SessionLogOutput = readonly type: "session.forked" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID readonly parentID: Session.ID readonly boundary: Session.ForkBoundary - readonly instructions?: - | { readonly [x: string & Brand.Brand<"Instruction.Key">]: string & Brand.Brand<"Instruction.Hash"> } - | undefined + readonly instructions?: { readonly [x: string]: string } | undefined readonly instructionEntries?: InstructionEntry.Snapshot | undefined } } @@ -612,10 +570,7 @@ export type SessionLogOutput = readonly type: "session.inbox.delivered" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly inboxID: SessionMessage.ID } } @@ -626,10 +581,7 @@ export type SessionLogOutput = readonly type: "session.inbox.enqueued" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -644,10 +596,7 @@ export type SessionLogOutput = readonly type: "session.inbox.cancelled" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly inboxID: SessionMessage.ID } } @@ -658,10 +607,7 @@ export type SessionLogOutput = readonly type: "session.inbox.delivery.changed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -676,10 +622,7 @@ export type SessionLogOutput = readonly type: "session.execution.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID } } @@ -690,10 +633,7 @@ export type SessionLogOutput = readonly type: "session.execution.succeeded" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID } } @@ -704,10 +644,7 @@ export type SessionLogOutput = readonly type: "session.execution.failed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -726,10 +663,7 @@ export type SessionLogOutput = readonly type: "session.execution.interrupted" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -743,14 +677,11 @@ export type SessionLogOutput = readonly type: "session.instructions.updated" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID - readonly delta: { readonly [x: string]: (string & Brand.Brand<"Instruction.Hash">) | "removed" } + readonly delta: { readonly [x: string]: string | "removed" } readonly text?: string | undefined } } @@ -761,10 +692,7 @@ export type SessionLogOutput = readonly type: "session.synthetic" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -780,10 +708,7 @@ export type SessionLogOutput = readonly type: "session.skill.activated" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -799,10 +724,7 @@ export type SessionLogOutput = readonly type: "session.shell.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly shell: Shell.Info } } @@ -813,10 +735,7 @@ export type SessionLogOutput = readonly type: "session.shell.ended" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -836,17 +755,14 @@ export type SessionLogOutput = readonly type: "session.step.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID readonly assistantMessageID: SessionMessage.ID readonly agent: Agent.ID readonly model: Model.Ref - readonly snapshot?: (string & Brand.Brand<"Snapshot.ID">) | undefined + readonly snapshot?: string | undefined readonly started: number } } @@ -857,10 +773,7 @@ export type SessionLogOutput = readonly type: "session.step.streamed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly assistantMessageID: SessionMessage.ID } } @@ -871,10 +784,7 @@ export type SessionLogOutput = readonly type: "session.step.ended" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -882,14 +792,14 @@ export type SessionLogOutput = readonly finish: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown" readonly rawFinish?: string | undefined readonly providerState?: SessionMessage.ProviderState | undefined - readonly cost: number & Brand.Brand<"Money.USD"> + readonly cost: number readonly tokens: { readonly input: number readonly output: number readonly reasoning: number readonly cache: { readonly read: number; readonly write: number } } - readonly snapshot?: (string & Brand.Brand<"Snapshot.ID">) | undefined + readonly snapshot?: string | undefined readonly files?: ReadonlyArray | undefined } } @@ -900,10 +810,7 @@ export type SessionLogOutput = readonly type: "session.step.failed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -917,7 +824,7 @@ export type SessionLogOutput = readonly finish?: "content-filter" | undefined readonly rawFinish?: string | undefined readonly providerState?: SessionMessage.ProviderState | undefined - readonly cost?: (number & Brand.Brand<"Money.USD">) | undefined + readonly cost?: number | undefined readonly tokens?: | { readonly input: number @@ -926,7 +833,7 @@ export type SessionLogOutput = readonly cache: { readonly read: number; readonly write: number } } | undefined - readonly snapshot?: (string & Brand.Brand<"Snapshot.ID">) | undefined + readonly snapshot?: string | undefined readonly files?: ReadonlyArray | undefined } } @@ -937,10 +844,7 @@ export type SessionLogOutput = readonly type: "session.text.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -955,10 +859,7 @@ export type SessionLogOutput = readonly type: "session.text.ended" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -975,10 +876,7 @@ export type SessionLogOutput = readonly type: "session.reasoning.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -994,10 +892,7 @@ export type SessionLogOutput = readonly type: "session.reasoning.ended" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1014,10 +909,7 @@ export type SessionLogOutput = readonly type: "session.tool.input.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1033,10 +925,7 @@ export type SessionLogOutput = readonly type: "session.tool.input.ended" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1052,10 +941,7 @@ export type SessionLogOutput = readonly type: "session.tool.called" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1073,10 +959,7 @@ export type SessionLogOutput = readonly type: "session.tool.success" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1114,10 +997,7 @@ export type SessionLogOutput = readonly type: "session.tool.failed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1163,10 +1043,7 @@ export type SessionLogOutput = readonly type: "session.retry.scheduled" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1188,10 +1065,7 @@ export type SessionLogOutput = readonly type: "session.compaction.started" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1207,10 +1081,7 @@ export type SessionLogOutput = readonly type: "session.compaction.ended" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1233,7 +1104,7 @@ export type SessionLogOutput = | undefined readonly text: string readonly recent: string - readonly cost?: (number & Brand.Brand<"Money.USD">) | undefined + readonly cost?: number | undefined readonly tokens?: | { readonly input: number @@ -1251,10 +1122,7 @@ export type SessionLogOutput = readonly type: "session.compaction.failed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID @@ -1266,7 +1134,7 @@ export type SessionLogOutput = readonly response?: { readonly body: string } | undefined } readonly inputID?: SessionMessage.ID | undefined - readonly cost?: (number & Brand.Brand<"Money.USD">) | undefined + readonly cost?: number | undefined readonly tokens?: | { readonly input: number @@ -1284,10 +1152,7 @@ export type SessionLogOutput = readonly type: "session.revert.staged" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly revert: Session.Revert } } @@ -1298,10 +1163,7 @@ export type SessionLogOutput = readonly type: "session.revert.cleared" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID } } @@ -1312,10 +1174,7 @@ export type SessionLogOutput = readonly type: "session.revert.committed" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID; readonly to: SessionMessage.ID } } @@ -1326,15 +1185,12 @@ export type SessionLogOutput = readonly type: "session.usage.recorded" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID readonly source: "title" | "compaction" - readonly cost: number & Brand.Brand<"Money.USD"> + readonly cost: number readonly tokens: { readonly input: number readonly output: number @@ -1350,10 +1206,7 @@ export type SessionLogOutput = readonly type: "session.message.content.updated" readonly durable: { readonly aggregateID: string; readonly seq: Event.Seq; readonly version: Event.Version } readonly location?: - | { - readonly directory: AbsolutePath - readonly workspaceID?: (string & Brand.Brand<"Workspace.ID">) | undefined - } + | { readonly directory: AbsolutePath; readonly workspaceID?: string | undefined } | undefined readonly data: { readonly sessionID: Session.ID diff --git a/packages/client/src/effect/client.ts b/packages/client/src/effect/client.ts index 7eba0c3d2ef3..c757acc80279 100644 --- a/packages/client/src/effect/client.ts +++ b/packages/client/src/effect/client.ts @@ -1,7 +1,7 @@ export * as OpenCode from "./client.js" import { Cause, Context, Effect, Stream } from "effect" -import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/http" import { SharedEvents } from "../shared-events.js" import { ClientError, OpenCode } from "./generated/index.js" import { RpcClientRuntime } from "./rpc.js" diff --git a/packages/client/src/effect/generated/client.ts b/packages/client/src/effect/generated/client.ts index e54254893672..d05df3493cdb 100644 --- a/packages/client/src/effect/generated/client.ts +++ b/packages/client/src/effect/generated/client.ts @@ -1,8 +1,8 @@ // Generated by @opencode/httpapi-codegen. Do not edit. import { Effect, Stream, Schema } from "effect" -import { Sse } from "effect/unstable/encoding" -import { HttpClientError } from "effect/unstable/http" -import { HttpApiClient } from "effect/unstable/httpapi" +import { Sse } from "effect/encoding" +import { HttpClientError } from "effect/http" +import { HttpApiClient } from "effect/http-api" import { ClientApi } from "../../contract" import type { ServerInfoOutput, diff --git a/packages/client/src/promise/generated/types.ts b/packages/client/src/promise/generated/types.ts index 1a450e13981c..18a655590caf 100644 --- a/packages/client/src/promise/generated/types.ts +++ b/packages/client/src/promise/generated/types.ts @@ -6,11 +6,19 @@ export type PairingCode = { code: string; expires_in: number } export type PairingSession = { token: string } -export type LocationPublicInfo = { directory: string; project: { id: string; directory: string; canonical: string } } +export type AbsolutePath = string -export type LocationPublicRef = { directory: string } +export type ProjectID = string -export type ModelRef = { id: string; providerID: string; variant?: string } +export type AgentID = string + +export type AgentName = string + +export type ModelID = string + +export type ProviderID = string + +export type ModelVariantID = string export type ProviderCompaction = { type: "summary" } | { type: "native" } @@ -20,6 +28,8 @@ export type AgentColor = string export type PermissionEffect = "allow" | "deny" | "ask" +export type PluginID = string + export type PluginSource = | { type: "builtin" } | { type: "package"; target: string; version?: string; outdated?: true; updating?: true } @@ -30,7 +40,7 @@ export type PluginFeatures = { server?: true; tui?: true; rpc?: true } export type PluginState = { status: "active" } | { status: "failed"; error: string; ref?: string } -export type SessionForkBoundary = { type: "before"; messageID: string } | { type: "through"; messageID: string } +export type SessionMessageID = string export type MoneyUSD = number @@ -41,8 +51,12 @@ export type TokenUsageInfo = { cache: { read: number; write: number } } +export type RelativePath = string + export type SessionMetadata = { [x: string]: JsonValue } +export type SnapshotID = string + export type FileDiffInfo = { file: string patch: string @@ -51,6 +65,8 @@ export type FileDiffInfo = { status: "added" | "deleted" | "modified" } +export type SessionsCursor = string + export type SessionStatsToolTotals = { calls: number; succeeded: number; failed: number; unfinished: number } export type SessionStatsToolUsage = { @@ -64,60 +80,17 @@ export type SessionStatsToolUsage = { export type SessionStatsActivity = { date: string; steps: number } -export type SessionMessageAgentSelected = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - type: "agent-switched" - agent: string - previous?: string -} - export type PromptBase64 = string export type PromptFileSource = { type: "inline" } | { type: "uri"; uri: string } export type PromptMention = { start: number; end: number; text: string } -export type SessionMessageSynthetic = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - text: string - description?: string - type: "synthetic" -} - -export type SessionMessageSystem = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - type: "system" - text: string - description?: string -} +export type SkillID = string -export type SessionMessageSkill = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - type: "skill" - skill: string - name: string - text: string -} +export type SkillName = string -export type SessionMessageShell = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number; completed?: number } - type: "shell" - shellID: string - command: string - status: "running" | "exited" | "timeout" | "killed" - exit?: number | "Infinity" | "-Infinity" | "NaN" - output?: { output: string; cursor: number; size: number; truncated: boolean } -} +export type ShellID = string export type SessionMessageProviderState = { [x: string]: JsonValue } @@ -135,34 +108,6 @@ export type ToolFileContent = { type: "file"; uri: string; mime: string; name?: export type SessionStructuredError = { type: string; message: string; status?: number; response?: { body: string } } -export type SessionMessageCompactionRunning = { - type: "compaction" - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - status: "running" - reason: "auto" | "manual" - summary: string - recent: string -} - -export type SessionProviderContextProvenance = { - providerID: string - provider: string - modelID: string - route: string - protocol: string - endpoint: string -} - -export type SessionMessageIdle = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - type: "idle" - outcome: "succeeded" | "failed" | "interrupted" -} - export type SessionActive = { type: "running" } export type SessionInboxDelivery = "steer" | "queue" @@ -175,23 +120,17 @@ export type InstructionEntryKey = string export type SessionGenerateResponse = { data: { text: string } } -export type LocationRef = { directory: string; workspaceID?: string } +export type EventID = string -export type SessionInboxSyntheticPayload1 = { text: string; description?: string; metadata?: { [x: string]: any } } +export type EventSeq = number -export type ShellInfo = { - id: string - status: "running" | "exited" | "timeout" | "killed" - command: string - cwd: string - shell: string - file: string - pid?: number - exit?: number - signal?: string - metadata: { [x: string]: any } - time: { started: number; completed?: number } -} +export type WorkspaceID = string + +export type InstructionKey = string + +export type InstructionHash = string + +export type SessionInboxSyntheticPayload1 = { text: string; description?: string; metadata?: { [x: string]: any } } export type SessionMessageProviderState1 = { [x: string]: any } @@ -203,10 +142,10 @@ export type SessionMessageToolStateRunning1 = { metadata: { [x: string]: JsonValue } } -export type EventLogSynced = { type: "log.synced"; aggregateID: string; seq?: number } - export type SessionInterruptResponse = { interrupted: boolean } +export type FormID = string + export type FormMetadata = { [x: string]: JsonValue } export type FormWhen = { @@ -221,6 +160,8 @@ export type FormExternalField = { key: string; type: "external"; url: string; ti export type FormValue = string | number | "Infinity" | "-Infinity" | "NaN" | boolean | Array +export type ModelFamily = string + export type ModelReasoningField = "reasoning" | "reasoning_content" | "reasoning_text" | (string & {}) export type ModelMaxTokensField = "max_completion_tokens" | "max_tokens" @@ -231,19 +172,17 @@ export type MoneyUSDPerMillionTokens = number export type GenerateTextResponse = { data: { text: string } } -export type IntegrationCommandMethod = { id: string; type: "command"; label: string; command: Array } +export type IntegrationID = string + +export type IntegrationMethodID = string export type IntegrationEnvMethod = { type: "env"; names: Array } +export type CredentialID = string + export type ConnectionStatus = { status: "needs_auth"; message: string; url?: string } -export type IntegrationAttempt = { - attemptID: string - url: string - instructions: string - mode: "auto" | "code" - time: { created: number; expires: number } -} +export type IntegrationAttemptID = string export type IntegrationAttemptStatus = | { status: "pending"; time: { created: number; expires: number } } @@ -251,8 +190,6 @@ export type IntegrationAttemptStatus = | { status: "failed"; message: string; time: { created: number; expires: number } } | { status: "expired"; time: { created: number; expires: number } } -export type IntegrationCommandAttempt = { attemptID: string; time: { created: number; expires: number } } - export type IntegrationCommandAttemptStatus = | { status: "pending" @@ -293,15 +230,6 @@ export type McpResourceTemplate = { mimeType?: string } -export type CredentialOAuth = { - type: "oauth" - methodID: string - refresh: string - access: string - expires: number - metadata?: { [x: string]: JsonValue } -} - export type ProjectVcs = string export type ProjectIcon = { url?: string; override?: string; color?: string } @@ -310,61 +238,18 @@ export type ProjectCommands = { start?: string } export type ProjectTime = { created: number; updated: number; active: number } -export type PermissionSource = { type: "tool"; messageID: string; id: string } - -export type PermissionSavedInfo = { - id: string - projectID: string - action: string - resource: string - time: { created: number; updated: number } -} +export type PermissionID = string -export type FileSystemEntry = { path: string; type: "file" | "directory" } +export type PermissionSource = { type: "tool"; messageID: string; id: string } -export type FileSystemWrite = { path: string } +export type PermissionSavedID = string export type CommandInfo = { name: string; description?: string } -export type SkillInfo = { - id: string - name: string - description?: string - autoinvoke?: boolean - path: string - content: string -} - export type RpcOutput = { output?: any } export type PermissionReply = "once" | "always" | "reject" -export type Pty = { - id: string - title: string - command: string - args: Array - cwd: string - status: "running" | "exited" - pid: number - exitCode?: number -} - -export type PersistentPtyInfo = { - id: string - title: string - command: string - args: Array - cwd: string - status: "running" | "exited" - pid: number - exitCode?: number - sessionID: string - foregroundProcess: string | null - size: { cols: number; rows: number } - output: { head: number; tail: number } -} - export type FormMetadata1 = { [x: string]: any } export type FormWhen1 = { key: string; op: "eq" | "neq"; value: string | number | boolean } @@ -384,38 +269,10 @@ export type SessionStatus = export type PtyTicketConnectToken = { ticket: string; expires_in: number } -export type PersistentPtyReadResult = { - ptyID: string - title: string - cwd: string - foregroundProcess: string | null - screen: { text: string; cols: number; rows: number; cursor: { x: number; y: number } } -} - export type PersistentPtyHandoff = { directory: string; instanceID: string; ticket: string; expiresAt: number } -export type ShellInfo1 = { - id: string - status: "running" | "exited" | "timeout" | "killed" - command: string - cwd: string - shell: string - file: string - pid?: number - exit?: number - signal?: string - metadata: { [x: string]: JsonValue } - time: { started: number; completed?: number } -} - -export type ReferenceLocalSource = { type: "local"; path: string } - export type ReferenceGitSource = { type: "git"; repository: string; branch?: string } -export type WorktreeDirectory = { directory: string; strategy?: string } - -export type WorktreeInfo = { directory: string } - export type VcsBranch = { current?: string; default?: string } export type VcsBase = { name: string; ref: string; source: "reflog" | "default" } @@ -429,7 +286,7 @@ export type VcsFileStatus = { export type VcsBranchList = Array -export type WebSearchProvider = { id: string; name: string } +export type WebSearchID = string export type WebSearchResult = { url: string; title?: string; content?: string; time: { published?: number } } @@ -439,36 +296,32 @@ export type ConfigWorktree = { directory: string } export type ConfigShellOption = { path: string; name: string; acceptable: boolean } -export type SessionMessageLocationSwitched = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - type: "location-switched" - projectID?: string - subpath?: string - location: LocationPublicRef - previous?: { location: LocationPublicRef; projectID?: string; subpath?: string } | null -} +export type LocationPublicRef = { directory: AbsolutePath } -export type SessionInboxMovePayload = { projectID: string; subpath?: string; location: LocationPublicRef } +export type FileSystemWrite = { path: AbsolutePath } -export type V2EventRpc = { - id: string - created: number - metadata?: { [x: string]: any } | undefined - type: `${"rpc."}${string}` - location: LocationPublicRef - data: { [x: string]: any } +export type ReferenceLocalSource = { type: "local"; path: AbsolutePath } + +export type WorktreeDirectory = { directory: AbsolutePath; strategy?: string } + +export type WorktreeInfo = { directory: AbsolutePath } + +export type LocationPublicInfo = { + directory: AbsolutePath + project: { id: ProjectID; directory: AbsolutePath; canonical: AbsolutePath } } -export type V2EventServerConnected = { - id: string - metadata?: { [x: string]: any } | undefined - location?: LocationPublicRef | undefined - type: "server.connected" - data: {} +export type SessionProviderContextProvenance = { + providerID: ProviderID + provider: string + modelID: string + route: string + protocol: string + endpoint: string } +export type ModelRef = { id: ModelID; providerID: ProviderID; variant?: ModelVariantID } + export type ModelSettings = { compaction?: ProviderCompaction } & { [x: string]: any } export type ConfigModelSettings = { compaction?: ProviderCompaction } & { [x: string]: JsonValue | null } @@ -489,68 +342,171 @@ export type ConfigProviderSettings = { export type PermissionRule = { action: string; resource: string; effect: PermissionEffect } -export type PluginInfo = { id?: string; source: PluginSource; features: PluginFeatures; state: PluginState } +export type PluginInfo = { id?: PluginID; source: PluginSource; features: PluginFeatures; state: PluginState } -export type SessionRevert = { messageID: string; partID?: string; snapshot?: string; files?: Array } +export type SessionForkBoundary = + | { type: "before"; messageID: SessionMessageID } + | { type: "through"; messageID: SessionMessageID } -export type SessionStatsTools = - | { mode: "none" } - | { mode: "summary"; totals: SessionStatsToolTotals } - | { mode: "detail"; totals: SessionStatsToolTotals; usage: Array } - -export type SessionStatsModelUsage = { model: ModelRef; steps: number; tokens: TokenUsageInfo; cost: MoneyUSD } - -export type SessionMessageModelSelected = { - id: string +export type SessionMessageAgentSelected = { + id: SessionMessageID metadata?: { [x: string]: JsonValue } time: { created: number } - type: "model-switched" - model: ModelRef - previous?: ModelRef + type: "agent-switched" + agent: AgentID + previous?: AgentID } -export type PromptFileAttachment = { - data: PromptBase64 - mime: string - source: PromptFileSource - name?: string +export type SessionMessageSynthetic = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + text: string description?: string - mention?: PromptMention + type: "synthetic" } -export type PromptAgentAttachment = { name: string; mention?: PromptMention } - -export type PromptSkillAttachment = { id: string; name: string; text?: string; mention?: PromptMention } - -export type SessionMessageAssistantText = { type: "text"; text: string; state?: SessionMessageProviderState } - -export type SessionMessageAssistantReasoning = { - type: "reasoning" +export type SessionMessageSystem = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + type: "system" text: string - state?: SessionMessageProviderState - time?: { created: number; completed?: number } + description?: string } -export type ToolContent = ToolTextContent | ToolFileContent - -export type SessionMessageAssistantRetry = { attempt: number; at: number; error: SessionStructuredError } - -export type SessionMessageCompactionFailed = { +export type SessionMessageCompactionRunning = { type: "compaction" - id: string + id: SessionMessageID metadata?: { [x: string]: JsonValue } time: { created: number } - status: "failed" + status: "running" + reason: "auto" | "manual" + summary: string + recent: string +} + +export type SessionMessageIdle = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + type: "idle" + outcome: "succeeded" | "failed" | "interrupted" +} + +export type FileSystemEntry = { path: RelativePath; type: "file" | "directory" } + +export type SessionRevert = { + messageID: SessionMessageID + partID?: string + snapshot?: SnapshotID + files?: Array +} + +export type SessionStatsTools = + | { mode: "none" } + | { mode: "summary"; totals: SessionStatsToolTotals } + | { mode: "detail"; totals: SessionStatsToolTotals; usage: Array } + +export type PromptFileAttachment = { + data: PromptBase64 + mime: string + source: PromptFileSource + name?: string + description?: string + mention?: PromptMention +} + +export type PromptAgentAttachment = { name: string; mention?: PromptMention } + +export type PromptSkillAttachment = { id: SkillID; name: SkillName; text?: string; mention?: PromptMention } + +export type SessionMessageSkill = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + type: "skill" + skill: SkillID + name: SkillName + text: string +} + +export type SkillInfo = { + id: SkillID + name: SkillName + description?: string + autoinvoke?: boolean + path: AbsolutePath + content: string +} + +export type SessionMessageShell = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number; completed?: number } + type: "shell" + shellID: ShellID + command: string + status: "running" | "exited" | "timeout" | "killed" + exit?: number | "Infinity" | "-Infinity" | "NaN" + output?: { output: string; cursor: number; size: number; truncated: boolean } +} + +export type ShellInfo = { + id: ShellID + status: "running" | "exited" | "timeout" | "killed" + command: string + cwd: string + shell: string + file: string + pid?: number + exit?: number + signal?: string + metadata: { [x: string]: any } + time: { started: number; completed?: number } +} + +export type ShellInfo1 = { + id: ShellID + status: "running" | "exited" | "timeout" | "killed" + command: string + cwd: string + shell: string + file: string + pid?: number + exit?: number + signal?: string + metadata: { [x: string]: JsonValue } + time: { started: number; completed?: number } +} + +export type SessionMessageAssistantText = { type: "text"; text: string; state?: SessionMessageProviderState } + +export type SessionMessageAssistantReasoning = { + type: "reasoning" + text: string + state?: SessionMessageProviderState + time?: { created: number; completed?: number } +} + +export type ToolContent = ToolTextContent | ToolFileContent + +export type SessionMessageAssistantRetry = { attempt: number; at: number; error: SessionStructuredError } + +export type SessionMessageCompactionFailed = { + type: "compaction" + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + status: "failed" reason: "auto" | "manual" error: SessionStructuredError cost?: MoneyUSD tokens?: TokenUsageInfo } -export type SessionProviderContext = { version: 1; provenance: SessionProviderContextProvenance; messages: JsonValue } - export type SessionInboxSynthetic = { - id: string + id: SessionMessageID sessionID: string time: { created: number } type: "synthetic" @@ -559,7 +515,7 @@ export type SessionInboxSynthetic = { } export type SessionInboxCompaction = { - id: string + id: SessionMessageID sessionID: string time: { created: number } type: "compaction" @@ -571,949 +527,1047 @@ export type InstructionEntryInfo = { key: InstructionEntryKey; value: JsonValue export type InstructionEntrySnapshot = Array<{ key: InstructionEntryKey; value: JsonValue; removed: boolean }> -export type SessionAgentSelected = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.agent.selected" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; agent: string; previous?: string } +export type EventLogSynced = { type: "log.synced"; aggregateID: string; seq?: EventSeq } + +export type LocationRef = { directory: AbsolutePath; workspaceID?: WorkspaceID } + +export type SessionMessageAssistantText1 = { type: "text"; text: string; state?: SessionMessageProviderState1 } + +export type SessionMessageAssistantReasoning1 = { + type: "reasoning" + text: string + state?: SessionMessageProviderState1 + time?: { created: number; completed?: number } } -export type SessionModelSelected = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.model.selected" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; model: ModelRef; previous?: ModelRef } +export type ToolContent1 = ToolTextContent | ToolFileContent1 + +export type FormNumberField = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "number" + minimum?: number | "Infinity" | "-Infinity" | "NaN" + maximum?: number | "Infinity" | "-Infinity" | "NaN" + default?: number | "Infinity" | "-Infinity" | "NaN" } -export type SessionRenamed = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.renamed" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; title: string } +export type FormIntegerField = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "integer" + minimum?: number | "Infinity" | "-Infinity" | "NaN" + maximum?: number | "Infinity" | "-Infinity" | "NaN" + default?: number | "Infinity" | "-Infinity" | "NaN" } -export type SessionViewed = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.viewed" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; idle: number } +export type FormBooleanField = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "boolean" + default?: boolean } -export type SessionDeleted = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.deleted" - durable: { aggregateID: string; seq: number; version: 2 } - location?: LocationRef - data: { sessionID: string } +export type FormStringField = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "string" + format?: "email" | "uri" | "date" | "date-time" + minLength?: number + maxLength?: number + pattern?: string + placeholder?: string + default?: string + options?: Array + custom?: boolean } -export type SessionInboxDelivered = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.inbox.delivered" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; inboxID: string } +export type FormMultiselectField = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "multiselect" + options: Array + minItems?: number + maxItems?: number + custom?: boolean + default?: Array } -export type SessionInboxCancelled = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.inbox.cancelled" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; inboxID: string } +export type FormAnswer = { [x: string]: FormValue } + +export type ModelCompatibility = { + reasoningField?: ModelReasoningField + requireReasoning?: boolean + maxTokensField?: ModelMaxTokensField + requireFinishReason?: boolean + requireAssistantAfterTool?: boolean + supportsPromptCacheKey?: boolean } -export type SessionInboxDeliveryChanged = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.inbox.delivery.changed" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; inboxID: string; delivery: SessionInboxDelivery } +export type ModelCost = { + tier?: { type: "context"; size: number } + input: MoneyUSDPerMillionTokens + output: MoneyUSDPerMillionTokens + cache: { read: MoneyUSDPerMillionTokens; write: MoneyUSDPerMillionTokens } } -export type SessionExecutionStarted = { +export type IntegrationCommandMethod = { + id: IntegrationMethodID + type: "command" + label: string + command: Array +} + +export type CredentialOAuth = { + type: "oauth" + methodID: IntegrationMethodID + refresh: string + access: string + expires: number + metadata?: { [x: string]: JsonValue } +} + +export type ConnectionCredentialInfo = { + type: "credential" + id: CredentialID + label: string + method: "key" | "oauth" + status?: ConnectionStatus +} + +export type ConnectionEnvInfo = { type: "env"; name: string; status?: ConnectionStatus } + +export type IntegrationCommandAttempt = { attemptID: IntegrationAttemptID; time: { created: number; expires: number } } + +export type McpServer = { + name: string + status: McpStatusConnected | McpStatusPending | McpStatusDisabled | McpStatusFailed | McpStatusNeedsAuth + integrationID?: IntegrationID +} + +export type McpResourceCatalog = { resources: Array; templates: Array } + +export type Project = { + id: ProjectID + canonical: AbsolutePath + vcs?: ProjectVcs + name?: string + icon?: ProjectIcon + commands?: ProjectCommands + time: ProjectTime + sandboxes: Array +} + +export type PermissionRequest = { + id: PermissionID + sessionID: string + action: string + resources: Array + save?: Array + metadata?: { [x: string]: JsonValue } + source?: PermissionSource + message?: string +} + +export type PermissionSavedInfo = { + id: PermissionSavedID + projectID: ProjectID + action: string + resource: string + time: { created: number; updated: number } +} + +export type Pty = { id: string - created: number - metadata?: { [x: string]: any } - type: "session.execution.started" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string } + title: string + command: string + args: Array + cwd: string + status: "running" | "exited" + pid: number + exitCode?: number } -export type SessionExecutionSucceeded = { +export type PersistentPtyInfo = { id: string - created: number - metadata?: { [x: string]: any } - type: "session.execution.succeeded" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string } + title: string + command: string + args: Array + cwd: string + status: "running" | "exited" + pid: number + exitCode?: number + sessionID: string + foregroundProcess: string | null + size: { cols: number; rows: number } + output: { head: number; tail: number } +} + +export type PersistentPtyReadResult = { + ptyID: string + title: string + cwd: string + foregroundProcess: string | null + screen: { text: string; cols: number; rows: number; cursor: { x: number; y: number } } +} + +export type FormStringField1 = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "string" + format?: "email" | "uri" | "date" | "date-time" + minLength?: number + maxLength?: number + pattern?: string + placeholder?: string + default?: string + options?: Array + custom?: boolean +} + +export type FormNumberField1 = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "number" + minimum?: number + maximum?: number + default?: number +} + +export type FormIntegerField1 = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "integer" + minimum?: number + maximum?: number + default?: number +} + +export type FormBooleanField1 = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "boolean" + default?: boolean +} + +export type FormMultiselectField1 = { + key: string + title?: string + description?: string + required?: boolean + hidden?: boolean + when?: Array + type: "multiselect" + options: Array + minItems?: number + maxItems?: number + custom?: boolean + default?: Array +} + +export type FormAnswer2 = { [x: string]: FormValue1 } + +export type VcsInfo = { provider?: string; branch: VcsBranch } + +export type WebSearchProvider = { id: WebSearchID; name: string } + +export type SessionMessageLocationSwitched = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + type: "location-switched" + projectID?: ProjectID + subpath?: RelativePath + location: LocationPublicRef + previous?: { location: LocationPublicRef; projectID?: ProjectID; subpath?: RelativePath } | null +} + +export type SessionInboxMovePayload = { projectID: ProjectID; subpath?: RelativePath; location: LocationPublicRef } + +export type V2EventRpc = { + id: EventID + created: number + metadata?: { [x: string]: any } | undefined + type: `${"rpc."}${string}` + location: LocationPublicRef + data: { [x: string]: any } } -export type SessionExecutionFailed = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.execution.failed" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; error: SessionStructuredError } +export type V2EventServerConnected = { + id: EventID + metadata?: { [x: string]: any } | undefined + location?: LocationPublicRef | undefined + type: "server.connected" + data: {} } -export type SessionExecutionInterrupted = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.execution.interrupted" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; reason: "user" | "shutdown" | "superseded" | "inactivity" } +export type ReferenceSource = ReferenceLocalSource | ReferenceGitSource + +export type WorktreeList = Array + +export type SessionProviderContext = { version: 1; provenance: SessionProviderContextProvenance; messages: JsonValue } + +export type SessionStatsModelUsage = { model: ModelRef; steps: number; tokens: TokenUsageInfo; cost: MoneyUSD } + +export type SessionMessageModelSelected = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + type: "model-switched" + model: ModelRef + previous?: ModelRef } -export type SessionInstructionsUpdated = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.instructions.updated" - durable: { aggregateID: string; seq: number; version: 2 } - location?: LocationRef - data: { sessionID: string; delta: { [x: string]: string | "removed" }; text?: string } +export type ModelVariant = { + id: ModelVariantID + settings?: ModelSettings + headers?: { [x: string]: string } + body?: { [x: string]: any } } -export type SessionSynthetic = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.synthetic" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; text: string; description?: string; metadata?: { [x: string]: any } } +export type ProviderRequest = { + settings: ProviderSettings + headers: { [x: string]: string } + body: { [x: string]: any } } -export type SessionSkillActivated = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.skill.activated" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; id: string; name: string; text: string } +export type ProviderInfo = { + id: ProviderID + canonical?: ProviderID + integrationID?: IntegrationID + name: string + activation: "auto" | "enabled" | "disabled" + package: string + settings?: ProviderSettings + headers?: { [x: string]: string } + body?: { [x: string]: any } } -export type SessionStepStarted = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.step.started" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { - sessionID: string - assistantMessageID: string - agent: string - model: ModelRef - snapshot?: string - started: number - } +export type PermissionRuleset = Array + +export type SessionMessageUser = { + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + text: string + files?: Array + agents?: Array + skills?: Array + type: "user" } -export type SessionStepStreamed = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.step.streamed" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; assistantMessageID: string } +export type SessionInboxUserPayload = { + text: string + files?: Array + agents?: Array + skills?: Array + metadata?: { [x: string]: JsonValue } } -export type SessionTextStarted = { - id: string - created: number +export type SessionInboxUserPayload1 = { + text: string + files?: Array + agents?: Array + skills?: Array metadata?: { [x: string]: any } - type: "session.text.started" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; assistantMessageID: string; ordinal: number } } -export type SessionToolInputStarted = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.tool.input.started" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; assistantMessageID: string; id: string; name: string } +export type SessionMessageToolStateCompleted = { + status: "completed" + input: { [x: string]: JsonValue } + content: [ToolContent, ...Array] + metadata?: { [x: string]: JsonValue } } -export type SessionToolInputEnded = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.tool.input.ended" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; assistantMessageID: string; id: string; text: string } +export type SessionMessageToolStateError = { + status: "error" + input: { [x: string]: JsonValue } + error: SessionStructuredError + content?: [ToolContent, ...Array] + metadata?: { [x: string]: JsonValue } } -export type SessionRetryScheduled = { - id: string +export type SessionAgentSelected = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.retry.scheduled" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.agent.selected" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; assistantMessageID: string; attempt: number; at: number; error: SessionStructuredError } + data: { sessionID: string; agent: AgentID; previous?: AgentID } } -export type SessionCompactionStarted = { - id: string +export type SessionModelSelected = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.compaction.started" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.model.selected" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; reason: "auto" | "manual"; recent: string; inputID?: string } + data: { sessionID: string; model: ModelRef; previous?: ModelRef } } -export type SessionCompactionFailed = { - id: string +export type SessionMoved = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.compaction.failed" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.moved" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { - sessionID: string - reason: "auto" | "manual" - error: SessionStructuredError - inputID?: string - cost?: MoneyUSD - tokens?: TokenUsageInfo - } + data: { sessionID: string; location: LocationRef; projectID: ProjectID; subpath?: RelativePath } } -export type SessionRevertCleared = { - id: string +export type SessionRenamed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.revert.cleared" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.renamed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string } + data: { sessionID: string; title: string } } -export type SessionRevertCommitted = { - id: string +export type SessionMetadataUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.revert.committed" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.metadata.updated" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; to: string } + data: { sessionID: string; metadata: SessionMetadata } } -export type SessionUsageRecorded = { - id: string +export type SessionViewed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.usage.recorded" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.viewed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; source: "title" | "compaction"; cost: MoneyUSD; tokens: TokenUsageInfo } + data: { sessionID: string; idle: number } } -export type LocationShutdown = { - id: string +export type SessionDeleted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "location.shutdown" + type: "session.deleted" + durable: { aggregateID: string; seq: EventSeq; version: 2 } location?: LocationRef - data: {} + data: { sessionID: string } } -export type ModelsDevRefreshed = { - id: string +export type SessionForked = { + id: EventID created: number metadata?: { [x: string]: any } - type: "models-dev.refreshed" + type: "session.forked" + durable: { aggregateID: string; seq: EventSeq; version: 2 } location?: LocationRef - data: {} + data: { + sessionID: string + parentID: string + boundary: SessionForkBoundary + instructions?: { [x: InstructionKey]: InstructionHash } + instructionEntries?: InstructionEntrySnapshot + } } -export type CredentialUpdated = { - id: string +export type SessionInboxDelivered = { + id: EventID created: number metadata?: { [x: string]: any } - type: "credential.updated" + type: "session.inbox.delivered" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string; inboxID: SessionMessageID } } -export type CredentialSwitched = { - id: string +export type SessionInboxMovePayload1 = { location: LocationRef; projectID: ProjectID; subpath?: RelativePath } + +export type SessionInboxCancelled = { + id: EventID created: number metadata?: { [x: string]: any } - type: "credential.switched" + type: "session.inbox.cancelled" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { integrationID: string; credentialID: string | null } + data: { sessionID: string; inboxID: SessionMessageID } } -export type IntegrationUpdated = { - id: string +export type SessionInboxDeliveryChanged = { + id: EventID created: number metadata?: { [x: string]: any } - type: "integration.updated" + type: "session.inbox.delivery.changed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string; inboxID: SessionMessageID; delivery: SessionInboxDelivery } } -export type ProviderUpdated = { - id: string +export type SessionExecutionStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "provider.updated" + type: "session.execution.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string } } -export type ModelUpdated = { - id: string +export type SessionExecutionSucceeded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "model.updated" + type: "session.execution.succeeded" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string } } -export type AgentUpdated = { - id: string +export type SessionExecutionFailed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "agent.updated" + type: "session.execution.failed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string; error: SessionStructuredError } } -export type SessionUsageUpdated = { - id: string +export type SessionExecutionInterrupted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.usage.updated" + type: "session.execution.interrupted" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; cost: MoneyUSD; tokens: TokenUsageInfo } + data: { sessionID: string; reason: "user" | "shutdown" | "superseded" | "inactivity" } } -export type SessionTextDelta = { - id: string +export type SessionInstructionsUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.text.delta" + type: "session.instructions.updated" + durable: { aggregateID: string; seq: EventSeq; version: 2 } location?: LocationRef - data: { sessionID: string; assistantMessageID: string; ordinal: number; delta: string } + data: { sessionID: string; delta: { [x: string]: InstructionHash | "removed" }; text?: string } } -export type SessionReasoningDelta = { - id: string +export type SessionSynthetic = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.reasoning.delta" + type: "session.synthetic" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; assistantMessageID: string; ordinal: number; delta: string } + data: { sessionID: string; text: string; description?: string; metadata?: { [x: string]: any } } } -export type SessionToolInputDelta = { - id: string +export type SessionSkillActivated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.tool.input.delta" + type: "session.skill.activated" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; assistantMessageID: string; id: string; delta: string } + data: { sessionID: string; id: SkillID; name: SkillName; text: string } } -export type SessionToolProgress = { - id: string +export type SessionShellStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.tool.progress" + type: "session.shell.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; assistantMessageID: string; id: string; metadata: { [x: string]: JsonValue } } + data: { sessionID: string; shell: ShellInfo } } -export type SessionCompactionDelta = { - id: string +export type SessionShellEnded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.compaction.delta" + type: "session.shell.ended" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; text: string } + data: { + sessionID: string + shell: ShellInfo + output: { output: string; cursor: number; size: number; truncated: boolean } + } } -export type FilesystemChanged = { - id: string +export type SessionStepStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "filesystem.changed" + type: "session.step.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { file: string; event: "add" | "change" | "unlink" } + data: { + sessionID: string + assistantMessageID: SessionMessageID + agent: AgentID + model: ModelRef + snapshot?: SnapshotID + started: number + } } -export type ReferenceUpdated = { - id: string +export type SessionStepStreamed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "reference.updated" + type: "session.step.streamed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string; assistantMessageID: SessionMessageID } } -export type PluginUpdated = { - id: string +export type SessionStepEnded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "plugin.updated" + type: "session.step.ended" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { + sessionID: string + assistantMessageID: SessionMessageID + finish: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown" + rawFinish?: string + providerState?: SessionMessageProviderState1 + cost: MoneyUSD + tokens: TokenUsageInfo + snapshot?: SnapshotID + files?: Array + } } -export type WorktreeUpdated = { - id: string +export type SessionStepFailed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "worktree.updated" + type: "session.step.failed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { projectID: string } + data: { + sessionID: string + assistantMessageID: SessionMessageID + error: SessionStructuredError + finish?: "content-filter" + rawFinish?: string + providerState?: SessionMessageProviderState1 + cost?: MoneyUSD + tokens?: TokenUsageInfo + snapshot?: SnapshotID + files?: Array + } } -export type WorktreeResolved = { - id: string +export type SessionTextStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "worktree.resolved" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.text.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { projectID: string; directory: string; previous: string; adopted?: Array } + data: { sessionID: string; assistantMessageID: SessionMessageID; ordinal: number } } -export type CommandUpdated = { - id: string +export type SessionTextEnded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "command.updated" + type: "session.text.ended" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { + sessionID: string + assistantMessageID: SessionMessageID + ordinal: number + text: string + state?: SessionMessageProviderState1 + } } -export type ConfigUpdated = { - id: string +export type SessionReasoningStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "config.updated" + type: "session.reasoning.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { + sessionID: string + assistantMessageID: SessionMessageID + ordinal: number + state?: SessionMessageProviderState1 + } } -export type SkillUpdated = { - id: string +export type SessionReasoningEnded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "skill.updated" + type: "session.reasoning.ended" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { + sessionID: string + assistantMessageID: SessionMessageID + ordinal: number + text: string + state?: SessionMessageProviderState1 + } } -export type PtyExited = { - id: string +export type SessionToolInputStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "pty.exited" + type: "session.tool.input.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { id: string; exitCode: number } + data: { sessionID: string; assistantMessageID: SessionMessageID; id: string; name: string } } -export type PtyDeleted = { - id: string +export type SessionToolInputEnded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "pty.deleted" + type: "session.tool.input.ended" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { id: string } + data: { sessionID: string; assistantMessageID: SessionMessageID; id: string; text: string } } -export type PersistentPtyRemoved = { - id: string +export type SessionToolCalled = { + id: EventID created: number metadata?: { [x: string]: any } - type: "persistent-pty.removed" + type: "session.tool.called" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; ptyID: string } + data: { + sessionID: string + assistantMessageID: SessionMessageID + id: string + input: { [x: string]: any } + executed: boolean + state?: SessionMessageProviderState1 + } } -export type ShellExited = { - id: string +export type SessionRetryScheduled = { + id: EventID created: number metadata?: { [x: string]: any } - type: "shell.exited" + type: "session.retry.scheduled" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { id: string; exit?: number; status: "running" | "exited" | "timeout" | "killed" } + data: { + sessionID: string + assistantMessageID: SessionMessageID + attempt: number + at: number + error: SessionStructuredError + } } -export type ShellDeleted = { - id: string +export type SessionCompactionStarted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "shell.deleted" + type: "session.compaction.started" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { id: string } + data: { sessionID: string; reason: "auto" | "manual"; recent: string; inputID?: SessionMessageID } } -export type FormCancelled = { - id: string +export type SessionCompactionFailed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "form.cancelled" + type: "session.compaction.failed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { id: string; sessionID: string } + data: { + sessionID: string + reason: "auto" | "manual" + error: SessionStructuredError + inputID?: SessionMessageID + cost?: MoneyUSD + tokens?: TokenUsageInfo + } } -export type WebsearchUpdated = { - id: string +export type SessionRevertStaged = { + id: EventID created: number metadata?: { [x: string]: any } - type: "websearch.updated" + type: "session.revert.staged" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: {} + data: { sessionID: string; revert: SessionRevert } } -export type SessionIdle = { - id: string +export type SessionRevertCleared = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.idle" + type: "session.revert.cleared" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef data: { sessionID: string } } -export type TuiPromptAppend = { - id: string +export type SessionRevertCommitted = { + id: EventID created: number metadata?: { [x: string]: any } - type: "tui.prompt.append" + type: "session.revert.committed" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { text: string } + data: { sessionID: string; to: SessionMessageID } } -export type TuiCommandExecute = { - id: string +export type SessionUsageRecorded = { + id: EventID created: number metadata?: { [x: string]: any } - type: "tui.command.execute" + type: "session.usage.recorded" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { - command: - | "session.list" - | "session.new" - | "session.share" - | "session.interrupt" - | "session.background" - | "session.compact" - | "session.page.up" - | "session.page.down" - | "session.line.up" - | "session.line.down" - | "session.half.page.up" - | "session.half.page.down" - | "session.first" - | "session.last" - | "prompt.clear" - | "prompt.submit" - | "agent.cycle" - | (string & {}) - } + data: { sessionID: string; source: "title" | "compaction"; cost: MoneyUSD; tokens: TokenUsageInfo } } -export type TuiToastShow = { - id: string +export type LocationShutdown = { + id: EventID created: number metadata?: { [x: string]: any } - type: "tui.toast.show" + type: "location.shutdown" location?: LocationRef - data: { - title?: string - message: string - variant: "info" | "success" | "warning" | "error" - duration?: number | undefined - } + data: {} } -export type TuiSessionSelect = { - id: string +export type ModelsDevRefreshed = { + id: EventID created: number metadata?: { [x: string]: any } - type: "tui.session.select" + type: "models-dev.refreshed" location?: LocationRef - data: { sessionID: string } + data: {} } -export type InstallationUpdated = { - id: string +export type CredentialUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "installation.updated" + type: "credential.updated" location?: LocationRef - data: { version: string } + data: {} } -export type InstallationUpdateAvailable = { - id: string +export type CredentialSwitched = { + id: EventID created: number metadata?: { [x: string]: any } - type: "installation.update-available" + type: "credential.switched" location?: LocationRef - data: { version: string } + data: { integrationID: IntegrationID; credentialID: CredentialID | null } } -export type VcsBranchUpdated = { - id: string +export type IntegrationUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "vcs.branch.updated" + type: "integration.updated" location?: LocationRef - data: { branch?: string } + data: {} } -export type McpStatusChanged = { - id: string +export type ProviderUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "mcp.status.changed" + type: "provider.updated" location?: LocationRef - data: { server: string } + data: {} } -export type McpResourcesChanged = { - id: string +export type ModelUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "mcp.resources.changed" + type: "model.updated" location?: LocationRef - data: { server: string } + data: {} } -export type SessionMoved = { - id: string +export type AgentUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.moved" - durable: { aggregateID: string; seq: number; version: 1 } + type: "agent.updated" location?: LocationRef - data: { sessionID: string; location: LocationRef; projectID: string; subpath?: string } + data: {} } -export type SessionInboxMovePayload1 = { location: LocationRef; projectID: string; subpath?: string } - -export type SessionMetadataUpdated = { - id: string +export type SessionUsageUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.metadata.updated" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.usage.updated" location?: LocationRef - data: { sessionID: string; metadata: SessionMetadata } + data: { sessionID: string; cost: MoneyUSD; tokens: TokenUsageInfo } } -export type SessionShellStarted = { - id: string +export type SessionTextDelta = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.shell.started" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.text.delta" location?: LocationRef - data: { sessionID: string; shell: ShellInfo } + data: { sessionID: string; assistantMessageID: SessionMessageID; ordinal: number; delta: string } } -export type SessionShellEnded = { - id: string +export type SessionReasoningDelta = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.shell.ended" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.reasoning.delta" location?: LocationRef - data: { - sessionID: string - shell: ShellInfo - output: { output: string; cursor: number; size: number; truncated: boolean } - } + data: { sessionID: string; assistantMessageID: SessionMessageID; ordinal: number; delta: string } } -export type ShellCreated = { - id: string +export type SessionToolInputDelta = { + id: EventID created: number metadata?: { [x: string]: any } - type: "shell.created" + type: "session.tool.input.delta" location?: LocationRef - data: { info: ShellInfo } + data: { sessionID: string; assistantMessageID: SessionMessageID; id: string; delta: string } } -export type SessionStepEnded = { - id: string +export type SessionToolProgress = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.step.ended" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.tool.progress" location?: LocationRef - data: { - sessionID: string - assistantMessageID: string - finish: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown" - rawFinish?: string - providerState?: SessionMessageProviderState1 - cost: MoneyUSD - tokens: TokenUsageInfo - snapshot?: string - files?: Array - } + data: { sessionID: string; assistantMessageID: SessionMessageID; id: string; metadata: { [x: string]: JsonValue } } } -export type SessionStepFailed = { - id: string +export type SessionCompactionDelta = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.step.failed" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.compaction.delta" location?: LocationRef - data: { - sessionID: string - assistantMessageID: string - error: SessionStructuredError - finish?: "content-filter" - rawFinish?: string - providerState?: SessionMessageProviderState1 - cost?: MoneyUSD - tokens?: TokenUsageInfo - snapshot?: string - files?: Array - } + data: { sessionID: string; text: string } } -export type SessionTextEnded = { - id: string +export type FilesystemChanged = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.text.ended" - durable: { aggregateID: string; seq: number; version: 1 } + type: "filesystem.changed" location?: LocationRef - data: { - sessionID: string - assistantMessageID: string - ordinal: number - text: string - state?: SessionMessageProviderState1 - } + data: { file: string; event: "add" | "change" | "unlink" } } -export type SessionReasoningStarted = { - id: string +export type ReferenceUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.reasoning.started" - durable: { aggregateID: string; seq: number; version: 1 } + type: "reference.updated" location?: LocationRef - data: { sessionID: string; assistantMessageID: string; ordinal: number; state?: SessionMessageProviderState1 } + data: {} } -export type SessionReasoningEnded = { - id: string +export type PermissionAsked = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.reasoning.ended" - durable: { aggregateID: string; seq: number; version: 1 } + type: "permission.asked" location?: LocationRef data: { + id: PermissionID sessionID: string - assistantMessageID: string - ordinal: number - text: string - state?: SessionMessageProviderState1 + action: string + resources: Array + save?: Array + metadata?: { [x: string]: any } + source?: PermissionSource + message?: string } } -export type SessionToolCalled = { - id: string +export type PermissionReplied = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.tool.called" - durable: { aggregateID: string; seq: number; version: 1 } + type: "permission.replied" location?: LocationRef - data: { - sessionID: string - assistantMessageID: string - id: string - input: { [x: string]: any } - executed: boolean - state?: SessionMessageProviderState1 - } -} - -export type SessionMessageAssistantText1 = { type: "text"; text: string; state?: SessionMessageProviderState1 } - -export type SessionMessageAssistantReasoning1 = { - type: "reasoning" - text: string - state?: SessionMessageProviderState1 - time?: { created: number; completed?: number } -} - -export type ToolContent1 = ToolTextContent | ToolFileContent1 - -export type FormNumberField = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "number" - minimum?: number | "Infinity" | "-Infinity" | "NaN" - maximum?: number | "Infinity" | "-Infinity" | "NaN" - default?: number | "Infinity" | "-Infinity" | "NaN" -} - -export type FormIntegerField = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "integer" - minimum?: number | "Infinity" | "-Infinity" | "NaN" - maximum?: number | "Infinity" | "-Infinity" | "NaN" - default?: number | "Infinity" | "-Infinity" | "NaN" -} - -export type FormBooleanField = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "boolean" - default?: boolean -} - -export type FormStringField = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "string" - format?: "email" | "uri" | "date" | "date-time" - minLength?: number - maxLength?: number - pattern?: string - placeholder?: string - default?: string - options?: Array - custom?: boolean -} - -export type FormMultiselectField = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "multiselect" - options: Array - minItems?: number - maxItems?: number - custom?: boolean - default?: Array -} - -export type FormAnswer = { [x: string]: FormValue } - -export type ModelCompatibility = { - reasoningField?: ModelReasoningField - requireReasoning?: boolean - maxTokensField?: ModelMaxTokensField - requireFinishReason?: boolean - requireAssistantAfterTool?: boolean - supportsPromptCacheKey?: boolean -} - -export type ModelCost = { - tier?: { type: "context"; size: number } - input: MoneyUSDPerMillionTokens - output: MoneyUSDPerMillionTokens - cache: { read: MoneyUSDPerMillionTokens; write: MoneyUSDPerMillionTokens } -} - -export type ConnectionCredentialInfo = { - type: "credential" - id: string - label: string - method: "key" | "oauth" - status?: ConnectionStatus -} - -export type ConnectionEnvInfo = { type: "env"; name: string; status?: ConnectionStatus } - -export type McpServer = { - name: string - status: McpStatusConnected | McpStatusPending | McpStatusDisabled | McpStatusFailed | McpStatusNeedsAuth - integrationID?: string + data: { sessionID: string; requestID: PermissionID; reply: PermissionReply } } -export type McpResourceCatalog = { resources: Array; templates: Array } - -export type Project = { - id: string - canonical: string - vcs?: ProjectVcs - name?: string - icon?: ProjectIcon - commands?: ProjectCommands - time: ProjectTime - sandboxes: Array +export type PluginUpdated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "plugin.updated" + location?: LocationRef + data: {} } export type ProjectUpdated = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "project.updated" location?: LocationRef data: { - id: string - canonical: string + id: ProjectID + canonical: AbsolutePath vcs?: ProjectVcs name?: string icon?: ProjectIcon @@ -1523,152 +1577,126 @@ export type ProjectUpdated = { } } -export type PermissionRequest = { - id: string - sessionID: string - action: string - resources: Array - save?: Array - metadata?: { [x: string]: JsonValue } - source?: PermissionSource - message?: string +export type WorktreeUpdated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "worktree.updated" + location?: LocationRef + data: { projectID: ProjectID } } -export type PermissionAsked = { - id: string +export type WorktreeResolved = { + id: EventID created: number metadata?: { [x: string]: any } - type: "permission.asked" + type: "worktree.resolved" + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { - id: string - sessionID: string - action: string - resources: Array - save?: Array - metadata?: { [x: string]: any } - source?: PermissionSource - message?: string - } + data: { projectID: ProjectID; directory: AbsolutePath; previous: ProjectID; adopted?: Array } } -export type PermissionReplied = { - id: string +export type CommandUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "permission.replied" + type: "command.updated" location?: LocationRef - data: { sessionID: string; requestID: string; reply: PermissionReply } + data: {} } -export type PtyCreated = { - id: string +export type ConfigUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "pty.created" + type: "config.updated" location?: LocationRef - data: { info: Pty } + data: {} } -export type PtyUpdated = { - id: string +export type SkillUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "pty.updated" + type: "skill.updated" location?: LocationRef - data: { info: Pty } + data: {} } -export type PersistentPtyAdded = { - id: string +export type PtyExited = { + id: EventID created: number metadata?: { [x: string]: any } - type: "persistent-pty.added" + type: "pty.exited" location?: LocationRef - data: { sessionID: string; terminal: PersistentPtyInfo } + data: { id: string; exitCode: number } } -export type PersistentPtySnapshot = { - info: PersistentPtyInfo - text: string - checkpoint: string - cursor: { x: number; y: number } +export type PtyDeleted = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "pty.deleted" + location?: LocationRef + data: { id: string } } -export type FormStringField1 = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "string" - format?: "email" | "uri" | "date" | "date-time" - minLength?: number - maxLength?: number - pattern?: string - placeholder?: string - default?: string - options?: Array - custom?: boolean +export type PersistentPtyRemoved = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "persistent-pty.removed" + location?: LocationRef + data: { sessionID: string; ptyID: string } } -export type FormNumberField1 = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "number" - minimum?: number - maximum?: number - default?: number +export type ShellCreated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "shell.created" + location?: LocationRef + data: { info: ShellInfo } } -export type FormIntegerField1 = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "integer" - minimum?: number - maximum?: number - default?: number +export type ShellExited = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "shell.exited" + location?: LocationRef + data: { id: ShellID; exit?: number; status: "running" | "exited" | "timeout" | "killed" } } -export type FormBooleanField1 = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "boolean" - default?: boolean +export type ShellDeleted = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "shell.deleted" + location?: LocationRef + data: { id: ShellID } } -export type FormMultiselectField1 = { - key: string - title?: string - description?: string - required?: boolean - hidden?: boolean - when?: Array - type: "multiselect" - options: Array - minItems?: number - maxItems?: number - custom?: boolean - default?: Array +export type FormCancelled = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "form.cancelled" + location?: LocationRef + data: { id: FormID; sessionID: string } } -export type FormAnswer2 = { [x: string]: FormValue1 } +export type WebsearchUpdated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "websearch.updated" + location?: LocationRef + data: {} +} export type SessionStatusUpdated = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "session.status" @@ -1676,177 +1704,131 @@ export type SessionStatusUpdated = { data: { sessionID: string; status: SessionStatus } } -export type ReferenceSource = ReferenceLocalSource | ReferenceGitSource - -export type WorktreeList = Array - -export type VcsInfo = { provider?: string; branch: VcsBranch } - -export type SessionInboxMove = { - id: string - sessionID: string - time: { created: number } - type: "move" - delivery: SessionInboxDelivery - payload: SessionInboxMovePayload -} - -export type ModelVariant = { - id: string - settings?: ModelSettings - headers?: { [x: string]: string } - body?: { [x: string]: any } -} - -export type ProviderRequest = { - settings: ProviderSettings - headers: { [x: string]: string } - body: { [x: string]: any } -} - -export type ProviderInfo = { - id: string - canonical?: string - integrationID?: string - name: string - activation: "auto" | "enabled" | "disabled" - package: string - settings?: ProviderSettings - headers?: { [x: string]: string } - body?: { [x: string]: any } -} - -export type PermissionRuleset = Array - -export type SessionRevertStaged = { - id: string +export type SessionIdle = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.revert.staged" - durable: { aggregateID: string; seq: number; version: 1 } + type: "session.idle" location?: LocationRef - data: { sessionID: string; revert: SessionRevert } -} - -export type SessionStatsInfo = { - range: { from: number; to: number } - sessions: number - subagents: number - prompts: number - steps: number - tokens: TokenUsageInfo - cost: MoneyUSD - tools: SessionStatsTools - activeDays: number - streak: number - activity: Array - models: Array + data: { sessionID: string } } -export type SessionMessageUser = { - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - text: string - files?: Array - agents?: Array - skills?: Array - type: "user" +export type TuiPromptAppend = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "tui.prompt.append" + location?: LocationRef + data: { text: string } } -export type SessionInboxUserPayload = { - text: string - files?: Array - agents?: Array - skills?: Array - metadata?: { [x: string]: JsonValue } +export type TuiCommandExecute = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "tui.command.execute" + location?: LocationRef + data: { + command: + | "session.list" + | "session.new" + | "session.share" + | "session.interrupt" + | "session.background" + | "session.compact" + | "session.page.up" + | "session.page.down" + | "session.line.up" + | "session.line.down" + | "session.half.page.up" + | "session.half.page.down" + | "session.first" + | "session.last" + | "prompt.clear" + | "prompt.submit" + | "agent.cycle" + | (string & {}) + } } -export type SessionInboxUserPayload1 = { - text: string - files?: Array - agents?: Array - skills?: Array +export type TuiToastShow = { + id: EventID + created: number metadata?: { [x: string]: any } + type: "tui.toast.show" + location?: LocationRef + data: { + title?: string + message: string + variant: "info" | "success" | "warning" | "error" + duration?: number | undefined + } } -export type SessionMessageToolStateCompleted = { - status: "completed" - input: { [x: string]: JsonValue } - content: [ToolContent, ...Array] - metadata?: { [x: string]: JsonValue } +export type TuiSessionSelect = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "tui.session.select" + location?: LocationRef + data: { sessionID: string } } -export type SessionMessageToolStateError = { - status: "error" - input: { [x: string]: JsonValue } - error: SessionStructuredError - content?: [ToolContent, ...Array] - metadata?: { [x: string]: JsonValue } +export type InstallationUpdated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "installation.updated" + location?: LocationRef + data: { version: string } } -export type SessionMessageCompactionCompleted = { - type: "compaction" - id: string - metadata?: { [x: string]: JsonValue } - time: { created: number } - status: "completed" - reason: "auto" | "manual" - model?: ModelRef - providerState?: SessionMessageProviderState - summary: string - recent: string - providerContext?: SessionProviderContext - cost?: MoneyUSD - tokens?: TokenUsageInfo +export type InstallationUpdateAvailable = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "installation.update-available" + location?: LocationRef + data: { version: string } } -export type SessionCompactionEnded = { - id: string +export type VcsBranchUpdated = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.compaction.ended" - durable: { aggregateID: string; seq: number; version: 1 } + type: "vcs.branch.updated" location?: LocationRef - data: { - sessionID: string - reason: "auto" | "manual" - model?: ModelRef - providerState?: SessionMessageProviderState1 - providerContext?: SessionProviderContext - text: string - recent: string - cost?: MoneyUSD - tokens?: TokenUsageInfo - } + data: { branch?: string } } -export type SessionForked = { - id: string +export type McpStatusChanged = { + id: EventID created: number metadata?: { [x: string]: any } - type: "session.forked" - durable: { aggregateID: string; seq: number; version: 2 } + type: "mcp.status.changed" location?: LocationRef - data: { - sessionID: string - parentID: string - boundary: SessionForkBoundary - instructions?: { [x: string]: string } - instructionEntries?: InstructionEntrySnapshot - } + data: { server: string } +} + +export type McpResourcesChanged = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "mcp.resources.changed" + location?: LocationRef + data: { server: string } } export type SessionToolSuccess = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "session.tool.success" - durable: { aggregateID: string; seq: number; version: 2 } + durable: { aggregateID: string; seq: EventSeq; version: 2 } location?: LocationRef data: { sessionID: string - assistantMessageID: string + assistantMessageID: SessionMessageID id: string content: [ToolContent1, ...Array] metadata?: { [x: string]: JsonValue } @@ -1856,15 +1838,15 @@ export type SessionToolSuccess = { } export type SessionToolFailed = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "session.tool.failed" - durable: { aggregateID: string; seq: number; version: 2 } + durable: { aggregateID: string; seq: EventSeq; version: 2 } location?: LocationRef data: { sessionID: string - assistantMessageID: string + assistantMessageID: SessionMessageID id: string error: SessionStructuredError content?: [ToolContent1, ...Array] @@ -1911,6 +1893,40 @@ export type CredentialKey = { export type ConnectionInfo = ConnectionCredentialInfo | ConnectionEnvInfo +export type PtyCreated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "pty.created" + location?: LocationRef + data: { info: Pty } +} + +export type PtyUpdated = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "pty.updated" + location?: LocationRef + data: { info: Pty } +} + +export type PersistentPtyAdded = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "persistent-pty.added" + location?: LocationRef + data: { sessionID: string; terminal: PersistentPtyInfo } +} + +export type PersistentPtySnapshot = { + info: PersistentPtyInfo + text: string + checkpoint: string + cursor: { x: number; y: number } +} + export type FormField1 = | FormStringField1 | FormNumberField1 @@ -1920,28 +1936,88 @@ export type FormField1 = | FormExternalField export type FormReplied = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "form.replied" location?: LocationRef - data: { id: string; sessionID: string; answer: FormAnswer2 } + data: { id: FormID; sessionID: string; answer: FormAnswer2 } +} + +export type SessionInboxMove = { + id: SessionMessageID + sessionID: string + time: { created: number } + type: "move" + delivery: SessionInboxDelivery + payload: SessionInboxMovePayload } export type ReferenceInfo = { name: string - path: string + path: AbsolutePath description?: string hidden?: boolean source: ReferenceSource } +export type SessionMessageCompactionCompleted = { + type: "compaction" + id: SessionMessageID + metadata?: { [x: string]: JsonValue } + time: { created: number } + status: "completed" + reason: "auto" | "manual" + model?: ModelRef + providerState?: SessionMessageProviderState + summary: string + recent: string + providerContext?: SessionProviderContext + cost?: MoneyUSD + tokens?: TokenUsageInfo +} + +export type SessionCompactionEnded = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "session.compaction.ended" + durable: { aggregateID: string; seq: EventSeq; version: 1 } + location?: LocationRef + data: { + sessionID: string + reason: "auto" | "manual" + model?: ModelRef + providerState?: SessionMessageProviderState1 + providerContext?: SessionProviderContext + text: string + recent: string + cost?: MoneyUSD + tokens?: TokenUsageInfo + } +} + +export type SessionStatsInfo = { + range: { from: number; to: number } + sessions: number + subagents: number + prompts: number + steps: number + tokens: TokenUsageInfo + cost: MoneyUSD + tools: SessionStatsTools + activeDays: number + streak: number + activity: Array + models: Array +} + export type ModelInfo = { - id: string - modelID: string - providerID: string - canonical?: string - family?: string + id: ModelID + modelID: ModelID + providerID: ProviderID + canonical?: ProviderID + family?: ModelFamily name: string compatibility?: ModelCompatibility package?: string @@ -1958,8 +2034,8 @@ export type ModelInfo = { } export type AgentInfo = { - id: string - name: string + id: AgentID + name: AgentName model?: ModelRef request: ProviderRequest system?: string @@ -1971,29 +2047,19 @@ export type AgentInfo = { permissions: PermissionRuleset } -export type SessionPermissions = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.permissions" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; permissions: PermissionRuleset } -} - export type SessionInfo = { id: string parentID?: string fork?: { sessionID: string; boundary: SessionForkBoundary } - projectID: string - agent?: string + projectID: ProjectID + agent?: AgentID model?: ModelRef cost: MoneyUSD tokens: TokenUsageInfo outcome?: "succeeded" | "failed" | "interrupted" time: { created: number; updated: number; idle?: number; viewed?: number; archived?: number } title?: string - subpath?: string + subpath?: RelativePath metadata?: SessionMetadata permissions?: PermissionRuleset revert?: SessionRevert @@ -2001,21 +2067,21 @@ export type SessionInfo = { } export type SessionCreated = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "session.created" - durable: { aggregateID: string; seq: number; version: 1 } + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef data: { sessionID: string - projectID: string + projectID: ProjectID location: LocationRef - subpath?: string + subpath?: RelativePath parentID?: string slug: string title?: string - agent?: string + agent?: AgentID model?: ModelRef metadata?: SessionMetadata permissions?: PermissionRuleset @@ -2023,10 +2089,20 @@ export type SessionCreated = { } } +export type SessionPermissions = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "session.permissions" + durable: { aggregateID: string; seq: EventSeq; version: 1 } + location?: LocationRef + data: { sessionID: string; permissions: PermissionRuleset } +} + export type ConfigEntry = | { type: "document" - path?: string + path?: AbsolutePath info: { $schema?: string shell?: string @@ -2134,13 +2210,13 @@ export type ConfigEntry = | { repository: string; branch?: string; description?: string; hidden?: boolean } | { path: string; description?: string; hidden?: boolean } } - websearch?: false | { provider: "random" | (string & {}) } + websearch?: false | { provider: "random" | WebSearchID } plugins?: Array worktree?: ConfigWorktree warming?: boolean | { prompt?: string; interval?: string; duration?: string } providers?: { [x: string]: { - canonical?: string + canonical?: ProviderID name?: string env?: Array package?: string @@ -2149,8 +2225,8 @@ export type ConfigEntry = body?: { [x: string]: JsonValue } models?: { [x: string]: { - modelID?: string - family?: string + modelID?: ModelID + family?: ModelFamily name?: string compatibility?: ModelCompatibility package?: string @@ -2159,7 +2235,7 @@ export type ConfigEntry = body?: { [x: string]: JsonValue } capabilities?: ModelCapabilities variants?: Array<{ - id: string + id: ModelVariantID settings?: ConfigModelSettings headers?: { [x: string]: string } body?: { [x: string]: JsonValue } @@ -2190,10 +2266,10 @@ export type ConfigEntry = } } } - | { type: "directory"; path: string } + | { type: "directory"; path: AbsolutePath } export type SessionInboxUser = { - id: string + id: SessionMessageID sessionID: string time: { created: number } type: "user" @@ -2201,12 +2277,6 @@ export type SessionInboxUser = { delivery: SessionInboxDelivery } -export type SessionInboxItem = - | { type: "user"; payload: SessionInboxUserPayload1; delivery: SessionInboxDelivery } - | { type: "synthetic"; payload: SessionInboxSyntheticPayload1; delivery: SessionInboxDelivery } - | { type: "compaction"; payload: SessionInboxCompactionPayload; delivery: SessionInboxDelivery } - | { type: "move"; payload: SessionInboxMovePayload1; delivery: SessionInboxDelivery } - export type SessionMessageAssistantTool = { type: "tool" id: string @@ -2222,10 +2292,11 @@ export type SessionMessageAssistantTool = { time: { created: number; ran?: number; completed?: number } } -export type SessionMessageCompaction = - | SessionMessageCompactionRunning - | SessionMessageCompactionCompleted - | SessionMessageCompactionFailed +export type SessionInboxItem = + | { type: "user"; payload: SessionInboxUserPayload1; delivery: SessionInboxDelivery } + | { type: "synthetic"; payload: SessionInboxSyntheticPayload1; delivery: SessionInboxDelivery } + | { type: "compaction"; payload: SessionInboxCompactionPayload; delivery: SessionInboxDelivery } + | { type: "move"; payload: SessionInboxMovePayload1; delivery: SessionInboxDelivery } export type SessionMessageAssistantTool1 = { type: "tool" @@ -2248,29 +2319,27 @@ export type CredentialValue = CredentialOAuth | CredentialKey export type FormFields2 = [FormField1, ...Array] -export type SessionsResponse = { data: Array; cursor: { previous?: string | null; next?: string | null } } - -export type SessionInboxInfo = SessionInboxUser | SessionInboxSynthetic | SessionInboxCompaction | SessionInboxMove +export type SessionMessageCompaction = + | SessionMessageCompactionRunning + | SessionMessageCompactionCompleted + | SessionMessageCompactionFailed -export type SessionInboxEnqueued = { - id: string - created: number - metadata?: { [x: string]: any } - type: "session.inbox.enqueued" - durable: { aggregateID: string; seq: number; version: 1 } - location?: LocationRef - data: { sessionID: string; inboxID: string; item: SessionInboxItem } +export type SessionsResponse = { + data: Array + cursor: { previous?: SessionsCursor | null; next?: SessionsCursor | null } } +export type SessionInboxInfo = SessionInboxUser | SessionInboxSynthetic | SessionInboxCompaction | SessionInboxMove + export type SessionMessageAssistant = { - id: string + id: SessionMessageID metadata?: { [x: string]: JsonValue } time: { created: number; streamed?: number; completed?: number } type: "assistant" - agent: string + agent: AgentID model: ModelRef content: Array - snapshot?: { start?: string; end?: string; files?: Array } + snapshot?: { start?: SnapshotID; end?: SnapshotID; files?: Array } finish?: "stop" | "length" | "tool-calls" | "content-filter" | "error" | "unknown" rawFinish?: string providerState?: SessionMessageProviderState @@ -2280,15 +2349,25 @@ export type SessionMessageAssistant = { retry?: SessionMessageAssistantRetry } +export type SessionInboxEnqueued = { + id: EventID + created: number + metadata?: { [x: string]: any } + type: "session.inbox.enqueued" + durable: { aggregateID: string; seq: EventSeq; version: 1 } + location?: LocationRef + data: { sessionID: string; inboxID: SessionMessageID; item: SessionInboxItem } +} + export type SessionMessageAssistantContentEncoded = | SessionMessageAssistantText1 | SessionMessageAssistantReasoning1 | SessionMessageAssistantTool1 -export type FormInfo = { id: string; sessionID: string; title: string; metadata?: FormMetadata; fields: FormFields } +export type FormInfo = { id: FormID; sessionID: string; title: string; metadata?: FormMetadata; fields: FormFields } export type FormDetail = { - id: string + id: FormID sessionID: string title: string metadata?: FormMetadata @@ -2296,19 +2375,19 @@ export type FormDetail = { state: FormState } -export type IntegrationOAuthMethod = { id: string; type: "oauth"; label: string; form?: FormFields } +export type IntegrationOAuthMethod = { id: IntegrationMethodID; type: "oauth"; label: string; form?: FormFields } export type IntegrationKeyMethod = { type: "key"; label?: string; form?: FormFields } export type CredentialEntry = { - id: string - integrationID: string + id: CredentialID + integrationID: IntegrationID label: string active: boolean value: CredentialValue } -export type FormInfo1 = { id: string; sessionID: string; title: string; metadata?: FormMetadata1; fields: FormFields2 } +export type FormInfo1 = { id: FormID; sessionID: string; title: string; metadata?: FormMetadata1; fields: FormFields2 } export type SessionMessageInfo = | SessionMessageAgentSelected @@ -2324,13 +2403,13 @@ export type SessionMessageInfo = | SessionMessageIdle export type SessionMessageContentUpdated = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "session.message.content.updated" - durable: { aggregateID: string; seq: number; version: 1 } + durable: { aggregateID: string; seq: EventSeq; version: 1 } location?: LocationRef - data: { sessionID: string; messageID: string; content: Array } + data: { sessionID: string; messageID: SessionMessageID; content: Array } } export type IntegrationMethod = @@ -2340,7 +2419,7 @@ export type IntegrationMethod = | IntegrationEnvMethod export type FormCreated = { - id: string + id: EventID created: number metadata?: { [x: string]: any } type: "form.created" @@ -2403,7 +2482,7 @@ export type SessionEventDurable = | SessionMessageContentUpdated export type IntegrationInfo = { - id: string + id: IntegrationID name: string metadata?: { [x: string]: any } methods: Array @@ -5677,7 +5756,16 @@ export type IntegrationOauthConnectInput = { }["label"] } -export type IntegrationOauthConnectOutput = { location: LocationPublicRef; data: IntegrationAttempt } +export type IntegrationOauthConnectOutput = { + location: LocationPublicRef + data: { + attemptID: IntegrationAttemptID + url: string + instructions: string + mode: "auto" | "code" + time: { created: number | "Infinity" | "-Infinity" | "NaN"; expires: number | "Infinity" | "-Infinity" | "NaN" } + } +} export type IntegrationOauthStatusInput = { readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"] @@ -6057,7 +6145,7 @@ export type PermissionCreateInput = { }["agent"] } -export type PermissionCreateOutput = { data: { id: string; effect: PermissionEffect } }["data"] +export type PermissionCreateOutput = { data: { id: PermissionID; effect: PermissionEffect } }["data"] export type PermissionListInput = { readonly sessionID: { readonly sessionID: string }["sessionID"] } @@ -6584,7 +6672,7 @@ export type WebsearchQueryInput = { export type WebsearchQueryOutput = { location: LocationPublicRef - data: { providerID: string; results: Array } + data: { providerID: WebSearchID; results: Array } } export type ConfigGetInput = { diff --git a/packages/client/test/effect.test.ts b/packages/client/test/effect.test.ts index 1e5e5b326ae8..93e02132a01f 100644 --- a/packages/client/test/effect.test.ts +++ b/packages/client/test/effect.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "bun:test" import { Context, DateTime, Effect, Stream } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientResponse } from "effect/http" import { AbsolutePath, Agent, @@ -249,7 +249,7 @@ test("session methods retain decoded Effect inputs and outputs", async () => { const created = yield* client.session.create({ location: Location.Ref.make({ directory: AbsolutePath.make("/tmp/project") }), }) - yield* client.session.view({ sessionID: Session.ID.make("ses_test"), idle: session.data.time.idle }) + yield* client.session.view({ sessionID: Session.ID.make("ses_test"), idle: DateTime.makeUnsafe(session.data.time.idle) }) yield* client.session.switchAgent({ sessionID: Session.ID.make("ses_test"), agent: Agent.ID.make("build") }) yield* client.session.switchModel({ sessionID: Session.ID.make("ses_test"), diff --git a/packages/client/test/import-boundaries.test.ts b/packages/client/test/import-boundaries.test.ts index 2f571d453ac1..5bd1e7971f21 100644 --- a/packages/client/test/import-boundaries.test.ts +++ b/packages/client/test/import-boundaries.test.ts @@ -39,7 +39,7 @@ describe("public import boundaries", () => { const effectService = await bundleInputs("@opencode/client/effect/service", "bun") expect(within(effectService.eager, effect).length).toBeGreaterThan(0) - expect(within(effectService.eager, protocol).length).toBeGreaterThan(0) + expect(within(effectService.all, protocol)).toEqual([]) expect(within(effectService.all, core)).toEqual([]) expect(within(effectService.all, server)).toEqual([]) }) diff --git a/packages/client/test/promise.test.ts b/packages/client/test/promise.test.ts index 4eb1ea22f169..c13d29501c0a 100644 --- a/packages/client/test/promise.test.ts +++ b/packages/client/test/promise.test.ts @@ -45,13 +45,13 @@ test("exposes every standard HTTP API group", () => { expect(Object.keys(client.integration.oauth)).toEqual(["connect", "status", "complete", "cancel"]) expect(Object.keys(client.integration.command)).toEqual(["connect", "status", "cancel"]) expect(Object.keys(client.websearch)).toEqual(["providers", "query"]) - expect(Object.keys(client.file)).toEqual(["read", "list", "find"]) - expect(Object.keys(client.vcs)).toEqual(["get", "base", "status", "branches", "diff"]) + expect(Object.keys(client.file)).toEqual(["read", "list", "find", "write"]) + expect(Object.keys(client.vcs)).toEqual(["get", "base", "status", "branch", "diff"]) expect(Object.keys(client.pty)).toEqual(["list", "create", "get", "update", "remove", "connect"]) expect(Object.keys(client.pty.connect)).toEqual(["token"]) expect(Object.keys(client.experimental)).toEqual(["persistentPty"]) expect(client.experimental.persistentPty.read).toBeFunction() - expect(Object.keys(client.shell)).toEqual(["list", "create", "get", "timeout", "output", "remove"]) + expect(Object.keys(client.shell)).toEqual(["list", "create", "get", "output", "remove"]) expect(Object.keys(client.project)).toEqual(["list", "update"]) expect(Object.keys(client.worktree)).toEqual(["list", "create", "remove", "refresh"]) }) @@ -995,7 +995,7 @@ test("session methods use the public HTTP contract", async () => { ["POST", "http://localhost:3000/api/experimental/session/ses_test/wait"], ["GET", "http://localhost:3000/api/session/ses_test/context"], ["GET", "http://localhost:3000/api/experimental/session/ses_test/log?after=0"], - ["POST", "http://localhost:3000/api/session/ses_test/interrupt?continue=true"], + ["POST", "http://localhost:3000/api/session/ses_test/interrupt"], ["GET", "http://localhost:3000/api/session/ses_test/message/msg_model"], ]) const viewBody = requests.find((request) => request.url.endsWith("/api/session/ses_test/view"))?.init?.body diff --git a/packages/codemode/src/openapi/index.ts b/packages/codemode/src/openapi/index.ts index bdf000718483..c44708febfba 100644 --- a/packages/codemode/src/openapi/index.ts +++ b/packages/codemode/src/openapi/index.ts @@ -1,4 +1,4 @@ -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { make, type Tool } from "../tool.js" import { invoke } from "./runtime.js" import { diff --git a/packages/codemode/src/openapi/runtime.ts b/packages/codemode/src/openapi/runtime.ts index 8548a42557f8..f2a0cfc3cdf9 100644 --- a/packages/codemode/src/openapi/runtime.ts +++ b/packages/codemode/src/openapi/runtime.ts @@ -1,5 +1,5 @@ import { Effect, Option, Schema, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse, type HttpMethod } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse, type HttpMethod } from "effect/http" import { ToolError, toolError } from "../tool-error.js" import { isRecord, own } from "./spec.js" import type { AppliedAuth, Credential, Plan, SecurityScheme } from "./types.js" diff --git a/packages/codemode/src/openapi/types.ts b/packages/codemode/src/openapi/types.ts index 79fdb7fbff08..2a4df8c44f91 100644 --- a/packages/codemode/src/openapi/types.ts +++ b/packages/codemode/src/openapi/types.ts @@ -1,5 +1,5 @@ import { Effect } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import type { Tool, JsonSchema } from "../tool.js" /** A parsed OpenAPI 3.x document. YAML must be parsed by the ctx. */ diff --git a/packages/codemode/test/openapi.test.ts b/packages/codemode/test/openapi.test.ts index 86b194c00139..5a70ae71e726 100644 --- a/packages/codemode/test/openapi.test.ts +++ b/packages/codemode/test/openapi.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Layer, Option } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { CodeMode, OpenAPI, Tool } from "../src/index.js" import { inputTypeScript, outputTypeScript } from "../src/tool-schema.js" diff --git a/packages/core/package.json b/packages/core/package.json index 8e47bc1a8478..d4ded5ff1695 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -92,7 +92,8 @@ "@types/bun": "catalog:", "@types/node": "catalog:", "@types/which": "3.0.4", - "drizzle-kit": "catalog:" + "drizzle-kit": "catalog:", + "fast-check": "4.9.0" }, "dependencies": { "@ai-sdk/cohere": "3.0.27", diff --git a/packages/core/script/benchmark-location-memory.ts b/packages/core/script/benchmark-location-memory.ts index 416589c935f5..5d6e674feaeb 100644 --- a/packages/core/script/benchmark-location-memory.ts +++ b/packages/core/script/benchmark-location-memory.ts @@ -13,7 +13,7 @@ import os from "os" import path from "path" import { heapStats } from "bun:jsc" import { Effect, Layer, Logger, Scope } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" import { Global } from "@opencode/util/global" import { LayerNode } from "@opencode/util/effect/layer-node" import { AppNodeBuilder } from "../src/effect/app-node-builder" diff --git a/packages/core/src/aisdk.ts b/packages/core/src/aisdk.ts index cb27a55584c6..1edd2cd12edd 100644 --- a/packages/core/src/aisdk.ts +++ b/packages/core/src/aisdk.ts @@ -33,8 +33,8 @@ import { import { Auth, Endpoint, RequestExecutor, type AnyRoute, type HttpMiddleware } from "@opencode/ai/route" import { ProviderShared } from "@opencode/ai/protocols/shared" import { Cause, Context, Effect, Layer, Option, Schema, Scope, Stream } from "effect" -import { makeParser } from "effect/unstable/encoding/Sse" -import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { makeParser } from "effect/encoding/Sse" +import { HttpClientRequest, HttpClientResponse } from "effect/http" import { AsyncLocalStorage } from "node:async_hooks" import type { ID, RuntimeInfo } from "./model.js" import { Provider } from "./provider.js" diff --git a/packages/core/src/config/plugin/agent.ts b/packages/core/src/config/plugin/agent.ts index 7f96a3f22af5..1d3949d015ea 100644 --- a/packages/core/src/config/plugin/agent.ts +++ b/packages/core/src/config/plugin/agent.ts @@ -196,11 +196,11 @@ function decode(file: { directory: string; filepath: string; primary: boolean }, const agent = legacy ? Option.getOrUndefined( Option.map( - decodeLegacyAgent({ name, ...markdown.data, prompt: body }, { errors: "all", propertyOrder: "original" }), + decodeLegacyAgent({ name, ...markdown.data, prompt: body }, { errors: "all" }), ConfigMigrateV1.migrateAgent, ), ) - : Option.getOrUndefined(decodeAgent({ ...data, system: body }, { errors: "all", propertyOrder: "original" })) + : Option.getOrUndefined(decodeAgent({ ...data, system: body }, { errors: "all" })) if (!agent) return const info = Option.getOrUndefined( decodeConfig({ diff --git a/packages/core/src/config/plugin/command.ts b/packages/core/src/config/plugin/command.ts index 8cef182c8201..a638897adfe9 100644 --- a/packages/core/src/config/plugin/command.ts +++ b/packages/core/src/config/plugin/command.ts @@ -8,7 +8,7 @@ import { Provider } from "@opencode/schema/provider" import { AppProcess } from "@opencode/util/process" import path from "path" import { Effect, Option, PubSub, Schema, Stream } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { Agent } from "../../agent.js" import { Config } from "../../config.js" import { Location } from "../../location.js" diff --git a/packages/core/src/database/database.ts b/packages/core/src/database/database.ts index 249152333da1..93724052fc00 100644 --- a/packages/core/src/database/database.ts +++ b/packages/core/src/database/database.ts @@ -3,7 +3,7 @@ export * as Database from "./database.js" import { EffectDrizzleSqlite } from "./drizzle.js" import { sqliteLayer, supportsForeignKeyToggle, supportsTuningPragmas } from "#sqlite" import { Context, Effect, Layer, Schema, Semaphore } from "effect" -import type { SqlClient } from "effect/unstable/sql" +import type { SqlClient } from "effect/sql" import { Global } from "@opencode/util/global" import { closeSync, existsSync, openSync } from "node:fs" import { chmod } from "node:fs/promises" diff --git a/packages/core/src/database/drizzle/effect-sqlite/driver.ts b/packages/core/src/database/drizzle/effect-sqlite/driver.ts index 669aa0d211f4..e5579e366ead 100644 --- a/packages/core/src/database/drizzle/effect-sqlite/driver.ts +++ b/packages/core/src/database/drizzle/effect-sqlite/driver.ts @@ -1,7 +1,7 @@ /* oxlint-disable */ import * as Effect from "effect/Effect" import * as Layer from "effect/Layer" -import { SqlClient } from "effect/unstable/sql/SqlClient" +import { SqlClient } from "effect/sql/SqlClient" import { EffectCache } from "drizzle-orm/cache/core/cache-effect" import { EffectLogger } from "drizzle-orm/effect-core" import { entityKind } from "drizzle-orm/entity" diff --git a/packages/core/src/database/drizzle/effect-sqlite/session.ts b/packages/core/src/database/drizzle/effect-sqlite/session.ts index 6b4ab20dd10e..9297bc7b6772 100644 --- a/packages/core/src/database/drizzle/effect-sqlite/session.ts +++ b/packages/core/src/database/drizzle/effect-sqlite/session.ts @@ -3,8 +3,8 @@ import * as Context from "effect/Context" import * as Effect from "effect/Effect" import * as Exit from "effect/Exit" import * as Scope from "effect/Scope" -import type { SqlClient } from "effect/unstable/sql/SqlClient" -import type { SqlError } from "effect/unstable/sql/SqlError" +import type { SqlClient } from "effect/sql/SqlClient" +import type { SqlError } from "effect/sql/SqlError" import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" import type { WithCacheConfig } from "drizzle-orm/cache/core/types" import type { EffectDrizzleQueryError } from "drizzle-orm/effect-core/errors" diff --git a/packages/core/src/database/drizzle/sqlite-core/effect/db.ts b/packages/core/src/database/drizzle/sqlite-core/effect/db.ts index a1c44b392ad5..ccf96e5fb271 100644 --- a/packages/core/src/database/drizzle/sqlite-core/effect/db.ts +++ b/packages/core/src/database/drizzle/sqlite-core/effect/db.ts @@ -1,6 +1,6 @@ /* oxlint-disable */ import { Effect } from "effect" -import type { SqlError } from "effect/unstable/sql/SqlError" +import type { SqlError } from "effect/sql/SqlError" import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" import type { MutationOption } from "drizzle-orm/cache/core/cache" import type { QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect" diff --git a/packages/core/src/database/drizzle/sqlite-core/effect/session.ts b/packages/core/src/database/drizzle/sqlite-core/effect/session.ts index 1ea0eca1b72d..d53f25447653 100644 --- a/packages/core/src/database/drizzle/sqlite-core/effect/session.ts +++ b/packages/core/src/database/drizzle/sqlite-core/effect/session.ts @@ -1,7 +1,7 @@ /* oxlint-disable */ import * as Cause from "effect/Cause" import * as Effect from "effect/Effect" -import type { SqlError } from "effect/unstable/sql/SqlError" +import type { SqlError } from "effect/sql/SqlError" import type { EffectCacheShape } from "drizzle-orm/cache/core/cache-effect" import { NoopCache, strategyFor } from "drizzle-orm/cache/core/cache" import type { WithCacheConfig } from "drizzle-orm/cache/core/types" diff --git a/packages/core/src/database/sqlite.bun.ts b/packages/core/src/database/sqlite.bun.ts index ddf586d945d7..7728bc8f4e95 100644 --- a/packages/core/src/database/sqlite.bun.ts +++ b/packages/core/src/database/sqlite.bun.ts @@ -1,8 +1,8 @@ import { Database, type SQLQueryBindings } from "bun:sqlite" import { Context, Effect, Layer } from "effect" -import { Reactivity } from "effect/unstable/reactivity" -import { SqlClient } from "effect/unstable/sql" -import { classifySqliteError, SqlError } from "effect/unstable/sql/SqlError" +import { Reactivity } from "effect/reactivity" +import { SqlClient } from "effect/sql" +import { classifySqliteError, SqlError } from "effect/sql/SqlError" import { Sqlite } from "./sqlite.js" const TypeId = "~@opencode/core/database/SqliteBun" as const diff --git a/packages/core/src/database/sqlite.node.ts b/packages/core/src/database/sqlite.node.ts index 354e14076558..9053a0def663 100644 --- a/packages/core/src/database/sqlite.node.ts +++ b/packages/core/src/database/sqlite.node.ts @@ -1,8 +1,8 @@ import { DatabaseSync, type SQLInputValue } from "node:sqlite" import { Context, Effect, Layer } from "effect" -import { Reactivity } from "effect/unstable/reactivity" -import { SqlClient } from "effect/unstable/sql" -import { classifySqliteError, SqlError } from "effect/unstable/sql/SqlError" +import { Reactivity } from "effect/reactivity" +import { SqlClient } from "effect/sql" +import { classifySqliteError, SqlError } from "effect/sql/SqlError" import { Sqlite } from "./sqlite.js" const TypeId = "~@opencode/core/database/SqliteNode" as const diff --git a/packages/core/src/database/sqlite.ts b/packages/core/src/database/sqlite.ts index 884626d6ad2e..186274fe3e31 100644 --- a/packages/core/src/database/sqlite.ts +++ b/packages/core/src/database/sqlite.ts @@ -2,9 +2,9 @@ export * as Sqlite from "./sqlite.js" import { Context, Effect, Fiber, Scope, Semaphore, Stream } from "effect" import { identity } from "effect/Function" -import { SqlClient, Statement } from "effect/unstable/sql" -import type { Connection } from "effect/unstable/sql/SqlConnection" -import type { SqlError } from "effect/unstable/sql/SqlError" +import { SqlClient, Statement } from "effect/sql" +import type { Connection } from "effect/sql/SqlConnection" +import type { SqlError } from "effect/sql/SqlError" export class Native extends Context.Service()("@opencode/core/database/SqliteNative") {} diff --git a/packages/core/src/database/sqlite.workerd.ts b/packages/core/src/database/sqlite.workerd.ts index 86e38e3163cb..7c032507f0f0 100644 --- a/packages/core/src/database/sqlite.workerd.ts +++ b/packages/core/src/database/sqlite.workerd.ts @@ -1,8 +1,8 @@ import { Context, Effect, Exit, Fiber, Layer, Scope, Semaphore } from "effect" -import { Reactivity } from "effect/unstable/reactivity" -import { SqlClient, Statement } from "effect/unstable/sql" -import type { Connection } from "effect/unstable/sql/SqlConnection" -import { classifySqliteError, SqlError, UnknownError } from "effect/unstable/sql/SqlError" +import { Reactivity } from "effect/reactivity" +import { SqlClient, Statement } from "effect/sql" +import type { Connection } from "effect/sql/SqlConnection" +import { classifySqliteError, SqlError, UnknownError } from "effect/sql/SqlError" import type { NativeTransactionSqlClient } from "./drizzle/effect-sqlite/session.js" import { Sqlite } from "./sqlite.js" diff --git a/packages/core/src/effect/app-node-platform.ts b/packages/core/src/effect/app-node-platform.ts index 718c6456c7b9..2f0070cfb316 100644 --- a/packages/core/src/effect/app-node-platform.ts +++ b/packages/core/src/effect/app-node-platform.ts @@ -1,5 +1,5 @@ import { LLMClient, RequestExecutor } from "@opencode/ai/route" -import { Socket } from "effect/unstable/socket" +import { Socket } from "effect/socket" import { makeGlobalNode } from "@opencode/util/effect/app-node" import { httpClient } from "@opencode/util/effect/app-node-platform" import { WebSocketConstructor } from "./websocket-constructor.js" diff --git a/packages/core/src/effect/websocket-constructor.ts b/packages/core/src/effect/websocket-constructor.ts index 4d1031902866..c0249f64e6fd 100644 --- a/packages/core/src/effect/websocket-constructor.ts +++ b/packages/core/src/effect/websocket-constructor.ts @@ -3,11 +3,10 @@ import { NodeWS } from "@effect/platform-node/NodeSocket" import { HttpProxyAgent } from "http-proxy-agent" import { HttpsProxyAgent } from "https-proxy-agent" import { Layer } from "effect" -import { Headers } from "effect/unstable/http" -import { Socket } from "effect/unstable/socket" +import { Socket } from "effect/socket" interface WebSocketOptions { - readonly headers?: Headers.Headers + readonly headers?: Readonly> readonly protocols?: string | Array } @@ -48,10 +47,9 @@ const proxy = (value: string, environment: Environment = process.env) => { ) } -const constructorOptions = (input: string | Array | undefined): WebSocketOptions => { +const constructorOptions = (input: Socket.WebSocketConstructorOptions | undefined): WebSocketOptions => { if (typeof input === "string" || Array.isArray(input)) return { protocols: input } - // AI routes pass handshake options through Effect's browser-shaped constructor. - return (input ?? {}) as WebSocketOptions + return input ?? {} } const proxyAgent = (url: string, selectedProxy: string | undefined) => { diff --git a/packages/core/src/environment/driver.ts b/packages/core/src/environment/driver.ts index 39c0d2c74559..85162fd123b3 100644 --- a/packages/core/src/environment/driver.ts +++ b/packages/core/src/environment/driver.ts @@ -1,4 +1,4 @@ -import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import type { ChildProcessSpawner } from "effect/process/ChildProcessSpawner" import type { FilesImpl } from "./files.js" export interface Driver { diff --git a/packages/core/src/environment/environment.ts b/packages/core/src/environment/environment.ts index 0dc997fda93f..416c0d08064d 100644 --- a/packages/core/src/environment/environment.ts +++ b/packages/core/src/environment/environment.ts @@ -1,7 +1,7 @@ import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner" import { makeLocationNode } from "@opencode/util/effect/app-node" import { Context, Effect, Layer } from "effect" -import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcessSpawner } from "effect/process/ChildProcessSpawner" import type { Files } from "./files.js" import { makeFiles } from "./index.js" import { makeLocalDriver } from "./local.js" diff --git a/packages/core/src/environment/exec-defaults.ts b/packages/core/src/environment/exec-defaults.ts index d2350fb75884..d315fb26e647 100644 --- a/packages/core/src/environment/exec-defaults.ts +++ b/packages/core/src/environment/exec-defaults.ts @@ -1,6 +1,6 @@ import { Effect, Stream } from "effect" -import { ChildProcess } from "effect/unstable/process" -import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcess } from "effect/process" +import type { ChildProcessSpawner } from "effect/process/ChildProcessSpawner" import { collectStream } from "@opencode/util/process" import { Failed, NotFound, WrongKind, type FileInfo, type FileType, type FilesImpl } from "./files.js" diff --git a/packages/core/src/environment/local.ts b/packages/core/src/environment/local.ts index a2a044523a08..24b237855ea6 100644 --- a/packages/core/src/environment/local.ts +++ b/packages/core/src/environment/local.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises" import path from "node:path" import { Effect } from "effect" -import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import type { ChildProcessSpawner } from "effect/process/ChildProcessSpawner" import type { Driver } from "./driver.js" import { Failed, NotFound, WrongKind, type FileInfo, type FilesImpl, type FileType } from "./files.js" diff --git a/packages/core/src/environment/memory.ts b/packages/core/src/environment/memory.ts index 0e8003a6e3d3..c7f23115645e 100644 --- a/packages/core/src/environment/memory.ts +++ b/packages/core/src/environment/memory.ts @@ -1,6 +1,6 @@ import path from "node:path" import { Effect, PlatformError } from "effect" -import { make } from "effect/unstable/process/ChildProcessSpawner" +import { make } from "effect/process/ChildProcessSpawner" import type { Driver } from "./driver.js" import { Failed, NotFound, WrongKind, type FileInfo, type FilesImpl, type FileType } from "./files.js" diff --git a/packages/core/src/environment/unavailable.ts b/packages/core/src/environment/unavailable.ts index 59db611a77fd..56e7b290444c 100644 --- a/packages/core/src/environment/unavailable.ts +++ b/packages/core/src/environment/unavailable.ts @@ -1,5 +1,5 @@ import { Effect, Layer, PlatformError } from "effect" -import { ChildProcessSpawner, make } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcessSpawner, make } from "effect/process/ChildProcessSpawner" export const spawner = make(() => Effect.fail( diff --git a/packages/core/src/formatter.ts b/packages/core/src/formatter.ts index eb85babf56ee..46bb4e6b2835 100644 --- a/packages/core/src/formatter.ts +++ b/packages/core/src/formatter.ts @@ -1,7 +1,7 @@ export * as Formatter from "./formatter.js" import { Context, Effect, Layer } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import path from "path" import { makeLocationNode } from "@opencode/util/effect/app-node" import { AppProcess } from "@opencode/util/process" diff --git a/packages/core/src/formatter/builtins.ts b/packages/core/src/formatter/builtins.ts index ba8354f807b4..86b3714add58 100644 --- a/packages/core/src/formatter/builtins.ts +++ b/packages/core/src/formatter/builtins.ts @@ -1,5 +1,5 @@ import { Effect } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { FSUtil } from "@opencode/util/fs-util" import { Npm } from "@opencode/util/npm" import { AppProcess } from "@opencode/util/process" diff --git a/packages/core/src/git.ts b/packages/core/src/git.ts index 224cd801cc54..4395bf4334b6 100644 --- a/packages/core/src/git.ts +++ b/packages/core/src/git.ts @@ -2,7 +2,7 @@ export * as Git from "./git.js" import path from "path" import { Context, Effect, Layer, Schema } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { AbsolutePath, RelativePath } from "./schema.js" import { FSUtil } from "@opencode/util/fs-util" import { AppProcess } from "@opencode/util/process" diff --git a/packages/core/src/integration.ts b/packages/core/src/integration.ts index 39904eaed1b8..afeb2c8be984 100644 --- a/packages/core/src/integration.ts +++ b/packages/core/src/integration.ts @@ -24,7 +24,7 @@ import { State } from "./state.js" import { Bus } from "./bus.js" import { IntegrationConnection } from "./integration/connection.js" import { AppProcess } from "@opencode/util/process" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { Form } from "./form.js" export const ID = Integration.ID diff --git a/packages/core/src/mcp/stdio.ts b/packages/core/src/mcp/stdio.ts index 79faf9536e73..31dd7f224e14 100644 --- a/packages/core/src/mcp/stdio.ts +++ b/packages/core/src/mcp/stdio.ts @@ -2,8 +2,8 @@ export * as McpStdio from "./stdio.js" import { ReadBuffer, serializeMessage, type JSONRPCMessage, type Transport } from "@modelcontextprotocol/client" import { Cause, Duration, Effect, Fiber, Option, Queue, Scope, Stream } from "effect" -import { ChildProcess } from "effect/unstable/process" -import type { ChildProcessHandle } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcess } from "effect/process" +import type { ChildProcessHandle } from "effect/process/ChildProcessSpawner" import { Environment } from "../environment/index.js" /** Mirrors StdioClientTransport: wait this long for a graceful exit after stdin closes. */ diff --git a/packages/core/src/models-dev.ts b/packages/core/src/models-dev.ts index f11f07c79dbd..1c23e5918f52 100644 --- a/packages/core/src/models-dev.ts +++ b/packages/core/src/models-dev.ts @@ -1,5 +1,5 @@ import { Cause, Context, Duration, Effect, Layer, Option, Schedule, Schema, Semaphore } from "effect" -import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/http" import { ModelsDev } from "@opencode/schema/models-dev" import { Money } from "@opencode/schema/money" import { App } from "./app.js" diff --git a/packages/core/src/plugin/internal.ts b/packages/core/src/plugin/internal.ts index 4e72100119e7..630bd119afdf 100644 --- a/packages/core/src/plugin/internal.ts +++ b/packages/core/src/plugin/internal.ts @@ -6,7 +6,7 @@ import { LayerNode } from "@opencode/util/effect/layer-node" import { httpClient } from "@opencode/util/effect/app-node-platform" import { AppProcess } from "@opencode/util/process" import { Context, Effect, Scope } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { Agent } from "../agent.js" import { Model } from "../model.js" import { Provider } from "../provider.js" diff --git a/packages/core/src/plugin/provider/azure.ts b/packages/core/src/plugin/provider/azure.ts index 40cdeb015161..f0d573306c78 100644 --- a/packages/core/src/plugin/provider/azure.ts +++ b/packages/core/src/plugin/provider/azure.ts @@ -1,6 +1,6 @@ import { Clock, Effect, FiberHandle, Option, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" -import { ChildProcess } from "effect/unstable/process" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" +import { ChildProcess } from "effect/process" import { define } from "@opencode/plugin/effect/plugin" import { Form } from "@opencode/schema/form" import { AppProcess } from "@opencode/util/process" diff --git a/packages/core/src/plugin/provider/chatgpt.ts b/packages/core/src/plugin/provider/chatgpt.ts index d09c647b7876..373b5904d52d 100644 --- a/packages/core/src/plugin/provider/chatgpt.ts +++ b/packages/core/src/plugin/provider/chatgpt.ts @@ -2,7 +2,7 @@ import type { IntegrationOAuthMethodRegistration } from "@opencode/plugin/effect import type { Context } from "@opencode/plugin/effect/plugin" import { define } from "@opencode/plugin/effect/plugin" import { Deferred, Duration, Effect, Option, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import type { Server, ServerResponse } from "node:http" import { App } from "../../app.js" import { Credential } from "../../credential.js" diff --git a/packages/core/src/plugin/provider/digitalocean.ts b/packages/core/src/plugin/provider/digitalocean.ts index 1d2a6358c18e..653d3243fbdd 100644 --- a/packages/core/src/plugin/provider/digitalocean.ts +++ b/packages/core/src/plugin/provider/digitalocean.ts @@ -1,7 +1,7 @@ import type { IntegrationOAuthMethodRegistration } from "@opencode/plugin/effect/integration" import { define } from "@opencode/plugin/effect/plugin" import { Clock, Deferred, Effect, Option, Schedule, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import type { Server } from "node:http" import { App } from "../../app.js" import { Bus } from "../../bus.js" diff --git a/packages/core/src/plugin/provider/gitlab.ts b/packages/core/src/plugin/provider/gitlab.ts index 4f50815434d2..7572c8af9b04 100644 --- a/packages/core/src/plugin/provider/gitlab.ts +++ b/packages/core/src/plugin/provider/gitlab.ts @@ -1,7 +1,7 @@ import os from "os" import { App } from "../../app.js" import { Clock, Deferred, Effect, Exit, Option, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import type { Server, ServerResponse } from "node:http" import { define } from "@opencode/plugin/effect/plugin" import { Form } from "@opencode/schema/form" diff --git a/packages/core/src/plugin/provider/lmstudio.ts b/packages/core/src/plugin/provider/lmstudio.ts index 1c87eec44878..0ef90c396266 100644 --- a/packages/core/src/plugin/provider/lmstudio.ts +++ b/packages/core/src/plugin/provider/lmstudio.ts @@ -1,7 +1,7 @@ import { define } from "@opencode/plugin/effect/plugin" import type { Entry } from "@opencode/schema/config" import { Duration, Effect, Schedule, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { Config } from "../../config.js" import { Model } from "../../model.js" import type { PluginInternal } from "../internal.js" diff --git a/packages/core/src/plugin/provider/ollama.ts b/packages/core/src/plugin/provider/ollama.ts index 690ec7229de5..970b75e1126d 100644 --- a/packages/core/src/plugin/provider/ollama.ts +++ b/packages/core/src/plugin/provider/ollama.ts @@ -1,7 +1,7 @@ import { define } from "@opencode/plugin/effect/plugin" import type { Entry } from "@opencode/schema/config" import { Duration, Effect, Schedule, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { Config } from "../../config.js" import { Model } from "../../model.js" import type { PluginInternal } from "../internal.js" diff --git a/packages/core/src/plugin/provider/opencode.ts b/packages/core/src/plugin/provider/opencode.ts index 3edff6084624..1e5f31bdf3bf 100644 --- a/packages/core/src/plugin/provider/opencode.ts +++ b/packages/core/src/plugin/provider/opencode.ts @@ -2,7 +2,7 @@ import { Duration, Effect, Equal, Option, Schema, Scope, Semaphore, Stream } fro import type { IntegrationOAuthMethodRegistration } from "@opencode/plugin/effect/integration" import { define } from "@opencode/plugin/effect/plugin" import type { SessionHttpResponse } from "@opencode/plugin/effect/session" -import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { App } from "../../app.js" import { Bus } from "../../bus.js" import { Credential } from "../../credential.js" diff --git a/packages/core/src/plugin/provider/poe.ts b/packages/core/src/plugin/provider/poe.ts index f04c9b88839c..24edb14757f8 100644 --- a/packages/core/src/plugin/provider/poe.ts +++ b/packages/core/src/plugin/provider/poe.ts @@ -1,6 +1,6 @@ import { define } from "@opencode/plugin/effect/plugin" import { Clock, Deferred, Effect, Option, Schema } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import type { ServerResponse } from "node:http" import { Credential } from "../../credential.js" import { Integration } from "../../integration.js" diff --git a/packages/core/src/plugin/provider/snowflake-cortex.ts b/packages/core/src/plugin/provider/snowflake-cortex.ts index f36cab51892f..741f51a08c63 100644 --- a/packages/core/src/plugin/provider/snowflake-cortex.ts +++ b/packages/core/src/plugin/provider/snowflake-cortex.ts @@ -1,7 +1,7 @@ import { define } from "@opencode/plugin/effect/plugin" import { Form } from "@opencode/schema/form" import { Clock, Deferred, Effect, Option, Schema, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { App } from "../../app.js" import { Bus } from "../../bus.js" import { Credential } from "../../credential.js" diff --git a/packages/core/src/plugin/provider/vllm.ts b/packages/core/src/plugin/provider/vllm.ts index e5c83065d8ec..154451dd17b4 100644 --- a/packages/core/src/plugin/provider/vllm.ts +++ b/packages/core/src/plugin/provider/vllm.ts @@ -1,7 +1,7 @@ import { define } from "@opencode/plugin/effect/plugin" import type { Entry } from "@opencode/schema/config" import { Duration, Effect, Schedule, Schema, Semaphore, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { Config } from "../../config.js" import { Model } from "../../model.js" import type { PluginInternal } from "../internal.js" diff --git a/packages/core/src/plugin/vcs/git.ts b/packages/core/src/plugin/vcs/git.ts index 6314d86e0b0c..70cf59a9946a 100644 --- a/packages/core/src/plugin/vcs/git.ts +++ b/packages/core/src/plugin/vcs/git.ts @@ -2,7 +2,7 @@ export * as VcsGitPlugin from "./git.js" import { define } from "@opencode/plugin/effect/plugin" import { Effect } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { FileDiff } from "@opencode/schema/file-diff" import { Base, BranchList, FileStatus, Info, Mode } from "@opencode/schema/vcs" import { AppProcess } from "@opencode/util/process" diff --git a/packages/core/src/plugin/vcs/hg.ts b/packages/core/src/plugin/vcs/hg.ts index fbf5a09410a2..be53bcf1db81 100644 --- a/packages/core/src/plugin/vcs/hg.ts +++ b/packages/core/src/plugin/vcs/hg.ts @@ -2,7 +2,7 @@ export * as VcsHgPlugin from "./hg.js" import path from "path" import { Effect } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { define } from "@opencode/plugin/effect/plugin" import { FileDiff } from "@opencode/schema/file-diff" import { FileStatus, Info, Mode } from "@opencode/schema/vcs" diff --git a/packages/core/src/plugin/websearch/exa.ts b/packages/core/src/plugin/websearch/exa.ts index 1dc3a26108b1..555780f4f2af 100644 --- a/packages/core/src/plugin/websearch/exa.ts +++ b/packages/core/src/plugin/websearch/exa.ts @@ -2,7 +2,7 @@ export * as WebSearchExa from "./exa.js" import { define } from "@opencode/plugin/effect/plugin" import { Effect, Schema, Scope } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { WebSearchMcp } from "./mcp.js" export const endpoint = "https://mcp.exa.ai/mcp" diff --git a/packages/core/src/plugin/websearch/firecrawl.ts b/packages/core/src/plugin/websearch/firecrawl.ts index 1ea260e0c5da..39126ffcc776 100644 --- a/packages/core/src/plugin/websearch/firecrawl.ts +++ b/packages/core/src/plugin/websearch/firecrawl.ts @@ -2,7 +2,7 @@ export * as WebSearchFirecrawl from "./firecrawl.js" import { define } from "@opencode/plugin/effect/plugin" import { Effect, Option, Schema, Scope } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { App } from "../../app.js" import { WebSearchMcp } from "./mcp.js" diff --git a/packages/core/src/plugin/websearch/mcp.ts b/packages/core/src/plugin/websearch/mcp.ts index 478d4feb5f8d..568d27b983b6 100644 --- a/packages/core/src/plugin/websearch/mcp.ts +++ b/packages/core/src/plugin/websearch/mcp.ts @@ -1,7 +1,7 @@ export * as WebSearchMcp from "./mcp.js" import { Duration, Effect, Schema } from "effect" -import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/http" import { collectBoundedResponseBody } from "../../tool/http-body.js" export const MAX_RESPONSE_BYTES = 256 * 1024 diff --git a/packages/core/src/plugin/websearch/parallel.ts b/packages/core/src/plugin/websearch/parallel.ts index 5184155482bd..5b858aff5260 100644 --- a/packages/core/src/plugin/websearch/parallel.ts +++ b/packages/core/src/plugin/websearch/parallel.ts @@ -2,7 +2,7 @@ export * as WebSearchParallel from "./parallel.js" import { define } from "@opencode/plugin/effect/plugin" import { Effect, Schema, Scope } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { App } from "../../app.js" import { WebSearchMcp } from "./mcp.js" diff --git a/packages/core/src/plugin/websearch/tavily.ts b/packages/core/src/plugin/websearch/tavily.ts index 4b568a1fb0d2..54c047740133 100644 --- a/packages/core/src/plugin/websearch/tavily.ts +++ b/packages/core/src/plugin/websearch/tavily.ts @@ -2,7 +2,7 @@ export * as WebSearchTavily from "./tavily.js" import { define } from "@opencode/plugin/effect/plugin" import { Duration, Effect, Schema, Scope } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { App } from "../../app.js" export const endpoint = "https://api.tavily.com/search" diff --git a/packages/core/src/plugin/websearch/tinyfish.ts b/packages/core/src/plugin/websearch/tinyfish.ts index 77d86acddc1d..604540f373ba 100644 --- a/packages/core/src/plugin/websearch/tinyfish.ts +++ b/packages/core/src/plugin/websearch/tinyfish.ts @@ -2,7 +2,7 @@ export * as WebSearchTinyFish from "./tinyfish.js" import { define } from "@opencode/plugin/effect/plugin" import { Effect, Option, Schema, Scope } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { App } from "../../app.js" import { WebSearchMcp } from "./mcp.js" diff --git a/packages/core/src/project.ts b/packages/core/src/project.ts index bb51148330b8..6229abab030d 100644 --- a/packages/core/src/project.ts +++ b/packages/core/src/project.ts @@ -1,7 +1,7 @@ export * as Project from "./project.js" import { Context, Effect, Layer, Schema } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { and, asc, desc, eq, gte, isNull, lte, sql } from "drizzle-orm" import path from "path" import { AbsolutePath } from "./schema.js" diff --git a/packages/core/src/ripgrep.ts b/packages/core/src/ripgrep.ts index 4f2317e0d820..aa3b06f827dc 100644 --- a/packages/core/src/ripgrep.ts +++ b/packages/core/src/ripgrep.ts @@ -1,7 +1,7 @@ export * as Ripgrep from "./ripgrep.js" import { Context, Effect, Fiber, Layer, Schema, Stream } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { Entry, Match } from "@opencode/schema/filesystem" import { makeLocationNode } from "@opencode/util/effect/app-node" import { collectStream, waitForAbort } from "@opencode/util/process" diff --git a/packages/core/src/ripgrep/binary.ts b/packages/core/src/ripgrep/binary.ts index 4ca73e8bb8da..2b013128b3a9 100644 --- a/packages/core/src/ripgrep/binary.ts +++ b/packages/core/src/ripgrep/binary.ts @@ -1,8 +1,8 @@ import path from "path" import { Context, Effect, Layer, Stream } from "effect" -import { HttpClient, HttpClientRequest } from "effect/unstable/http" -import { ChildProcess } from "effect/unstable/process" -import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import { HttpClient, HttpClientRequest } from "effect/http" +import { ChildProcess } from "effect/process" +import { ChildProcessSpawner } from "effect/process/ChildProcessSpawner" import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner" import { makeGlobalNode } from "@opencode/util/effect/app-node" import { httpClient } from "@opencode/util/effect/app-node-platform" diff --git a/packages/core/src/schema.ts b/packages/core/src/schema.ts index eb0ae4b07dc7..3909960fba48 100644 --- a/packages/core/src/schema.ts +++ b/packages/core/src/schema.ts @@ -43,8 +43,8 @@ export type DeepMutable = T extends string | number | boolean | bigint | symb * Nominal wrapper for scalar types. The class itself is a valid schema — * pass it directly to `Schema.decodeUnknownSync`, `Schema.decodeEffect`, etc. * - * The runtime value remains an unwrapped primitive. `Schema.brand` supplies - * the primitive schema behavior and constructor validation, while the class + * The runtime value remains an unwrapped primitive. The underlying schema + * supplies primitive behavior and constructor validation, while the class * supplies the nominal TypeScript identity. * Apply checks and annotations to the underlying schema before wrapping it; * schema rebuild operations intentionally return the underlying schema shape. @@ -83,7 +83,8 @@ export function Newtype() { declare readonly _newtype: Tag } - Object.setPrototypeOf(Base, schema.pipe(Schema.brand(tag))) + // The class carries the nominal type; Effect 4's brand is type-only and no longer stores the tag on the schema. + Object.setPrototypeOf(Base, schema) return Base as unknown as NewtypeSchema } } diff --git a/packages/core/src/session/model-request.ts b/packages/core/src/session/model-request.ts index 26cecde25d02..bc420aa13f80 100644 --- a/packages/core/src/session/model-request.ts +++ b/packages/core/src/session/model-request.ts @@ -24,7 +24,7 @@ import type { Agent } from "@opencode/schema/agent" import type { Model } from "@opencode/schema/model" import type { Content } from "@opencode/schema/tool" import { Cause, Context, Effect, Layer, Result, Stream } from "effect" -import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClientRequest, HttpClientResponse } from "effect/http" import { makeLocationNode } from "@opencode/util/effect/app-node" import { App } from "../app.js" import { Permission } from "../permission.js" diff --git a/packages/core/src/session/model-transport.ts b/packages/core/src/session/model-transport.ts index 638ef66af4d9..830855e27c6c 100644 --- a/packages/core/src/session/model-transport.ts +++ b/packages/core/src/session/model-transport.ts @@ -13,8 +13,8 @@ import { import { AIError, AIErrorReason, TransportError, type TransportOperation } from "@opencode/ai" import { Hash } from "@opencode/util/hash" import { Cause, Clock, Context, Effect, Fiber, Layer, Metric, Queue, Scope, Semaphore, 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 { makeGlobalNode } from "@opencode/util/effect/app-node" import { SessionSchema } from "./schema.js" import { webSocketConstructor } from "../effect/app-node-platform.js" diff --git a/packages/core/src/shell.ts b/packages/core/src/shell.ts index 393275517141..6953692dfbad 100644 --- a/packages/core/src/shell.ts +++ b/packages/core/src/shell.ts @@ -2,7 +2,7 @@ export * as Shell from "./shell.js" import path from "path" import { Context, Deferred, Duration, Effect, Fiber, Latch, Layer, Schema, Schedule, Stream } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { produce } from "immer" import { Shell } from "@opencode/schema/shell" import { AppProcess } from "@opencode/util/process" diff --git a/packages/core/src/skill/discovery.ts b/packages/core/src/skill/discovery.ts index f3173184cecf..2d2dbe70c938 100644 --- a/packages/core/src/skill/discovery.ts +++ b/packages/core/src/skill/discovery.ts @@ -2,7 +2,7 @@ export * as SkillDiscovery from "./discovery.js" import path from "path" import { Context, Effect, Layer, Schedule, Schema } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { FSUtil } from "@opencode/util/fs-util" import { Global } from "@opencode/util/global" import { makeGlobalNode } from "@opencode/util/effect/app-node" diff --git a/packages/core/src/tool/http-body.ts b/packages/core/src/tool/http-body.ts index 7cb534a444fc..beaad3851d66 100644 --- a/packages/core/src/tool/http-body.ts +++ b/packages/core/src/tool/http-body.ts @@ -1,5 +1,5 @@ import { Effect, Stream } from "effect" -import { HttpClientResponse } from "effect/unstable/http" +import { HttpClientResponse } from "effect/http" export const collectBoundedResponseBody = ( response: HttpClientResponse.HttpClientResponse, diff --git a/packages/core/src/tool/plugin/webfetch.ts b/packages/core/src/tool/plugin/webfetch.ts index ec445e469b54..7c40d5b5106c 100644 --- a/packages/core/src/tool/plugin/webfetch.ts +++ b/packages/core/src/tool/plugin/webfetch.ts @@ -3,7 +3,7 @@ export * as WebFetchTool from "./webfetch.js" import type { Context } from "@opencode/plugin/effect/plugin" import { ToolFailure } from "@opencode/ai" import { Duration, Effect, Schema } from "effect" -import { HttpClient, type HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, type HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/http" import { Parser } from "htmlparser2" import { Permission } from "../../permission.js" import { convertHTMLToMarkdown, MAX_MARKDOWN_BYTES } from "../html-markdown.js" diff --git a/packages/core/src/tool/plugin/websearch.ts b/packages/core/src/tool/plugin/websearch.ts index 0338dfdb601e..e25084b0a406 100644 --- a/packages/core/src/tool/plugin/websearch.ts +++ b/packages/core/src/tool/plugin/websearch.ts @@ -4,7 +4,7 @@ import type { Context } from "@opencode/plugin/effect/plugin" import type { SessionHooks } from "@opencode/plugin/effect/session" import { ToolFailure } from "@opencode/ai" import { Effect, Schema, Semaphore } from "effect" -import { HttpClientError } from "effect/unstable/http" +import { HttpClientError } from "effect/http" import { Form } from "../../form.js" import { Permission } from "../../permission.js" import { WebSearch } from "../../websearch.js" diff --git a/packages/core/src/websearch.ts b/packages/core/src/websearch.ts index 7ec63bb7b970..dc37dd45c05b 100644 --- a/packages/core/src/websearch.ts +++ b/packages/core/src/websearch.ts @@ -4,7 +4,7 @@ import { WebSearch } from "@opencode/schema/websearch" import type { Session } from "@opencode/schema/session" import { SessionEvent } from "@opencode/schema/session-event" import { Clock, Context, Effect, Layer, Option, Schema, Stream } from "effect" -import { HttpClientError } from "effect/unstable/http" +import { HttpClientError } from "effect/http" import { makeLocationNode } from "@opencode/util/effect/app-node" import { Bus } from "./bus.js" import { KV } from "./kv.js" diff --git a/packages/core/src/wellknown.ts b/packages/core/src/wellknown.ts index 206e42071fb0..9e0eb7704ba0 100644 --- a/packages/core/src/wellknown.ts +++ b/packages/core/src/wellknown.ts @@ -2,7 +2,7 @@ export * as WellKnown from "./wellknown.js" import { Integration } from "@opencode/schema/integration" import { Context, Effect, Layer, Ref, Schema, Semaphore } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { isDeepStrictEqual } from "node:util" import { makeGlobalNode } from "@opencode/util/effect/app-node" import { httpClient } from "@opencode/util/effect/app-node-platform" diff --git a/packages/core/src/workspace.ts b/packages/core/src/workspace.ts index a71b84bfba75..a397a87ebd3c 100644 --- a/packages/core/src/workspace.ts +++ b/packages/core/src/workspace.ts @@ -5,7 +5,7 @@ import { makeGlobalNode } from "@opencode/util/effect/app-node" import { eq } from "drizzle-orm" import { Clock, Context, Deferred, Duration, Effect, Exit, FiberSet, Layer, Ref, Schedule, Schema, Scope } from "effect" import { systemError } from "effect/PlatformError" -import { make } from "effect/unstable/process/ChildProcessSpawner" +import { make } from "effect/process/ChildProcessSpawner" import type { EnvironmentDriver } from "./environment/driver.js" import { Database } from "./database/database.js" import { KeyedMutex } from "./effect/keyed-mutex.js" diff --git a/packages/core/src/worktree.ts b/packages/core/src/worktree.ts index 8f2fb35b6dea..f64233eb074b 100644 --- a/packages/core/src/worktree.ts +++ b/packages/core/src/worktree.ts @@ -21,7 +21,7 @@ import { WorktreeGit } from "./worktree/git.js" import type { EffectDrizzleSqlite } from "./database/drizzle.js" import { ProjectTable } from "./project/sql.js" import { AppProcess } from "@opencode/util/process" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { WorktreeStrategies } from "./worktree/strategies.js" export type { Strategy, Editor } from "./worktree/strategies.js" diff --git a/packages/core/test/aisdk.test.ts b/packages/core/test/aisdk.test.ts index f4a2a2cceaf1..6e755d1924fd 100644 --- a/packages/core/test/aisdk.test.ts +++ b/packages/core/test/aisdk.test.ts @@ -25,7 +25,7 @@ import { LLMClient, RequestExecutor } from "@opencode/ai/route" import { compileRequest } from "@opencode/ai/route/client" import { expect } from "bun:test" import { Effect, Layer } from "effect" -import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClientRequest, HttpClientResponse } from "effect/http" import { testEffect } from "./lib/effect" const it = testEffect(AISDK.locationLayer) diff --git a/packages/core/test/config/config.test.ts b/packages/core/test/config/config.test.ts index c3deb28d364f..0be8a798fceb 100644 --- a/packages/core/test/config/config.test.ts +++ b/packages/core/test/config/config.test.ts @@ -1,8 +1,7 @@ import path from "path" import fs from "fs/promises" import { describe, expect, test } from "bun:test" -import { Effect, Fiber, Layer, Logger, Schema, Stream } from "effect" -import { FastCheck } from "effect/testing" +import { Arbitrary, Effect, Fiber, Layer, Logger, Schema, Stream } from "effect" import { Config } from "@opencode/core/config" import { Directory, Document, Event, Info } from "@opencode/schema/config" import { ConfigModel } from "@opencode/schema/config/model" @@ -632,17 +631,15 @@ describe("Config", () => { }) test("migrates arbitrary v1 configuration into valid v2 configuration", () => { - FastCheck.assert( - FastCheck.property(Schema.toArbitrary(ConfigV1.Info)(FastCheck), (info) => { - const parsed = Schema.decodeUnknownSync(ConfigV1.Info)( - Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown))( - Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown))(info), - ), - ) - Schema.decodeUnknownSync(Info)(ConfigMigrateV1.migrate(parsed), { errors: "all" }) - }), - { numRuns: 100 }, - ) + const infos = Effect.runSync(Arbitrary.sampleEffect(Arbitrary.schema(ConfigV1.Info), { count: 100 })) + for (const info of infos) { + const parsed = Schema.decodeUnknownSync(ConfigV1.Info)( + Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown))( + Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown))(info), + ), + ) + Schema.decodeUnknownSync(Info)(ConfigMigrateV1.migrate(parsed), { errors: "all" }) + } }, 30_000) test("migrates the v1 experimental subagent depth", () => { diff --git a/packages/core/test/config/normalization.test.ts b/packages/core/test/config/normalization.test.ts index 28702520f248..99508547b862 100644 --- a/packages/core/test/config/normalization.test.ts +++ b/packages/core/test/config/normalization.test.ts @@ -1,6 +1,5 @@ import { describe, expect, test } from "bun:test" -import { Duration, Schema } from "effect" -import { FastCheck } from "effect/testing" +import { Arbitrary, Duration, Effect, Schema } from "effect" import { ConfigNormalize } from "@opencode/core/config/normalize" import { Info } from "@opencode/schema/config" @@ -80,16 +79,14 @@ describe("ConfigNormalize", () => { }) test("preserves arbitrary JSON-round-tripped native configuration", () => { - FastCheck.assert( - FastCheck.property(Schema.toArbitrary(Info)(FastCheck), (info) => { - const source = JSON.parse(JSON.stringify(Schema.encodeSync(Info)(info))) - const result = normalized(source) - expect(Schema.decodeUnknownSync(Info)(result.encoded)).toEqual( - Schema.decodeUnknownSync(Info)(withoutEmptyCompatibilityContainers(source)), - ) - }), - { numRuns: 100 }, - ) + const infos = Effect.runSync(Arbitrary.sampleEffect(Arbitrary.schema(Info), { count: 100 })) + for (const info of infos) { + const source = JSON.parse(JSON.stringify(Schema.encodeSync(Info)(info))) + const result = normalized(source) + expect(Schema.decodeUnknownSync(Info)(result.encoded)).toEqual( + Schema.decodeUnknownSync(Info)(withoutEmptyCompatibilityContainers(source)), + ) + } }) test("merges named maps by entry and gives valid native entries precedence", () => { diff --git a/packages/core/test/database-drizzle.test.ts b/packages/core/test/database-drizzle.test.ts index d2c0958dcefc..e863b7f6b588 100644 --- a/packages/core/test/database-drizzle.test.ts +++ b/packages/core/test/database-drizzle.test.ts @@ -7,8 +7,8 @@ import { SqliteClient } from "@effect/sql-sqlite-bun" import { eq, sql } from "drizzle-orm" import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core" import { Cause, Effect, Tracer } from "effect" -import type { SqlClient } from "effect/unstable/sql/SqlClient" -import { isSqlError } from "effect/unstable/sql/SqlError" +import type { SqlClient } from "effect/sql/SqlClient" +import { isSqlError } from "effect/sql/SqlError" import { EffectDrizzleSqlite } from "@opencode/core/database/drizzle" import { EffectDrizzleQueryError } from "drizzle-orm/effect-core/errors" diff --git a/packages/core/test/database-migration.test.ts b/packages/core/test/database-migration.test.ts index 33e350175856..bfd8a9ecdfcd 100644 --- a/packages/core/test/database-migration.test.ts +++ b/packages/core/test/database-migration.test.ts @@ -5,8 +5,8 @@ import path from "path" import { SqliteClient } from "@effect/sql-sqlite-bun" import { EffectDrizzleSqlite } from "@opencode/core/database/drizzle" import { Deferred, Effect, Fiber, Layer } from "effect" -import { Reactivity } from "effect/unstable/reactivity" -import { SqlClient, Statement } from "effect/unstable/sql" +import { Reactivity } from "effect/reactivity" +import { SqlClient, Statement } from "effect/sql" import { sql } from "drizzle-orm" import { DatabaseMigration } from "@opencode/core/database/migration" import { migrations } from "@opencode/core/database/migration.gen" diff --git a/packages/core/test/effect-app-node-platform.test.ts b/packages/core/test/effect-app-node-platform.test.ts index 380852721cf9..8c52f824190c 100644 --- a/packages/core/test/effect-app-node-platform.test.ts +++ b/packages/core/test/effect-app-node-platform.test.ts @@ -2,8 +2,8 @@ import { describe, expect, test } from "bun:test" import { WebSocketTransport } from "@opencode/ai/route" import { WebSocketConstructor } from "@opencode/core/effect/websocket-constructor" import { Effect } from "effect" -import { Headers } from "effect/unstable/http" -import { Socket } from "effect/unstable/socket" +import { Headers } from "effect/http" +import { Socket } from "effect/socket" const makeServer = (fetch: (request: Request, server: Bun.Server) => Response | undefined) => Effect.acquireRelease( diff --git a/packages/core/test/effect/cross-spawn-spawner.test.ts b/packages/core/test/effect/cross-spawn-spawner.test.ts index a7887642723e..bd265a5a7112 100644 --- a/packages/core/test/effect/cross-spawn-spawner.test.ts +++ b/packages/core/test/effect/cross-spawn-spawner.test.ts @@ -3,7 +3,7 @@ import fs from "node:fs/promises" import os from "node:os" import path from "node:path" import { Deferred, Effect, Exit, PlatformError, Stream } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess, ChildProcessSpawner } from "effect/process" import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner" import { LayerNode } from "@opencode/util/effect/layer-node" import { testEffect } from "../lib/effect" diff --git a/packages/core/test/environment.test.ts b/packages/core/test/environment.test.ts index a093eab9ec7c..f1a238f06028 100644 --- a/packages/core/test/environment.test.ts +++ b/packages/core/test/environment.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises" import { describe, expect } from "bun:test" import { Effect } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess, ChildProcessSpawner } from "effect/process" import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner" import { LayerNode } from "@opencode/util/effect/layer-node" import { EnvironmentUnavailable } from "../src/environment/unavailable" diff --git a/packages/core/test/fixture/environment.ts b/packages/core/test/fixture/environment.ts index 31c31535d0fc..272a86c7f886 100644 --- a/packages/core/test/fixture/environment.ts +++ b/packages/core/test/fixture/environment.ts @@ -2,7 +2,7 @@ import { Environment } from "@opencode/core/environment/index" import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner" import { LayerNode } from "@opencode/util/effect/layer-node" import { Effect, Layer } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess, ChildProcessSpawner } from "effect/process" /** * The host environment, without the workspace machinery: what a location with no `workspaceID` diff --git a/packages/core/test/generate.test.ts b/packages/core/test/generate.test.ts index 0e0540da22db..7b30f59652e2 100644 --- a/packages/core/test/generate.test.ts +++ b/packages/core/test/generate.test.ts @@ -11,7 +11,7 @@ import { ID, Info, Model, Ref } from "@opencode/core/model" import { Provider } from "@opencode/core/provider" import { Npm } from "@opencode/util/npm" import { Effect, Layer } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientResponse } from "effect/http" import { testEffect } from "./lib/effect" const selected = Info.make({ diff --git a/packages/core/test/lib/effect.ts b/packages/core/test/lib/effect.ts index 8cc23621b54a..8d67db19f5e9 100644 --- a/packages/core/test/lib/effect.ts +++ b/packages/core/test/lib/effect.ts @@ -1,7 +1,7 @@ import { test, type TestOptions } from "bun:test" import { Cause, Effect, Exit, Layer, type Scope } from "effect" import { TestClock, TestConsole } from "effect/testing" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" type Body = Effect.Effect | (() => Effect.Effect) diff --git a/packages/core/test/lib/websearch.ts b/packages/core/test/lib/websearch.ts index defe86af230b..3af091a3f33e 100644 --- a/packages/core/test/lib/websearch.ts +++ b/packages/core/test/lib/websearch.ts @@ -1,7 +1,7 @@ export * as TestWebSearch from "./websearch" import { Context, Deferred, Effect, Layer } from "effect" -import { HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClientError, HttpClientRequest, HttpClientResponse } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { LayerNode } from "@opencode/util/effect/layer-node" import { Bus } from "@opencode/core/bus" diff --git a/packages/core/test/mcp.test.ts b/packages/core/test/mcp.test.ts index 81785d1d3698..894903ae661a 100644 --- a/packages/core/test/mcp.test.ts +++ b/packages/core/test/mcp.test.ts @@ -51,8 +51,8 @@ import { Stream, } from "effect" import { TestClock } from "effect/testing" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" -import { ExitCode, makeHandle, ProcessId } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcess, ChildProcessSpawner } from "effect/process" +import { ExitCode, makeHandle, ProcessId } from "effect/process/ChildProcessSpawner" import { Image } from "@opencode/core/image" import { advance, drain } from "./lib/clock" import { testEffect } from "./lib/effect" diff --git a/packages/core/test/model-resolver.test.ts b/packages/core/test/model-resolver.test.ts index e748490224c4..8a30ba7dfe24 100644 --- a/packages/core/test/model-resolver.test.ts +++ b/packages/core/test/model-resolver.test.ts @@ -3,7 +3,7 @@ import { LLM, LanguageModel, Message } from "@opencode/ai" import { OpenAIChat } from "@opencode/ai/protocols" import { compileRequest } from "@opencode/ai/route/client" import { ConfigProvider, Effect, Layer } from "effect" -import { Headers } from "effect/unstable/http" +import { Headers } from "effect/http" import { AISDKNative } from "@opencode/core/aisdk-native" import { Credential } from "@opencode/core/credential" import { Integration } from "@opencode/core/integration" diff --git a/packages/core/test/models.test.ts b/packages/core/test/models.test.ts index c0780e57f7a4..8f00ce7a9c67 100644 --- a/packages/core/test/models.test.ts +++ b/packages/core/test/models.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { Money } from "@opencode/schema/money" import { Effect, Fiber, Layer, Ref, Scope, Stream } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientResponse } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { LayerNodePlatform } from "@opencode/util/effect/app-node-platform" import { LayerNode } from "@opencode/util/effect/layer-node" diff --git a/packages/core/test/network-guard.test.ts b/packages/core/test/network-guard.test.ts index c4b8481afb76..0efc867fc9e7 100644 --- a/packages/core/test/network-guard.test.ts +++ b/packages/core/test/network-guard.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Layer } from "effect" -import { FetchHttpClient, HttpClient, HttpClientResponse } from "effect/unstable/http" +import { FetchHttpClient, HttpClient, HttpClientResponse } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { LayerNodePlatform } from "@opencode/util/effect/app-node-platform" import { it, refuseNetwork } from "./lib/effect" diff --git a/packages/core/test/plugin/provider-chatgpt.test.ts b/packages/core/test/plugin/provider-chatgpt.test.ts index 98747b909a66..d4e3d144565d 100644 --- a/packages/core/test/plugin/provider-chatgpt.test.ts +++ b/packages/core/test/plugin/provider-chatgpt.test.ts @@ -6,7 +6,7 @@ import { AIError, HttpContext, RateLimitError } from "@opencode/ai" import { classifyProviderFailure } from "@opencode/ai/provider-error" import { describe, expect } from "bun:test" import { ConfigProvider, DateTime, Deferred, Effect, Schedule } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientResponse } from "effect/http" import { exportJWK, generateKeyPair, SignJWT } from "jose" import { App } from "@opencode/core/app" import { Credential } from "@opencode/core/credential" diff --git a/packages/core/test/plugin/provider-digitalocean.test.ts b/packages/core/test/plugin/provider-digitalocean.test.ts index c62517606996..5386fa6a9eb3 100644 --- a/packages/core/test/plugin/provider-digitalocean.test.ts +++ b/packages/core/test/plugin/provider-digitalocean.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { Clock, Effect, Schedule } from "effect" import { TestClock } from "effect/testing" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { Credential } from "@opencode/core/credential" import { Integration } from "@opencode/core/integration" import { Model } from "@opencode/core/model" diff --git a/packages/core/test/plugin/provider-gitlab-oauth.test.ts b/packages/core/test/plugin/provider-gitlab-oauth.test.ts index 6699a077f49e..7abed9c5ba3e 100644 --- a/packages/core/test/plugin/provider-gitlab-oauth.test.ts +++ b/packages/core/test/plugin/provider-gitlab-oauth.test.ts @@ -1,6 +1,6 @@ import { describe, expect } from "bun:test" import { Clock, Effect, Schedule } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { Credential } from "@opencode/core/credential" import { Integration } from "@opencode/core/integration" import { Plugin } from "@opencode/core/plugin" diff --git a/packages/core/test/plugin/provider-opencode.test.ts b/packages/core/test/plugin/provider-opencode.test.ts index 3ce2960dbb51..991091f4092e 100644 --- a/packages/core/test/plugin/provider-opencode.test.ts +++ b/packages/core/test/plugin/provider-opencode.test.ts @@ -5,7 +5,7 @@ import { ConfigPolicy } from "@opencode/schema/config/policy" import { Money } from "@opencode/schema/money" import { Effect, Layer, Stream } from "effect" import { TestClock } from "effect/testing" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { Agent } from "@opencode/core/agent" import { App } from "@opencode/core/app" import { Config } from "@opencode/core/config" diff --git a/packages/core/test/plugin/provider-poe.test.ts b/packages/core/test/plugin/provider-poe.test.ts index c7afed50f19e..bc53389c390d 100644 --- a/packages/core/test/plugin/provider-poe.test.ts +++ b/packages/core/test/plugin/provider-poe.test.ts @@ -12,7 +12,7 @@ import { Provider } from "@opencode/core/provider" import { expect } from "bun:test" import { Clock, Deferred, Effect, Fiber, Layer, Schedule, Stream } from "effect" import { TestClock } from "effect/testing" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { testEffect } from "../lib/effect" import { PluginTestLayer } from "./fixture" diff --git a/packages/core/test/plugin/provider-snowflake-cortex.test.ts b/packages/core/test/plugin/provider-snowflake-cortex.test.ts index 5651dcac311b..36959af196f0 100644 --- a/packages/core/test/plugin/provider-snowflake-cortex.test.ts +++ b/packages/core/test/plugin/provider-snowflake-cortex.test.ts @@ -16,8 +16,8 @@ import { SessionModelRequest } from "@opencode/core/session/model-request" import { SessionModelTransport } from "@opencode/core/session/model-transport" import { expect } from "bun:test" import { Effect, Layer, Schedule, Stream } from "effect" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" -import { Socket } from "effect/unstable/socket" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" +import { Socket } from "effect/socket" import { withEnv } from "../fixture/env" import { testEffect } from "../lib/effect" import { PluginTestLayer } from "./fixture" diff --git a/packages/core/test/plugin/websearch-fixture.ts b/packages/core/test/plugin/websearch-fixture.ts index 3933adcde16e..21ed89ba9cbe 100644 --- a/packages/core/test/plugin/websearch-fixture.ts +++ b/packages/core/test/plugin/websearch-fixture.ts @@ -1,5 +1,5 @@ import { Effect, Layer } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientResponse } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { LayerNode } from "@opencode/util/effect/layer-node" import { Credential } from "@opencode/core/credential" diff --git a/packages/core/test/process/process.test.ts b/packages/core/test/process/process.test.ts index 1ee13c4cbb76..e644aafe2760 100644 --- a/packages/core/test/process/process.test.ts +++ b/packages/core/test/process/process.test.ts @@ -5,7 +5,7 @@ import { realpathSync } from "node:fs" import { tmpdir } from "node:os" import path from "node:path" import { Effect, Exit, Fiber, Stream } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { LayerNode } from "@opencode/util/effect/layer-node" import { AppProcess } from "@opencode/util/process" import { testEffect } from "../lib/effect" diff --git a/packages/core/test/session-checkpoint-transport.test.ts b/packages/core/test/session-checkpoint-transport.test.ts index 16726a4ad43d..4c23590db1ab 100644 --- a/packages/core/test/session-checkpoint-transport.test.ts +++ b/packages/core/test/session-checkpoint-transport.test.ts @@ -6,7 +6,7 @@ import { SessionModelTransport } from "../src/session/model-transport" import { WebSocketConstructor } from "../src/effect/websocket-constructor" import { Session } from "@opencode/schema/session" import { Effect, Layer, Schema } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" import { testEffect } from "./lib/effect" import { makeWebSocketServer } from "./lib/websocket-server" diff --git a/packages/core/test/session-compaction-transport.test.ts b/packages/core/test/session-compaction-transport.test.ts index 96b01be66851..938397b5b33b 100644 --- a/packages/core/test/session-compaction-transport.test.ts +++ b/packages/core/test/session-compaction-transport.test.ts @@ -6,8 +6,8 @@ import { SessionModelTransport } from "@opencode/core/session/model-transport" import { WebSocketConstructor } from "@opencode/core/effect/websocket-constructor" import { Session } from "@opencode/schema/session" import { Effect, Latch, Layer, Schema } from "effect" -import { FetchHttpClient } from "effect/unstable/http" -import { Socket } from "effect/unstable/socket" +import { FetchHttpClient } from "effect/http" +import { Socket } from "effect/socket" import { testEffect } from "./lib/effect" const decodeBody = Schema.decodeSync(Schema.fromJsonString(Schema.Record(Schema.String, Schema.Unknown))) diff --git a/packages/core/test/session-model-request-hooks.test.ts b/packages/core/test/session-model-request-hooks.test.ts index 3b7b1d45f45b..8e7612066344 100644 --- a/packages/core/test/session-model-request-hooks.test.ts +++ b/packages/core/test/session-model-request-hooks.test.ts @@ -12,7 +12,7 @@ import { SessionModelRequest } from "@opencode/core/session/model-request" import { SessionModelTransport } from "@opencode/core/session/model-transport" import { SessionRunnerModel } from "@opencode/core/session/runner/model" import { DateTime, Effect, Stream } from "effect" -import { HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClientRequest, HttpClientResponse } from "effect/http" import { testEffect } from "./lib/effect" import { PluginTestLayer } from "./plugin/fixture" diff --git a/packages/core/test/session-model-transport-live.test.ts b/packages/core/test/session-model-transport-live.test.ts index 3ca601baceb6..e14177e97249 100644 --- a/packages/core/test/session-model-transport-live.test.ts +++ b/packages/core/test/session-model-transport-live.test.ts @@ -12,8 +12,8 @@ import { SessionModelTransport } from "@opencode/core/session/model-transport" import { WebSocketConstructor } from "@opencode/core/effect/websocket-constructor" import { Session } from "@opencode/schema/session" import { Effect, Fiber, Layer, 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 { makeWebSocketServer, type WebSocketServerFixture, type WebSocketServerOptions } from "./lib/websocket-server" const sessionID = Session.ID.make("ses_live_websocket") diff --git a/packages/core/test/session-model-transport.test.ts b/packages/core/test/session-model-transport.test.ts index e38c3fda60e5..fd126bf28206 100644 --- a/packages/core/test/session-model-transport.test.ts +++ b/packages/core/test/session-model-transport.test.ts @@ -10,7 +10,7 @@ import { SessionModelTransport } from "@opencode/core/session/model-transport" import { Session } from "@opencode/schema/session" import { Cause, Deferred, Effect, Fiber, Metric, Queue, Stream } from "effect" import { TestClock } from "effect/testing" -import { Headers } from "effect/unstable/http" +import { Headers } from "effect/http" const session = Session.ID.make("ses_transport") const otherSession = Session.ID.make("ses_transport_other") diff --git a/packages/core/test/shell-retention.test.ts b/packages/core/test/shell-retention.test.ts index d0a400d8230b..36879be3d1ac 100644 --- a/packages/core/test/shell-retention.test.ts +++ b/packages/core/test/shell-retention.test.ts @@ -1,7 +1,7 @@ import { expect } from "bun:test" import { Deferred, Effect, Fiber, Layer, Queue, Scope, Sink, Stream } from "effect" -import { ChildProcessSpawner } from "effect/unstable/process" -import { ExitCode, makeHandle, ProcessId } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcessSpawner } from "effect/process" +import { ExitCode, makeHandle, ProcessId } from "effect/process/ChildProcessSpawner" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { Config } from "@opencode/core/config" import { Environment } from "@opencode/core/environment/index" diff --git a/packages/core/test/skill-discovery.test.ts b/packages/core/test/skill-discovery.test.ts index fb60bf9014c6..ce9eb980a46a 100644 --- a/packages/core/test/skill-discovery.test.ts +++ b/packages/core/test/skill-discovery.test.ts @@ -4,7 +4,7 @@ import { createServer } from "node:http" import { describe, expect } from "bun:test" import { NodeHttpServer } from "@effect/platform-node" import { Effect } from "effect" -import { HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { HttpServer, HttpServerRequest, HttpServerResponse } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { Global } from "@opencode/util/global" import { SkillDiscovery } from "@opencode/core/skill/discovery" diff --git a/packages/core/test/sqlite-workerd.test.ts b/packages/core/test/sqlite-workerd.test.ts index 8bfdaf3663c8..ae5ef2601144 100644 --- a/packages/core/test/sqlite-workerd.test.ts +++ b/packages/core/test/sqlite-workerd.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { Effect, Layer } from "effect" -import { SqlClient } from "effect/unstable/sql" -import { SqlError } from "effect/unstable/sql/SqlError" +import { SqlClient } from "effect/sql" +import { SqlError } from "effect/sql/SqlError" import { sqliteLayer } from "@opencode/core/database/sqlite.workerd" import type { DurableObjectStorage } from "@opencode/core/database/sqlite.workerd" import { makeDurableObjectStorage } from "./fixture/durable-object-storage" diff --git a/packages/core/test/state-replay.test.ts b/packages/core/test/state-replay.test.ts index 299f42255f39..91e46fb2ae22 100644 --- a/packages/core/test/state-replay.test.ts +++ b/packages/core/test/state-replay.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { State } from "@opencode/core/state" import { Effect } from "effect" -import { FastCheck } from "effect/testing" +import FastCheck from "fast-check" type Operation = { multiply: number; add: number } type Value = { value: number; order: number[] } diff --git a/packages/core/test/tool-read-filesystem.test.ts b/packages/core/test/tool-read-filesystem.test.ts index 184e0448a5f2..1410f92de873 100644 --- a/packages/core/test/tool-read-filesystem.test.ts +++ b/packages/core/test/tool-read-filesystem.test.ts @@ -9,7 +9,7 @@ import { CrossSpawnSpawner } from "@opencode/util/cross-spawn-spawner" import { LayerNodePlatform } from "@opencode/util/effect/app-node-platform" import { LayerNode } from "@opencode/util/effect/layer-node" import { Effect, FileSystem } from "effect" -import { ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcessSpawner } from "effect/process" import { testEffect } from "./lib/effect" const it = testEffect(LayerNode.compile(LayerNode.group([CrossSpawnSpawner.node, LayerNodePlatform.filesystem]))) diff --git a/packages/core/test/tool-registry.test.ts b/packages/core/test/tool-registry.test.ts index f77e05a6630a..a2fcc03dbf67 100644 --- a/packages/core/test/tool-registry.test.ts +++ b/packages/core/test/tool-registry.test.ts @@ -1063,7 +1063,7 @@ describe("Tool", () => { value: Schema.Boolean.pipe( Schema.decodeTo(Schema.String, { decode: SchemaGetter.transform((value) => String(value)), - encode: SchemaGetter.transformOrFail((value) => + encode: SchemaGetter.transformEffect((value) => value === "valid" ? Effect.succeed(true) : Effect.fail(new SchemaIssue.InvalidValue({ message: "invalid output" }, value)), diff --git a/packages/core/test/tool-webfetch.test.ts b/packages/core/test/tool-webfetch.test.ts index bcec31a6735e..557182723744 100644 --- a/packages/core/test/tool-webfetch.test.ts +++ b/packages/core/test/tool-webfetch.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test" import { Duration, Effect, Fiber, Layer, Schema } from "effect" import * as TestClock from "effect/testing/TestClock" -import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { LayerNode } from "@opencode/util/effect/layer-node" import { LayerNodePlatform } from "@opencode/util/effect/app-node-platform" diff --git a/packages/core/test/tool-websearch.test.ts b/packages/core/test/tool-websearch.test.ts index 7e3f8e8dd723..c3f1fcf5d238 100644 --- a/packages/core/test/tool-websearch.test.ts +++ b/packages/core/test/tool-websearch.test.ts @@ -1,6 +1,6 @@ import { describe, expect } from "bun:test" import { Context, Effect, Layer } from "effect" -import type { HttpClientError } from "effect/unstable/http" +import type { HttpClientError } from "effect/http" import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder" import { LayerNode } from "@opencode/util/effect/layer-node" import { Permission } from "@opencode/core/permission" diff --git a/packages/core/test/v1-migration.test.ts b/packages/core/test/v1-migration.test.ts index f0201e6cb683..d9f5b86698db 100644 --- a/packages/core/test/v1-migration.test.ts +++ b/packages/core/test/v1-migration.test.ts @@ -13,7 +13,7 @@ import { AbsolutePath } from "@opencode/core/schema" import { Global } from "@opencode/util/global" import { Effect, Fiber, Layer, Logger, Schedule, Schema, Scope } from "effect" import { eq, sql } from "drizzle-orm" -import type { SqlClient } from "effect/unstable/sql/SqlClient" +import type { SqlClient } from "effect/sql/SqlClient" import { tmpdir } from "./fixture/tmpdir" import path from "path" diff --git a/packages/core/test/wellknown.test.ts b/packages/core/test/wellknown.test.ts index 1e49c90e8b81..0363735f427e 100644 --- a/packages/core/test/wellknown.test.ts +++ b/packages/core/test/wellknown.test.ts @@ -1,6 +1,6 @@ import { expect } from "bun:test" import { Effect, Fiber, Stream } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" import { KV } from "@opencode/core/kv" import { LayerNode } from "@opencode/util/effect/layer-node" import { Bus } from "@opencode/core/bus" diff --git a/packages/core/test/workspace.test.ts b/packages/core/test/workspace.test.ts index 8666b05e2260..f122991798c7 100644 --- a/packages/core/test/workspace.test.ts +++ b/packages/core/test/workspace.test.ts @@ -9,7 +9,7 @@ import { LayerNode } from "@opencode/util/effect/layer-node" import { eq } from "drizzle-orm" import { Deferred, Effect, Fiber } from "effect" import { TestClock } from "effect/testing" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { testEffect } from "./lib/effect" const calls: Array<{ readonly operation: string; readonly binding?: WorkspaceDriver.Binding | null }> = [] diff --git a/packages/desktop/package.json b/packages/desktop/package.json index e9b8b4fe68a9..2625fda62dc3 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -54,7 +54,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": { diff --git a/packages/desktop/src/main/files/attachment-picker.ts b/packages/desktop/src/main/files/attachment-picker.ts index 11a460dce8dd..2b6166e33281 100644 --- a/packages/desktop/src/main/files/attachment-picker.ts +++ b/packages/desktop/src/main/files/attachment-picker.ts @@ -42,7 +42,7 @@ export function readAttachment(filePath: string, maxBytes = MAX_ATTACHMENT_BYTES const fs = yield* FileSystem.FileSystem const file = yield* fs.open(filePath, { flag: "r" }) const info = yield* file.stat - if (info.size > FileSystem.Size(maxBytes)) + if (info.size > BigInt(maxBytes)) throw new Error(nativeT("desktop.picker.error.sizeLimit", { limit: MAX_ATTACHMENT_BYTES / 1024 / 1024 })) const bytes = new Uint8Array(Number(info.size)) diff --git a/packages/desktop/src/main/ipc-transport.test.ts b/packages/desktop/src/main/ipc-transport.test.ts index f48eca43b70d..1d3d96bad0d1 100644 --- a/packages/desktop/src/main/ipc-transport.test.ts +++ b/packages/desktop/src/main/ipc-transport.test.ts @@ -3,8 +3,8 @@ import { EventEmitter } from "node:events" import { MessageChannel } from "node:worker_threads" import type { MessagePortMain, WebContents } from "electron" import { Effect, Layer, ManagedRuntime, Schema, Stream } from "effect" -import { Rpc, RpcGroup, RpcMessage, RpcServer } from "effect/unstable/rpc" -import { Transferable } from "effect/unstable/workers" +import { Rpc, RpcGroup, RpcMessage, RpcServer } from "effect/rpc" +import { Transferable } from "effect/workers" import { omitUndefined } from "../shared/ipc-transport" import { FilesOpenFilePicker } from "../shared/ipc-rpc/files" import { IpcPortHandoff, IpcServerProtocolLive } from "./ipc-transport" diff --git a/packages/desktop/src/main/ipc-transport.ts b/packages/desktop/src/main/ipc-transport.ts index 91e6e84acce8..2fb93c484a40 100644 --- a/packages/desktop/src/main/ipc-transport.ts +++ b/packages/desktop/src/main/ipc-transport.ts @@ -1,6 +1,6 @@ import type { MessagePortMain, WebContents } from "electron" import { Context, Effect, Layer, Option, Queue, Schema, Stream } from "effect" -import { RpcMessage, RpcServer } from "effect/unstable/rpc" +import { RpcMessage, RpcServer } from "effect/rpc" import { bindIpcEvents } from "./ipc-events" type PortBinding = { diff --git a/packages/desktop/src/main/ipc.ts b/packages/desktop/src/main/ipc.ts index 01308f3ceaf3..9ee40a4b86a6 100644 --- a/packages/desktop/src/main/ipc.ts +++ b/packages/desktop/src/main/ipc.ts @@ -2,7 +2,7 @@ export * as Ipc from "./ipc" import { app, BrowserWindow, MessageChannelMain } from "electron" import { Effect, Layer } from "effect" -import { RpcServer } from "effect/unstable/rpc" +import { RpcServer } from "effect/rpc" import { DesktopRpcs } from "../shared/ipc-rpc" import { DragCancelEvent, IpcTransportPort } from "../shared/ipc-transport" import { Extensions } from "./extension" diff --git a/packages/desktop/src/renderer/ipc-client.ts b/packages/desktop/src/renderer/ipc-client.ts index 904b0592bc17..72fad8df1cb6 100644 --- a/packages/desktop/src/renderer/ipc-client.ts +++ b/packages/desktop/src/renderer/ipc-client.ts @@ -1,5 +1,5 @@ import type { Effect } from "effect" -import type { RpcMessage } from "effect/unstable/rpc" +import type { RpcMessage } from "effect/rpc" import type { DesktopRpcClient } from "../shared/ipc-rpc" import type { DesktopEvent } from "../shared/ipc-rpc/events" import { IpcTransportPort, omitUndefined } from "../shared/ipc-transport" diff --git a/packages/desktop/src/shared/ipc-rpc.ts b/packages/desktop/src/shared/ipc-rpc.ts index 6cad9a24ff88..f3a6e23fb255 100644 --- a/packages/desktop/src/shared/ipc-rpc.ts +++ b/packages/desktop/src/shared/ipc-rpc.ts @@ -1,4 +1,4 @@ -import { RpcClient, RpcClientError } from "effect/unstable/rpc" +import { RpcClient, RpcClientError } from "effect/rpc" import { AppRpcs } from "./ipc-rpc/app" import { EventRpcs } from "./ipc-rpc/events" import { ExtensionRpcs } from "./ipc-rpc/extensions" diff --git a/packages/desktop/src/shared/ipc-rpc/app.ts b/packages/desktop/src/shared/ipc-rpc/app.ts index f964e8dc1982..8a7d8cdef523 100644 --- a/packages/desktop/src/shared/ipc-rpc/app.ts +++ b/packages/desktop/src/shared/ipc-rpc/app.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" +import { Rpc, RpcGroup } from "effect/rpc" const ServerReadyData = Schema.Struct({ url: Schema.String, diff --git a/packages/desktop/src/shared/ipc-rpc/events.ts b/packages/desktop/src/shared/ipc-rpc/events.ts index cc0b9333336c..33121477fb96 100644 --- a/packages/desktop/src/shared/ipc-rpc/events.ts +++ b/packages/desktop/src/shared/ipc-rpc/events.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" +import { Rpc, RpcGroup } from "effect/rpc" import { ExtensionInstalled, ExtensionMenubarItem, ExtensionPayload } from "./extensions" export class DeepLinksOpened extends Schema.TaggedClass()("DeepLinksOpened", { diff --git a/packages/desktop/src/shared/ipc-rpc/extensions.ts b/packages/desktop/src/shared/ipc-rpc/extensions.ts index 9e6deba5f04f..76542fefd7b9 100644 --- a/packages/desktop/src/shared/ipc-rpc/extensions.ts +++ b/packages/desktop/src/shared/ipc-rpc/extensions.ts @@ -1,6 +1,6 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" -import { Transferable } from "effect/unstable/workers" +import { Rpc, RpcGroup } from "effect/rpc" +import { Transferable } from "effect/workers" const text = (maximum: number) => Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(maximum)) const id = text(256) diff --git a/packages/desktop/src/shared/ipc-rpc/files.ts b/packages/desktop/src/shared/ipc-rpc/files.ts index ca68ba5db5a0..e8f497212370 100644 --- a/packages/desktop/src/shared/ipc-rpc/files.ts +++ b/packages/desktop/src/shared/ipc-rpc/files.ts @@ -1,6 +1,6 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" -import { Transferable } from "effect/unstable/workers" +import { Rpc, RpcGroup } from "effect/rpc" +import { Transferable } from "effect/workers" const OptionalString = Schema.optional(Schema.String) const PickerOptions = Schema.Struct({ diff --git a/packages/desktop/src/shared/ipc-rpc/menu.ts b/packages/desktop/src/shared/ipc-rpc/menu.ts index def7a5b308be..7b9dff46d211 100644 --- a/packages/desktop/src/shared/ipc-rpc/menu.ts +++ b/packages/desktop/src/shared/ipc-rpc/menu.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" +import { Rpc, RpcGroup } from "effect/rpc" const DesktopMenuAction = Schema.Literals([ "app.installCli", diff --git a/packages/desktop/src/shared/ipc-rpc/storage.ts b/packages/desktop/src/shared/ipc-rpc/storage.ts index 2b920b3986ba..de88996d72e2 100644 --- a/packages/desktop/src/shared/ipc-rpc/storage.ts +++ b/packages/desktop/src/shared/ipc-rpc/storage.ts @@ -1,6 +1,6 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" -import { Transferable } from "effect/unstable/workers" +import { Rpc, RpcGroup } from "effect/rpc" +import { Transferable } from "effect/workers" export const StorageItems = Rpc.make("StorageItems", { payload: { name: Schema.String }, diff --git a/packages/desktop/src/shared/ipc-rpc/window.ts b/packages/desktop/src/shared/ipc-rpc/window.ts index bb659b61af79..2f8882587be8 100644 --- a/packages/desktop/src/shared/ipc-rpc/window.ts +++ b/packages/desktop/src/shared/ipc-rpc/window.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" +import { Rpc, RpcGroup } from "effect/rpc" export const WindowThemeReady = Rpc.make("WindowThemeReady") export const WindowGetFocused = Rpc.make("WindowGetFocused", { success: Schema.Boolean }) diff --git a/packages/gui-extensions/src/browser/network.ts b/packages/gui-extensions/src/browser/network.ts index 4969085d1dec..b042557d128b 100644 --- a/packages/gui-extensions/src/browser/network.ts +++ b/packages/gui-extensions/src/browser/network.ts @@ -3,7 +3,8 @@ import type { RpcClient } from "@opencode/client/effect/api" import type { Session } from "@opencode/schema/session" import { Browser } from "@opencode/plugin-browser/rpc" import { BrowserProxy } from "@opencode/plugin-browser/proxy" -import { Effect, Encoding } from "effect" +import { Effect } from "effect" +import { Base64 } from "effect/encoding" export type BrowserNetwork = Effect.Success> @@ -24,7 +25,7 @@ export const createBrowserNetwork = Effect.fn("BrowserNetwork.create")(function* write: (tunnelID, data, end, signal) => Effect.runPromise( input.rpc["tunnel.write"]( - { ...input.attachment, tunnelID, data: Encoding.encodeBase64(data), end }, + { ...input.attachment, tunnelID, data: Base64.encode(data), end }, options, ), { signal }, diff --git a/packages/gui-extensions/src/browser/pane.ts b/packages/gui-extensions/src/browser/pane.ts index 3f75a1ff57e3..2b0863b494fd 100644 --- a/packages/gui-extensions/src/browser/pane.ts +++ b/packages/gui-extensions/src/browser/pane.ts @@ -4,7 +4,7 @@ import { OpenCode } from "@opencode/client/effect" import { SessionID } from "@opencode/schema/session-id" import electron, { type BrowserWindow } from "electron" import { Deferred, Effect, ManagedRuntime, Queue, Schedule, Schema, Stream } from "effect" -import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/http" import type { MainApp, MainStorage, Surfaces, Windows } from "../sdk/main" import { createBrowserPage, type BrowserPage, type Shared } from "./chromium" import { browserFailure } from "./errors" diff --git a/packages/gui-extensions/src/browser/remote.ts b/packages/gui-extensions/src/browser/remote.ts index 2a138043e224..4be06bbcc969 100644 --- a/packages/gui-extensions/src/browser/remote.ts +++ b/packages/gui-extensions/src/browser/remote.ts @@ -50,7 +50,7 @@ export const BrowserPane = Remote.define({ input: Schema.Struct({ binding, server: text(16_384), - session: text(256).check(Schema.isStartsWith("ses")), + session: text(256).check(Schema.isStartingWith("ses")), restore: Schema.optionalKey(Browser.State), }), }, diff --git a/packages/gui-extensions/src/ssh/askpass.test.ts b/packages/gui-extensions/src/ssh/askpass.test.ts index 57495b9f2997..edb26769f437 100644 --- a/packages/gui-extensions/src/ssh/askpass.test.ts +++ b/packages/gui-extensions/src/ssh/askpass.test.ts @@ -1,6 +1,7 @@ import { expect } from "bun:test" import { NodeSocket } from "@effect/platform-node" import { Deferred, Effect, Fiber, Layer, Queue, Scope, Exit } from "effect" +import { Socket } from "effect/socket" import { testEffect } from "../../../core/test/lib/effect" import { createAskpass } from "./askpass" @@ -13,15 +14,14 @@ const request = Effect.fn("test.askpass.request")(function* ( ) { const socket = yield* NodeSocket.makeNet({ host: "127.0.0.1", port: Number(env.OPENCODE_SSH_ASKPASS_PORT) }) const write = yield* socket.writer + const pull = yield* Socket.readerString(socket) const result = { text: "" } yield* Effect.all( [ - socket - .runString((text) => { - result.text += text - }) - .pipe(Effect.ignore), - write(JSON.stringify({ token: env.OPENCODE_SSH_ASKPASS_TOKEN, text, confirm }) + "\n").pipe(Effect.ignore), + Effect.forever( + pull.pipe(Effect.tap((chunks) => Effect.sync(() => chunks.forEach((chunk) => (result.text += chunk))))), + ).pipe(Effect.ignore), + write.write(JSON.stringify({ token: env.OPENCODE_SSH_ASKPASS_TOKEN, text, confirm }) + "\n").pipe(Effect.ignore), ], { concurrency: "unbounded" }, ) diff --git a/packages/gui-extensions/src/ssh/askpass.ts b/packages/gui-extensions/src/ssh/askpass.ts index bff73df673ab..0baffcecb781 100644 --- a/packages/gui-extensions/src/ssh/askpass.ts +++ b/packages/gui-extensions/src/ssh/askpass.ts @@ -1,5 +1,6 @@ import { NodeSocketServer } from "@effect/platform-node" import { Deferred, Effect, Fiber, Schema, Semaphore } from "effect" +import { Socket } from "effect/socket" import { randomUUID } from "node:crypto" import { SshFailure } from "./command" @@ -16,23 +17,26 @@ export const createAskpass = Effect.fn("Ssh.askpass")(function* (input: { const pending = new Map>() const prompts = yield* Semaphore.make(1) const server = yield* NodeSocketServer.make({ host: "127.0.0.1", port: 0 }).pipe(Effect.mapError(SshFailure.from)) - if (server.address._tag !== "TcpAddress") return yield* Effect.fail(new SshFailure("connection")) + if (server.address._tag !== "InetAddressV4") return yield* Effect.fail(new SshFailure("connection")) const serving = yield* server .run((socket) => Effect.gen(function* () { const request = yield* Deferred.make() const state = { buffer: "", received: false } - const reader = yield* socket - .runString((chunk) => { - if (state.received) return Effect.fail(new SshFailure("connection")) - state.buffer += chunk - if (state.buffer.length > 16_384) return Effect.fail(new SshFailure("connection")) - if (!state.buffer.includes("\n")) return Effect.void - state.received = true - return Deferred.succeed(request, state.buffer.trim()) - }) - .pipe(Effect.ensuring(Deferred.fail(request, new SshFailure("connection"))), Effect.forkScoped) + const pull = yield* Socket.readerString(socket) + const reader = yield* Effect.forever( + Effect.gen(function* () { + for (const chunk of yield* pull) { + if (state.received) return yield* Effect.fail(new SshFailure("connection")) + state.buffer += chunk + if (state.buffer.length > 16_384) return yield* Effect.fail(new SshFailure("connection")) + if (!state.buffer.includes("\n")) continue + state.received = true + yield* Deferred.succeed(request, state.buffer.trim()) + } + }), + ).pipe(Effect.ensuring(Deferred.fail(request, new SshFailure("connection"))), Effect.forkScoped) const message = yield* Deferred.await(request).pipe(Effect.flatMap(Schema.decodeUnknownEffect(Request))) if (message.token !== token) return @@ -50,7 +54,7 @@ export const createAskpass = Effect.fn("Ssh.askpass")(function* (input: { yield* input.prompt({ id, text: message.text, confirm: message.confirm }) const value = yield* Deferred.await(response) const write = yield* socket.writer - yield* write(JSON.stringify({ value })) + yield* write.write(JSON.stringify({ value })) }).pipe(Effect.scoped), ) .pipe(Effect.raceFirst(Fiber.join(reader).pipe(Effect.andThen(Effect.fail(new SshFailure("connection")))))) diff --git a/packages/gui-extensions/src/ssh/bootstrap.ts b/packages/gui-extensions/src/ssh/bootstrap.ts index daf1258167b9..bb09f4dd038a 100644 --- a/packages/gui-extensions/src/ssh/bootstrap.ts +++ b/packages/gui-extensions/src/ssh/bootstrap.ts @@ -1,5 +1,5 @@ import { Effect, Schema } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { parseTarget, quote, runSsh, sshArgs, SshFailure } from "./command" import { RemoteCli } from "./remote-cli" diff --git a/packages/gui-extensions/src/ssh/command.ts b/packages/gui-extensions/src/ssh/command.ts index 85b34cef4fcb..e7aba8d32b89 100644 --- a/packages/gui-extensions/src/ssh/command.ts +++ b/packages/gui-extensions/src/ssh/command.ts @@ -1,5 +1,5 @@ import { Effect, PlatformError, Schema, Stream } from "effect" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { ChildProcess, ChildProcessSpawner } from "effect/process" import { RemoteCli } from "./remote-cli" export class SshFailure extends Schema.TaggedError()("SshFailure", { diff --git a/packages/gui-extensions/src/ssh/controller.ts b/packages/gui-extensions/src/ssh/controller.ts index 9accd2506426..083636a464e1 100644 --- a/packages/gui-extensions/src/ssh/controller.ts +++ b/packages/gui-extensions/src/ssh/controller.ts @@ -14,8 +14,8 @@ import { Scope, Stream, } from "effect" -import { HttpClient } from "effect/unstable/http" -import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" +import { HttpClient } from "effect/http" +import { ChildProcess, ChildProcessSpawner } from "effect/process" import type { SshConfig, SshHttp, SshItem, SshStart, SshState } from "./contract" import { createAskpass } from "./askpass" import { bootstrap } from "./bootstrap" @@ -337,7 +337,7 @@ export const createSshController = Effect.fn("Ssh.controller")(function* (input: const freePort = Effect.gen(function* () { const server = yield* NodeSocketServer.make({ host: "127.0.0.1", port: 0 }) - if (server.address._tag !== "TcpAddress") return yield* Effect.fail(new SshFailure("connection")) + if (server.address._tag !== "InetAddressV4") return yield* Effect.fail(new SshFailure("connection")) return server.address.port }).pipe(Effect.scoped) diff --git a/packages/gui-extensions/src/ssh/main.ts b/packages/gui-extensions/src/ssh/main.ts index 15ed12edefd3..8f402023a956 100644 --- a/packages/gui-extensions/src/ssh/main.ts +++ b/packages/gui-extensions/src/ssh/main.ts @@ -1,6 +1,6 @@ import { NodeServices } from "@effect/platform-node" import { Effect, Exit, Fiber, Layer, ManagedRuntime, Schema, Scope, Stream } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" import { Cli, MainStorage, Windows, type Setup } from "../sdk/main" import { SshFailure } from "./command" import { Ssh, SshConfig } from "./contract" diff --git a/packages/gui-extensions/src/ssh/remote-cli.ts b/packages/gui-extensions/src/ssh/remote-cli.ts index e516f558fad2..f88963f09c53 100644 --- a/packages/gui-extensions/src/ssh/remote-cli.ts +++ b/packages/gui-extensions/src/ssh/remote-cli.ts @@ -1,7 +1,7 @@ export * as RemoteCli from "./remote-cli" import { Effect, Schema } from "effect" -import { HttpClient, HttpClientResponse } from "effect/unstable/http" +import { HttpClient, HttpClientResponse } from "effect/http" export class Failure extends Schema.TaggedError()("RemoteCliFailure", { code: Schema.Literals(["platform", "version", "install"]), diff --git a/packages/http-recorder/README.md b/packages/http-recorder/README.md index 05cde80c9637..97401fd73c98 100644 --- a/packages/http-recorder/README.md +++ b/packages/http-recorder/README.md @@ -30,7 +30,7 @@ Effect `4.0.0-beta.107` currently contains unresolved symbols in its published d ```ts import { assert, describe, it } from "@effect/vitest" import { Effect, Schema } from "effect" -import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/http" import { HttpRecorder } from "@opencode/http-recorder" const User = Schema.Struct({ @@ -112,7 +112,7 @@ Real applications often select WebSocket URLs inside domain services. Effect rep import { NodeSocket } from "@effect/platform-node" import { it } from "@effect/vitest" import { Deferred, Effect, Layer } from "effect" -import { Socket } from "effect/unstable/socket" +import { Socket } from "effect/socket" import { HttpRecorder } from "@opencode/http-recorder" const roundTrip = Effect.fn("Echo.roundTrip")(function* (url: string, message: string) { diff --git a/packages/http-recorder/package.json b/packages/http-recorder/package.json index 0c1c4b8447fd..b5252403243b 100644 --- a/packages/http-recorder/package.json +++ b/packages/http-recorder/package.json @@ -52,7 +52,7 @@ "typescript": "catalog:" }, "dependencies": { - "@effect/platform-node-shared": "4.0.0-rc.112" + "@effect/platform-node-shared": "4.0.0" }, "peerDependencies": { "effect": "catalog:" diff --git a/packages/http-recorder/script/verify-package.ts b/packages/http-recorder/script/verify-package.ts index bc4beb540429..3b89af635d9b 100644 --- a/packages/http-recorder/script/verify-package.ts +++ b/packages/http-recorder/script/verify-package.ts @@ -27,8 +27,8 @@ export const verifyPackage = async (archive: string) => { `import { HttpRecorder } from "@opencode/http-recorder" import { NodeSocket } from "@effect/platform-node" import { Layer } from "effect" -import { HttpClient } from "effect/unstable/http" -import { Socket } from "effect/unstable/socket" +import { HttpClient } from "effect/http" +import { Socket } from "effect/socket" const options: HttpRecorder.RecorderOptions = { match: () => true, redact: { jsonFields: ["access_token"] } } const socketOptions: HttpRecorder.SocketRecorderOptions = { redact: { jsonFields: ["access_token"] } } diff --git a/packages/http-recorder/src/http/recorder.ts b/packages/http-recorder/src/http/recorder.ts index 568b101743ad..d9e36a44f5ed 100644 --- a/packages/http-recorder/src/http/recorder.ts +++ b/packages/http-recorder/src/http/recorder.ts @@ -6,7 +6,7 @@ import { HttpClientError, HttpClientRequest, HttpClientResponse, -} from "effect/unstable/http" +} from "effect/http" import { fileSystem, Service } from "../cassette/store.js" import type { RecorderOptions } from "../options.js" import { make, redactUrl, type Redactor } from "../redaction/redactor.js" diff --git a/packages/http-recorder/src/index.ts b/packages/http-recorder/src/index.ts index 2dcba03e6fcb..37a26873af15 100644 --- a/packages/http-recorder/src/index.ts +++ b/packages/http-recorder/src/index.ts @@ -1,6 +1,6 @@ import { Layer } from "effect" -import { HttpClient } from "effect/unstable/http" -import { Socket } from "effect/unstable/socket" +import { HttpClient } from "effect/http" +import { Socket } from "effect/socket" import { Api } from "./api.js" import { hasCassetteSync, removeCassetteSync } from "./cassette/store.js" import { layer, layerFetch } from "./http/recorder.js" diff --git a/packages/http-recorder/src/websocket/recorder.ts b/packages/http-recorder/src/websocket/recorder.ts index e1900f729f83..f9f2d392fc13 100644 --- a/packages/http-recorder/src/websocket/recorder.ts +++ b/packages/http-recorder/src/websocket/recorder.ts @@ -1,6 +1,6 @@ import { NodeFileSystem } from "@effect/platform-node-shared" -import { Deferred, Effect, Exit, FiberSet, Layer, Option, Ref, Scope, Semaphore } from "effect" -import { Socket } from "effect/unstable/socket" +import { Deferred, Effect, Exit, Layer, Ref, Scope, Semaphore } from "effect" +import { Socket } from "effect/socket" import { fileSystem, type Interface, Service } from "../cassette/store.js" import type { SocketRecorderOptions } from "../options.js" import { make, type Redactor } from "../redaction/redactor.js" @@ -28,7 +28,7 @@ interface ActiveRecording { interface PendingRecordings { readonly promises: Set> readonly errors: Array - readonly sockets: Set + readonly sockets: Set } type Frame = string | Uint8Array @@ -79,7 +79,7 @@ const webSocketFacade = ( readonly send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void readonly close: (code?: number, reason?: string) => void }, -): globalThis.WebSocket => { +): Socket.WebSocketLike => { Object.defineProperties(target, { url: { get: properties.url }, readyState: { get: properties.readyState }, @@ -105,7 +105,7 @@ const webSocketFacade = ( }, }) } - return target as globalThis.WebSocket + return target as unknown as Socket.WebSocketLike } const encodeEvent = (direction: "client" | "server", message: Frame): WebSocketEvent => @@ -134,45 +134,7 @@ const assertEvent = (actual: WebSocketEvent, expected: WebSocketEvent | undefine if (expected && comparable(actual, asJson) === comparable(expected, asJson)) return throw new Error(`WebSocket event ${index + 1}: expected ${safeText(expected)}, received ${safeText(actual)}`) }) -const runHandler = (handler: (value: A) => Effect.Effect | void, value: A) => - Effect.suspend(() => { - const result = handler(value) - return Effect.isEffect(result) ? Effect.asVoid(result) : Effect.void - }) -const runReplay = ( - state: ActiveReplay, - handler: (value: A) => Effect.Effect | void, - decode: (event: WebSocketEvent) => A, - onOpen: Effect.Effect | undefined, -) => - Effect.scoped( - Effect.gen(function* () { - const handlers = yield* FiberSet.make() - const run = yield* FiberSet.runtime(handlers)() - if (onOpen) yield* onOpen - const drive = Effect.gen(function* () { - while (true) { - const current = yield* Ref.get(state.progress) - const event = state.interaction.events[current.position] - if (!event) return - if (yield* Ref.get(state.closed)) - return yield* Effect.die( - new Error( - `WebSocket closed with unconsumed events: used ${current.position} of ${state.interaction.events.length}`, - ), - ) - if (event.direction === "server") { - yield* Ref.set(state.progress, { position: current.position + 1, changed: yield* Deferred.make() }) - run(runHandler(handler, decode(event))) - continue - } - yield* Deferred.await(current.changed) - } - }) - yield* drive.pipe(Effect.raceFirst(FiberSet.join(handlers))) - yield* FiberSet.awaitEmpty(handlers).pipe(Effect.raceFirst(FiberSet.join(handlers))) - }), - ) +const normalClose = () => new Socket.SocketError({ reason: new Socket.SocketCloseError({ code: 1000 }) }) const makeRecordingSocket = ( upstream: Socket.Socket, @@ -185,71 +147,84 @@ const makeRecordingSocket = ( const active = yield* Ref.make(undefined) const writeLock = yield* Semaphore.make(1) return Socket.make({ - runRaw: (handler, runOptions) => - Effect.gen(function* () { - const state: ActiveRecording = { - events: [], - eventLock: yield* Semaphore.make(1), - accepting: yield* Ref.make(true), - opened: false, - valid: true, - } - const occupied = yield* Ref.modify(active, (current) => [current !== undefined, current ?? state]) - if (occupied) return yield* Effect.die("Concurrent runs of a recorded WebSocket are not supported") - yield* upstream - .runRaw( - (message) => { - if (!Ref.getUnsafe(state.accepting)) throw new Error("WebSocket received a frame after closing") - state.events.push(redactEvent(encodeEvent("server", message), redactor)) - return handler(message) - }, - { - ...runOptions, - onOpen: Effect.gen(function* () { - state.opened = true - if (runOptions?.onOpen) yield* runOptions.onOpen + reader: Effect.gen(function* () { + const state: ActiveRecording = { + events: [], + eventLock: yield* Semaphore.make(1), + accepting: yield* Ref.make(true), + opened: false, + valid: true, + } + const occupied = yield* Ref.modify(active, (current) => [current !== undefined, current ?? state]) + if (occupied) return yield* Effect.die("Concurrent runs of a recorded WebSocket are not supported") + yield* Effect.addFinalizer((exit) => + writeLock.withPermit( + state.eventLock.withPermit( + Effect.gen(function* () { + yield* Ref.set(state.accepting, false) + yield* Ref.set(active, undefined) + if (!Exit.isSuccess(exit) || !state.opened || !state.valid) return + yield* cassette + .append(name, { transport: "websocket", events: [...state.events] }, options.metadata) + .pipe(Effect.orDie) + }), + ), + ), + ) + const reader = yield* upstream.reader + state.opened = true + return { + upgrade: reader.upgrade, + pull: reader.pull.pipe( + Effect.flatMap((messages) => + state.eventLock.withPermit( + Effect.sync(() => { + if (!Ref.getUnsafe(state.accepting)) throw new Error("WebSocket received a frame after closing") + state.events.push(...messages.map((message) => redactEvent(encodeEvent("server", message), redactor))) + return messages }), - }, - ) - .pipe( - Effect.onExit((exit) => - writeLock.withPermit( - state.eventLock.withPermit( - Effect.gen(function* () { - yield* Ref.set(state.accepting, false) - yield* Ref.set(active, undefined) - if (!Exit.isSuccess(exit) || !state.opened || !state.valid) return - yield* cassette - .append( - name, - { - transport: "websocket", - events: [...state.events], - }, - options.metadata, - ) - .pipe(Effect.orDie) - }), - ), - ), ), - ) - }), + ), + Effect.tapError((error) => + Effect.sync(() => { + if (error.reason._tag !== "SocketCloseError" || error.reason.code !== 1000) state.valid = false + }), + ), + ), + } + }), writer: upstream.writer.pipe( - Effect.map( - (write) => (message) => + Effect.map((writer) => { + const write: Socket.Writer["write"] = (message) => writeLock.withPermit( Effect.gen(function* () { - if (Socket.isCloseEvent(message)) return yield* write(message) + if (Socket.isCloseEvent(message)) return yield* writer.write(message) const state = yield* Ref.get(active) if (!state || !(yield* Ref.get(state.accepting))) return yield* Effect.die("WebSocket writer used without an active socket run") const event = redactEvent(encodeEvent("client", message), redactor) yield* state.eventLock.withPermit(Effect.sync(() => state.events.push(event))) - return yield* write(message).pipe(Effect.onError(() => Effect.sync(() => (state.valid = false)))) + return yield* writer.write(message).pipe(Effect.onError(() => Effect.sync(() => (state.valid = false)))) }), - ), - ), + ) + return { + write, + writeAll: (messages) => + writeLock.withPermit( + Effect.gen(function* () { + const state = yield* Ref.get(active) + if (!state || !(yield* Ref.get(state.accepting))) + return yield* Effect.die("WebSocket writer used without an active socket run") + yield* state.eventLock.withPermit( + Effect.sync(() => { + state.events.push(...messages.map((message) => redactEvent(encodeEvent("client", message), redactor))) + }), + ) + return yield* writer.writeAll(messages).pipe(Effect.onError(() => Effect.sync(() => (state.valid = false)))) + }), + ), + } + }), ), }) }) @@ -263,72 +238,90 @@ const makeReplaySocket = ( Effect.gen(function* () { const replay = yield* makeReplayState(cassette, name, webSocketInteractions) const active = yield* Ref.make(undefined) - const runLock = yield* Semaphore.make(1) + const running = yield* Ref.make(false) return Socket.make({ - runRaw: (handler, runOptions) => - runLock - .withPermitsIfAvailable(1)( - Effect.gen(function* () { - const claimed = yield* replay - .claim((interaction) => - interaction ? Effect.void : Effect.die("Missing recorded WebSocket interaction"), - ) - .pipe(Effect.orDie) - const state = { - interaction: claimed.interaction, - progress: yield* Ref.make({ position: 0, changed: yield* Deferred.make() }), - writeLock: yield* Semaphore.make(1), - closed: yield* Ref.make(false), - } - yield* Ref.set(active, state) - yield* runReplay(state, handler, decodeEvent, runOptions?.onOpen).pipe( - Effect.ensuring(Ref.set(active, undefined)), - ) - }), - ) - .pipe( - Effect.flatMap( - Option.match({ - onNone: () => Effect.die("Concurrent runs of a replayed WebSocket are not supported"), - onSome: () => Effect.void, - }), - ), + reader: Effect.gen(function* () { + const occupied = yield* Ref.getAndSet(running, true) + if (occupied) return yield* Effect.die("Concurrent runs of a replayed WebSocket are not supported") + yield* Effect.addFinalizer(() => Ref.set(running, false).pipe(Effect.andThen(Ref.set(active, undefined)))) + const claimed = yield* replay + .claim((interaction) => (interaction ? Effect.void : Effect.die("Missing recorded WebSocket interaction"))) + .pipe(Effect.orDie) + const state: ActiveReplay = { + interaction: claimed.interaction, + progress: yield* Ref.make({ position: 0, changed: yield* Deferred.make() }), + writeLock: yield* Semaphore.make(1), + closed: yield* Ref.make(false), + } + yield* Ref.set(active, state) + yield* Effect.addFinalizer(() => + Ref.set(state.closed, true).pipe( + Effect.andThen(Ref.get(state.progress)), + Effect.flatMap((progress) => Deferred.succeed(progress.changed, undefined)), ), - writer: Effect.succeed((message) => - Ref.get(active).pipe( - Effect.flatMap((state) => - state - ? state.writeLock.withPermit( - Effect.gen(function* () { - const current = yield* Ref.get(state.progress) - if (Socket.isCloseEvent(message)) { - yield* Ref.set(state.closed, true) - yield* Deferred.succeed(current.changed, undefined) - if (current.position === state.interaction.events.length) return - return yield* Effect.die( - new Error( - `WebSocket closed with unconsumed events: used ${current.position} of ${state.interaction.events.length}`, - ), + ) + return { + upgrade: Socket.SocketUpgradeError.unsupported, + pull: Effect.gen(function* () { + while (true) { + const current = yield* Ref.get(state.progress) + const events = state.interaction.events + if (yield* Ref.get(state.closed)) return yield* Effect.fail(normalClose()) + if (current.position === events.length) return yield* Effect.fail(normalClose()) + if (events[current.position]?.direction === "client") { + yield* Deferred.await(current.changed) + continue + } + // Stop at the next expected client frame, preserving the causal boundary. + const count = events.slice(current.position).findIndex((event) => event.direction === "client") + const messages = events + .slice(current.position, count < 0 ? undefined : current.position + count) + .map(decodeEvent) + yield* Ref.set(state.progress, { + position: current.position + messages.length, + changed: yield* Deferred.make(), + }) + return messages as [Frame, ...Frame[]] + } + }), + } + }), + writer: Effect.sync(() => { + const send = (messages: ReadonlyArray) => + Ref.get(active).pipe( + Effect.flatMap((state) => + state + ? state.writeLock.withPermit( + Effect.forEach(messages, (message) => Effect.gen(function* () { + const current = yield* Ref.get(state.progress) + if (Socket.isCloseEvent(message)) { + yield* Ref.set(state.closed, true) + yield* Deferred.succeed(current.changed, undefined) + if (current.position === state.interaction.events.length) return + return yield* Effect.die( + new Error( + `WebSocket closed with unconsumed events: used ${current.position} of ${state.interaction.events.length}`, + ), + ) + } + yield* assertEvent( + redactEvent(encodeEvent("client", message), redactor), + state.interaction.events[current.position], + current.position, + options.compareClientMessagesAsJson === true, ) - } - const actual = redactEvent(encodeEvent("client", message), redactor) - yield* assertEvent( - actual, - state.interaction.events[current.position], - current.position, - options.compareClientMessagesAsJson === true, - ) - yield* Ref.set(state.progress, { - position: current.position + 1, - changed: yield* Deferred.make(), - }) - yield* Deferred.succeed(current.changed, undefined) - }), - ) - : Effect.die("WebSocket writer used without an active socket run"), - ), - ), - ), + yield* Ref.set(state.progress, { + position: current.position + 1, + changed: yield* Deferred.make(), + }) + yield* Deferred.succeed(current.changed, undefined) + }), { discard: true }), + ) + : Effect.die("WebSocket writer used without an active socket run"), + ), + ) + return { write: (message: Frame | Socket.CloseEvent) => send([message]), writeAll: send } + }), }) }) @@ -399,13 +392,13 @@ const makeRecordingWebSocketConstructor = ( const onOpen = () => { opened = true } - const onMessage = (event: MessageEvent) => { + const onMessage = (event: Socket.WebSocketEvent) => { appendEvent("server", event.data) } const onError = () => { failed = true } - const onClose = (event: CloseEvent) => { + const onClose = (event: Socket.WebSocketEvent) => { native.removeEventListener("open", onOpen) native.removeEventListener("message", onMessage) native.removeEventListener("error", onError) @@ -421,7 +414,7 @@ const makeRecordingWebSocketConstructor = ( sequence, url: request.url, protocols: requestedProtocols, - close: { code: event.code, reason: event.reason }, + close: { code: event.code ?? 1006, reason: event.reason ?? "" }, }, events: [...events], } @@ -592,8 +585,8 @@ export const layerWebSocketConstructor = ( Effect.sync(() => { for (const socket of pending.sockets) if ( - socket.readyState !== globalThis.WebSocket.CLOSING && - socket.readyState !== globalThis.WebSocket.CLOSED + socket.readyState !== 2 && + socket.readyState !== 3 ) socket.close(1000) }).pipe( diff --git a/packages/http-recorder/test/http.test.ts b/packages/http-recorder/test/http.test.ts index ebba965c7df1..1387cf2f369a 100644 --- a/packages/http-recorder/test/http.test.ts +++ b/packages/http-recorder/test/http.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "bun:test" import { Effect, Exit } from "effect" -import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http" +import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http" import { existsSync } from "node:fs" import { isHttpInteraction } from "../src/cassette/model" import { HttpRecorder } from "../src" diff --git a/packages/http-recorder/test/redaction.test.ts b/packages/http-recorder/test/redaction.test.ts index 64e139b01fa5..d3a8a1be20e1 100644 --- a/packages/http-recorder/test/redaction.test.ts +++ b/packages/http-recorder/test/redaction.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { HttpBody, HttpClientRequest } from "effect/unstable/http" +import { HttpBody, HttpClientRequest } from "effect/http" import { redactedErrorRequest } from "../src/http/recorder" import { make, redactHeaders, redactUrl } from "../src/redaction/redactor" import { secretFindings } from "../src/redaction/secrets" diff --git a/packages/http-recorder/test/support.ts b/packages/http-recorder/test/support.ts index 30fa8205f220..d2589ddd3b4d 100644 --- a/packages/http-recorder/test/support.ts +++ b/packages/http-recorder/test/support.ts @@ -1,6 +1,6 @@ import { NodeFileSystem } from "@effect/platform-node-shared" import { Cause, Effect, Exit } from "effect" -import { HttpBody, HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpBody, HttpClient, HttpClientRequest } from "effect/http" import { mkdtempSync, readFileSync, rmSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" diff --git a/packages/http-recorder/test/websocket.test.ts b/packages/http-recorder/test/websocket.test.ts index 2856d157cee3..67a711140305 100644 --- a/packages/http-recorder/test/websocket.test.ts +++ b/packages/http-recorder/test/websocket.test.ts @@ -1,14 +1,17 @@ import { describe, expect, test } from "bun:test" -import { Deferred, Effect, Exit, Fiber, Layer } from "effect" -import { Socket } from "effect/unstable/socket" +import { Deferred, Effect, Exit, Fiber, Layer, Scope } from "effect" +import { Socket } from "effect/socket" import { existsSync } from "node:fs" import { HttpRecorder } from "../src" import { layerSocketWithMode } from "../src/websocket/recorder" import { failureText, readCassette, seedCassetteDirectory, tempDirectory, withEnvironment } from "./support" const unavailableSocket = Socket.make({ - runRaw: () => Effect.die(new Error("unexpected live WebSocket run")), - writer: Effect.succeed(() => Effect.die(new Error("unexpected live WebSocket write"))), + reader: Effect.die(new Error("unexpected live WebSocket run")), + writer: Effect.succeed({ + write: () => Effect.die(new Error("unexpected live WebSocket write")), + writeAll: () => Effect.die(new Error("unexpected live WebSocket write")), + }), }) class EchoWebSocket extends EventTarget { @@ -44,21 +47,19 @@ describe("WebSocket", () => { directory: directory.path, }).pipe( Layer.provide( - Layer.succeed(Socket.WebSocketConstructor, (url) => new EchoWebSocket(url) as unknown as globalThis.WebSocket), + Layer.succeed(Socket.WebSocketConstructor, (url) => new EchoWebSocket(url) as unknown as Socket.WebSocketLike), ), ) await withEnvironment("CI", undefined, () => Effect.runPromise( Effect.gen(function* () { - const socket = yield* Socket.makeWebSocket("wss://echo.example.test/one", { - protocols: ["echo.v1"], - closeCodeIsError: () => false, - }) - const write = yield* socket.writer - yield* socket.runString(() => write(new Socket.CloseEvent(1000, "complete")).pipe(Effect.orDie), { - onOpen: write("hello").pipe(Effect.orDie), - }) + const socket = yield* Socket.makeWebSocket("wss://echo.example.test/one", { protocols: ["echo.v1"] }) + const reader = yield* Socket.readerString(socket) + const writer = yield* socket.writer + yield* writer.write("hello") + expect(yield* reader).toEqual(["hello"]) + yield* writer.write(new Socket.CloseEvent(1000, "complete")) }).pipe(Effect.scoped, Effect.provide(recorder)), ), ) @@ -90,7 +91,7 @@ describe("WebSocket", () => { Layer.succeed(Socket.WebSocketConstructor, (url, options) => { received = options // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- the fixture implements the WebSocket surface used by the recorder. - return new EchoWebSocket(url) as unknown as globalThis.WebSocket + return new EchoWebSocket(url) as unknown as Socket.WebSocketLike }), ), ) @@ -139,21 +140,13 @@ describe("WebSocket", () => { const received = await Effect.runPromise( Effect.gen(function* () { - const socket = yield* Socket.makeWebSocket("wss://events.example.test/workspaces/one", { - protocols: ["events.v1"], - closeCodeIsError: () => false, - }) - const write = yield* socket.writer - const received: string[] = [] - yield* socket.runString( - (message) => { - received.push(message) - }, - { - onOpen: write('{"type":"subscribe"}').pipe(Effect.orDie), - }, - ) - return received + const socket = yield* Socket.makeWebSocket("wss://events.example.test/workspaces/one", { + protocols: ["events.v1"], + }) + const pull = yield* Socket.readerString(socket) + const writer = yield* socket.writer + yield* writer.write('{"type":"subscribe"}') + return yield* pull }).pipe(Effect.scoped, Effect.provide(recorder)), ) @@ -187,7 +180,7 @@ describe("WebSocket", () => { const exit = await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.makeWebSocket("wss://events.example.test/workspaces/two") - yield* socket.runString(() => {}) + yield* socket.reader }).pipe(Effect.scoped, Effect.exit, Effect.provide(recorder)), ) @@ -196,27 +189,27 @@ describe("WebSocket", () => { test("records WebSocket frames in observed client/server order", async () => { using directory = tempDirectory("http-recorder-websocket-") + const batches: Array> = [] const response = JSON.stringify({ type: "response.completed", token: "server-secret", }) const upstream = Socket.make({ - runRaw: (handler, options) => - Effect.gen(function* () { - if (options?.onOpen) yield* options.onOpen - const result = handler(response) - if (Effect.isEffect(result)) yield* result - }), - writer: Effect.succeed(() => Effect.void), + reader: Effect.succeed({ pull: Effect.succeed([response] as const), upgrade: Socket.SocketUpgradeError.unsupported }), + writer: Effect.succeed({ + write: () => Effect.void, + writeAll: (messages) => Effect.sync(() => { batches.push(messages) }), + }), }) await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - const write = yield* socket.writer - yield* socket.runRaw(() => {}, { - onOpen: write(JSON.stringify({ type: "response.create", token: "client-secret" })).pipe(Effect.orDie), - }) + const reader = yield* socket.reader + const writer = yield* socket.writer + yield* writer.write(JSON.stringify({ type: "response.create", token: "client-secret" })) + yield* writer.writeAll(["first", "second"]) + yield* reader.pull }).pipe( Effect.scoped, Effect.provide( @@ -239,6 +232,8 @@ describe("WebSocket", () => { kind: "text", body: '{"type":"response.create","token":"[REDACTED]"}', }, + { direction: "client", kind: "text", body: "first" }, + { direction: "client", kind: "text", body: "second" }, { direction: "server", kind: "text", @@ -248,6 +243,7 @@ describe("WebSocket", () => { }, ], }) + expect(batches).toEqual([["first", "second"]]) }) test("WebSocket replay preserves causal frame ordering", async () => { @@ -279,16 +275,11 @@ describe("WebSocket", () => { await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - const write = yield* socket.writer - yield* socket.runRaw((message) => - Effect.gen(function* () { - if (typeof message !== "string") return - received.push(message) - const event: unknown = JSON.parse(message) - if (typeof event !== "object" || event === null || !("type" in event)) return - if (event.type === "session.created") yield* write('{"prompt":"hello","type":"response.create"}') - }), - ) + const reader = yield* socket.reader + const writer = yield* socket.writer + received.push(...(yield* reader.pull).filter((message): message is string => typeof message === "string")) + yield* writer.write('{"prompt":"hello","type":"response.create"}') + received.push(...(yield* reader.pull).filter((message): message is string => typeof message === "string")) }).pipe( Effect.scoped, Effect.provide( @@ -343,23 +334,14 @@ describe("WebSocket", () => { await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - const write = yield* socket.writer - yield* socket.runString((message) => - Effect.gen(function* () { - received.push(message) - const event: unknown = JSON.parse(message) - if (typeof event !== "object" || event === null) return - if ("type" in event && event.type === "session.created") { - yield* write('{"prompt":"first","type":"response.create"}') - return - } - if ("id" in event && event.id === "first") { - yield* write('{"prompt":"second","type":"response.create"}') - return - } - yield* write(new Socket.CloseEvent(1000, "done")) - }), - ) + const pull = yield* Socket.readerString(socket) + const writer = yield* socket.writer + received.push(...(yield* pull)) + yield* writer.write('{"prompt":"first","type":"response.create"}') + received.push(...(yield* pull)) + yield* writer.write('{"prompt":"second","type":"response.create"}') + received.push(...(yield* pull)) + yield* writer.write(new Socket.CloseEvent(1000, "done")) }).pipe( Effect.scoped, Effect.provide( @@ -377,7 +359,7 @@ describe("WebSocket", () => { ]) }) - test("WebSocket replay runs message handlers concurrently", async () => { + test("WebSocket replay pulls consecutive server frames in one batch", async () => { using directory = tempDirectory("http-recorder-websocket-") await seedCassetteDirectory(directory.path, "websocket/concurrent-handlers", [ { @@ -392,10 +374,8 @@ describe("WebSocket", () => { await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - const second = yield* Deferred.make() - yield* socket.runString((message) => - message === "first" ? Deferred.await(second) : Deferred.succeed(second, undefined), - ) + const pull = yield* Socket.readerString(socket) + expect(yield* pull).toEqual(["first", "second"]) }).pipe( Effect.scoped, Effect.provide( @@ -420,23 +400,27 @@ describe("WebSocket", () => { const socket = yield* Socket.Socket const started = yield* Deferred.make() const release = yield* Deferred.make() - const first = yield* socket - .runString((message) => - Effect.gen(function* () { - received.push(message) - yield* Deferred.succeed(started, undefined) - yield* Deferred.await(release) - }), - ) - .pipe(Effect.forkChild) + const first = yield* Effect.scoped( + Effect.gen(function* () { + const pull = yield* Socket.readerString(socket) + received.push(...(yield* pull)) + yield* Deferred.succeed(started, undefined) + yield* Deferred.await(release) + }), + ).pipe(Effect.forkChild) yield* Deferred.await(started) - const concurrent = yield* Effect.exit(socket.runString(() => Effect.void)) + const concurrent = yield* Effect.exit(Effect.scoped(socket.reader)) expect(failureText(concurrent)).toContain("Concurrent runs") yield* Deferred.succeed(release, undefined) yield* Fiber.join(first) - yield* socket.runString((message) => Effect.sync(() => received.push(message))) + yield* Effect.scoped( + Effect.gen(function* () { + const pull = yield* Socket.readerString(socket) + received.push(...(yield* pull)) + }), + ) }).pipe( Effect.scoped, Effect.provide( @@ -462,11 +446,10 @@ describe("WebSocket", () => { const exit = await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - const write = yield* socket.writer + const reader = yield* socket.reader + const writer = yield* socket.writer return yield* Effect.exit( - socket.runRaw(() => {}, { - onOpen: write(new Socket.CloseEvent(1000)).pipe(Effect.orDie), - }), + writer.write(new Socket.CloseEvent(1000)).pipe(Effect.andThen(reader.pull)), ) }).pipe( Effect.scoped, @@ -486,7 +469,7 @@ describe("WebSocket", () => { const exit = await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - return yield* Effect.exit(socket.runRaw(() => {})) + return yield* Effect.exit(socket.reader) }).pipe( Effect.scoped, Effect.provide( @@ -495,8 +478,8 @@ describe("WebSocket", () => { Layer.succeed( Socket.Socket, Socket.make({ - runRaw: () => Effect.die(new Error("connection failed")), - writer: Effect.succeed(() => Effect.void), + reader: Effect.die(new Error("connection failed")), + writer: Effect.succeed({ write: () => Effect.void, writeAll: () => Effect.void }), }), ), ), @@ -509,6 +492,60 @@ describe("WebSocket", () => { expect(existsSync(`${directory.path}/websocket/failed-run.json`)).toBe(false) }) + test("a failed reader scope does not record a completed WebSocket interaction", async () => { + using directory = tempDirectory("http-recorder-websocket-") + const upstream = Socket.make({ + reader: Effect.succeed({ pull: Effect.succeed(["received"] as const), upgrade: Socket.SocketUpgradeError.unsupported }), + writer: Effect.succeed({ write: () => Effect.void, writeAll: () => Effect.void }), + }) + + const exit = await Effect.runPromise( + Effect.scoped( + Effect.gen(function* () { + const socket = yield* Socket.Socket + const reader = yield* socket.reader + yield* reader.pull + return yield* Effect.fail(new Error("consumer failed")) + }), + ).pipe( + Effect.exit, + Effect.provide( + layerSocketWithMode("websocket/failed-consumer", { directory: directory.path, mode: "record" }).pipe( + Layer.provide(Layer.succeed(Socket.Socket, upstream)), + ), + ), + ), + ) + + expect(Exit.isFailure(exit)).toBe(true) + expect(existsSync(`${directory.path}/websocket/failed-consumer.json`)).toBe(false) + }) + + test("closing a replay reader scope releases a suspended pull", async () => { + using directory = tempDirectory("http-recorder-websocket-") + await seedCassetteDirectory(directory.path, "websocket/waiting", [ + { transport: "websocket", events: [{ direction: "client", kind: "text", body: "expected" }] }, + ]) + + await Effect.runPromise( + Effect.gen(function* () { + const socket = yield* Socket.Socket + const scope = yield* Scope.make() + const reader = yield* Scope.provide(socket.reader, scope) + const waiting = yield* reader.pull.pipe(Effect.exit, Effect.forkChild) + yield* Scope.close(scope, Exit.void) + expect(failureText(yield* Fiber.join(waiting))).toContain("SocketError: 1000") + }).pipe( + Effect.scoped, + Effect.provide( + layerSocketWithMode("websocket/waiting", { directory: directory.path, mode: "replay" }).pipe( + Layer.provide(Layer.succeed(Socket.Socket, unavailableSocket)), + ), + ), + ), + ) + }) + test("WebSocket replay preserves binary frame kinds across reconnects", async () => { using directory = tempDirectory("http-recorder-websocket-") const interaction = { @@ -534,13 +571,16 @@ describe("WebSocket", () => { await Effect.runPromise( Effect.gen(function* () { const socket = yield* Socket.Socket - const write = yield* socket.writer - const run = socket.runRaw( - (message) => { - if (typeof message === "string") throw new Error("Expected a binary WebSocket frame") - received.push([...message]) - }, - { onOpen: write(new Uint8Array([1, 2])).pipe(Effect.orDie) }, + const run = Effect.scoped( + Effect.gen(function* () { + const reader = yield* socket.reader + const writer = yield* socket.writer + yield* writer.writeAll([new Uint8Array([1, 2])]) + for (const message of yield* reader.pull) { + if (typeof message === "string") throw new Error("Expected a binary WebSocket frame") + received.push([...message]) + } + }), ) yield* run yield* run diff --git a/packages/httpapi-codegen/src/index.ts b/packages/httpapi-codegen/src/index.ts index ae7cd0712918..8eced80e4d68 100644 --- a/packages/httpapi-codegen/src/index.ts +++ b/packages/httpapi-codegen/src/index.ts @@ -1,7 +1,7 @@ import { isAbsolute, join } from "node:path" import { Context, Effect, FileSystem, PlatformError, Schema, SchemaAST, SchemaRepresentation } from "effect" -import { HttpMethod, type HttpRouter } from "effect/unstable/http" -import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpMethod, type HttpRouter } from "effect/http" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { format } from "prettier" export type InputField = { @@ -588,7 +588,8 @@ function assertPromiseEndpoint(endpoint: Endpoint) { const payloadEncoding = payload === undefined ? undefined - : (resolveHttpApiEncoding(payload.ast)?._tag ?? (HttpMethod.hasBody(endpoint.endpoint.method) ? "Json" : "FormUrlEncoded")) + : (resolveHttpApiEncoding(payload.ast)?._tag ?? + (HttpMethod.hasBody(endpoint.endpoint.method) ? "Json" : "FormUrlEncoded")) if (payloadEncoding !== undefined && payloadEncoding !== "Json" && payloadEncoding !== "Uint8Array") { throw new GenerationError({ reason: `Unsupported Promise payload encoding: ${name}` }) } @@ -746,8 +747,8 @@ function renderImportedEffectFiles( const imports = projection === undefined ? `import { ${api} } from ${JSON.stringify(options.module)}` - : `import { HttpApi, HttpApiClient${"endpoints" in options ? ", HttpApiGroup" : ""} } from "effect/unstable/httpapi"\nimport { ${projection.imports.join(", ")} } from ${JSON.stringify(options.module)}` - const httpApiImport = projection === undefined ? 'import { HttpApiClient } from "effect/unstable/httpapi"\n' : "" + : `import { HttpApi, HttpApiClient${"endpoints" in options ? ", HttpApiGroup" : ""} } from "effect/http-api"\nimport { ${projection.imports.join(", ")} } from ${JSON.stringify(options.module)}` + const httpApiImport = projection === undefined ? 'import { HttpApiClient } from "effect/http-api"\n' : "" const shapeTypes = groups.flatMap((group) => group.endpoints.flatMap((endpoint) => [ ...(endpoint.operation.inputMode === "none" ? [] : [`${endpointTypeName(group, endpoint)}Input`]), @@ -762,7 +763,7 @@ function renderImportedEffectFiles( options.shapeModule === undefined ? "" : `const preserveEffect = () => (effect: Effect.Effect) => effect\n${usesStream ? "const preserveStream = () => (stream: Stream.Stream) => stream\n" : ""}\n` - const client = `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect${usesStream ? ", Stream" : ""}, Schema } from "effect"\nimport { Sse } from "effect/unstable/encoding"\nimport { HttpClientError } from "effect/unstable/http"\n${httpApiImport}${imports}\n${shapeImport}import { ClientError } from "./client-error.js"\n\n${projection?.source ?? ""}type RawClient = HttpApiClient.ForApi\n\nconst mapClientError = (error: E) => HttpClientError.isHttpClientError(error) || Schema.isSchemaError(error) || Sse.Retry.is(error) ? new ClientError({ cause: error }) : error\n\n${preserve}${adapters.join("\n\n")}\n\nconst adaptClient = (raw: RawClient) => ({ ${fields.join(", ")} })\n\nexport const make = (options?: { readonly baseUrl?: URL | string }) => HttpApiClient.make(${api}, options).pipe(Effect.map(adaptClient))\n` + const client = `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect${usesStream ? ", Stream" : ""}, Schema } from "effect"\nimport { Sse } from "effect/encoding"\nimport { HttpClientError } from "effect/http"\n${httpApiImport}${imports}\n${shapeImport}import { ClientError } from "./client-error.js"\n\n${projection?.source ?? ""}type RawClient = HttpApiClient.ForApi\n\nconst mapClientError = (error: E) => HttpClientError.isHttpClientError(error) || Schema.isSchemaError(error) || Sse.Retry.is(error) ? new ClientError({ cause: error }) : error\n\n${preserve}${adapters.join("\n\n")}\n\nconst adaptClient = (raw: RawClient) => ({ ${fields.join(", ")} })\n\nexport const make = (options?: { readonly baseUrl?: URL | string }) => HttpApiClient.make(${api}, options).pipe(Effect.map(adaptClient))\n` return [ { path: "client-error.ts", @@ -1253,7 +1254,7 @@ function normalizePromiseClientContent(content: string, groups: ReadonlyArray): boolean { + if (seen.has(ast)) return false + seen.add(ast) + if (SchemaAST.isDeclaration(ast) && ast.annotations?.["~constructor"] && !ast.annotations.toCode) + return taggedErrorFields(Schema.make(ast)) === undefined + if (ast.encoding?.some((link) => containsClassWithoutCode(link.to, seen))) return true + if (SchemaAST.isDeclaration(ast)) return ast.typeParameters.some((item) => containsClassWithoutCode(item, seen)) + if (SchemaAST.isSuspend(ast)) return containsClassWithoutCode(ast.thunk(), seen) + if (SchemaAST.isUnion(ast)) return ast.types.some((item) => containsClassWithoutCode(item, seen)) + if (SchemaAST.isArrays(ast)) + return [...ast.elements, ...ast.rest].some((item) => containsClassWithoutCode(item, seen)) + if (SchemaAST.isObjects(ast)) + return ( + ast.propertySignatures.some((field) => containsClassWithoutCode(field.type, seen)) || + ast.indexSignatures.some( + (field) => containsClassWithoutCode(field.parameter, seen) || containsClassWithoutCode(field.type, seen), + ) + ) + return false +} + function isPathInput(path: string): path is HttpRouter.PathInput { return path === "*" || path.startsWith("/") } @@ -1638,9 +1661,8 @@ function checksPortable(checks: SchemaAST.Checks | undefined): boolean { ? !check.aborted && check.annotations?.representation !== undefined && serializable(check.annotations.representation) && - typeof check.annotations.arbitrary === "object" && - check.annotations.arbitrary !== null && - "constraint" in check.annotations.arbitrary + typeof check.annotations.arbitraryConstraint === "object" && + check.annotations.arbitraryConstraint !== null : checksPortable(check.checks), ) } @@ -1680,6 +1702,7 @@ function annotationsPortable(annotations: Schema.Annotations.Annotations | undef "toCodecJson", "toCodecStringTree", "toArbitrary", + "toCodecArbitrary", "toFormatter", "toEquivalence", "toCode", @@ -1888,7 +1911,7 @@ function renderGroup(group: Group) { ? `HttpApiClient.Client` : `HttpApiClient.Client.Group` const usesStream = group.endpoints.some((item) => item.operation.success === "stream") - return `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect, Schema${usesStream ? ", Stream" : ""} } from "effect"\nimport { Sse } from "effect/unstable/encoding"\nimport { HttpClientError } from "effect/unstable/http"\nimport { HttpApiClient, HttpApiEndpoint, HttpApiGroup${usesHttpApiSchema ? ", HttpApiSchema" : ""} } from "effect/unstable/httpapi"\nimport { ClientError } from "./client-error.js"\n\n${declarations}\n\nexport const Group${name} = ${groupSource}\n\ntype RawGroup = ${rawGroup}\n\n${adapters.join("\n\n")}\n\nexport const adaptGroup${name} = (raw: RawGroup) => ({ ${methods} })\n` + return `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect, Schema${usesStream ? ", Stream" : ""} } from "effect"\nimport { Sse } from "effect/encoding"\nimport { HttpClientError } from "effect/http"\nimport { HttpApiClient, HttpApiEndpoint, HttpApiGroup${usesHttpApiSchema ? ", HttpApiSchema" : ""} } from "effect/http-api"\nimport { ClientError } from "./client-error.js"\n\n${declarations}\n\nexport const Group${name} = ${groupSource}\n\ntype RawGroup = ${rawGroup}\n\n${adapters.join("\n\n")}\n\nexport const adaptGroup${name} = (raw: RawGroup) => ({ ${methods} })\n` } function renderEffectRequestPart( @@ -1973,5 +1996,5 @@ function renderClient(groups: ReadonlyArray) { const raw = `{ ${group.endpoints.map((item) => `${JSON.stringify(item.endpoint.identifier)}: raw[${JSON.stringify(item.endpoint.identifier)}]`).join(", ")} }` return [`...adaptGroup${groupTypeName(group)}(${raw})`] }) - return `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect } from "effect"\nimport { HttpApi, HttpApiClient } from "effect/unstable/httpapi"\n${imports}\n\nconst Api = ${api}\nconst adaptClient = (raw: HttpApiClient.ForApi) => ({ ${fields.join(", ")} })\n\nexport const make = (options?: { readonly baseUrl?: URL | string }) =>\n HttpApiClient.make(Api, options).pipe(Effect.map(adaptClient))\n` + return `// Generated by @opencode/httpapi-codegen. Do not edit.\nimport { Effect } from "effect"\nimport { HttpApi, HttpApiClient } from "effect/http-api"\n${imports}\n\nconst Api = ${api}\nconst adaptClient = (raw: HttpApiClient.ForApi) => ({ ${fields.join(", ")} })\n\nexport const make = (options?: { readonly baseUrl?: URL | string }) =>\n HttpApiClient.make(Api, options).pipe(Effect.map(adaptClient))\n` } diff --git a/packages/httpapi-codegen/test/fixture.ts b/packages/httpapi-codegen/test/fixture.ts index 6210cd1422b2..d9cd879e4183 100644 --- a/packages/httpapi-codegen/test/fixture.ts +++ b/packages/httpapi-codegen/test/fixture.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" export class Missing extends Schema.TaggedError()("Missing", { message: Schema.String, diff --git a/packages/httpapi-codegen/test/generate.test.ts b/packages/httpapi-codegen/test/generate.test.ts index 8432988dfda5..188e1f7616d2 100644 --- a/packages/httpapi-codegen/test/generate.test.ts +++ b/packages/httpapi-codegen/test/generate.test.ts @@ -11,7 +11,7 @@ import { HttpApiMiddleware, HttpApiSchema, OpenApi, -} from "effect/unstable/httpapi" +} from "effect/http-api" import { format } from "prettier" import { compile as compileContract, diff --git a/packages/httpapi-codegen/test/generated-consumer.ts b/packages/httpapi-codegen/test/generated-consumer.ts index 4b72c3ff6b97..3676387beba4 100644 --- a/packages/httpapi-codegen/test/generated-consumer.ts +++ b/packages/httpapi-codegen/test/generated-consumer.ts @@ -1,5 +1,5 @@ import { Effect, Stream } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { ClientError, OpenCode } from "./generated" import { Missing } from "./fixture" diff --git a/packages/httpapi-codegen/test/generated/client.ts b/packages/httpapi-codegen/test/generated/client.ts index 0e412b20ef5d..b158bc82c6b0 100644 --- a/packages/httpapi-codegen/test/generated/client.ts +++ b/packages/httpapi-codegen/test/generated/client.ts @@ -1,6 +1,6 @@ // Generated by @opencode/httpapi-codegen. Do not edit. import { Effect } from "effect" -import { HttpApi, HttpApiClient } from "effect/unstable/httpapi" +import { HttpApi, HttpApiClient } from "effect/http-api" import { adaptGroupSession, GroupSession } from "./session" import { adaptGroupEvent, GroupEvent } from "./event" import { adaptGroupSystem, GroupSystem } from "./system" diff --git a/packages/httpapi-codegen/test/generated/event.ts b/packages/httpapi-codegen/test/generated/event.ts index 1f6411dfb26a..7fe72e0bd48f 100644 --- a/packages/httpapi-codegen/test/generated/event.ts +++ b/packages/httpapi-codegen/test/generated/event.ts @@ -1,8 +1,8 @@ // Generated by @opencode/httpapi-codegen. Do not edit. import { Effect, Schema, Stream } from "effect" -import { Sse } from "effect/unstable/encoding" -import { HttpClientError } from "effect/unstable/http" -import { HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/unstable/httpapi" +import { Sse } from "effect/encoding" +import { HttpClientError } from "effect/http" +import { HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from "effect/http-api" import { ClientError } from "./client-error.js" const EndpointSubscribeSuccessData = Schema.Struct({ type: Schema.String }) diff --git a/packages/httpapi-codegen/test/generated/session.ts b/packages/httpapi-codegen/test/generated/session.ts index 23c35b74b0a2..7f0a649472cc 100644 --- a/packages/httpapi-codegen/test/generated/session.ts +++ b/packages/httpapi-codegen/test/generated/session.ts @@ -1,8 +1,8 @@ // Generated by @opencode/httpapi-codegen. Do not edit. import { Effect, Schema } from "effect" -import { Sse } from "effect/unstable/encoding" -import { HttpClientError } from "effect/unstable/http" -import { HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { Sse } from "effect/encoding" +import { HttpClientError } from "effect/http" +import { HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { ClientError } from "./client-error.js" const EndpointHealthSuccess = Schema.String diff --git a/packages/httpapi-codegen/test/generated/system.ts b/packages/httpapi-codegen/test/generated/system.ts index 7b85ecd6011a..50fd40f66f1a 100644 --- a/packages/httpapi-codegen/test/generated/system.ts +++ b/packages/httpapi-codegen/test/generated/system.ts @@ -1,8 +1,8 @@ // Generated by @opencode/httpapi-codegen. Do not edit. import { Effect, Schema } from "effect" -import { Sse } from "effect/unstable/encoding" -import { HttpClientError } from "effect/unstable/http" -import { HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/unstable/httpapi" +import { Sse } from "effect/encoding" +import { HttpClientError } from "effect/http" +import { HttpApiClient, HttpApiEndpoint, HttpApiGroup } from "effect/http-api" import { ClientError } from "./client-error.js" const EndpointStatusSuccess = Schema.String diff --git a/packages/httpapi-codegen/test/write.test.ts b/packages/httpapi-codegen/test/write.test.ts index 734028b30095..734c3b48be88 100644 --- a/packages/httpapi-codegen/test/write.test.ts +++ b/packages/httpapi-codegen/test/write.test.ts @@ -1,6 +1,6 @@ import { describe, expect } from "bun:test" import { join } from "node:path" -import { Effect, FileSystem, Option } from "effect" +import { ByteSize, Effect, FileSystem, Option } from "effect" import { write, type Output } from "../src" import { it } from "./effect" @@ -150,7 +150,7 @@ describe("HttpApiCodegen.write", () => { uid: Option.none(), gid: Option.none(), rdev: Option.none(), - size: FileSystem.Size(0), + size: ByteSize.bytes(0), blksize: Option.none(), blocks: Option.none(), }), diff --git a/packages/plugin-browser/src/tools.ts b/packages/plugin-browser/src/tools.ts index 5ecf68a04142..7afb621efaa7 100644 --- a/packages/plugin-browser/src/tools.ts +++ b/packages/plugin-browser/src/tools.ts @@ -2,7 +2,8 @@ export * as BrowserTools from "./tools.js" import type { Context } from "@opencode/plugin/effect/plugin" import { Tool } from "@opencode/schema/tool" -import { Effect, Encoding, Result, Schema } from "effect" +import { Effect, Result, Schema } from "effect" +import { Base64 } from "effect/encoding" import type { BrowserConnection } from "./connection.js" import { BrowserFiles } from "./files.js" import { Browser } from "./rpc.js" @@ -104,7 +105,7 @@ function exportResult(output: Schema.Schema.Type, f .filter((file) => file.mime.startsWith("image/")) .map((file) => ({ type: "file" as const, - uri: `data:${file.mime};base64,${Encoding.encodeBase64(file.data)}`, + uri: `data:${file.mime};base64,${Base64.encode(file.data)}`, mime: file.mime, name: file.name, })), diff --git a/packages/plugin/src/promise/adapter.ts b/packages/plugin/src/promise/adapter.ts index 473b2260af0e..bce47874b21d 100644 --- a/packages/plugin/src/promise/adapter.ts +++ b/packages/plugin/src/promise/adapter.ts @@ -3,7 +3,7 @@ import type { Rpc } from "@opencode/schema/rpc" import type { RpcCallOptions, RpcEventPayload } from "@opencode/client/promise/api" import { Effect, Schema, SchemaAST, Stream } from "effect" import type { Scope } from "effect" -import { HttpApiEndpoint, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiSchema } from "effect/http-api" import { define } from "../effect/plugin.js" import type { Plugin } from "./plugin.js" import type { Info } from "./tool.js" diff --git a/packages/protocol/openapi.json b/packages/protocol/openapi.json index e4fbd2f5d3c6..4e48ee5be66a 100644 --- a/packages/protocol/openapi.json +++ b/packages/protocol/openapi.json @@ -48,6 +48,99 @@ "summary": "Get server info" } }, + "/api/pair": { + "post": { + "tags": ["server"], + "operationId": "server.pair", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "PairingCode", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairingCode" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Create a short-lived, single-use code for a /auth/connect/:code pairing link.", + "summary": "Create pairing code" + } + }, + "/auth/connect/{code}": { + "get": { + "tags": ["server"], + "operationId": "server.connect", + "parameters": [ + { + "name": "code", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "security": [], + "responses": { + "200": { + "description": "PairingSession", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairingSession" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Redeem a pairing code. Browsers receive a session cookie and a redirect to the web app; requests that accept JSON receive a session token to use as the password.", + "summary": "Redeem pairing code" + } + }, "/api/location": { "get": { "tags": ["location"], @@ -261,7 +354,7 @@ "name": "agentID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "required": true }, @@ -505,14 +598,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -601,14 +687,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -719,8 +798,7 @@ { "anyOf": [ { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, { "type": "string", @@ -742,7 +820,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, { "type": "null" @@ -757,7 +835,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -772,7 +850,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, { "type": "null" @@ -819,9 +897,6 @@ { "$ref": "#/components/schemas/InvalidCursorErrorEncoded" }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, { "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } @@ -886,9 +961,19 @@ } } } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + } + } + } } }, - "description": "Create a session at the requested location.", + "description": "Create a session at the requested location. A parentID creates a linked child session at its parent's location.", "summary": "Create session", "requestBody": { "content": { @@ -899,8 +984,17 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" + }, + { + "type": "null" + } + ] + }, + "parentID": { + "anyOf": [ + { + "$ref": "#/components/schemas/SessionID" }, { "type": "null" @@ -920,7 +1014,7 @@ "agent": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, { "type": "null" @@ -1017,7 +1111,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -1082,14 +1176,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1220,8 +1307,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -1326,7 +1412,8 @@ "^ses": { "$ref": "#/components/schemas/SessionActive" } - } + }, + "additionalProperties": false } }, "required": ["data"], @@ -1369,8 +1456,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1436,8 +1522,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1489,8 +1574,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1525,14 +1609,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1594,8 +1671,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1624,14 +1700,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1652,14 +1721,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" } ] } @@ -1678,8 +1744,7 @@ "before": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -1704,8 +1769,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1740,14 +1804,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1762,7 +1819,7 @@ "type": "object", "properties": { "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" } }, "required": ["agent"], @@ -1783,8 +1840,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1819,14 +1875,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1862,8 +1911,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1878,14 +1926,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1920,7 +1961,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "delivery": { "anyOf": [ @@ -1951,8 +1992,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1981,14 +2021,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -2008,14 +2041,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2042,8 +2068,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2113,8 +2138,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2150,14 +2174,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/CommandNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/CommandNotFoundErrorEncoded" } ] } @@ -2236,8 +2257,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2273,14 +2293,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/SkillNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/SkillNotFoundErrorEncoded" } ] } @@ -2297,7 +2314,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "resume": { "anyOf": [ @@ -2328,8 +2345,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2378,14 +2394,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2412,8 +2421,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2475,8 +2483,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2511,14 +2518,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2535,8 +2535,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2565,8 +2564,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2615,14 +2613,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2649,8 +2640,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2685,8 +2675,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2721,14 +2710,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2757,8 +2739,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2811,9 +2792,6 @@ { "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } @@ -2852,8 +2830,7 @@ "type": "object", "properties": { "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "files": { "anyOf": [ @@ -2884,8 +2861,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2920,14 +2896,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2965,8 +2934,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3001,14 +2969,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3036,8 +2997,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3118,8 +3078,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3129,8 +3088,7 @@ "schema": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -3146,8 +3104,7 @@ "schema": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -3201,14 +3158,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -3264,8 +3214,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3336,8 +3285,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3345,8 +3293,7 @@ "name": "inboxID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -3398,8 +3345,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3407,8 +3353,7 @@ "name": "inboxID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -3489,8 +3434,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3542,14 +3486,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3568,8 +3505,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3612,14 +3548,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3661,8 +3590,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3705,14 +3633,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3731,8 +3652,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3774,14 +3694,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3827,8 +3740,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3838,7 +3750,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Event.SeqEncoded" }, { "type": "null" @@ -3890,7 +3802,7 @@ "$ref": "#/components/schemas/SessionLogItemEncoded" } }, - "required": ["id", "event", "data"], + "required": ["event", "data"], "additionalProperties": false }, "x-effect-stream": { @@ -3952,7 +3864,7 @@ "errorSchema": { "not": {} }, - "failureEvent": "effect/httpapi/stream/failure" + "failureEvent": "effect/http-api/stream/failure" } } } @@ -4001,8 +3913,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -4059,15 +3970,8 @@ "description": "SessionNotFoundError", "content": { "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "schema": { + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4086,8 +3990,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4122,14 +4025,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4148,8 +4044,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -4157,8 +4052,7 @@ "name": "messageID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -4285,14 +4179,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4338,14 +4225,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -4365,14 +4245,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4419,8 +4292,7 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true } @@ -4470,14 +4342,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4504,10 +4373,24 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true + }, + { + "name": "message", + "in": "query", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "required": false } ], "security": [], @@ -4541,14 +4424,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4587,25 +4467,9 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true - }, - { - "name": "message", - "in": "query", - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "required": false } ], "security": [], @@ -4646,14 +4510,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4694,8 +4555,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4769,8 +4629,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4841,8 +4700,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -5206,14 +5064,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5375,7 +5226,7 @@ "name": "providerID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "required": true }, @@ -5572,7 +5423,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5710,14 +5561,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5763,7 +5607,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5808,14 +5652,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5891,7 +5728,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5953,14 +5790,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5985,7 +5815,7 @@ "type": "object", "properties": { "methodID": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "answer": { "anyOf": [ @@ -6026,7 +5856,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6034,7 +5864,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6140,7 +5970,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6148,7 +5978,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6222,7 +6052,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6230,7 +6060,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6275,14 +6105,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -6351,7 +6174,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6413,14 +6236,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -6462,7 +6278,7 @@ "type": "object", "properties": { "methodID": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "label": { "anyOf": [ @@ -6493,7 +6309,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6501,7 +6317,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6607,7 +6423,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6615,7 +6431,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -7159,14 +6975,113 @@ "schema": { "type": "object", "properties": { - "location": { - "$ref": "#/components/schemas/Location.PublicRef" - }, + "location": { + "$ref": "#/components/schemas/Location.PublicRef" + }, + "data": { + "$ref": "#/components/schemas/Mcp.ResourceCatalog" + } + }, + "required": ["location", "data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Retrieve resources and resource templates from connected MCP servers.", + "summary": "List MCP resources" + } + }, + "/api/credential": { + "get": { + "tags": ["credential"], + "operationId": "credential.list", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Credential.Entry" + } + } + }, + "required": ["data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "List every stored integration credential, including its secret value.", + "summary": "List credentials" + }, + "post": { + "tags": ["credential"], + "operationId": "credential.create", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "data": { - "$ref": "#/components/schemas/Mcp.ResourceCatalog" + "$ref": "#/components/schemas/Credential.Entry" } }, - "required": ["location", "data"], + "required": ["data"], "additionalProperties": false } } @@ -7191,10 +7106,30 @@ } } } + }, + "409": { + "description": "ConflictError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConflictErrorEncoded" + } + } + } } }, - "description": "Retrieve resources and resource templates from connected MCP servers.", - "summary": "List MCP resources" + "description": "Store an integration credential. It becomes the integration's active credential unless activate is false and the integration already has one. Fails with a conflict when the requested ID already exists.", + "summary": "Create credential", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential.CreateInput" + } + } + }, + "required": true + } } }, "/api/credential/{credentialID}": { @@ -7206,7 +7141,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7265,7 +7200,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7309,7 +7244,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7398,7 +7333,7 @@ "name": "projectID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "required": true } @@ -7455,7 +7390,7 @@ "type": "object", "properties": { "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "name": { "type": "string" @@ -7658,7 +7593,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -7724,7 +7659,7 @@ "name": "id", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/PermissionSaved.ID" }, "required": true } @@ -7768,8 +7703,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -7787,8 +7721,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "effect": { "$ref": "#/components/schemas/Permission.Effect" @@ -7829,14 +7762,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -7853,8 +7779,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, { "type": "null" @@ -7885,7 +7810,7 @@ "agent": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, { "type": "null" @@ -7909,8 +7834,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -7981,8 +7905,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -7990,8 +7913,7 @@ "name": "requestID", "in": "path", "schema": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "required": true } @@ -8041,14 +7963,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" } ] } @@ -8069,8 +7988,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -8078,8 +7996,7 @@ "name": "requestID", "in": "path", "schema": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "required": true } @@ -8115,14 +8032,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" } ] } @@ -8887,7 +8801,7 @@ "$ref": "#/components/schemas/V2EventEncoded" } }, - "required": ["id", "event", "data"], + "required": ["event", "data"], "additionalProperties": false }, "x-effect-stream": { @@ -8949,7 +8863,7 @@ "errorSchema": { "not": {} }, - "failureEvent": "effect/httpapi/stream/failure" + "failureEvent": "effect/http-api/stream/failure" } } } @@ -9189,8 +9103,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9289,8 +9202,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9420,8 +9332,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9505,8 +9416,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9632,8 +9542,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9726,8 +9635,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -9817,8 +9725,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -9850,14 +9757,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -9892,8 +9792,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -9922,14 +9821,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -10083,8 +9975,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10158,8 +10049,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10243,8 +10133,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10306,8 +10195,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10383,8 +10271,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -10485,8 +10372,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -10804,8 +10690,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -10904,8 +10789,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -10979,8 +10863,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -11203,7 +11086,7 @@ "name": "projectID", "in": "query", "schema": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "required": true } @@ -11439,7 +11322,7 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" } }, "required": ["projectID"], @@ -12339,14 +12222,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -12384,7 +12260,7 @@ "type": "string" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" } }, "required": ["query"], @@ -12565,17 +12441,23 @@ }, "components": { "schemas": { + "AbsolutePath": { + "type": "string" + }, "Agent.Color": { "type": "string" }, + "Agent.ID": { + "type": "string" + }, "Agent.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Agent.Name" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -12610,6 +12492,9 @@ "required": ["id", "name", "request", "mode", "hidden", "permissions"], "additionalProperties": false }, + "Agent.Name": { + "type": "string" + }, "AgentNotFoundErrorEncoded": { "type": "object", "properties": { @@ -12680,23 +12565,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -12733,8 +12614,7 @@ "type": "boolean" }, "color": { - "type": "string", - "pattern": "^#[0-9a-fA-F]{6}$" + "type": "string" }, "steps": { "type": "integer", @@ -12764,23 +12644,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -12807,7 +12683,7 @@ "enum": ["directory"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["type", "path"], @@ -12821,7 +12697,7 @@ "enum": ["document"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "info": { "$ref": "#/components/schemas/Config.InfoEncoded" @@ -12879,23 +12755,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -13301,10 +13173,10 @@ "type": "object", "properties": { "modelID": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "family": { - "type": "string" + "$ref": "#/components/schemas/Model.Family" }, "name": { "type": "string" @@ -13336,7 +13208,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" }, "settings": { "$ref": "#/components/schemas/Config.Model.Settings" @@ -13461,7 +13333,7 @@ "type": "object", "properties": { "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "name": { "type": "string" @@ -13582,84 +13454,218 @@ "enum": ["random"], "description": "Reuse a randomly selected provider until it is rate limited, then switch to another available provider." }, + { + "$ref": "#/components/schemas/WebSearch.ID" + } + ] + } + }, + "required": ["provider"], + "additionalProperties": false + }, + "ConflictErrorEncoded": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["ConflictError"] + }, + "message": { + "type": "string" + }, + "resource": { + "anyOf": [ { "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "Connection.CredentialInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["credential"] + }, + "id": { + "$ref": "#/components/schemas/Credential.ID" + }, + "label": { + "type": "string" + }, + "method": { + "type": "string", + "enum": ["key", "oauth"] + }, + "status": { + "$ref": "#/components/schemas/Connection.Status" + } + }, + "required": ["type", "id", "label", "method"], + "additionalProperties": false + }, + "Connection.EnvInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["env"] + }, + "name": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/Connection.Status" + } + }, + "required": ["type", "name"], + "additionalProperties": false + }, + "Connection.Info": { + "anyOf": [ + { + "$ref": "#/components/schemas/Connection.CredentialInfo" + }, + { + "$ref": "#/components/schemas/Connection.EnvInfo" + } + ] + }, + "Connection.Status": { + "type": "object", + "properties": { + "status": { + "anyOf": [ + { + "type": "string", + "enum": ["needs_auth"] } ] + }, + "message": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": ["status", "message"], + "additionalProperties": false + }, + "Credential.CreateInput": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/Credential.ID" + }, + "integrationID": { + "$ref": "#/components/schemas/Integration.ID" + }, + "label": { + "type": "string" + }, + "value": { + "$ref": "#/components/schemas/Credential.Value" + }, + "activate": { + "type": "boolean" } }, - "required": ["provider"], + "required": ["integrationID", "value"], "additionalProperties": false }, - "ConflictErrorEncoded": { + "Credential.Entry": { "type": "object", "properties": { - "_tag": { - "type": "string", - "enum": ["ConflictError"] + "id": { + "$ref": "#/components/schemas/Credential.ID" }, - "message": { + "integrationID": { + "$ref": "#/components/schemas/Integration.ID" + }, + "label": { "type": "string" }, - "resource": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] + "active": { + "type": "boolean" + }, + "value": { + "$ref": "#/components/schemas/Credential.Value" } }, - "required": ["_tag", "message"], + "required": ["id", "integrationID", "label", "active", "value"], "additionalProperties": false }, - "Connection.CredentialInfo": { + "Credential.ID": { + "type": "string" + }, + "Credential.Key": { "type": "object", "properties": { "type": { "type": "string", - "enum": ["credential"] + "enum": ["key"] }, - "id": { + "key": { "type": "string" }, - "label": { - "type": "string" + "metadata": { + "type": "object" }, - "method": { - "type": "string", - "enum": ["key", "oauth"] + "configuration": { + "$ref": "#/components/schemas/Form.Answer_1" } }, - "required": ["type", "id", "label", "method"], + "required": ["type", "key"], "additionalProperties": false }, - "Connection.EnvInfo": { + "Credential.OAuth": { "type": "object", "properties": { "type": { "type": "string", - "enum": ["env"] + "enum": ["oauth"] }, - "name": { + "methodID": { + "$ref": "#/components/schemas/Integration.MethodID" + }, + "refresh": { + "type": "string" + }, + "access": { "type": "string" + }, + "expires": { + "type": "integer", + "minimum": 0 + }, + "metadata": { + "type": "object" } }, - "required": ["type", "name"], + "required": ["type", "methodID", "refresh", "access", "expires"], "additionalProperties": false }, - "Connection.Info": { + "Credential.Value": { "anyOf": [ { - "$ref": "#/components/schemas/Connection.CredentialInfo" + "$ref": "#/components/schemas/Credential.OAuth" }, { - "$ref": "#/components/schemas/Connection.EnvInfo" + "$ref": "#/components/schemas/Credential.Key" } ] }, + "Event.SeqEncoded": { + "type": "string" + }, "FileDiff.Info": { "type": "object", "properties": { @@ -13706,7 +13712,7 @@ "type": "object", "properties": { "path": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "type": { "type": "string", @@ -13720,7 +13726,7 @@ "type": "object", "properties": { "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["path"], @@ -13746,6 +13752,12 @@ "$ref": "#/components/schemas/Form.Value" } }, + "Form.Answer_1": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Form.Value" + } + }, "Form.BooleanField": { "type": "object", "properties": { @@ -13787,8 +13799,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, { "type": "null" @@ -13812,8 +13823,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "sessionID": { "type": "string" @@ -13915,12 +13925,15 @@ "$ref": "#/components/schemas/Form.Field" } }, + "Form.ID": { + "type": "string", + "pattern": "^frm_" + }, "Form.Info": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "sessionID": { "type": "string" @@ -14402,7 +14415,6 @@ }, "InstructionEntry.Key": { "type": "string", - "pattern": "^[a-z0-9][a-z0-9._-]*$", "description": "Instruction entry key (lowercase alphanumerics plus . _ -)" }, "InstructionEntryValueTooLargeErrorEncoded": { @@ -14429,7 +14441,7 @@ "type": "object", "properties": { "attemptID": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "url": { "type": "string" @@ -14474,6 +14486,9 @@ "required": ["attemptID", "url", "instructions", "mode", "time"], "additionalProperties": false }, + "Integration.AttemptID": { + "type": "string" + }, "Integration.AttemptStatus": { "anyOf": [ { @@ -14645,7 +14660,7 @@ "type": "object", "properties": { "attemptID": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "time": { "type": "object", @@ -14854,7 +14869,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "type": { "type": "string", @@ -14890,11 +14905,14 @@ "required": ["type", "names"], "additionalProperties": false }, + "Integration.ID": { + "type": "string" + }, "Integration.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "name": { "type": "string" @@ -14951,11 +14969,14 @@ } ] }, + "Integration.MethodID": { + "type": "string" + }, "Integration.OAuthMethod": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "type": { "type": "string", @@ -15080,19 +15101,19 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "project": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["id", "directory", "canonical"], @@ -15106,7 +15127,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["directory"], @@ -15343,7 +15364,7 @@ ] }, "integrationID": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" } }, "required": ["name", "status"], @@ -15533,23 +15554,29 @@ "required": ["input", "output", "cache"], "additionalProperties": false }, + "Model.Family": { + "type": "string" + }, + "Model.ID": { + "type": "string" + }, "Model.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "modelID": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "family": { - "type": "string" + "$ref": "#/components/schemas/Model.Family" }, "name": { "type": "string" @@ -15655,13 +15682,13 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "variant": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" } }, "required": ["id", "providerID"], @@ -15685,7 +15712,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" }, "settings": { "$ref": "#/components/schemas/Model.Settings" @@ -15703,16 +15730,46 @@ "required": ["id"], "additionalProperties": false }, + "Model.VariantID": { + "type": "string" + }, "Money.USD": { "type": "number" }, "Money.USDPerMillionTokens": { "type": "number" }, + "PairingCode": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "required": ["code", "expires_in"], + "additionalProperties": false + }, + "PairingSession": { + "type": "object", + "properties": { + "token": { + "type": "string" + } + }, + "required": ["token"], + "additionalProperties": false + }, "Permission.Effect": { "type": "string", "enum": ["allow", "deny", "ask"] }, + "Permission.ID": { + "type": "string", + "pattern": "^per" + }, "Permission.Reply": { "type": "string", "enum": ["once", "always", "reject"] @@ -15721,12 +15778,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "action": { "type": "string" @@ -15816,14 +15871,17 @@ "required": ["_tag", "requestID", "message"], "additionalProperties": false }, + "PermissionSaved.ID": { + "type": "string" + }, "PermissionSaved.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/PermissionSaved.ID" }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "action": { "type": "string" @@ -15922,8 +15980,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -15953,8 +16010,7 @@ "minimum": 0 }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "foregroundProcess": { "anyOf": [ @@ -16019,8 +16075,7 @@ "type": "object", "properties": { "ptyID": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -16151,11 +16206,14 @@ }, "additionalProperties": false }, + "Plugin.ID": { + "type": "string" + }, "Plugin.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Plugin.ID" }, "source": { "$ref": "#/components/schemas/Plugin.Source" @@ -16271,10 +16329,10 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "vcs": { "$ref": "#/components/schemas/Project.Vcs" @@ -16311,6 +16369,9 @@ }, "additionalProperties": false }, + "Project.ID": { + "type": "string" + }, "Project.Icon": { "type": "object", "properties": { @@ -16346,8 +16407,7 @@ "additionalProperties": false }, "Project.Vcs": { - "type": "string", - "pattern": "^[a-z][a-z0-9._-]*$" + "type": "string" }, "ProjectNotFoundErrorEncoded": { "type": "object", @@ -16380,8 +16440,7 @@ "additionalProperties": false }, "Prompt.Base64": { - "type": "string", - "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + "type": "string" }, "Prompt.FileAttachment": { "type": "object", @@ -16457,10 +16516,10 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "text": { "type": "string" @@ -16495,7 +16554,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "mention": { "$ref": "#/components/schemas/Prompt.Mention" @@ -16530,17 +16589,20 @@ } ] }, + "Provider.ID": { + "type": "string" + }, "Provider.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "integrationID": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "name": { "type": "string" @@ -16643,8 +16705,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -16677,6 +16738,10 @@ "required": ["id", "title", "command", "args", "cwd", "status", "pid"], "additionalProperties": false }, + "PtyID": { + "type": "string", + "pattern": "^pty" + }, "PtyNotFoundErrorEncoded": { "type": "object", "properties": { @@ -16732,7 +16797,7 @@ "type": "string" }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "description": { "type": "string" @@ -16755,7 +16820,7 @@ "enum": ["local"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["type", "path"], @@ -16771,6 +16836,9 @@ } ] }, + "RelativePath": { + "type": "string" + }, "Rpc.Input": { "type": "object", "properties": { @@ -16900,8 +16968,7 @@ "enum": ["before"] }, "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" } }, "required": ["type", "messageID"], @@ -16915,8 +16982,7 @@ "enum": ["through"] }, "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" } }, "required": ["type", "messageID"], @@ -16928,12 +16994,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -16960,14 +17024,9 @@ "additionalProperties": false }, "Session.Inbox.CompactionPayload": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "array" - } - ] + "not": { + "type": "null" + } }, "Session.Inbox.Delivery": { "type": "string", @@ -16993,12 +17052,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17028,10 +17085,10 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "location": { "$ref": "#/components/schemas/Location.PublicRef" @@ -17044,12 +17101,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17095,12 +17150,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17161,19 +17214,16 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "parentID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "fork": { "type": "object", "properties": { "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "boundary": { "$ref": "#/components/schemas/Session.ForkBoundary" @@ -17183,10 +17233,10 @@ "additionalProperties": false }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -17227,7 +17277,7 @@ "type": "string" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "metadata": { "$ref": "#/components/schemas/Session.Metadata" @@ -17249,8 +17299,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17270,10 +17319,10 @@ "enum": ["agent-switched"] }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "previous": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" } }, "required": ["id", "time", "type", "agent"], @@ -17283,8 +17332,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17310,7 +17358,7 @@ "enum": ["assistant"] }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -17335,15 +17383,15 @@ "type": "object", "properties": { "start": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "end": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "files": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" } } }, @@ -17518,8 +17566,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17575,8 +17622,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17620,8 +17666,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17654,12 +17699,15 @@ "required": ["type", "id", "time", "status", "reason", "summary", "recent"], "additionalProperties": false }, + "Session.Message.ID": { + "type": "string", + "pattern": "^msg_" + }, "Session.Message.Idle": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17727,8 +17775,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17748,10 +17795,10 @@ "enum": ["location-switched"] }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "location": { "$ref": "#/components/schemas/Location.PublicRef" @@ -17765,10 +17812,10 @@ "$ref": "#/components/schemas/Location.PublicRef" }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" } }, "required": ["location"], @@ -17787,8 +17834,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17839,8 +17885,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17863,8 +17908,7 @@ "enum": ["shell"] }, "shellID": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "command": { "type": "string" @@ -17913,8 +17957,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17934,10 +17977,10 @@ "enum": ["skill"] }, "skill": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "text": { "type": "string" @@ -17950,8 +17993,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17984,8 +18026,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -18110,8 +18151,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -18177,7 +18217,7 @@ "type": "object", "properties": { "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "provider": { "type": "string" @@ -18202,14 +18242,13 @@ "type": "object", "properties": { "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "partID": { "type": "string" }, "snapshot": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "files": { "type": "array", @@ -18234,6 +18273,16 @@ "type": "integer", "minimum": 100, "maximum": 599 + }, + "response": { + "type": "object", + "properties": { + "body": { + "type": "string" + } + }, + "required": ["body"], + "additionalProperties": false } }, "required": ["type", "message"], @@ -18284,6 +18333,10 @@ "required": ["data"], "additionalProperties": false }, + "SessionID": { + "type": "string", + "pattern": "^ses" + }, "SessionInterruptResponse": { "type": "object", "properties": { @@ -18584,6 +18637,9 @@ "required": ["info", "messages"], "additionalProperties": false }, + "SessionsCursor": { + "type": "string" + }, "SessionsResponse": { "type": "object", "properties": { @@ -18599,7 +18655,7 @@ "previous": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SessionsCursor" }, { "type": "null" @@ -18609,7 +18665,7 @@ "next": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SessionsCursor" }, { "type": "null" @@ -18623,12 +18679,15 @@ "required": ["data", "cursor"], "additionalProperties": false }, + "Shell.ID": { + "type": "string", + "pattern": "^sh_" + }, "Shell.Info": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "status": { "type": "string", @@ -18653,6 +18712,9 @@ "exit": { "type": "number" }, + "signal": { + "type": "string" + }, "metadata": { "type": "object" }, @@ -18691,14 +18753,17 @@ "required": ["_tag", "id", "message"], "additionalProperties": false }, + "Skill.ID": { + "type": "string" + }, "Skill.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "description": { "type": "string" @@ -18707,7 +18772,7 @@ "type": "boolean" }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "content": { "type": "string" @@ -18716,6 +18781,9 @@ "required": ["id", "name", "path", "content"], "additionalProperties": false }, + "Skill.Name": { + "type": "string" + }, "SkillNotFoundErrorEncoded": { "type": "object", "properties": { @@ -18724,7 +18792,7 @@ "enum": ["SkillNotFoundError"] }, "skill": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "message": { "type": "string" @@ -18733,6 +18801,9 @@ "required": ["_tag", "skill", "message"], "additionalProperties": false }, + "Snapshot.ID": { + "type": "string" + }, "TokenUsage.Info": { "type": "object", "properties": { @@ -18929,11 +19000,14 @@ "type": "string", "enum": ["working", "branch", "committed"] }, + "WebSearch.ID": { + "type": "string" + }, "WebSearch.Provider": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" }, "name": { "type": "string" @@ -18946,7 +19020,7 @@ "type": "object", "properties": { "providerID": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" }, "results": { "type": "array", @@ -18987,16 +19061,16 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "from": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "branch": { "type": "string" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "name": { "type": "string" @@ -19009,7 +19083,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "strategy": { "type": "string" @@ -19022,7 +19096,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["directory"], @@ -19038,10 +19112,10 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "force": { "type": "boolean" diff --git a/packages/protocol/script/generate-openapi.ts b/packages/protocol/script/generate-openapi.ts index 61c4ddecd11b..7fbb47b83d96 100644 --- a/packages/protocol/script/generate-openapi.ts +++ b/packages/protocol/script/generate-openapi.ts @@ -1,4 +1,4 @@ -import { OpenApi } from "effect/unstable/httpapi" +import { OpenApi } from "effect/http-api" import { format } from "prettier" import { fileURLToPath } from "url" import { ClientApi } from "../src/client.js" diff --git a/packages/protocol/src/api.ts b/packages/protocol/src/api.ts index e837cff11653..7d64d18f0b0e 100644 --- a/packages/protocol/src/api.ts +++ b/packages/protocol/src/api.ts @@ -1,5 +1,5 @@ import { Context } from "effect" -import { HttpApi, HttpApiGroup, HttpApiMiddleware, OpenApi } from "effect/unstable/httpapi" +import { HttpApi, HttpApiGroup, HttpApiMiddleware, OpenApi } from "effect/http-api" import { SchemaErrorMiddleware } from "./middleware/schema-error.js" import { GenerateGroup } from "./groups/generate.js" import { MessageGroup } from "./groups/message.js" diff --git a/packages/protocol/src/client.ts b/packages/protocol/src/client.ts index 2d6cdb9c50e1..27322c251ed8 100644 --- a/packages/protocol/src/client.ts +++ b/packages/protocol/src/client.ts @@ -2,7 +2,7 @@ import { InvalidRequestError, SessionNotFoundError } from "./errors.js" import { makeDefaultApi } from "./api.js" import type { Api } from "./api.js" import type { Context } from "effect" -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpApiMiddleware } from "effect/http-api" import type { EventGroup } from "./groups/event.js" class LocationMiddleware extends HttpApiMiddleware.Service()( diff --git a/packages/protocol/src/groups/agent.ts b/packages/protocol/src/groups/agent.ts index 4fd6e58159bc..485d0ae37cbf 100644 --- a/packages/protocol/src/groups/agent.ts +++ b/packages/protocol/src/groups/agent.ts @@ -1,7 +1,7 @@ import { Agent } from "@opencode/schema/agent" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" import { AgentNotFoundError } from "../errors.js" diff --git a/packages/protocol/src/groups/command.ts b/packages/protocol/src/groups/command.ts index dc9b850114e4..f1360b57f82f 100644 --- a/packages/protocol/src/groups/command.ts +++ b/packages/protocol/src/groups/command.ts @@ -1,7 +1,7 @@ import { Command } from "@opencode/schema/command" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" export const CommandGroup = HttpApiGroup.make("server.command") diff --git a/packages/protocol/src/groups/config.ts b/packages/protocol/src/groups/config.ts index cb4692838aaf..c6f6693fe257 100644 --- a/packages/protocol/src/groups/config.ts +++ b/packages/protocol/src/groups/config.ts @@ -1,7 +1,7 @@ import { Config } from "@opencode/schema/config" import { ConfigShell } from "@opencode/schema/config/shell" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" export const ConfigGroup = HttpApiGroup.make("server.config") diff --git a/packages/protocol/src/groups/credential.ts b/packages/protocol/src/groups/credential.ts index 7832916326ed..4123a48a7a43 100644 --- a/packages/protocol/src/groups/credential.ts +++ b/packages/protocol/src/groups/credential.ts @@ -1,6 +1,6 @@ import { Credential } from "@opencode/schema/credential" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { ConflictError } from "../errors.js" export const CredentialGroup = HttpApiGroup.make("server.credential") diff --git a/packages/protocol/src/groups/debug.ts b/packages/protocol/src/groups/debug.ts index 8b9860076651..fb7777c57cc0 100644 --- a/packages/protocol/src/groups/debug.ts +++ b/packages/protocol/src/groups/debug.ts @@ -1,6 +1,6 @@ import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" export const DebugGroup = HttpApiGroup.make("server.debug") diff --git a/packages/protocol/src/groups/event.ts b/packages/protocol/src/groups/event.ts index f067ecfe3967..288709c44090 100644 --- a/packages/protocol/src/groups/event.ts +++ b/packages/protocol/src/groups/event.ts @@ -3,7 +3,7 @@ import { EventManifest } from "@opencode/schema/event-manifest" import { Location } from "@opencode/schema/location" import type { Definition } from "@opencode/schema/event" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" const fields = { id: Event.ID, diff --git a/packages/protocol/src/groups/form.ts b/packages/protocol/src/groups/form.ts index 16abef80ff98..20407989f8ca 100644 --- a/packages/protocol/src/groups/form.ts +++ b/packages/protocol/src/groups/form.ts @@ -1,7 +1,7 @@ import { Form } from "@opencode/schema/form" import { Location } from "@opencode/schema/location" import { Context, Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" export const makeFormGroup = ( diff --git a/packages/protocol/src/groups/fs.ts b/packages/protocol/src/groups/fs.ts index d9f73b3ca4b6..c5ea87ac414e 100644 --- a/packages/protocol/src/groups/fs.ts +++ b/packages/protocol/src/groups/fs.ts @@ -2,7 +2,7 @@ import { FileSystem } from "@opencode/schema/filesystem" import { Location } from "@opencode/schema/location" import { PositiveInt } from "@opencode/schema/schema" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { FileNotFoundError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/generate.ts b/packages/protocol/src/groups/generate.ts index 6bef53bac02a..a66d5c3c69c1 100644 --- a/packages/protocol/src/groups/generate.ts +++ b/packages/protocol/src/groups/generate.ts @@ -1,6 +1,6 @@ import { Model } from "@opencode/schema/model" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { InvalidRequestError, ServiceUnavailableError } from "../errors.js" export const GenerateGroup = HttpApiGroup.make("server.generate") diff --git a/packages/protocol/src/groups/integration.ts b/packages/protocol/src/groups/integration.ts index 1688ee670175..7c747386e913 100644 --- a/packages/protocol/src/groups/integration.ts +++ b/packages/protocol/src/groups/integration.ts @@ -2,7 +2,7 @@ import { Integration } from "@opencode/schema/integration" import { Location } from "@opencode/schema/location" import { Form } from "@opencode/schema/form" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { IntegrationAttemptNotFoundError, IntegrationMethodNotFoundError, diff --git a/packages/protocol/src/groups/location.ts b/packages/protocol/src/groups/location.ts index ffcce9a4cd2f..37f171d8db05 100644 --- a/packages/protocol/src/groups/location.ts +++ b/packages/protocol/src/groups/location.ts @@ -1,6 +1,6 @@ import { Location } from "@opencode/schema/location" import { Context, Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/http-api" import { ServiceUnavailableError } from "../errors.js" export const LocationQuery = Schema.Struct({ diff --git a/packages/protocol/src/groups/mcp.ts b/packages/protocol/src/groups/mcp.ts index eb17f3632f2a..639466e7244f 100644 --- a/packages/protocol/src/groups/mcp.ts +++ b/packages/protocol/src/groups/mcp.ts @@ -1,7 +1,7 @@ import { Mcp } from "@opencode/schema/mcp" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { McpServerNotFoundError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/message.ts b/packages/protocol/src/groups/message.ts index c744abd880f1..0a2b4c8622d6 100644 --- a/packages/protocol/src/groups/message.ts +++ b/packages/protocol/src/groups/message.ts @@ -2,7 +2,7 @@ import { Session } from "@opencode/schema/session" import { SessionMessage } from "@opencode/schema/session-message" import { Location } from "@opencode/schema/location" import { Schema, Struct } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { InvalidCursorError, SessionNotFoundError, UnknownError } from "../errors.js" export const SessionMessagesQuery = Schema.Struct({ diff --git a/packages/protocol/src/groups/migration.ts b/packages/protocol/src/groups/migration.ts index fb069604b17a..d41db114a7d8 100644 --- a/packages/protocol/src/groups/migration.ts +++ b/packages/protocol/src/groups/migration.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" const V1MigrationProgress = Schema.Struct({ label: Schema.String, diff --git a/packages/protocol/src/groups/model.ts b/packages/protocol/src/groups/model.ts index 4b8ebee3491c..8df7d46fce62 100644 --- a/packages/protocol/src/groups/model.ts +++ b/packages/protocol/src/groups/model.ts @@ -1,7 +1,7 @@ import { Model } from "@opencode/schema/model" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { ServiceUnavailableError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/permission.ts b/packages/protocol/src/groups/permission.ts index b35a71c8f9cb..71cd7d535140 100644 --- a/packages/protocol/src/groups/permission.ts +++ b/packages/protocol/src/groups/permission.ts @@ -5,7 +5,7 @@ import { PermissionSaved } from "@opencode/schema/permission-saved" import { Project } from "@opencode/schema/project" import { Session } from "@opencode/schema/session" import { Context, Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/http-api" import { PermissionNotFoundError, SessionNotFoundError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/persistent-pty.ts b/packages/protocol/src/groups/persistent-pty.ts index dd1abbe9d1a4..9974318772e6 100644 --- a/packages/protocol/src/groups/persistent-pty.ts +++ b/packages/protocol/src/groups/persistent-pty.ts @@ -3,7 +3,7 @@ import { Pty } from "@opencode/schema/pty" import { PtyTicket } from "@opencode/schema/pty-ticket" import { Session } from "@opencode/schema/session" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { ForbiddenError, InvalidRequestError, PtyNotFoundError, ServiceUnavailableError } from "../errors.js" import { PTY_CONNECT_TICKET_QUERY, PTY_CONNECT_TOKEN_HEADER, PTY_CONNECT_TOKEN_HEADER_VALUE } from "./pty.js" diff --git a/packages/protocol/src/groups/plugin.ts b/packages/protocol/src/groups/plugin.ts index 24409d72233c..8e756e8fe467 100644 --- a/packages/protocol/src/groups/plugin.ts +++ b/packages/protocol/src/groups/plugin.ts @@ -1,7 +1,7 @@ import { Location } from "@opencode/schema/location" import { Plugin } from "@opencode/schema/plugin" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { InvalidRequestError, ServiceUnavailableError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/project.ts b/packages/protocol/src/groups/project.ts index 13fd20cb47f3..f7aae9cf3673 100644 --- a/packages/protocol/src/groups/project.ts +++ b/packages/protocol/src/groups/project.ts @@ -1,6 +1,6 @@ import { Project } from "@opencode/schema/project" import { Schema, Struct } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { ProjectNotFoundError } from "../errors.js" const root = "/api/project" diff --git a/packages/protocol/src/groups/provider.ts b/packages/protocol/src/groups/provider.ts index 77e8fdb3fe70..e5b6b39f242d 100644 --- a/packages/protocol/src/groups/provider.ts +++ b/packages/protocol/src/groups/provider.ts @@ -1,7 +1,7 @@ import { Provider } from "@opencode/schema/provider" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { ProviderNotFoundError, ServiceUnavailableError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/pty.ts b/packages/protocol/src/groups/pty.ts index 00efe91a9392..cfe782a39324 100644 --- a/packages/protocol/src/groups/pty.ts +++ b/packages/protocol/src/groups/pty.ts @@ -2,7 +2,7 @@ import { Pty } from "@opencode/schema/pty" import { PtyTicket } from "@opencode/schema/pty-ticket" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { ForbiddenError, PtyNotFoundError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/reference.ts b/packages/protocol/src/groups/reference.ts index c1f727ff6555..6935a75b84c1 100644 --- a/packages/protocol/src/groups/reference.ts +++ b/packages/protocol/src/groups/reference.ts @@ -1,7 +1,7 @@ import { Location } from "@opencode/schema/location" import { Reference } from "@opencode/schema/reference" import { Schema, Struct } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" const PublicLocalSource = Schema.Struct(Struct.omit(Reference.LocalSource.fields, ["description", "hidden"])).annotate({ diff --git a/packages/protocol/src/groups/rpc.ts b/packages/protocol/src/groups/rpc.ts index ab533c17104a..175229a7f063 100644 --- a/packages/protocol/src/groups/rpc.ts +++ b/packages/protocol/src/groups/rpc.ts @@ -1,6 +1,6 @@ import { optional } from "@opencode/schema/schema" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { RpcError, RpcInternalError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/server.ts b/packages/protocol/src/groups/server.ts index c0113598fd9a..261da97d6f2f 100644 --- a/packages/protocol/src/groups/server.ts +++ b/packages/protocol/src/groups/server.ts @@ -1,5 +1,5 @@ import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { UnauthorizedError } from "../errors.js" export const ServerInfo = Schema.Struct({ diff --git a/packages/protocol/src/groups/session.ts b/packages/protocol/src/groups/session.ts index 32e4a9fdee05..d0645b464f63 100644 --- a/packages/protocol/src/groups/session.ts +++ b/packages/protocol/src/groups/session.ts @@ -14,8 +14,9 @@ import { statics, } from "@opencode/schema/schema" import { Event } from "@opencode/schema/event" -import { Context, Effect, Encoding, Result, Schema, SchemaGetter, Struct } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { Context, Effect, Result, Schema, SchemaGetter, Struct } from "effect" +import { Base64Url } from "effect/encoding" +import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/http-api" import { ConflictError, CommandExecutionError, @@ -97,13 +98,14 @@ const invalidCursor = "Invalid cursor" as const export const SessionsCursor = Schema.String.pipe( Schema.brand("SessionsCursor"), + Schema.annotate({ identifier: "SessionsCursor" }), statics((schema) => { const make = schema.make.bind(schema) return { - make: (input: typeof SessionsCursorInput.Type) => make(Encoding.encodeBase64Url(encodeSessionsCursor(input))), + make: (input: typeof SessionsCursorInput.Type) => make(Base64Url.encode(encodeSessionsCursor(input))), parse: (input: string) => Effect.suspend(() => { - const result = Encoding.decodeBase64UrlString(input) + const result = Base64Url.decodeString(input) return Result.isFailure(result) ? Effect.fail(invalidCursor) : decodeSessionsCursor(result.success).pipe(Effect.mapError(() => invalidCursor)) @@ -158,7 +160,7 @@ const BooleanFromString = Schema.Literals(["true", "false"]).pipe( }), ) -const SessionsQueryCursor = SessionsCursor.annotate({ +const SessionsQueryCursor = Schema.String.annotate({ description: "Opaque pagination cursor returned as cursor.previous or cursor.next in the previous response.", }) @@ -170,12 +172,10 @@ export const SessionsQuery = Schema.Struct({ cursor: SessionsQueryCursor.pipe(Schema.optional), }).annotate({ identifier: "SessionsQuery" }) -export const makeSessionGroup = < - I extends HttpApiMiddleware.AnyId, - S, - FormI extends HttpApiMiddleware.AnyId, - FormS, ->(sessionLocationMiddleware: Context.Key, formLocationMiddleware: Context.Key) => +export const makeSessionGroup = ( + sessionLocationMiddleware: Context.Key, + formLocationMiddleware: Context.Key, +) => HttpApiGroup.make("server.session") .add( HttpApiEndpoint.get("session.list", "/api/session", { @@ -562,9 +562,7 @@ export const makeSessionGroup = < error: [SessionNotFoundError, SessionBusyError], }) .middleware(sessionLocationMiddleware) - .annotateMerge( - OpenApi.annotations({ identifier: "session.revert.commit", summary: "Commit staged revert" }), - ), + .annotateMerge(OpenApi.annotations({ identifier: "session.revert.commit", summary: "Commit staged revert" })), ) .add( HttpApiEndpoint.get("session.context", "/api/session/:sessionID/context", { diff --git a/packages/protocol/src/groups/shell.ts b/packages/protocol/src/groups/shell.ts index ab908f4c8264..f8948caae937 100644 --- a/packages/protocol/src/groups/shell.ts +++ b/packages/protocol/src/groups/shell.ts @@ -1,7 +1,7 @@ import { Shell } from "@opencode/schema/shell" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { ShellNotFoundError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/skill.ts b/packages/protocol/src/groups/skill.ts index 103e52515f44..b01bf265d4d4 100644 --- a/packages/protocol/src/groups/skill.ts +++ b/packages/protocol/src/groups/skill.ts @@ -1,7 +1,7 @@ import { Skill } from "@opencode/schema/skill" import { Location } from "@opencode/schema/location" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" export const SkillGroup = HttpApiGroup.make("server.skill") diff --git a/packages/protocol/src/groups/vcs.ts b/packages/protocol/src/groups/vcs.ts index f2f4062baf7b..5fb871d54212 100644 --- a/packages/protocol/src/groups/vcs.ts +++ b/packages/protocol/src/groups/vcs.ts @@ -3,7 +3,7 @@ import { Location } from "@opencode/schema/location" import { NonNegativeInt, PositiveInt, optional } from "@opencode/schema/schema" import { Vcs } from "@opencode/schema/vcs" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { LocationQuery, locationQueryOpenApi } from "./location.js" import { ServiceUnavailableError } from "../errors.js" diff --git a/packages/protocol/src/groups/websearch.ts b/packages/protocol/src/groups/websearch.ts index 8a333898de08..7218d67364d8 100644 --- a/packages/protocol/src/groups/websearch.ts +++ b/packages/protocol/src/groups/websearch.ts @@ -1,7 +1,7 @@ import { Location } from "@opencode/schema/location" import { WebSearch } from "@opencode/schema/websearch" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api" import { InvalidRequestError, ServiceUnavailableError } from "../errors.js" import { LocationQuery, locationQueryOpenApi } from "./location.js" diff --git a/packages/protocol/src/groups/worktree.ts b/packages/protocol/src/groups/worktree.ts index dd3b41cd6b5a..7ff76e2d1d3e 100644 --- a/packages/protocol/src/groups/worktree.ts +++ b/packages/protocol/src/groups/worktree.ts @@ -1,6 +1,6 @@ import { Worktree } from "@opencode/schema/worktree" import { Schema } from "effect" -import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/unstable/httpapi" +import { HttpApiEndpoint, HttpApiGroup, HttpApiSchema, OpenApi } from "effect/http-api" import { Project } from "@opencode/schema/project" import { ProjectNotFoundError } from "../errors.js" diff --git a/packages/protocol/src/middleware/authorization.ts b/packages/protocol/src/middleware/authorization.ts index 54d33bc26ee2..57bbf8434ccd 100644 --- a/packages/protocol/src/middleware/authorization.ts +++ b/packages/protocol/src/middleware/authorization.ts @@ -1,4 +1,4 @@ -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpApiMiddleware } from "effect/http-api" import { UnauthorizedError } from "../errors.js" export class Authorization extends HttpApiMiddleware.Service()("@opencode/HttpApiAuthorization", { diff --git a/packages/protocol/src/middleware/schema-error.ts b/packages/protocol/src/middleware/schema-error.ts index a4c36d5b8c05..d8d917930ae5 100644 --- a/packages/protocol/src/middleware/schema-error.ts +++ b/packages/protocol/src/middleware/schema-error.ts @@ -1,4 +1,4 @@ -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpApiMiddleware } from "effect/http-api" import { InvalidRequestError } from "../errors.js" export class SchemaErrorMiddleware extends HttpApiMiddleware.Service()( diff --git a/packages/protocol/src/simulation.ts b/packages/protocol/src/simulation.ts index 38c9fde40fa0..ad94fc8e4275 100644 --- a/packages/protocol/src/simulation.ts +++ b/packages/protocol/src/simulation.ts @@ -1,5 +1,5 @@ import { Effect, Schema } from "effect" -import { Rpc, RpcGroup } from "effect/unstable/rpc" +import { Rpc, RpcGroup } from "effect/rpc" const JsonRpcID = Schema.Union([Schema.String, Schema.Number, Schema.Null]) const decodeJson = Schema.decodeUnknownSync(Schema.Json) diff --git a/packages/schema/src/agent.ts b/packages/schema/src/agent.ts index 422be62da6bc..2f3f374e00aa 100644 --- a/packages/schema/src/agent.ts +++ b/packages/schema/src/agent.ts @@ -10,10 +10,10 @@ import { PositiveInt, statics } from "./schema.js" const Updated = ephemeral({ type: "agent.updated", schema: {} }) -export const ID = Schema.String.pipe(Schema.brand("Agent.ID")) +export const ID = Schema.String.pipe(Schema.brand("Agent.ID"), Schema.annotate({ identifier: "Agent.ID" })) export type ID = typeof ID.Type -export const Name = Schema.String.pipe(Schema.brand("Agent.Name")) +export const Name = Schema.String.pipe(Schema.brand("Agent.Name"), Schema.annotate({ identifier: "Agent.Name" })) export type Name = typeof Name.Type export const Color = Schema.String.annotate({ identifier: "Agent.Color" }) diff --git a/packages/schema/src/credential.ts b/packages/schema/src/credential.ts index 408ca68e8ac0..d0cb6c4cb346 100644 --- a/packages/schema/src/credential.ts +++ b/packages/schema/src/credential.ts @@ -10,6 +10,7 @@ import { Form } from "./form.js" export const ID = Schema.String.pipe( Schema.brand("Credential.ID"), + Schema.annotate({ identifier: "Credential.ID" }), statics((schema) => ({ create: () => schema.make("cred_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/event.ts b/packages/schema/src/event.ts index db0c8c557357..47b68dd4f258 100644 --- a/packages/schema/src/event.ts +++ b/packages/schema/src/event.ts @@ -6,8 +6,9 @@ import { ascending } from "./identifier.js" import { Location } from "./location.js" import { statics } from "./schema.js" -export const ID = Schema.String.check(Schema.isStartsWith("evt_")).pipe( +export const ID = Schema.String.check(Schema.isStartingWith("evt_")).pipe( Schema.brand("Event.ID"), + Schema.annotate({ identifier: "Event.ID" }), statics((schema) => ({ create: () => schema.make("evt_" + ascending()) })), ) export type ID = typeof ID.Type @@ -17,11 +18,17 @@ export type ID = typeof ID.Type * event envelope and synced markers; * `after` cursors accept only values that came from those sources. */ -export const Seq = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)).pipe(Schema.brand("Event.Seq")) +export const Seq = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)).pipe( + Schema.brand("Event.Seq"), + Schema.annotate({ identifier: "Event.Seq" }), +) export type Seq = typeof Seq.Type /** Durable schema version of one event type, from the event definition that committed it. */ -export const Version = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)).pipe(Schema.brand("Event.Version")) +export const Version = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)).pipe( + Schema.brand("Event.Version"), + Schema.annotate({ identifier: "Event.Version" }), +) export type Version = typeof Version.Type const DurableEnvelope = Schema.Struct({ aggregateID: Schema.String, seq: Seq, version: Version }) diff --git a/packages/schema/src/form.ts b/packages/schema/src/form.ts index adbf14a9b65e..7873dae66993 100644 --- a/packages/schema/src/form.ts +++ b/packages/schema/src/form.ts @@ -5,7 +5,10 @@ import { ephemeral, inventory } from "./event.js" import { ascending } from "./identifier.js" import { NonNegativeInt, optional, statics } from "./schema.js" -const IDSchema = Schema.String.check(Schema.isStartsWith("frm_")).pipe(Schema.brand("Form.ID")) +const IDSchema = Schema.String.check(Schema.isStartingWith("frm_")).pipe( + Schema.brand("Form.ID"), + Schema.annotate({ identifier: "Form.ID" }), +) export const ID = IDSchema.pipe( statics((schema: typeof IDSchema) => ({ create: (id?: string) => schema.make(id ?? "frm_" + ascending()) })), diff --git a/packages/schema/src/instruction.ts b/packages/schema/src/instruction.ts index a2c1e93a1c9d..4712543a49df 100644 --- a/packages/schema/src/instruction.ts +++ b/packages/schema/src/instruction.ts @@ -4,10 +4,14 @@ import { Schema } from "effect" export const Key = Schema.String.check(Schema.isPattern(/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._/-]*$/)).pipe( Schema.brand("Instruction.Key"), + Schema.annotate({ identifier: "Instruction.Key" }), ) export type Key = typeof Key.Type -export const Hash = Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/)).pipe(Schema.brand("Instruction.Hash")) +export const Hash = Schema.String.check(Schema.isPattern(/^[a-f0-9]{64}$/)).pipe( + Schema.brand("Instruction.Hash"), + Schema.annotate({ identifier: "Instruction.Hash" }), +) export type Hash = typeof Hash.Type export const Values = Schema.Record(Key, Hash) diff --git a/packages/schema/src/integration-id.ts b/packages/schema/src/integration-id.ts index 2590dfe9f691..b936c1c51b76 100644 --- a/packages/schema/src/integration-id.ts +++ b/packages/schema/src/integration-id.ts @@ -1,7 +1,13 @@ import { Schema } from "effect" -export const IntegrationID = Schema.String.pipe(Schema.brand("Integration.ID")) +export const IntegrationID = Schema.String.pipe( + Schema.brand("Integration.ID"), + Schema.annotate({ identifier: "Integration.ID" }), +) export type IntegrationID = typeof IntegrationID.Type -export const IntegrationMethodID = Schema.String.pipe(Schema.brand("Integration.MethodID")) +export const IntegrationMethodID = Schema.String.pipe( + Schema.brand("Integration.MethodID"), + Schema.annotate({ identifier: "Integration.MethodID" }), +) export type IntegrationMethodID = typeof IntegrationMethodID.Type diff --git a/packages/schema/src/integration.ts b/packages/schema/src/integration.ts index 299dc7718ddd..093e4c6c2396 100644 --- a/packages/schema/src/integration.ts +++ b/packages/schema/src/integration.ts @@ -73,6 +73,7 @@ export interface Info extends Schema.Schema.Type {} export const AttemptID = Schema.String.pipe( Schema.brand("Integration.AttemptID"), + Schema.annotate({ identifier: "Integration.AttemptID" }), statics((schema) => ({ create: () => schema.make("con_" + ascending()) })), ) export type AttemptID = typeof AttemptID.Type diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index b52018f9271b..83d4887c379a 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -6,13 +6,16 @@ import { Provider } from "./provider.js" import { Money } from "./money.js" import { ephemeral, inventory } from "./event.js" -export const ID = Schema.String.pipe(Schema.brand("Model.ID")) +export const ID = Schema.String.pipe(Schema.brand("Model.ID"), Schema.annotate({ identifier: "Model.ID" })) export type ID = typeof ID.Type const Updated = ephemeral({ type: "model.updated", schema: {} }) export const Event = { Updated, Definitions: inventory(Updated) } -export const VariantID = Schema.String.pipe(Schema.brand("Model.VariantID")) +export const VariantID = Schema.String.pipe( + Schema.brand("Model.VariantID"), + Schema.annotate({ identifier: "Model.VariantID" }), +) export type VariantID = typeof VariantID.Type export const Ref = Schema.Struct({ @@ -42,7 +45,7 @@ export const Ref = Schema.Struct({ ) export interface Ref extends Schema.Schema.Type {} -export const Family = Schema.String.pipe(Schema.brand("Model.Family")) +export const Family = Schema.String.pipe(Schema.brand("Model.Family"), Schema.annotate({ identifier: "Model.Family" })) export type Family = typeof Family.Type export type ReasoningField = "reasoning" | "reasoning_content" | "reasoning_text" | (string & {}) diff --git a/packages/schema/src/permission-saved.ts b/packages/schema/src/permission-saved.ts index 301036e0c579..29a31d0ca4b5 100644 --- a/packages/schema/src/permission-saved.ts +++ b/packages/schema/src/permission-saved.ts @@ -7,6 +7,7 @@ import { DateTimeUtcFromMillis, statics } from "./schema.js" export const ID = Schema.String.pipe( Schema.brand("PermissionSaved.ID"), + Schema.annotate({ identifier: "PermissionSaved.ID" }), statics((schema) => ({ create: () => schema.make("psv_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/permission.ts b/packages/schema/src/permission.ts index e978c9463292..41887ed9ea64 100644 --- a/packages/schema/src/permission.ts +++ b/packages/schema/src/permission.ts @@ -7,8 +7,9 @@ import { ascending } from "./identifier.js" import { SessionID } from "./session-id.js" import { statics } from "./schema.js" -export const ID = Schema.String.check(Schema.isStartsWith("per")).pipe( +export const ID = Schema.String.check(Schema.isStartingWith("per")).pipe( Schema.brand("Permission.ID"), + Schema.annotate({ identifier: "Permission.ID" }), statics((schema) => ({ create: (id?: string) => schema.make(id ?? "per_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/plugin.ts b/packages/schema/src/plugin.ts index 7087dfc17a6a..aca4560ebe5f 100644 --- a/packages/schema/src/plugin.ts +++ b/packages/schema/src/plugin.ts @@ -4,7 +4,7 @@ import { Schema } from "effect" import { ephemeral, inventory } from "./event.js" import { optional } from "./schema.js" -export const ID = Schema.String.pipe(Schema.brand("Plugin.ID")) +export const ID = Schema.String.pipe(Schema.brand("Plugin.ID"), Schema.annotate({ identifier: "Plugin.ID" })) export type ID = typeof ID.Type export const Source = Schema.Union([ diff --git a/packages/schema/src/project-id.ts b/packages/schema/src/project-id.ts index 8114d35e0e1f..8b04323b05c2 100644 --- a/packages/schema/src/project-id.ts +++ b/packages/schema/src/project-id.ts @@ -3,6 +3,7 @@ import { statics } from "./schema.js" export const ProjectID = Schema.String.pipe( Schema.brand("Project.ID"), + Schema.annotate({ identifier: "Project.ID" }), statics((schema) => ({ global: schema.make("global") })), ) export type ProjectID = typeof ProjectID.Type diff --git a/packages/schema/src/provider.ts b/packages/schema/src/provider.ts index a8493801d9be..bda65c1220a7 100644 --- a/packages/schema/src/provider.ts +++ b/packages/schema/src/provider.ts @@ -7,6 +7,7 @@ import { ephemeral, inventory } from "./event.js" export const ID = Schema.String.pipe( Schema.brand("Provider.ID"), + Schema.annotate({ identifier: "Provider.ID" }), statics((schema) => ({ opencode: schema.make("opencode"), anthropic: schema.make("anthropic"), diff --git a/packages/schema/src/pty.ts b/packages/schema/src/pty.ts index b2da9093f0fb..3d8f0be5ebaa 100644 --- a/packages/schema/src/pty.ts +++ b/packages/schema/src/pty.ts @@ -6,7 +6,10 @@ import { ephemeral, inventory } from "./event.js" import { ascending } from "./identifier.js" import { NonNegativeInt, PositiveInt, statics } from "./schema.js" -const IDSchema = Schema.String.check(Schema.isStartsWith("pty")).pipe(Schema.brand("PtyID")) +const IDSchema = Schema.String.check(Schema.isStartingWith("pty")).pipe( + Schema.brand("PtyID"), + Schema.annotate({ identifier: "PtyID" }), +) export const ID = IDSchema.pipe( statics((schema: typeof IDSchema) => { diff --git a/packages/schema/src/schema.ts b/packages/schema/src/schema.ts index d19a39b9708c..487b7d135770 100644 --- a/packages/schema/src/schema.ts +++ b/packages/schema/src/schema.ts @@ -3,10 +3,16 @@ import { DateTime, Option, Schema, SchemaGetter } from "effect" export const PositiveInt = Schema.Int.check(Schema.isGreaterThan(0)) export const NonNegativeInt = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)) -export const RelativePath = Schema.String.pipe(Schema.brand("RelativePath")) +export const RelativePath = Schema.String.pipe( + Schema.brand("RelativePath"), + Schema.annotate({ identifier: "RelativePath" }), +) export type RelativePath = typeof RelativePath.Type -export const AbsolutePath = Schema.String.pipe(Schema.brand("AbsolutePath")) +export const AbsolutePath = Schema.String.pipe( + Schema.brand("AbsolutePath"), + Schema.annotate({ identifier: "AbsolutePath" }), +) export type AbsolutePath = typeof AbsolutePath.Type export const optional = (schema: S) => @@ -17,10 +23,15 @@ export const optional = (schema: S) => }), ) +// Effect 4 caches `make` and other schema methods as non-configurable own properties on first access. +// Keep the original schema as a prototype so domain constructors can shadow those methods safely. +export const extendSchema = >(schema: S, methods: M): S & M => + Object.defineProperties(Object.create(schema) as S, Object.getOwnPropertyDescriptors(methods)) as S & M + export const statics = >(methods: (schema: S) => M) => (schema: S): S & M => - Object.assign(schema, methods(schema)) + extendSchema(schema, methods(schema)) export const DateTimeUtcFromMillis = Schema.Finite.pipe( Schema.decodeTo(Schema.DateTimeUtc, { diff --git a/packages/schema/src/session-id.ts b/packages/schema/src/session-id.ts index ba0b48ce7ef5..75c3deba6f70 100644 --- a/packages/schema/src/session-id.ts +++ b/packages/schema/src/session-id.ts @@ -2,8 +2,9 @@ import { Schema } from "effect" import { descending } from "./identifier.js" import { statics } from "./schema.js" -export const SessionID = Schema.String.check(Schema.isStartsWith("ses")).pipe( +export const SessionID = Schema.String.check(Schema.isStartingWith("ses")).pipe( Schema.brand("SessionID"), + Schema.annotate({ identifier: "SessionID" }), statics((schema) => { const create = () => schema.make("ses_" + descending()) return { diff --git a/packages/schema/src/session-message.ts b/packages/schema/src/session-message.ts index 55ef745584dd..a77494a8ae00 100644 --- a/packages/schema/src/session-message.ts +++ b/packages/schema/src/session-message.ts @@ -20,8 +20,9 @@ import { Money } from "./money.js" import { Snapshot } from "./snapshot.js" import { TokenUsage } from "./token-usage.js" -export const ID = Schema.String.check(Schema.isStartsWith("msg_")).pipe( +export const ID = Schema.String.check(Schema.isStartingWith("msg_")).pipe( Schema.brand("Session.Message.ID"), + Schema.annotate({ identifier: "Session.Message.ID" }), statics((schema) => ({ create: () => schema.make("msg_" + ascending()), fromEvent: (eventID: Event.ID) => schema.make(eventID.replace(/^evt_/, "msg_")), diff --git a/packages/schema/src/shell.ts b/packages/schema/src/shell.ts index 251a61417b11..c260091a6ff1 100644 --- a/packages/schema/src/shell.ts +++ b/packages/schema/src/shell.ts @@ -6,7 +6,10 @@ import { ephemeral, inventory } from "./event.js" import { ascending } from "./identifier.js" import { NonNegativeInt, statics } from "./schema.js" -const IDSchema = Schema.String.check(Schema.isStartsWith("sh_")).pipe(Schema.brand("Shell.ID")) +const IDSchema = Schema.String.check(Schema.isStartingWith("sh_")).pipe( + Schema.brand("Shell.ID"), + Schema.annotate({ identifier: "Shell.ID" }), +) export const ID = IDSchema.pipe( statics((schema: typeof IDSchema) => { diff --git a/packages/schema/src/skill.ts b/packages/schema/src/skill.ts index 6059476b1332..12494e2fd685 100644 --- a/packages/schema/src/skill.ts +++ b/packages/schema/src/skill.ts @@ -1,14 +1,14 @@ export * as Skill from "./skill.js" import { Schema } from "effect" -import { optional } from "./schema.js" +import { extendSchema, optional } from "./schema.js" import { AbsolutePath } from "./schema.js" import { ephemeral, inventory } from "./event.js" -export const ID = Schema.String.pipe(Schema.brand("Skill.ID")) +export const ID = Schema.String.pipe(Schema.brand("Skill.ID"), Schema.annotate({ identifier: "Skill.ID" })) export type ID = typeof ID.Type -export const Name = Schema.String.pipe(Schema.brand("Skill.Name")) +export const Name = Schema.String.pipe(Schema.brand("Skill.Name"), Schema.annotate({ identifier: "Skill.Name" })) export type Name = typeof Name.Type export interface DirectorySource extends Schema.Schema.Type {} @@ -43,7 +43,7 @@ export const EmbeddedSource = Schema.Struct({ }).annotate({ identifier: "Skill.EmbeddedSource" }) export type Source = DirectorySource | UrlSource | EmbeddedSource -export const Source = Object.assign( +export const Source = extendSchema( Schema.Union([DirectorySource, UrlSource, EmbeddedSource]).pipe( Schema.toTaggedUnion("type"), Schema.annotate({ identifier: "Skill.Source" }), diff --git a/packages/schema/src/snapshot.ts b/packages/schema/src/snapshot.ts index 375981b41590..83ccfd5ae3ea 100644 --- a/packages/schema/src/snapshot.ts +++ b/packages/schema/src/snapshot.ts @@ -2,5 +2,5 @@ export * as Snapshot from "./snapshot.js" import { Schema } from "effect" -export const ID = Schema.String.pipe(Schema.brand("Snapshot.ID")) +export const ID = Schema.String.pipe(Schema.brand("Snapshot.ID"), Schema.annotate({ identifier: "Snapshot.ID" })) export type ID = typeof ID.Type diff --git a/packages/schema/src/tool.ts b/packages/schema/src/tool.ts index 06dec1c0c57c..799fcf00331d 100644 --- a/packages/schema/src/tool.ts +++ b/packages/schema/src/tool.ts @@ -8,7 +8,7 @@ import type { SessionMessage } from "./session-message.js" export type Metadata = Readonly> -export const CallID = Schema.String.pipe(Schema.brand("Tool.CallID")) +export const CallID = Schema.String.pipe(Schema.brand("Tool.CallID"), Schema.annotate({ identifier: "Tool.CallID" })) export type CallID = typeof CallID.Type export interface Context { diff --git a/packages/schema/src/v1/permission.ts b/packages/schema/src/v1/permission.ts index c7d2e71b3da0..332ba17cce80 100644 --- a/packages/schema/src/v1/permission.ts +++ b/packages/schema/src/v1/permission.ts @@ -7,8 +7,9 @@ import { Project } from "../project.js" import { statics } from "../schema.js" import { SessionID } from "../session-id.js" -export const ID = Schema.String.check(Schema.isStartsWith("per")).pipe( +export const ID = Schema.String.check(Schema.isStartingWith("per")).pipe( Schema.brand("PermissionV1.ID"), + Schema.annotate({ identifier: "PermissionV1.ID" }), statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "per_" + ascending()) })), ) export type ID = typeof ID.Type diff --git a/packages/schema/src/v1/question.ts b/packages/schema/src/v1/question.ts index dfd6dc8ee217..bf2f12747cd0 100644 --- a/packages/schema/src/v1/question.ts +++ b/packages/schema/src/v1/question.ts @@ -7,8 +7,9 @@ import { statics } from "../schema.js" import { SessionID } from "../session-id.js" import { SessionV1 } from "./session.js" -export const ID = Schema.String.check(Schema.isStartsWith("que")).pipe( +export const ID = Schema.String.check(Schema.isStartingWith("que")).pipe( Schema.brand("QuestionV1.ID"), + Schema.annotate({ identifier: "QuestionV1.ID" }), statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "que_" + ascending()) })), ) diff --git a/packages/schema/src/v1/session.ts b/packages/schema/src/v1/session.ts index 293c68c96dac..b141e1932973 100644 --- a/packages/schema/src/v1/session.ts +++ b/packages/schema/src/v1/session.ts @@ -14,14 +14,16 @@ import { FileDiff } from "../file-diff.js" const Timestamp = Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0)) -export const MessageID = Schema.String.check(Schema.isStartsWith("msg")).pipe( +export const MessageID = Schema.String.check(Schema.isStartingWith("msg")).pipe( Schema.brand("SessionV1.MessageID"), + Schema.annotate({ identifier: "SessionV1.MessageID" }), statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "msg_" + ascending()) })), ) export type MessageID = typeof MessageID.Type -export const PartID = Schema.String.check(Schema.isStartsWith("prt")).pipe( +export const PartID = Schema.String.check(Schema.isStartingWith("prt")).pipe( Schema.brand("SessionV1.PartID"), + Schema.annotate({ identifier: "SessionV1.PartID" }), statics((schema) => ({ ascending: (id?: string) => schema.make(id ?? "prt_" + ascending()) })), ) export type PartID = typeof PartID.Type diff --git a/packages/schema/src/websearch.ts b/packages/schema/src/websearch.ts index 36c957f224f0..35c447b26fd5 100644 --- a/packages/schema/src/websearch.ts +++ b/packages/schema/src/websearch.ts @@ -4,7 +4,7 @@ import { Schema } from "effect" import { ephemeral, inventory } from "./event.js" import { optional } from "./schema.js" -export const ID = Schema.String.pipe(Schema.brand("WebSearch.ID")) +export const ID = Schema.String.pipe(Schema.brand("WebSearch.ID"), Schema.annotate({ identifier: "WebSearch.ID" })) export type ID = typeof ID.Type export interface Provider extends Schema.Schema.Type {} diff --git a/packages/schema/src/workspace-id.ts b/packages/schema/src/workspace-id.ts index ad2ed5a71291..e930e5df391c 100644 --- a/packages/schema/src/workspace-id.ts +++ b/packages/schema/src/workspace-id.ts @@ -2,8 +2,9 @@ import { Schema } from "effect" import { ascending } from "./identifier.js" import { statics } from "./schema.js" -export const WorkspaceID = Schema.String.check(Schema.isStartsWith("wrk")).pipe( +export const WorkspaceID = Schema.String.check(Schema.isStartingWith("wrk")).pipe( Schema.brand("Workspace.ID"), + Schema.annotate({ identifier: "Workspace.ID" }), statics((schema) => { const create = () => schema.make("wrk_" + ascending()) return { diff --git a/packages/schema/src/worktree.ts b/packages/schema/src/worktree.ts index 97f542cdcdc7..8391630a8cd6 100644 --- a/packages/schema/src/worktree.ts +++ b/packages/schema/src/worktree.ts @@ -5,7 +5,11 @@ import { durable, ephemeral, inventory } from "./event.js" import { AbsolutePath, optional } from "./schema.js" import { Project } from "./project.js" -export const StrategyID = Schema.Trim.pipe(Schema.check(Schema.isNonEmpty()), Schema.brand("Worktree.StrategyID")) +export const StrategyID = Schema.Trim.pipe( + Schema.check(Schema.isNonEmpty()), + Schema.brand("Worktree.StrategyID"), + Schema.annotate({ identifier: "Worktree.StrategyID" }), +) export type StrategyID = typeof StrategyID.Type export const CreateInput = Schema.Struct({ diff --git a/packages/sdk/src/effect/opencode.ts b/packages/sdk/src/effect/opencode.ts index f4c88089132e..4787d8fbec74 100644 --- a/packages/sdk/src/effect/opencode.ts +++ b/packages/sdk/src/effect/opencode.ts @@ -5,7 +5,7 @@ import type { Session } from "@opencode/core/session" import type { Workspace } from "@opencode/core/workspace" import { Context, Effect, Layer } from "effect" import type { Config, Scope } from "effect" -import { FetchHttpClient, HttpClient } from "effect/unstable/http" +import { FetchHttpClient, HttpClient } from "effect/http" import { EmbeddedHost } from "../internal/host" import type { SdkInstances } from "../internal/instances" diff --git a/packages/sdk/src/internal/host.ts b/packages/sdk/src/internal/host.ts index 5e1dd60404a7..3c354ae6653e 100644 --- a/packages/sdk/src/internal/host.ts +++ b/packages/sdk/src/internal/host.ts @@ -9,7 +9,7 @@ import { createEmbeddedRoutes } from "@opencode/server/routes" import type { ServerOptions } from "@opencode/server/options" import type { LayerNode } from "@opencode/util/effect/layer-node" import { Context, Effect, Layer, ManagedRuntime, Scope } from "effect" -import { HttpEffect, HttpRouter, HttpServer, HttpServerRequest } from "effect/unstable/http" +import { HttpEffect, HttpRouter, HttpServer, HttpServerRequest } from "effect/http" import { context, layer, type LogOptions } from "../logging" import { OwnedFetch } from "./fetch" import { SdkInstances } from "./instances" diff --git a/packages/sdk/test/transport.test.ts b/packages/sdk/test/transport.test.ts index 2da7f7dac4a1..f7243d0deccb 100644 --- a/packages/sdk/test/transport.test.ts +++ b/packages/sdk/test/transport.test.ts @@ -1,6 +1,6 @@ import { expect } from "bun:test" import { Context, Effect, Exit, Layer, Scope, Stream } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" import { tmpdirScoped } from "../../core/test/fixture/tmpdir" import { testEffect } from "../../core/test/lib/effect" import { AbsolutePath, Location, OpenCode, Session } from "../src/effect" diff --git a/packages/server/src/fetch.ts b/packages/server/src/fetch.ts index 88a52634897b..e6aba4da568e 100644 --- a/packages/server/src/fetch.ts +++ b/packages/server/src/fetch.ts @@ -1,7 +1,7 @@ export * as ServerFetch from "./fetch" import { Context, Effect, Layer } from "effect" -import { HttpEffect, HttpMiddleware, HttpRouter, HttpServer } from "effect/unstable/http" +import { HttpEffect, HttpMiddleware, HttpRouter, HttpServer } from "effect/http" import { SessionRestart } from "@opencode/core/session/execution/restart" import type { LayerNode } from "@opencode/util/effect/layer-node" import { isAllowedCorsOrigin } from "./cors" diff --git a/packages/server/src/handlers/agent.ts b/packages/server/src/handlers/agent.ts index 713cf3f62626..f54148af2266 100644 --- a/packages/server/src/handlers/agent.ts +++ b/packages/server/src/handlers/agent.ts @@ -1,6 +1,6 @@ import { Agent } from "@opencode/core/agent" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" import { AgentNotFoundError } from "@opencode/protocol/errors" diff --git a/packages/server/src/handlers/command.ts b/packages/server/src/handlers/command.ts index bf289721bc8b..c540478fa51b 100644 --- a/packages/server/src/handlers/command.ts +++ b/packages/server/src/handlers/command.ts @@ -1,5 +1,5 @@ import { Command } from "@opencode/core/command" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/config.ts b/packages/server/src/handlers/config.ts index 4a22939dba26..9713b10a5201 100644 --- a/packages/server/src/handlers/config.ts +++ b/packages/server/src/handlers/config.ts @@ -1,7 +1,7 @@ import { Config } from "@opencode/core/config" import { ShellSelect } from "@opencode/core/shell/select" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" export const ConfigHandler = HttpApiBuilder.group(Api, "server.config", (handlers) => diff --git a/packages/server/src/handlers/credential.ts b/packages/server/src/handlers/credential.ts index a2cf71581812..4f6f31a9c0cb 100644 --- a/packages/server/src/handlers/credential.ts +++ b/packages/server/src/handlers/credential.ts @@ -1,7 +1,7 @@ import { Credential } from "@opencode/core/credential" import { ConflictError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { Api } from "../api" export const CredentialHandler = HttpApiBuilder.group(Api, "server.credential", (handlers) => diff --git a/packages/server/src/handlers/debug.ts b/packages/server/src/handlers/debug.ts index dd5b83762f60..bb875b170816 100644 --- a/packages/server/src/handlers/debug.ts +++ b/packages/server/src/handlers/debug.ts @@ -1,6 +1,6 @@ import { LocationServiceMap } from "@opencode/core/location-service-map" import { Effect, Option, RcMap } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { requestRef } from "../location" diff --git a/packages/server/src/handlers/event.ts b/packages/server/src/handlers/event.ts index af1d26b5e41d..81fc8ae8360d 100644 --- a/packages/server/src/handlers/event.ts +++ b/packages/server/src/handlers/event.ts @@ -1,8 +1,8 @@ import { Bus } from "@opencode/core/bus" import { Event } from "@opencode/schema/event" import { Effect, Stream } from "effect" -import { HttpServerResponse } from "effect/unstable/http" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpServerResponse } from "effect/http" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { EventFeed } from "../event-feed" diff --git a/packages/server/src/handlers/form.ts b/packages/server/src/handlers/form.ts index 15f2714c0562..8d9640481fef 100644 --- a/packages/server/src/handlers/form.ts +++ b/packages/server/src/handlers/form.ts @@ -1,6 +1,6 @@ import { Form } from "@opencode/core/form" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/fs.ts b/packages/server/src/handlers/fs.ts index 27d3fbc3476d..ff67a3b35358 100644 --- a/packages/server/src/handlers/fs.ts +++ b/packages/server/src/handlers/fs.ts @@ -2,8 +2,8 @@ import { FileSystem } from "@opencode/core/filesystem" import { RelativePath } from "@opencode/core/schema" import { FileNotFoundError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpServerResponse } from "effect/unstable/http" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpServerResponse } from "effect/http" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/generate.ts b/packages/server/src/handlers/generate.ts index 57fefbe12499..4c9ffb2223dd 100644 --- a/packages/server/src/handlers/generate.ts +++ b/packages/server/src/handlers/generate.ts @@ -5,7 +5,7 @@ import { AbsolutePath } from "@opencode/core/schema" import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors" import { Global } from "@opencode/util/global" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" export const GenerateHandler = HttpApiBuilder.group(Api, "server.generate", (handlers) => diff --git a/packages/server/src/handlers/integration.ts b/packages/server/src/handlers/integration.ts index 8d2e285ffbb2..c331c5e0cd40 100644 --- a/packages/server/src/handlers/integration.ts +++ b/packages/server/src/handlers/integration.ts @@ -1,7 +1,7 @@ import { Integration } from "@opencode/core/integration" import { Plugin } from "@opencode/core/plugin" import { Effect } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { Api } from "../api" import { IntegrationAttemptNotFoundError, diff --git a/packages/server/src/handlers/location.ts b/packages/server/src/handlers/location.ts index bfd7eec2785b..21c6321c9ba9 100644 --- a/packages/server/src/handlers/location.ts +++ b/packages/server/src/handlers/location.ts @@ -2,7 +2,7 @@ import { Location } from "@opencode/core/location" import { LocationServiceMap } from "@opencode/core/location-service-map" import { ServiceUnavailableError } from "@opencode/protocol/errors" import { Cause, Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" export const LocationHandler = HttpApiBuilder.group(Api, "server.location", (handlers) => diff --git a/packages/server/src/handlers/mcp.ts b/packages/server/src/handlers/mcp.ts index 47933234585c..d6b47b27e632 100644 --- a/packages/server/src/handlers/mcp.ts +++ b/packages/server/src/handlers/mcp.ts @@ -1,7 +1,7 @@ import { Mcp } from "@opencode/core/mcp/index" import { McpServerNotFoundError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/message.ts b/packages/server/src/handlers/message.ts index 04f6120b74b4..5bf8d6213952 100644 --- a/packages/server/src/handlers/message.ts +++ b/packages/server/src/handlers/message.ts @@ -1,7 +1,7 @@ import { SessionMessage } from "@opencode/core/session/message" import { Session } from "@opencode/core/session" import { Effect, Schema } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { InvalidCursorError } from "@opencode/protocol/errors" import { failedMessageDecode, missingSession } from "./session-error" diff --git a/packages/server/src/handlers/migration.ts b/packages/server/src/handlers/migration.ts index 1c287560050b..15c0e5f435b8 100644 --- a/packages/server/src/handlers/migration.ts +++ b/packages/server/src/handlers/migration.ts @@ -1,5 +1,5 @@ import { V1Migration } from "@opencode/core/database/v1-migration" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Effect } from "effect" import { Api } from "../api" diff --git a/packages/server/src/handlers/model.ts b/packages/server/src/handlers/model.ts index b316fd2b6ddf..43599e9ea940 100644 --- a/packages/server/src/handlers/model.ts +++ b/packages/server/src/handlers/model.ts @@ -1,6 +1,6 @@ import { Model } from "@opencode/core/model" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/permission.ts b/packages/server/src/handlers/permission.ts index cec7bdb9bd9e..f622dae11411 100644 --- a/packages/server/src/handlers/permission.ts +++ b/packages/server/src/handlers/permission.ts @@ -4,7 +4,7 @@ import { Permission } from "@opencode/core/permission" import { PermissionSaved } from "@opencode/core/permission/saved" import { Session } from "@opencode/core/session" import { Effect } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { Api } from "../api" import { PermissionNotFoundError } from "@opencode/protocol/errors" import { response, sessionInfo } from "../location" diff --git a/packages/server/src/handlers/persistent-pty.ts b/packages/server/src/handlers/persistent-pty.ts index 76aa3a025bfe..97d7e077d397 100644 --- a/packages/server/src/handlers/persistent-pty.ts +++ b/packages/server/src/handlers/persistent-pty.ts @@ -7,9 +7,9 @@ import { PTY_CONNECT_TOKEN_HEADER_VALUE, } from "@opencode/protocol/groups/persistent-pty" import { Effect, Queue, Semaphore } from "effect" -import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" -import { Socket } from "effect/unstable/socket" +import { HttpServerRequest, HttpServerResponse } from "effect/http" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" +import { Socket } from "effect/socket" import { Api } from "../api" import { CorsConfig, isAllowedRequestOrigin } from "../cors" import { runPtySocket } from "./pty-socket" @@ -124,7 +124,7 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment if (!Number.isSafeInteger(cursor) || cursor < 0) return HttpServerResponse.empty({ status: 400 }) const socket = yield* Effect.orDie(ctx.request.upgrade) - const write = yield* socket.writer + const writer = yield* socket.writer const outbox = yield* Queue.unbounded() const input = yield* Semaphore.make(1) let attachment: PersistentPty.Attachment | undefined @@ -187,16 +187,17 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment const drain = Effect.gen(function* () { while (true) { const item = yield* Queue.take(outbox) - yield* write(item) + yield* writer.write(item) if (item instanceof Socket.CloseEvent) return } }) - yield* runPtySocket( - drain, - socket.runRaw( - (message) => - input.withPermit( + const receive = Effect.gen(function* () { + const reader = yield* socket.reader + yield* onOpen + while (true) { + for (const message of yield* reader.pull) { + yield* input.withPermit( Effect.suspend(() => { if (!attachment) return Effect.void const data = typeof message === "string" ? Buffer.from(message) : message @@ -219,11 +220,12 @@ export const PersistentPtyHandler = HttpApiBuilder.group(Api, "server.experiment if (type === 0) return pty.control(ctx.params.ptyID, attachmentID, cols, rows).pipe(Effect.ignore) return pty.input(ctx.params.ptyID, attachmentID, cols, rows, data.subarray(5)).pipe(Effect.ignore) }), - ), - { onOpen }, - ), - () => attachment?.detach(), - ).pipe( + ) + } + } + }).pipe(Effect.scoped) + + yield* runPtySocket(drain, receive, () => attachment?.detach()).pipe( Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.orDie, ) diff --git a/packages/server/src/handlers/plugin.ts b/packages/server/src/handlers/plugin.ts index 31fe39c483e8..76e157466e0e 100644 --- a/packages/server/src/handlers/plugin.ts +++ b/packages/server/src/handlers/plugin.ts @@ -2,7 +2,7 @@ import { Plugin } from "@opencode/core/plugin" import { PluginUpdate } from "@opencode/core/plugin/update" import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors" import { Cause, Effect, Exit } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/project.ts b/packages/server/src/handlers/project.ts index f6bcf2a13583..7a32951b3fee 100644 --- a/packages/server/src/handlers/project.ts +++ b/packages/server/src/handlers/project.ts @@ -1,6 +1,6 @@ import { Project } from "@opencode/core/project" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { ProjectNotFoundError } from "@opencode/protocol/errors" diff --git a/packages/server/src/handlers/provider.ts b/packages/server/src/handlers/provider.ts index 75bdb0e5503e..ab9c2201a5ee 100644 --- a/packages/server/src/handlers/provider.ts +++ b/packages/server/src/handlers/provider.ts @@ -1,7 +1,7 @@ import { Provider } from "@opencode/core/provider" import { ProviderNotFoundError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/pty.ts b/packages/server/src/handlers/pty.ts index 4e8f922edbbf..166e26f307d6 100644 --- a/packages/server/src/handlers/pty.ts +++ b/packages/server/src/handlers/pty.ts @@ -3,9 +3,9 @@ import { PtyProtocol } from "@opencode/core/pty/protocol" import { PtyTicket } from "@opencode/core/pty/ticket" import { Location } from "@opencode/core/location" import { Effect, Queue } from "effect" -import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" -import { Socket } from "effect/unstable/socket" +import { HttpServerRequest, HttpServerResponse } from "effect/http" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" +import { Socket } from "effect/socket" import { Api } from "../api" import { CorsConfig, isAllowedRequestOrigin } from "../cors" import { ForbiddenError, PtyNotFoundError } from "@opencode/protocol/errors" @@ -165,15 +165,18 @@ export const PtyHandler = HttpApiBuilder.group(Api, "server.pty", (handlers) => : undefined const socket = yield* Effect.orDie(ctx.request.upgrade) - const write = yield* socket.writer + const writer = yield* socket.writer const closeAccepted = (event: Socket.CloseEvent) => - socket - .runRaw(() => Effect.void, { onOpen: write(event).pipe(Effect.catch(() => Effect.void)) }) - .pipe( - Effect.timeout("1 second"), - Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), - Effect.catch(() => Effect.void), - ) + Effect.gen(function* () { + const reader = yield* socket.reader + yield* writer.write(event).pipe(Effect.catch(() => Effect.void)) + while (true) yield* reader.pull + }).pipe( + Effect.scoped, + Effect.timeout("1 second"), + Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), + Effect.catch(() => Effect.void), + ) // Outbound frames flow through one queue drained by a single writer so replay, live // output, and the close frame keep their order. @@ -202,19 +205,22 @@ export const PtyHandler = HttpApiBuilder.group(Api, "server.pty", (handlers) => const drain = Effect.gen(function* () { while (true) { const item = yield* Queue.take(outbox) - yield* write(item) + yield* writer.write(item) if (item instanceof Socket.CloseEvent) return } }) - yield* runPtySocket( - drain, - socket.runRaw((message) => { - const decoded = PtyProtocol.decodeInput(message) - if (decoded !== undefined) attachment.write(decoded) - }), - attachment.detach, - ).pipe( + const receive = Effect.gen(function* () { + const reader = yield* socket.reader + while (true) { + for (const message of yield* reader.pull) { + const decoded = PtyProtocol.decodeInput(message) + if (decoded !== undefined) attachment.write(decoded) + } + } + }).pipe(Effect.scoped) + + yield* runPtySocket(drain, receive, attachment.detach).pipe( Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void), Effect.orDie, ) diff --git a/packages/server/src/handlers/reference.ts b/packages/server/src/handlers/reference.ts index 3fb20bc328c1..aae02c9b1c43 100644 --- a/packages/server/src/handlers/reference.ts +++ b/packages/server/src/handlers/reference.ts @@ -1,5 +1,5 @@ import { Reference } from "@opencode/core/reference" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/rpc.ts b/packages/server/src/handlers/rpc.ts index a0bd96a28e75..ded5610ae618 100644 --- a/packages/server/src/handlers/rpc.ts +++ b/packages/server/src/handlers/rpc.ts @@ -2,7 +2,7 @@ import { Rpc } from "@opencode/core/rpc" import { Plugin } from "@opencode/core/plugin" import { RpcError, RpcInternalError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" export const RpcHandler = HttpApiBuilder.group(Api, "server.rpc", (handlers) => diff --git a/packages/server/src/handlers/server.ts b/packages/server/src/handlers/server.ts index 72a63c43aa66..ada9b156754c 100644 --- a/packages/server/src/handlers/server.ts +++ b/packages/server/src/handlers/server.ts @@ -1,6 +1,6 @@ import { Duration, Effect } from "effect" -import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpServerRequest, HttpServerResponse } from "effect/http" +import { HttpApiBuilder } from "effect/http-api" import { UnauthorizedError } from "@opencode/protocol/errors" import { Api } from "../api" import { ServerAuth } from "../auth" diff --git a/packages/server/src/handlers/session.ts b/packages/server/src/handlers/session.ts index 7a2586fb323a..6b188df05be6 100644 --- a/packages/server/src/handlers/session.ts +++ b/packages/server/src/handlers/session.ts @@ -5,7 +5,7 @@ import { SessionTransfer } from "@opencode/core/session/transfer" import { InstructionEntry } from "@opencode/core/session/instruction-entry" import { Form } from "@opencode/core/form" import { DateTime, Effect, Stream } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { Api } from "../api" import { SessionsCursor } from "@opencode/protocol/groups/session" import { diff --git a/packages/server/src/handlers/shell.ts b/packages/server/src/handlers/shell.ts index 0beeafc279a7..6b08faf80753 100644 --- a/packages/server/src/handlers/shell.ts +++ b/packages/server/src/handlers/shell.ts @@ -1,7 +1,7 @@ import { Shell } from "@opencode/core/shell" import { Location } from "@opencode/core/location" import { Effect } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { ShellNotFoundError } from "@opencode/protocol/errors" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/skill.ts b/packages/server/src/handlers/skill.ts index a0cba465d33a..39039fcd638b 100644 --- a/packages/server/src/handlers/skill.ts +++ b/packages/server/src/handlers/skill.ts @@ -1,5 +1,5 @@ import { Skill } from "@opencode/core/skill" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/vcs.ts b/packages/server/src/handlers/vcs.ts index 655c1814ad66..39f2d179772c 100644 --- a/packages/server/src/handlers/vcs.ts +++ b/packages/server/src/handlers/vcs.ts @@ -1,7 +1,7 @@ import { Vcs } from "@opencode/core/vcs" import { ServiceUnavailableError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/websearch.ts b/packages/server/src/handlers/websearch.ts index bb838a6173cc..71808b86e206 100644 --- a/packages/server/src/handlers/websearch.ts +++ b/packages/server/src/handlers/websearch.ts @@ -1,7 +1,7 @@ import { WebSearch } from "@opencode/core/websearch" import { InvalidRequestError, ServiceUnavailableError } from "@opencode/protocol/errors" import { Effect } from "effect" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpApiBuilder } from "effect/http-api" import { Api } from "../api" import { response } from "../location" diff --git a/packages/server/src/handlers/worktree.ts b/packages/server/src/handlers/worktree.ts index c90b57e608e3..dc6867da86c1 100644 --- a/packages/server/src/handlers/worktree.ts +++ b/packages/server/src/handlers/worktree.ts @@ -4,7 +4,7 @@ import { Project } from "@opencode/core/project" import { ProjectNotFoundError } from "@opencode/protocol/errors" import { WorktreeError } from "@opencode/protocol/groups/worktree" import { Effect } from "effect" -import { HttpApiBuilder, HttpApiSchema } from "effect/unstable/httpapi" +import { HttpApiBuilder, HttpApiSchema } from "effect/http-api" import { Api } from "../api" export const WorktreeHandler = HttpApiBuilder.group(Api, "server.worktree", (handlers) => diff --git a/packages/server/src/location.ts b/packages/server/src/location.ts index 83e66df301dd..808895c024f2 100644 --- a/packages/server/src/location.ts +++ b/packages/server/src/location.ts @@ -4,8 +4,8 @@ import { AbsolutePath } from "@opencode/core/schema" import { Session } from "@opencode/core/session" import { InvalidRequestError } from "@opencode/protocol/errors" import { Effect, Layer, Schema } from "effect" -import { HttpServerRequest } from "effect/unstable/http" -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpServerRequest } from "effect/http" +import { HttpApiMiddleware } from "effect/http-api" import { missingSession } from "./handlers/session-error" export type LocationServices = Layer.Success> diff --git a/packages/server/src/middleware/authorization.ts b/packages/server/src/middleware/authorization.ts index 84906429d776..7e995c79059e 100644 --- a/packages/server/src/middleware/authorization.ts +++ b/packages/server/src/middleware/authorization.ts @@ -5,8 +5,9 @@ export { Authorization } from "@opencode/protocol/middleware/authorization" import { hasPtyConnectTicketURL } from "@opencode/protocol/groups/pty" import { hasPersistentPtyConnectTicketURL } from "@opencode/protocol/groups/persistent-pty" import { isPairingConnectURL } from "@opencode/protocol/groups/server" -import { Effect, Encoding, Layer, Redacted } from "effect" -import { HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { Effect, Layer, Redacted } from "effect" +import { Base64 } from "effect/encoding" +import { HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/http" const AUTH_TOKEN_QUERY = "auth_token" const WWW_AUTHENTICATE = 'Basic realm="Secure Area"' @@ -16,7 +17,7 @@ function emptyCredential() { } function decodeCredential(input: string) { - return Effect.fromResult(Encoding.decodeBase64String(input)).pipe( + return Effect.fromResult(Base64.decodeString(input)).pipe( Effect.match({ onFailure: emptyCredential, onSuccess: (header) => { diff --git a/packages/server/src/middleware/form-location.ts b/packages/server/src/middleware/form-location.ts index dc18de75fbda..c9a9eb246501 100644 --- a/packages/server/src/middleware/form-location.ts +++ b/packages/server/src/middleware/form-location.ts @@ -3,8 +3,8 @@ import { LocationServiceMap } from "@opencode/core/location-services" import { Session } from "@opencode/core/session" import { InvalidRequestError, SessionNotFoundError } from "@opencode/protocol/errors" import { Effect, Layer } from "effect" -import { HttpRouter, HttpServerRequest } from "effect/unstable/http" -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpRouter, HttpServerRequest } from "effect/http" +import { HttpApiMiddleware } from "effect/http-api" import { requestRef, sessionInfo, type LocationServices } from "../location" export class FormLocationMiddleware extends HttpApiMiddleware.Service< diff --git a/packages/server/src/middleware/schema-error.ts b/packages/server/src/middleware/schema-error.ts index 6762cd461618..36a4ee7af9df 100644 --- a/packages/server/src/middleware/schema-error.ts +++ b/packages/server/src/middleware/schema-error.ts @@ -1,5 +1,5 @@ import { Effect } from "effect" -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpApiMiddleware } from "effect/http-api" import { InvalidRequestError } from "@opencode/protocol/errors" import { SchemaErrorMiddleware } from "@opencode/protocol/middleware/schema-error" export { SchemaErrorMiddleware } from "@opencode/protocol/middleware/schema-error" diff --git a/packages/server/src/middleware/session-location.ts b/packages/server/src/middleware/session-location.ts index f3a9a2234483..2bc0ed33fddc 100644 --- a/packages/server/src/middleware/session-location.ts +++ b/packages/server/src/middleware/session-location.ts @@ -1,8 +1,8 @@ import { Instance } from "@opencode/core/instance/service" import { Session } from "@opencode/core/session" import { Effect, Layer } from "effect" -import { HttpRouter } from "effect/unstable/http" -import { HttpApiMiddleware } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApiMiddleware } from "effect/http-api" import { InvalidRequestError, SessionNotFoundError } from "@opencode/protocol/errors" import { sessionInfo, type LocationServices } from "../location" diff --git a/packages/server/src/process.ts b/packages/server/src/process.ts index 1c11586d6308..5a6cec7d2b6f 100644 --- a/packages/server/src/process.ts +++ b/packages/server/src/process.ts @@ -9,7 +9,7 @@ import { hasPersistentPtyConnectTicketURL } from "@opencode/protocol/groups/pers import { isPairingConnectURL } from "@opencode/protocol/groups/server" import { Global } from "@opencode/util/global" import { Cause, Context, Effect, Exit, Latch, Layer, Option, Ref, Scope } from "effect" -import { HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { HttpMiddleware, HttpRouter, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/http" import { createServer } from "node:http" import { ServerAuth } from "./auth" import { isAllowedCorsOrigin } from "./cors" @@ -22,7 +22,7 @@ import type { ServerOptions } from "./options" export interface Lifecycle { readonly onListen: ( - address: HttpServer.Address, + address: HttpServer.HttpServer["Service"]["address"], shutdown: Effect.Effect, ) => Effect.Effect, E, R> } diff --git a/packages/server/src/routes.ts b/packages/server/src/routes.ts index c4f746f1d82b..6a0cc8dbcde8 100644 --- a/packages/server/src/routes.ts +++ b/packages/server/src/routes.ts @@ -32,8 +32,8 @@ import { SdkPlugins } from "@opencode/core/plugin/sdk" import { WellKnown } from "@opencode/core/wellknown" import { Workspace } from "@opencode/core/workspace" import { Watcher } from "@opencode/core/filesystem/watcher" -import { HttpRouter } from "effect/unstable/http" -import { HttpApiBuilder } from "effect/unstable/httpapi" +import { HttpRouter } from "effect/http" +import { HttpApiBuilder } from "effect/http-api" import { Context, Effect, Layer, Option } from "effect" import { Api } from "./api" import { ServerAuth } from "./auth" diff --git a/packages/server/test/fixture/server.ts b/packages/server/test/fixture/server.ts index 8eeeece1860b..0a13c02fead4 100644 --- a/packages/server/test/fixture/server.ts +++ b/packages/server/test/fixture/server.ts @@ -1,5 +1,5 @@ import { Effect } from "effect" -import { HttpServer } from "effect/unstable/http" +import { HttpServer } from "effect/http" import { ServerProcess } from "../../src/process" export const startServer = Effect.fnUntraced(function* (directory: string) { diff --git a/packages/server/test/persistent-pty.test.ts b/packages/server/test/persistent-pty.test.ts index 1d4b85fe9aad..deb0daedb1c1 100644 --- a/packages/server/test/persistent-pty.test.ts +++ b/packages/server/test/persistent-pty.test.ts @@ -6,7 +6,7 @@ import { expect } from "bun:test" import { PersistentPty } from "@opencode/schema/persistent-pty" import { Session } from "@opencode/schema/session" import { Effect, Exit, Schema, Scope } from "effect" -import { HttpServer } from "effect/unstable/http" +import { HttpServer } from "effect/http" import { OpenCode } from "../../client/src/promise/index" import { it } from "../../core/test/lib/effect" import { ServerProcess } from "../src/process" diff --git a/packages/server/test/process.test.ts b/packages/server/test/process.test.ts index f5d4071a73b8..7ddf93b59622 100644 --- a/packages/server/test/process.test.ts +++ b/packages/server/test/process.test.ts @@ -1,6 +1,6 @@ import { expect } from "bun:test" import { Effect } from "effect" -import { HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { HttpServer, HttpServerRequest, HttpServerResponse } from "effect/http" import { it } from "../../core/test/lib/effect" import { ServerProcess } from "../src/process" diff --git a/packages/server/test/provider.test.ts b/packages/server/test/provider.test.ts index 77d2cea8c526..9da592289ee8 100644 --- a/packages/server/test/provider.test.ts +++ b/packages/server/test/provider.test.ts @@ -2,7 +2,7 @@ import { expect } from "bun:test" import { SdkPlugins } from "@opencode/core/plugin/sdk" import { Plugin } from "@opencode/plugin/effect" import { Context, Deferred, Effect, Fiber, Layer } from "effect" -import { HttpEffect, HttpRouter, HttpServer } from "effect/unstable/http" +import { HttpEffect, HttpRouter, HttpServer } from "effect/http" import { tmpdirScoped } from "../../core/test/fixture/tmpdir" import { it } from "../../core/test/lib/effect" import { createRoutes } from "../src/routes" diff --git a/packages/server/test/request-tracing.test.ts b/packages/server/test/request-tracing.test.ts index 94a37f759a78..3854a11b5e5d 100644 --- a/packages/server/test/request-tracing.test.ts +++ b/packages/server/test/request-tracing.test.ts @@ -1,6 +1,6 @@ import { expect, test } from "bun:test" import { Effect, Option, Scope, Tracer } from "effect" -import { HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { HttpMiddleware, HttpServerRequest, HttpServerResponse } from "effect/http" import { withoutParentSpan } from "../src/request-tracing" test("requests ignore ambient parents and continue inbound trace context", async () => { diff --git a/packages/server/test/rpc-handler-errors.test.ts b/packages/server/test/rpc-handler-errors.test.ts index c99377ef67ed..6b141d0e25bd 100644 --- a/packages/server/test/rpc-handler-errors.test.ts +++ b/packages/server/test/rpc-handler-errors.test.ts @@ -3,7 +3,7 @@ import { SdkPlugins } from "@opencode/core/plugin/sdk" import { define } from "@opencode/plugin/effect/plugin" import { Rpc } from "@opencode/schema/rpc" import { Context, Effect, Layer, Schema } from "effect" -import { HttpEffect, HttpRouter, HttpServer } from "effect/unstable/http" +import { HttpEffect, HttpRouter, HttpServer } from "effect/http" import { tmpdirScoped } from "../../core/test/fixture/tmpdir" import { it } from "../../core/test/lib/effect" import { createEmbeddedRoutes } from "../src/routes" diff --git a/packages/server/test/session-instances.test.ts b/packages/server/test/session-instances.test.ts index 0cea57e4aff4..8ddc3601f94b 100644 --- a/packages/server/test/session-instances.test.ts +++ b/packages/server/test/session-instances.test.ts @@ -21,7 +21,7 @@ import { LayerNode } from "@opencode/util/effect/layer-node" import { makeGlobalNode } from "@opencode/util/effect/app-node" import { Global } from "@opencode/util/global" import { Context, Duration, Effect, Layer, LayerMap, RcMap, Schema } from "effect" -import { HttpEffect, HttpRouter, HttpServer } from "effect/unstable/http" +import { HttpEffect, HttpRouter, HttpServer } from "effect/http" import { LanguageModel, LLMClient } from "../../ai/src" import { OpenAIChat } from "../../ai/src/protocols/openai-chat" import { TestLLM } from "../../ai/src/testing" diff --git a/packages/simulation/src/backend/index.ts b/packages/simulation/src/backend/index.ts index a3ec0f61dbea..00d4fe1bd7fa 100644 --- a/packages/simulation/src/backend/index.ts +++ b/packages/simulation/src/backend/index.ts @@ -3,7 +3,7 @@ import { makeGlobalNode } from "@opencode/util/effect/app-node" import { httpClient } from "@opencode/util/effect/app-node-platform" import { SdkPlugins } from "@opencode/core/plugin/sdk" import { Config, Effect, FileSystem, Layer } from "effect" -import { HttpClient } from "effect/unstable/http" +import { HttpClient } from "effect/http" import { DriveManifest } from "../manifest" import { SimulationNetwork } from "./network" import { SimulationOpenAI } from "./openai" @@ -28,7 +28,7 @@ export const simulationReplacements: (app: { // ModelsDev dies when its catalog fetch fails, so simulation answers it with // an empty catalog; providers come from seeded config instead. const models = SimulationNetwork.json("GET", "https://models.opencode.ai/api.json", {}) - const drive = yield* Config.string("OPENCODE_DRIVE").pipe(Config.withDefault(undefined)) + const drive = yield* Config.String("OPENCODE_DRIVE").pipe(Config.withDefault(undefined)) if (!drive) return [httpClient.replace(SimulationNetwork.layer([models]))] satisfies LayerNode.Replacements const manifest = yield* DriveManifest.resolve() diff --git a/packages/simulation/src/backend/network.ts b/packages/simulation/src/backend/network.ts index f91ec8246ceb..52aacd8e4d08 100644 --- a/packages/simulation/src/backend/network.ts +++ b/packages/simulation/src/backend/network.ts @@ -1,7 +1,7 @@ import { Clock, Effect, Layer, Ref } from "effect" -import { HttpClient, HttpClientResponse, type HttpMethod } from "effect/unstable/http" -import { HttpClientError, TransportError } from "effect/unstable/http/HttpClientError" -import type { HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientResponse, type HttpMethod } from "effect/http" +import { HttpClientError, TransportError } from "effect/http/HttpClientError" +import type { HttpClientRequest } from "effect/http" import { SimulationProtocol } from "../protocol" /** diff --git a/packages/simulation/src/backend/openai.ts b/packages/simulation/src/backend/openai.ts index ccf67d716555..2ed835aac60d 100644 --- a/packages/simulation/src/backend/openai.ts +++ b/packages/simulation/src/backend/openai.ts @@ -1,6 +1,6 @@ import { Effect, Schema, Stream } from "effect" -import { HttpClientResponse } from "effect/unstable/http" -import { HttpClientError, TransportError } from "effect/unstable/http/HttpClientError" +import { HttpClientResponse } from "effect/http" +import { HttpClientError, TransportError } from "effect/http/HttpClientError" import { OpenAIChatEvent, DEFAULT_BASE_URL, PATH } from "@opencode/ai/protocols/openai-chat" import { SimulationNetwork } from "./network" import { SimulatedProvider } from "./simulated-provider" diff --git a/packages/simulation/src/frontend/actions.ts b/packages/simulation/src/frontend/actions.ts index 82823519be85..da1c94bc1cf5 100644 --- a/packages/simulation/src/frontend/actions.ts +++ b/packages/simulation/src/frontend/actions.ts @@ -7,7 +7,8 @@ import { type MockInput, type MockMouse, } from "@opentui/core/testing" -import { Effect, Encoding, Schema } from "effect" +import { Effect, Schema } from "effect" +import { Base64 } from "effect/encoding" import { SimulationProtocol } from "../protocol" import { SimulationRenderer } from "./renderer" import { SimulationSemantics } from "./semantics" @@ -206,7 +207,7 @@ function captureImages(renderer: CliRenderer): SimulationProtocol.Frontend.Captu height: fitted.height, pixelWidth: raw.width, pixelHeight: raw.height, - rgba: Encoding.encodeBase64(rgba), + rgba: Base64.encode(rgba), }] } finally { extracted?.dispose() diff --git a/packages/simulation/src/frontend/simulation.ts b/packages/simulation/src/frontend/simulation.ts index 0f077fb2b8b2..0b67f429f604 100644 --- a/packages/simulation/src/frontend/simulation.ts +++ b/packages/simulation/src/frontend/simulation.ts @@ -7,7 +7,7 @@ import { SimulationServer } from "./server" /** Drive-mode renderer and control-server acquisition. */ export const create = Effect.fn("Drive.create")(function* (options: CliRendererConfig, version: string) { - const headless = (yield* Config.string("OPENCODE_DRIVE_RENDERER").pipe(Config.withDefault("visible"))) === "headless" + const headless = (yield* Config.String("OPENCODE_DRIVE_RENDERER").pipe(Config.withDefault("visible"))) === "headless" const manifest = yield* DriveManifest.resolve() const renderer = headless ? yield* SimulationRenderer.create(options, manifest.recording?.timeline, manifest.viewport) diff --git a/packages/simulation/src/manifest.ts b/packages/simulation/src/manifest.ts index 1b48590db91c..25884594ffb4 100644 --- a/packages/simulation/src/manifest.ts +++ b/packages/simulation/src/manifest.ts @@ -70,11 +70,11 @@ export const resolve = Effect.fn("DriveManifest.resolve")(function* () { const name = yield* Config.schema(InstanceName, "OPENCODE_DRIVE").pipe(Effect.mapError(configError)) if (name === "1") return defaults - const state = yield* Config.string("XDG_STATE_HOME").pipe( + const state = yield* Config.String("XDG_STATE_HOME").pipe( Config.withDefault(join(homedir(), ".local", "state")), Effect.mapError(configError), ) - const directory = yield* Config.string("DRIVE_REGISTRY_DIR").pipe( + const directory = yield* Config.String("DRIVE_REGISTRY_DIR").pipe( Config.withDefault(join(state, "opencode-drive", "instances")), Effect.mapError(configError), ) diff --git a/packages/simulation/test/network.test.ts b/packages/simulation/test/network.test.ts index 9049b5700ca8..863048e1ff73 100644 --- a/packages/simulation/test/network.test.ts +++ b/packages/simulation/test/network.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "bun:test" import { Effect, Exit } from "effect" import { TestClock } from "effect/testing" -import { HttpClientRequest } from "effect/unstable/http" +import { HttpClientRequest } from "effect/http" import { SimulationNetwork } from "../src/backend/network" test("keeps routes and request logs local to each network", async () => { diff --git a/packages/simulation/test/openai.test.ts b/packages/simulation/test/openai.test.ts index 6b5fd2f5b7d5..b500b5a6af11 100644 --- a/packages/simulation/test/openai.test.ts +++ b/packages/simulation/test/openai.test.ts @@ -1,8 +1,8 @@ import { expect, test } from "bun:test" import { DEFAULT_BASE_URL, PATH } from "@opencode/ai/protocols/openai-chat" import { Effect, Stream } from "effect" -import { HttpClientRequest } from "effect/unstable/http" -import { HttpClientError } from "effect/unstable/http/HttpClientError" +import { HttpClientRequest } from "effect/http" +import { HttpClientError } from "effect/http/HttpClientError" import { SimulationOpenAI } from "../src/backend/openai" import { SimulatedProvider } from "../src/backend/simulated-provider" diff --git a/packages/stats/core/src/config.ts b/packages/stats/core/src/config.ts index fb5a4de35290..f6aa6d63323e 100644 --- a/packages/stats/core/src/config.ts +++ b/packages/stats/core/src/config.ts @@ -11,7 +11,7 @@ const decodeAppConfigValue = Schema.decodeUnknownSync(AppConfigValue) const config = Config.all({ stage: Config.succeed(Resource.App.stage), - publicUrl: Config.string("PUBLIC_URL").pipe(Config.withDefault("http://localhost:3000")), + publicUrl: Config.String("PUBLIC_URL").pipe(Config.withDefault("http://localhost:3000")), }).pipe(Config.map(decodeAppConfigValue)) export class AppConfig extends Context.Service()("@opencode/stats/AppConfig") { diff --git a/packages/stats/core/src/database.ts b/packages/stats/core/src/database.ts index 8821714d7bdb..c8df5bd402f5 100644 --- a/packages/stats/core/src/database.ts +++ b/packages/stats/core/src/database.ts @@ -16,8 +16,8 @@ export class DatabaseSettings extends Schema.Class("DatabaseSe const decodeDatabaseSettings = Schema.decodeUnknownSync(DatabaseSettings) const config = Config.all({ - url: Config.nonEmptyString("DATABASE_URL").pipe(Config.withDefault(Resource.StatsDatabase.url)), - migrationsDir: Config.nonEmptyString("DATABASE_MIGRATIONS_DIR").pipe(Config.withDefault("./migrations")), + url: Config.NonEmptyString("DATABASE_URL").pipe(Config.withDefault(Resource.StatsDatabase.url)), + migrationsDir: Config.NonEmptyString("DATABASE_MIGRATIONS_DIR").pipe(Config.withDefault("./migrations")), }).pipe(Config.map(decodeDatabaseSettings)) export class DatabaseConfig extends Context.Service()( diff --git a/packages/stats/server/src/router.ts b/packages/stats/server/src/router.ts index e951118079ea..0fea1f2efa67 100644 --- a/packages/stats/server/src/router.ts +++ b/packages/stats/server/src/router.ts @@ -2,7 +2,7 @@ import { Buffer } from "node:buffer" import { timingSafeEqual } from "node:crypto" import { Effect, Schema } from "effect" import * as Semaphore from "effect/Semaphore" -import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" +import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http" import { Resource } from "sst/resource" import { Ingest } from "./ingest" import { isShuttingDown } from "./shutdown" diff --git a/packages/stats/server/src/server.ts b/packages/stats/server/src/server.ts index 95104bc45eee..424c5fe8cf36 100644 --- a/packages/stats/server/src/server.ts +++ b/packages/stats/server/src/server.ts @@ -1,7 +1,7 @@ import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer" import * as NodeRuntime from "@effect/platform-node/NodeRuntime" import { Config, Layer } from "effect" -import { HttpRouter } from "effect/unstable/http" +import { HttpRouter } from "effect/http" import { createServer } from "node:http" import { Ingest } from "./ingest" import { Routes } from "./router" @@ -12,8 +12,8 @@ registerShutdownSignalHandlers() const ServerLive = NodeHttpServer.layerConfig( () => createServer(), Config.all({ - port: Config.number("PORT").pipe(Config.withDefault(3000)), - host: Config.string("HOST").pipe(Config.withDefault("0.0.0.0")), + port: Config.Number("PORT").pipe(Config.withDefault(3000)), + host: Config.String("HOST").pipe(Config.withDefault("0.0.0.0")), }), ) diff --git a/packages/util/src/cross-spawn-spawner.ts b/packages/util/src/cross-spawn-spawner.ts index ffd9071cb024..36e8c27f2220 100644 --- a/packages/util/src/cross-spawn-spawner.ts +++ b/packages/util/src/cross-spawn-spawner.ts @@ -3,7 +3,7 @@ import * as NodeSink from "@effect/platform-node/NodeSink" import * as NodeStream from "@effect/platform-node/NodeStream" import { Deferred, Effect, Exit, FileSystem, Layer, Path, PlatformError, Predicate, Sink, Stream } from "effect" import type { Scope } from "effect" -import { ChildProcess } from "effect/unstable/process" +import { ChildProcess } from "effect/process" import { ChildProcessSpawner, ExitCode, @@ -11,8 +11,7 @@ import { makeHandle, ProcessId, type ChildProcessHandle, -} from "effect/unstable/process/ChildProcessSpawner" -// ast-grep-ignore: no-star-import +} from "effect/process/ChildProcessSpawner" import * as NodeChildProcess from "node:child_process" import { PassThrough } from "node:stream" import launch from "cross-spawn" diff --git a/packages/util/src/effect/app-node-platform.ts b/packages/util/src/effect/app-node-platform.ts index a34f0447ddb2..ee9e462039f7 100644 --- a/packages/util/src/effect/app-node-platform.ts +++ b/packages/util/src/effect/app-node-platform.ts @@ -3,7 +3,7 @@ import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem" import * as NodePath from "@effect/platform-node/NodePath" import { FileSystem, Path } from "effect" -import { FetchHttpClient, HttpClient } from "effect/unstable/http" +import { FetchHttpClient, HttpClient } from "effect/http" import { makeGlobalNode } from "./app-node.js" export const filesystem = makeGlobalNode({ service: FileSystem.FileSystem, layer: NodeFileSystem.layer, deps: [] }) diff --git a/packages/util/src/observability.ts b/packages/util/src/observability.ts index e518fbeccf99..78be301eeaf4 100644 --- a/packages/util/src/observability.ts +++ b/packages/util/src/observability.ts @@ -3,8 +3,8 @@ export * as Observability from "./observability.js" import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem" import { LayerNode } from "./effect/layer-node.js" import { Effect, Layer, Logger, References, Schema } from "effect" -import { FetchHttpClient } from "effect/unstable/http" -import { OtlpExporter, OtlpSerialization } from "effect/unstable/observability" +import { FetchHttpClient } from "effect/http" +import { OtlpExporter, OtlpSerialization } from "effect/observability" import { Logging } from "./observability/logging.js" import { Otlp } from "./observability/otlp.js" diff --git a/packages/util/src/observability/logging.ts b/packages/util/src/observability/logging.ts index 1dd56270fa37..d942afae6bc2 100644 --- a/packages/util/src/observability/logging.ts +++ b/packages/util/src/observability/logging.ts @@ -111,7 +111,7 @@ export const trim = Effect.fn("Logging.trim")(function* ( if (size <= max) return const handle = yield* fs.open(target, { flag: "r+" }) const start = yield* lineStart(handle, size - keep) - yield* handle.seek(0, "start") + yield* handle.seek(0n, "start") // Reads run to the current EOF so lines appended since the stat survive; the write cursor always // trails the read cursor so the forward copy never overwrites unread bytes. const written = yield* fs.stream(target, { offset: start, chunkSize: LOG_TRIM_CHUNK }).pipe( @@ -146,7 +146,7 @@ function lineStart(handle: FileSystem.File, from: number) { return Effect.gen(function* () { let cursor = from while (true) { - yield* handle.seek(cursor, "start") + yield* handle.seek(BigInt(cursor), "start") const chunk = yield* handle.readAlloc(LOG_TRIM_CHUNK) if (Option.isNone(chunk)) return cursor const newline = chunk.value.indexOf(10) diff --git a/packages/util/src/observability/otlp.ts b/packages/util/src/observability/otlp.ts index a72a5a85bcbf..2fa76f114a3a 100644 --- a/packages/util/src/observability/otlp.ts +++ b/packages/util/src/observability/otlp.ts @@ -1,5 +1,5 @@ import { Effect, Layer, Scope } from "effect" -import { OtlpLogger } from "effect/unstable/observability" +import { OtlpLogger } from "effect/observability" import { runID } from "./shared.js" export interface Options { diff --git a/packages/util/src/process.ts b/packages/util/src/process.ts index 88758b07b952..e971a9e62c5b 100644 --- a/packages/util/src/process.ts +++ b/packages/util/src/process.ts @@ -1,7 +1,7 @@ import { Context, Duration, Effect, Fiber, Layer, Schema, Stream } from "effect" import type { PlatformError } from "effect/PlatformError" -import { ChildProcess } from "effect/unstable/process" -import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner" +import { ChildProcess } from "effect/process" +import { ChildProcessSpawner } from "effect/process/ChildProcessSpawner" import { CrossSpawnSpawner } from "./cross-spawn-spawner.js" import { makeGlobalNode } from "./effect/app-node.js" diff --git a/services/www/openapi.json b/services/www/openapi.json index e4fbd2f5d3c6..4e48ee5be66a 100644 --- a/services/www/openapi.json +++ b/services/www/openapi.json @@ -48,6 +48,99 @@ "summary": "Get server info" } }, + "/api/pair": { + "post": { + "tags": ["server"], + "operationId": "server.pair", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "PairingCode", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairingCode" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Create a short-lived, single-use code for a /auth/connect/:code pairing link.", + "summary": "Create pairing code" + } + }, + "/auth/connect/{code}": { + "get": { + "tags": ["server"], + "operationId": "server.connect", + "parameters": [ + { + "name": "code", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "security": [], + "responses": { + "200": { + "description": "PairingSession", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairingSession" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Redeem a pairing code. Browsers receive a session cookie and a redirect to the web app; requests that accept JSON receive a session token to use as the password.", + "summary": "Redeem pairing code" + } + }, "/api/location": { "get": { "tags": ["location"], @@ -261,7 +354,7 @@ "name": "agentID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "required": true }, @@ -505,14 +598,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -601,14 +687,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -719,8 +798,7 @@ { "anyOf": [ { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, { "type": "string", @@ -742,7 +820,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, { "type": "null" @@ -757,7 +835,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -772,7 +850,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, { "type": "null" @@ -819,9 +897,6 @@ { "$ref": "#/components/schemas/InvalidCursorErrorEncoded" }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, { "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } @@ -886,9 +961,19 @@ } } } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + } + } + } } }, - "description": "Create a session at the requested location.", + "description": "Create a session at the requested location. A parentID creates a linked child session at its parent's location.", "summary": "Create session", "requestBody": { "content": { @@ -899,8 +984,17 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" + }, + { + "type": "null" + } + ] + }, + "parentID": { + "anyOf": [ + { + "$ref": "#/components/schemas/SessionID" }, { "type": "null" @@ -920,7 +1014,7 @@ "agent": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, { "type": "null" @@ -1017,7 +1111,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -1082,14 +1176,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1220,8 +1307,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -1326,7 +1412,8 @@ "^ses": { "$ref": "#/components/schemas/SessionActive" } - } + }, + "additionalProperties": false } }, "required": ["data"], @@ -1369,8 +1456,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1436,8 +1522,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1489,8 +1574,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1525,14 +1609,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1594,8 +1671,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1624,14 +1700,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1652,14 +1721,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" } ] } @@ -1678,8 +1744,7 @@ "before": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -1704,8 +1769,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1740,14 +1804,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1762,7 +1819,7 @@ "type": "object", "properties": { "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" } }, "required": ["agent"], @@ -1783,8 +1840,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1819,14 +1875,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1862,8 +1911,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1878,14 +1926,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1920,7 +1961,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "delivery": { "anyOf": [ @@ -1951,8 +1992,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1981,14 +2021,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -2008,14 +2041,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2042,8 +2068,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2113,8 +2138,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2150,14 +2174,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/CommandNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/CommandNotFoundErrorEncoded" } ] } @@ -2236,8 +2257,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2273,14 +2293,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/SkillNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/SkillNotFoundErrorEncoded" } ] } @@ -2297,7 +2314,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "resume": { "anyOf": [ @@ -2328,8 +2345,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2378,14 +2394,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2412,8 +2421,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2475,8 +2483,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2511,14 +2518,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2535,8 +2535,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2565,8 +2564,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2615,14 +2613,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2649,8 +2640,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2685,8 +2675,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2721,14 +2710,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2757,8 +2739,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2811,9 +2792,6 @@ { "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } @@ -2852,8 +2830,7 @@ "type": "object", "properties": { "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "files": { "anyOf": [ @@ -2884,8 +2861,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2920,14 +2896,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2965,8 +2934,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3001,14 +2969,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3036,8 +2997,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3118,8 +3078,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3129,8 +3088,7 @@ "schema": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -3146,8 +3104,7 @@ "schema": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -3201,14 +3158,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -3264,8 +3214,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3336,8 +3285,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3345,8 +3293,7 @@ "name": "inboxID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -3398,8 +3345,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3407,8 +3353,7 @@ "name": "inboxID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -3489,8 +3434,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3542,14 +3486,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3568,8 +3505,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3612,14 +3548,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3661,8 +3590,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3705,14 +3633,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3731,8 +3652,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3774,14 +3694,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3827,8 +3740,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3838,7 +3750,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Event.SeqEncoded" }, { "type": "null" @@ -3890,7 +3802,7 @@ "$ref": "#/components/schemas/SessionLogItemEncoded" } }, - "required": ["id", "event", "data"], + "required": ["event", "data"], "additionalProperties": false }, "x-effect-stream": { @@ -3952,7 +3864,7 @@ "errorSchema": { "not": {} }, - "failureEvent": "effect/httpapi/stream/failure" + "failureEvent": "effect/http-api/stream/failure" } } } @@ -4001,8 +3913,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -4059,15 +3970,8 @@ "description": "SessionNotFoundError", "content": { "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "schema": { + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4086,8 +3990,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4122,14 +4025,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4148,8 +4044,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -4157,8 +4052,7 @@ "name": "messageID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -4285,14 +4179,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4338,14 +4225,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -4365,14 +4245,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4419,8 +4292,7 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true } @@ -4470,14 +4342,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4504,10 +4373,24 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true + }, + { + "name": "message", + "in": "query", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "required": false } ], "security": [], @@ -4541,14 +4424,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4587,25 +4467,9 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true - }, - { - "name": "message", - "in": "query", - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "required": false } ], "security": [], @@ -4646,14 +4510,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4694,8 +4555,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4769,8 +4629,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4841,8 +4700,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -5206,14 +5064,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5375,7 +5226,7 @@ "name": "providerID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "required": true }, @@ -5572,7 +5423,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5710,14 +5561,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5763,7 +5607,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5808,14 +5652,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5891,7 +5728,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5953,14 +5790,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5985,7 +5815,7 @@ "type": "object", "properties": { "methodID": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "answer": { "anyOf": [ @@ -6026,7 +5856,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6034,7 +5864,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6140,7 +5970,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6148,7 +5978,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6222,7 +6052,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6230,7 +6060,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6275,14 +6105,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -6351,7 +6174,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6413,14 +6236,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -6462,7 +6278,7 @@ "type": "object", "properties": { "methodID": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "label": { "anyOf": [ @@ -6493,7 +6309,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6501,7 +6317,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6607,7 +6423,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6615,7 +6431,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -7159,14 +6975,113 @@ "schema": { "type": "object", "properties": { - "location": { - "$ref": "#/components/schemas/Location.PublicRef" - }, + "location": { + "$ref": "#/components/schemas/Location.PublicRef" + }, + "data": { + "$ref": "#/components/schemas/Mcp.ResourceCatalog" + } + }, + "required": ["location", "data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Retrieve resources and resource templates from connected MCP servers.", + "summary": "List MCP resources" + } + }, + "/api/credential": { + "get": { + "tags": ["credential"], + "operationId": "credential.list", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Credential.Entry" + } + } + }, + "required": ["data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "List every stored integration credential, including its secret value.", + "summary": "List credentials" + }, + "post": { + "tags": ["credential"], + "operationId": "credential.create", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "data": { - "$ref": "#/components/schemas/Mcp.ResourceCatalog" + "$ref": "#/components/schemas/Credential.Entry" } }, - "required": ["location", "data"], + "required": ["data"], "additionalProperties": false } } @@ -7191,10 +7106,30 @@ } } } + }, + "409": { + "description": "ConflictError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConflictErrorEncoded" + } + } + } } }, - "description": "Retrieve resources and resource templates from connected MCP servers.", - "summary": "List MCP resources" + "description": "Store an integration credential. It becomes the integration's active credential unless activate is false and the integration already has one. Fails with a conflict when the requested ID already exists.", + "summary": "Create credential", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential.CreateInput" + } + } + }, + "required": true + } } }, "/api/credential/{credentialID}": { @@ -7206,7 +7141,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7265,7 +7200,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7309,7 +7244,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7398,7 +7333,7 @@ "name": "projectID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "required": true } @@ -7455,7 +7390,7 @@ "type": "object", "properties": { "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "name": { "type": "string" @@ -7658,7 +7593,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -7724,7 +7659,7 @@ "name": "id", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/PermissionSaved.ID" }, "required": true } @@ -7768,8 +7703,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -7787,8 +7721,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "effect": { "$ref": "#/components/schemas/Permission.Effect" @@ -7829,14 +7762,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -7853,8 +7779,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, { "type": "null" @@ -7885,7 +7810,7 @@ "agent": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, { "type": "null" @@ -7909,8 +7834,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -7981,8 +7905,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -7990,8 +7913,7 @@ "name": "requestID", "in": "path", "schema": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "required": true } @@ -8041,14 +7963,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" } ] } @@ -8069,8 +7988,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -8078,8 +7996,7 @@ "name": "requestID", "in": "path", "schema": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "required": true } @@ -8115,14 +8032,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" } ] } @@ -8887,7 +8801,7 @@ "$ref": "#/components/schemas/V2EventEncoded" } }, - "required": ["id", "event", "data"], + "required": ["event", "data"], "additionalProperties": false }, "x-effect-stream": { @@ -8949,7 +8863,7 @@ "errorSchema": { "not": {} }, - "failureEvent": "effect/httpapi/stream/failure" + "failureEvent": "effect/http-api/stream/failure" } } } @@ -9189,8 +9103,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9289,8 +9202,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9420,8 +9332,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9505,8 +9416,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9632,8 +9542,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9726,8 +9635,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -9817,8 +9725,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -9850,14 +9757,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -9892,8 +9792,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -9922,14 +9821,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -10083,8 +9975,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10158,8 +10049,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10243,8 +10133,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10306,8 +10195,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10383,8 +10271,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -10485,8 +10372,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -10804,8 +10690,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -10904,8 +10789,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -10979,8 +10863,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -11203,7 +11086,7 @@ "name": "projectID", "in": "query", "schema": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "required": true } @@ -11439,7 +11322,7 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" } }, "required": ["projectID"], @@ -12339,14 +12222,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -12384,7 +12260,7 @@ "type": "string" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" } }, "required": ["query"], @@ -12565,17 +12441,23 @@ }, "components": { "schemas": { + "AbsolutePath": { + "type": "string" + }, "Agent.Color": { "type": "string" }, + "Agent.ID": { + "type": "string" + }, "Agent.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Agent.Name" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -12610,6 +12492,9 @@ "required": ["id", "name", "request", "mode", "hidden", "permissions"], "additionalProperties": false }, + "Agent.Name": { + "type": "string" + }, "AgentNotFoundErrorEncoded": { "type": "object", "properties": { @@ -12680,23 +12565,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -12733,8 +12614,7 @@ "type": "boolean" }, "color": { - "type": "string", - "pattern": "^#[0-9a-fA-F]{6}$" + "type": "string" }, "steps": { "type": "integer", @@ -12764,23 +12644,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -12807,7 +12683,7 @@ "enum": ["directory"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["type", "path"], @@ -12821,7 +12697,7 @@ "enum": ["document"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "info": { "$ref": "#/components/schemas/Config.InfoEncoded" @@ -12879,23 +12755,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -13301,10 +13173,10 @@ "type": "object", "properties": { "modelID": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "family": { - "type": "string" + "$ref": "#/components/schemas/Model.Family" }, "name": { "type": "string" @@ -13336,7 +13208,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" }, "settings": { "$ref": "#/components/schemas/Config.Model.Settings" @@ -13461,7 +13333,7 @@ "type": "object", "properties": { "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "name": { "type": "string" @@ -13582,84 +13454,218 @@ "enum": ["random"], "description": "Reuse a randomly selected provider until it is rate limited, then switch to another available provider." }, + { + "$ref": "#/components/schemas/WebSearch.ID" + } + ] + } + }, + "required": ["provider"], + "additionalProperties": false + }, + "ConflictErrorEncoded": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["ConflictError"] + }, + "message": { + "type": "string" + }, + "resource": { + "anyOf": [ { "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "Connection.CredentialInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["credential"] + }, + "id": { + "$ref": "#/components/schemas/Credential.ID" + }, + "label": { + "type": "string" + }, + "method": { + "type": "string", + "enum": ["key", "oauth"] + }, + "status": { + "$ref": "#/components/schemas/Connection.Status" + } + }, + "required": ["type", "id", "label", "method"], + "additionalProperties": false + }, + "Connection.EnvInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["env"] + }, + "name": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/Connection.Status" + } + }, + "required": ["type", "name"], + "additionalProperties": false + }, + "Connection.Info": { + "anyOf": [ + { + "$ref": "#/components/schemas/Connection.CredentialInfo" + }, + { + "$ref": "#/components/schemas/Connection.EnvInfo" + } + ] + }, + "Connection.Status": { + "type": "object", + "properties": { + "status": { + "anyOf": [ + { + "type": "string", + "enum": ["needs_auth"] } ] + }, + "message": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": ["status", "message"], + "additionalProperties": false + }, + "Credential.CreateInput": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/Credential.ID" + }, + "integrationID": { + "$ref": "#/components/schemas/Integration.ID" + }, + "label": { + "type": "string" + }, + "value": { + "$ref": "#/components/schemas/Credential.Value" + }, + "activate": { + "type": "boolean" } }, - "required": ["provider"], + "required": ["integrationID", "value"], "additionalProperties": false }, - "ConflictErrorEncoded": { + "Credential.Entry": { "type": "object", "properties": { - "_tag": { - "type": "string", - "enum": ["ConflictError"] + "id": { + "$ref": "#/components/schemas/Credential.ID" }, - "message": { + "integrationID": { + "$ref": "#/components/schemas/Integration.ID" + }, + "label": { "type": "string" }, - "resource": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] + "active": { + "type": "boolean" + }, + "value": { + "$ref": "#/components/schemas/Credential.Value" } }, - "required": ["_tag", "message"], + "required": ["id", "integrationID", "label", "active", "value"], "additionalProperties": false }, - "Connection.CredentialInfo": { + "Credential.ID": { + "type": "string" + }, + "Credential.Key": { "type": "object", "properties": { "type": { "type": "string", - "enum": ["credential"] + "enum": ["key"] }, - "id": { + "key": { "type": "string" }, - "label": { - "type": "string" + "metadata": { + "type": "object" }, - "method": { - "type": "string", - "enum": ["key", "oauth"] + "configuration": { + "$ref": "#/components/schemas/Form.Answer_1" } }, - "required": ["type", "id", "label", "method"], + "required": ["type", "key"], "additionalProperties": false }, - "Connection.EnvInfo": { + "Credential.OAuth": { "type": "object", "properties": { "type": { "type": "string", - "enum": ["env"] + "enum": ["oauth"] }, - "name": { + "methodID": { + "$ref": "#/components/schemas/Integration.MethodID" + }, + "refresh": { + "type": "string" + }, + "access": { "type": "string" + }, + "expires": { + "type": "integer", + "minimum": 0 + }, + "metadata": { + "type": "object" } }, - "required": ["type", "name"], + "required": ["type", "methodID", "refresh", "access", "expires"], "additionalProperties": false }, - "Connection.Info": { + "Credential.Value": { "anyOf": [ { - "$ref": "#/components/schemas/Connection.CredentialInfo" + "$ref": "#/components/schemas/Credential.OAuth" }, { - "$ref": "#/components/schemas/Connection.EnvInfo" + "$ref": "#/components/schemas/Credential.Key" } ] }, + "Event.SeqEncoded": { + "type": "string" + }, "FileDiff.Info": { "type": "object", "properties": { @@ -13706,7 +13712,7 @@ "type": "object", "properties": { "path": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "type": { "type": "string", @@ -13720,7 +13726,7 @@ "type": "object", "properties": { "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["path"], @@ -13746,6 +13752,12 @@ "$ref": "#/components/schemas/Form.Value" } }, + "Form.Answer_1": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Form.Value" + } + }, "Form.BooleanField": { "type": "object", "properties": { @@ -13787,8 +13799,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, { "type": "null" @@ -13812,8 +13823,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "sessionID": { "type": "string" @@ -13915,12 +13925,15 @@ "$ref": "#/components/schemas/Form.Field" } }, + "Form.ID": { + "type": "string", + "pattern": "^frm_" + }, "Form.Info": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "sessionID": { "type": "string" @@ -14402,7 +14415,6 @@ }, "InstructionEntry.Key": { "type": "string", - "pattern": "^[a-z0-9][a-z0-9._-]*$", "description": "Instruction entry key (lowercase alphanumerics plus . _ -)" }, "InstructionEntryValueTooLargeErrorEncoded": { @@ -14429,7 +14441,7 @@ "type": "object", "properties": { "attemptID": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "url": { "type": "string" @@ -14474,6 +14486,9 @@ "required": ["attemptID", "url", "instructions", "mode", "time"], "additionalProperties": false }, + "Integration.AttemptID": { + "type": "string" + }, "Integration.AttemptStatus": { "anyOf": [ { @@ -14645,7 +14660,7 @@ "type": "object", "properties": { "attemptID": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "time": { "type": "object", @@ -14854,7 +14869,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "type": { "type": "string", @@ -14890,11 +14905,14 @@ "required": ["type", "names"], "additionalProperties": false }, + "Integration.ID": { + "type": "string" + }, "Integration.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "name": { "type": "string" @@ -14951,11 +14969,14 @@ } ] }, + "Integration.MethodID": { + "type": "string" + }, "Integration.OAuthMethod": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "type": { "type": "string", @@ -15080,19 +15101,19 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "project": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["id", "directory", "canonical"], @@ -15106,7 +15127,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["directory"], @@ -15343,7 +15364,7 @@ ] }, "integrationID": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" } }, "required": ["name", "status"], @@ -15533,23 +15554,29 @@ "required": ["input", "output", "cache"], "additionalProperties": false }, + "Model.Family": { + "type": "string" + }, + "Model.ID": { + "type": "string" + }, "Model.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "modelID": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "family": { - "type": "string" + "$ref": "#/components/schemas/Model.Family" }, "name": { "type": "string" @@ -15655,13 +15682,13 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "variant": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" } }, "required": ["id", "providerID"], @@ -15685,7 +15712,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" }, "settings": { "$ref": "#/components/schemas/Model.Settings" @@ -15703,16 +15730,46 @@ "required": ["id"], "additionalProperties": false }, + "Model.VariantID": { + "type": "string" + }, "Money.USD": { "type": "number" }, "Money.USDPerMillionTokens": { "type": "number" }, + "PairingCode": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "required": ["code", "expires_in"], + "additionalProperties": false + }, + "PairingSession": { + "type": "object", + "properties": { + "token": { + "type": "string" + } + }, + "required": ["token"], + "additionalProperties": false + }, "Permission.Effect": { "type": "string", "enum": ["allow", "deny", "ask"] }, + "Permission.ID": { + "type": "string", + "pattern": "^per" + }, "Permission.Reply": { "type": "string", "enum": ["once", "always", "reject"] @@ -15721,12 +15778,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "action": { "type": "string" @@ -15816,14 +15871,17 @@ "required": ["_tag", "requestID", "message"], "additionalProperties": false }, + "PermissionSaved.ID": { + "type": "string" + }, "PermissionSaved.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/PermissionSaved.ID" }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "action": { "type": "string" @@ -15922,8 +15980,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -15953,8 +16010,7 @@ "minimum": 0 }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "foregroundProcess": { "anyOf": [ @@ -16019,8 +16075,7 @@ "type": "object", "properties": { "ptyID": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -16151,11 +16206,14 @@ }, "additionalProperties": false }, + "Plugin.ID": { + "type": "string" + }, "Plugin.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Plugin.ID" }, "source": { "$ref": "#/components/schemas/Plugin.Source" @@ -16271,10 +16329,10 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "vcs": { "$ref": "#/components/schemas/Project.Vcs" @@ -16311,6 +16369,9 @@ }, "additionalProperties": false }, + "Project.ID": { + "type": "string" + }, "Project.Icon": { "type": "object", "properties": { @@ -16346,8 +16407,7 @@ "additionalProperties": false }, "Project.Vcs": { - "type": "string", - "pattern": "^[a-z][a-z0-9._-]*$" + "type": "string" }, "ProjectNotFoundErrorEncoded": { "type": "object", @@ -16380,8 +16440,7 @@ "additionalProperties": false }, "Prompt.Base64": { - "type": "string", - "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + "type": "string" }, "Prompt.FileAttachment": { "type": "object", @@ -16457,10 +16516,10 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "text": { "type": "string" @@ -16495,7 +16554,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "mention": { "$ref": "#/components/schemas/Prompt.Mention" @@ -16530,17 +16589,20 @@ } ] }, + "Provider.ID": { + "type": "string" + }, "Provider.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "integrationID": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "name": { "type": "string" @@ -16643,8 +16705,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -16677,6 +16738,10 @@ "required": ["id", "title", "command", "args", "cwd", "status", "pid"], "additionalProperties": false }, + "PtyID": { + "type": "string", + "pattern": "^pty" + }, "PtyNotFoundErrorEncoded": { "type": "object", "properties": { @@ -16732,7 +16797,7 @@ "type": "string" }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "description": { "type": "string" @@ -16755,7 +16820,7 @@ "enum": ["local"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["type", "path"], @@ -16771,6 +16836,9 @@ } ] }, + "RelativePath": { + "type": "string" + }, "Rpc.Input": { "type": "object", "properties": { @@ -16900,8 +16968,7 @@ "enum": ["before"] }, "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" } }, "required": ["type", "messageID"], @@ -16915,8 +16982,7 @@ "enum": ["through"] }, "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" } }, "required": ["type", "messageID"], @@ -16928,12 +16994,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -16960,14 +17024,9 @@ "additionalProperties": false }, "Session.Inbox.CompactionPayload": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "array" - } - ] + "not": { + "type": "null" + } }, "Session.Inbox.Delivery": { "type": "string", @@ -16993,12 +17052,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17028,10 +17085,10 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "location": { "$ref": "#/components/schemas/Location.PublicRef" @@ -17044,12 +17101,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17095,12 +17150,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17161,19 +17214,16 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "parentID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "fork": { "type": "object", "properties": { "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "boundary": { "$ref": "#/components/schemas/Session.ForkBoundary" @@ -17183,10 +17233,10 @@ "additionalProperties": false }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -17227,7 +17277,7 @@ "type": "string" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "metadata": { "$ref": "#/components/schemas/Session.Metadata" @@ -17249,8 +17299,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17270,10 +17319,10 @@ "enum": ["agent-switched"] }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "previous": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" } }, "required": ["id", "time", "type", "agent"], @@ -17283,8 +17332,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17310,7 +17358,7 @@ "enum": ["assistant"] }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -17335,15 +17383,15 @@ "type": "object", "properties": { "start": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "end": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "files": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" } } }, @@ -17518,8 +17566,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17575,8 +17622,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17620,8 +17666,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17654,12 +17699,15 @@ "required": ["type", "id", "time", "status", "reason", "summary", "recent"], "additionalProperties": false }, + "Session.Message.ID": { + "type": "string", + "pattern": "^msg_" + }, "Session.Message.Idle": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17727,8 +17775,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17748,10 +17795,10 @@ "enum": ["location-switched"] }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "location": { "$ref": "#/components/schemas/Location.PublicRef" @@ -17765,10 +17812,10 @@ "$ref": "#/components/schemas/Location.PublicRef" }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" } }, "required": ["location"], @@ -17787,8 +17834,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17839,8 +17885,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17863,8 +17908,7 @@ "enum": ["shell"] }, "shellID": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "command": { "type": "string" @@ -17913,8 +17957,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17934,10 +17977,10 @@ "enum": ["skill"] }, "skill": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "text": { "type": "string" @@ -17950,8 +17993,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17984,8 +18026,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -18110,8 +18151,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -18177,7 +18217,7 @@ "type": "object", "properties": { "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "provider": { "type": "string" @@ -18202,14 +18242,13 @@ "type": "object", "properties": { "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "partID": { "type": "string" }, "snapshot": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "files": { "type": "array", @@ -18234,6 +18273,16 @@ "type": "integer", "minimum": 100, "maximum": 599 + }, + "response": { + "type": "object", + "properties": { + "body": { + "type": "string" + } + }, + "required": ["body"], + "additionalProperties": false } }, "required": ["type", "message"], @@ -18284,6 +18333,10 @@ "required": ["data"], "additionalProperties": false }, + "SessionID": { + "type": "string", + "pattern": "^ses" + }, "SessionInterruptResponse": { "type": "object", "properties": { @@ -18584,6 +18637,9 @@ "required": ["info", "messages"], "additionalProperties": false }, + "SessionsCursor": { + "type": "string" + }, "SessionsResponse": { "type": "object", "properties": { @@ -18599,7 +18655,7 @@ "previous": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SessionsCursor" }, { "type": "null" @@ -18609,7 +18665,7 @@ "next": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SessionsCursor" }, { "type": "null" @@ -18623,12 +18679,15 @@ "required": ["data", "cursor"], "additionalProperties": false }, + "Shell.ID": { + "type": "string", + "pattern": "^sh_" + }, "Shell.Info": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "status": { "type": "string", @@ -18653,6 +18712,9 @@ "exit": { "type": "number" }, + "signal": { + "type": "string" + }, "metadata": { "type": "object" }, @@ -18691,14 +18753,17 @@ "required": ["_tag", "id", "message"], "additionalProperties": false }, + "Skill.ID": { + "type": "string" + }, "Skill.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "description": { "type": "string" @@ -18707,7 +18772,7 @@ "type": "boolean" }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "content": { "type": "string" @@ -18716,6 +18781,9 @@ "required": ["id", "name", "path", "content"], "additionalProperties": false }, + "Skill.Name": { + "type": "string" + }, "SkillNotFoundErrorEncoded": { "type": "object", "properties": { @@ -18724,7 +18792,7 @@ "enum": ["SkillNotFoundError"] }, "skill": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "message": { "type": "string" @@ -18733,6 +18801,9 @@ "required": ["_tag", "skill", "message"], "additionalProperties": false }, + "Snapshot.ID": { + "type": "string" + }, "TokenUsage.Info": { "type": "object", "properties": { @@ -18929,11 +19000,14 @@ "type": "string", "enum": ["working", "branch", "committed"] }, + "WebSearch.ID": { + "type": "string" + }, "WebSearch.Provider": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" }, "name": { "type": "string" @@ -18946,7 +19020,7 @@ "type": "object", "properties": { "providerID": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" }, "results": { "type": "array", @@ -18987,16 +19061,16 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "from": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "branch": { "type": "string" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "name": { "type": "string" @@ -19009,7 +19083,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "strategy": { "type": "string" @@ -19022,7 +19096,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["directory"], @@ -19038,10 +19112,10 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "force": { "type": "boolean" diff --git a/services/www/public/openapi.json b/services/www/public/openapi.json index e4fbd2f5d3c6..4e48ee5be66a 100644 --- a/services/www/public/openapi.json +++ b/services/www/public/openapi.json @@ -48,6 +48,99 @@ "summary": "Get server info" } }, + "/api/pair": { + "post": { + "tags": ["server"], + "operationId": "server.pair", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "PairingCode", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairingCode" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Create a short-lived, single-use code for a /auth/connect/:code pairing link.", + "summary": "Create pairing code" + } + }, + "/auth/connect/{code}": { + "get": { + "tags": ["server"], + "operationId": "server.connect", + "parameters": [ + { + "name": "code", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "security": [], + "responses": { + "200": { + "description": "PairingSession", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PairingSession" + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Redeem a pairing code. Browsers receive a session cookie and a redirect to the web app; requests that accept JSON receive a session token to use as the password.", + "summary": "Redeem pairing code" + } + }, "/api/location": { "get": { "tags": ["location"], @@ -261,7 +354,7 @@ "name": "agentID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "required": true }, @@ -505,14 +598,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -601,14 +687,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -719,8 +798,7 @@ { "anyOf": [ { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, { "type": "string", @@ -742,7 +820,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, { "type": "null" @@ -757,7 +835,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -772,7 +850,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, { "type": "null" @@ -819,9 +897,6 @@ { "$ref": "#/components/schemas/InvalidCursorErrorEncoded" }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, { "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } @@ -886,9 +961,19 @@ } } } + }, + "404": { + "description": "SessionNotFoundError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + } + } + } } }, - "description": "Create a session at the requested location.", + "description": "Create a session at the requested location. A parentID creates a linked child session at its parent's location.", "summary": "Create session", "requestBody": { "content": { @@ -899,8 +984,17 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" + }, + { + "type": "null" + } + ] + }, + "parentID": { + "anyOf": [ + { + "$ref": "#/components/schemas/SessionID" }, { "type": "null" @@ -920,7 +1014,7 @@ "agent": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, { "type": "null" @@ -1017,7 +1111,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -1082,14 +1176,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1220,8 +1307,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -1326,7 +1412,8 @@ "^ses": { "$ref": "#/components/schemas/SessionActive" } - } + }, + "additionalProperties": false } }, "required": ["data"], @@ -1369,8 +1456,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1436,8 +1522,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1489,8 +1574,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1525,14 +1609,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1594,8 +1671,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1624,14 +1700,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1652,14 +1721,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" } ] } @@ -1678,8 +1744,7 @@ "before": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -1704,8 +1769,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1740,14 +1804,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1762,7 +1819,7 @@ "type": "object", "properties": { "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" } }, "required": ["agent"], @@ -1783,8 +1840,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1819,14 +1875,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -1862,8 +1911,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1878,14 +1926,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -1920,7 +1961,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "delivery": { "anyOf": [ @@ -1951,8 +1992,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -1981,14 +2021,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -2008,14 +2041,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2042,8 +2068,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2113,8 +2138,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2150,14 +2174,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/CommandNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/CommandNotFoundErrorEncoded" } ] } @@ -2236,8 +2257,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2273,14 +2293,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/SkillNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/SkillNotFoundErrorEncoded" } ] } @@ -2297,7 +2314,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "resume": { "anyOf": [ @@ -2328,8 +2345,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2378,14 +2394,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2412,8 +2421,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2475,8 +2483,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2511,14 +2518,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2535,8 +2535,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2565,8 +2564,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2615,14 +2613,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2649,8 +2640,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -2685,8 +2675,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2721,14 +2710,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2757,8 +2739,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2811,9 +2792,6 @@ { "$ref": "#/components/schemas/MessageNotFoundErrorEncoded" }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } @@ -2852,8 +2830,7 @@ "type": "object", "properties": { "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "files": { "anyOf": [ @@ -2884,8 +2861,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -2920,14 +2896,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -2965,8 +2934,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3001,14 +2969,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3036,8 +2997,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3118,8 +3078,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3129,8 +3088,7 @@ "schema": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -3146,8 +3104,7 @@ "schema": { "anyOf": [ { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, { "type": "null" @@ -3201,14 +3158,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -3264,8 +3214,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3336,8 +3285,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3345,8 +3293,7 @@ "name": "inboxID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -3398,8 +3345,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3407,8 +3353,7 @@ "name": "inboxID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -3489,8 +3434,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3542,14 +3486,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3568,8 +3505,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3612,14 +3548,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3661,8 +3590,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3705,14 +3633,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3731,8 +3652,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -3774,14 +3694,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -3827,8 +3740,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -3838,7 +3750,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Event.SeqEncoded" }, { "type": "null" @@ -3890,7 +3802,7 @@ "$ref": "#/components/schemas/SessionLogItemEncoded" } }, - "required": ["id", "event", "data"], + "required": ["event", "data"], "additionalProperties": false }, "x-effect-stream": { @@ -3952,7 +3864,7 @@ "errorSchema": { "not": {} }, - "failureEvent": "effect/httpapi/stream/failure" + "failureEvent": "effect/http-api/stream/failure" } } } @@ -4001,8 +3913,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -4059,15 +3970,8 @@ "description": "SessionNotFoundError", "content": { "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "schema": { + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4086,8 +3990,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4122,14 +4025,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4148,8 +4044,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -4157,8 +4052,7 @@ "name": "messageID", "in": "path", "schema": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "required": true } @@ -4285,14 +4179,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4338,14 +4225,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -4365,14 +4245,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -4419,8 +4292,7 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true } @@ -4470,14 +4342,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4504,10 +4373,24 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true + }, + { + "name": "message", + "in": "query", + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "required": false } ], "security": [], @@ -4541,14 +4424,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4587,25 +4467,9 @@ "name": "formID", "in": "path", "schema": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "required": true - }, - { - "name": "message", - "in": "query", - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] - }, - "required": false } ], "security": [], @@ -4646,14 +4510,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/FormNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/FormNotFoundErrorEncoded" } ] } @@ -4694,8 +4555,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4769,8 +4629,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -4841,8 +4700,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -5206,14 +5064,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5375,7 +5226,7 @@ "name": "providerID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "required": true }, @@ -5572,7 +5423,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5710,14 +5561,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5763,7 +5607,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5808,14 +5652,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5891,7 +5728,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -5953,14 +5790,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -5985,7 +5815,7 @@ "type": "object", "properties": { "methodID": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "answer": { "anyOf": [ @@ -6026,7 +5856,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6034,7 +5864,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6140,7 +5970,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6148,7 +5978,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6222,7 +6052,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6230,7 +6060,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6275,14 +6105,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -6351,7 +6174,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6413,14 +6236,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -6462,7 +6278,7 @@ "type": "object", "properties": { "methodID": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "label": { "anyOf": [ @@ -6493,7 +6309,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6501,7 +6317,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -6607,7 +6423,7 @@ "name": "integrationID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "required": true }, @@ -6615,7 +6431,7 @@ "name": "attemptID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "required": true }, @@ -7159,14 +6975,113 @@ "schema": { "type": "object", "properties": { - "location": { - "$ref": "#/components/schemas/Location.PublicRef" - }, + "location": { + "$ref": "#/components/schemas/Location.PublicRef" + }, + "data": { + "$ref": "#/components/schemas/Mcp.ResourceCatalog" + } + }, + "required": ["location", "data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "Retrieve resources and resource templates from connected MCP servers.", + "summary": "List MCP resources" + } + }, + "/api/credential": { + "get": { + "tags": ["credential"], + "operationId": "credential.list", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Credential.Entry" + } + } + }, + "required": ["data"], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedErrorEncoded" + } + } + } + } + }, + "description": "List every stored integration credential, including its secret value.", + "summary": "List credentials" + }, + "post": { + "tags": ["credential"], + "operationId": "credential.create", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { "data": { - "$ref": "#/components/schemas/Mcp.ResourceCatalog" + "$ref": "#/components/schemas/Credential.Entry" } }, - "required": ["location", "data"], + "required": ["data"], "additionalProperties": false } } @@ -7191,10 +7106,30 @@ } } } + }, + "409": { + "description": "ConflictError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConflictErrorEncoded" + } + } + } } }, - "description": "Retrieve resources and resource templates from connected MCP servers.", - "summary": "List MCP resources" + "description": "Store an integration credential. It becomes the integration's active credential unless activate is false and the integration already has one. Fails with a conflict when the requested ID already exists.", + "summary": "Create credential", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Credential.CreateInput" + } + } + }, + "required": true + } } }, "/api/credential/{credentialID}": { @@ -7206,7 +7141,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7265,7 +7200,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7309,7 +7244,7 @@ "name": "credentialID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Credential.ID" }, "required": true } @@ -7398,7 +7333,7 @@ "name": "projectID", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "required": true } @@ -7455,7 +7390,7 @@ "type": "object", "properties": { "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "name": { "type": "string" @@ -7658,7 +7593,7 @@ "schema": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, { "type": "null" @@ -7724,7 +7659,7 @@ "name": "id", "in": "path", "schema": { - "type": "string" + "$ref": "#/components/schemas/PermissionSaved.ID" }, "required": true } @@ -7768,8 +7703,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -7787,8 +7721,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "effect": { "$ref": "#/components/schemas/Permission.Effect" @@ -7829,14 +7762,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - }, - { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" - } - ] + "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" } } } @@ -7853,8 +7779,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, { "type": "null" @@ -7885,7 +7810,7 @@ "agent": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, { "type": "null" @@ -7909,8 +7834,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -7981,8 +7905,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -7990,8 +7913,7 @@ "name": "requestID", "in": "path", "schema": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "required": true } @@ -8041,14 +7963,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" } ] } @@ -8069,8 +7988,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -8078,8 +7996,7 @@ "name": "requestID", "in": "path", "schema": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "required": true } @@ -8115,14 +8032,11 @@ "application/json": { "schema": { "anyOf": [ - { - "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" - }, { "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" }, { - "$ref": "#/components/schemas/SessionNotFoundErrorEncoded" + "$ref": "#/components/schemas/PermissionNotFoundErrorEncoded" } ] } @@ -8887,7 +8801,7 @@ "$ref": "#/components/schemas/V2EventEncoded" } }, - "required": ["id", "event", "data"], + "required": ["event", "data"], "additionalProperties": false }, "x-effect-stream": { @@ -8949,7 +8863,7 @@ "errorSchema": { "not": {} }, - "failureEvent": "effect/httpapi/stream/failure" + "failureEvent": "effect/http-api/stream/failure" } } } @@ -9189,8 +9103,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9289,8 +9202,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9420,8 +9332,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9505,8 +9416,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9632,8 +9542,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -9726,8 +9635,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true }, @@ -9817,8 +9725,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -9850,14 +9757,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -9892,8 +9792,7 @@ "name": "sessionID", "in": "path", "schema": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "required": true } @@ -9922,14 +9821,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -10083,8 +9975,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10158,8 +10049,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10243,8 +10133,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10306,8 +10195,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true } @@ -10383,8 +10271,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -10485,8 +10372,7 @@ "name": "ptyID", "in": "path", "schema": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "required": true }, @@ -10804,8 +10690,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -10904,8 +10789,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -10979,8 +10863,7 @@ "name": "id", "in": "path", "schema": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "required": true }, @@ -11203,7 +11086,7 @@ "name": "projectID", "in": "query", "schema": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "required": true } @@ -11439,7 +11322,7 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" } }, "required": ["projectID"], @@ -12339,14 +12222,7 @@ "content": { "application/json": { "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - }, - { - "$ref": "#/components/schemas/InvalidRequestErrorEncoded" - } - ] + "$ref": "#/components/schemas/InvalidRequestErrorEncoded" } } } @@ -12384,7 +12260,7 @@ "type": "string" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" } }, "required": ["query"], @@ -12565,17 +12441,23 @@ }, "components": { "schemas": { + "AbsolutePath": { + "type": "string" + }, "Agent.Color": { "type": "string" }, + "Agent.ID": { + "type": "string" + }, "Agent.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Agent.Name" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -12610,6 +12492,9 @@ "required": ["id", "name", "request", "mode", "hidden", "permissions"], "additionalProperties": false }, + "Agent.Name": { + "type": "string" + }, "AgentNotFoundErrorEncoded": { "type": "object", "properties": { @@ -12680,23 +12565,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -12733,8 +12614,7 @@ "type": "boolean" }, "color": { - "type": "string", - "pattern": "^#[0-9a-fA-F]{6}$" + "type": "string" }, "steps": { "type": "integer", @@ -12764,23 +12644,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -12807,7 +12683,7 @@ "enum": ["directory"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["type", "path"], @@ -12821,7 +12697,7 @@ "enum": ["document"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "info": { "$ref": "#/components/schemas/Config.InfoEncoded" @@ -12879,23 +12755,19 @@ "model": { "anyOf": [ { - "type": "string", - "pattern": "^[^/#]+\\/[^#]+(?:#[^#]+)?$" + "type": "string" }, { "type": "object", "properties": { "providerID": { - "type": "string", - "pattern": "^[^/#]+$" + "type": "string" }, "model": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" }, "variant": { - "type": "string", - "pattern": "^[^#]+$" + "type": "string" } }, "required": ["providerID", "model"], @@ -13301,10 +13173,10 @@ "type": "object", "properties": { "modelID": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "family": { - "type": "string" + "$ref": "#/components/schemas/Model.Family" }, "name": { "type": "string" @@ -13336,7 +13208,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" }, "settings": { "$ref": "#/components/schemas/Config.Model.Settings" @@ -13461,7 +13333,7 @@ "type": "object", "properties": { "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "name": { "type": "string" @@ -13582,84 +13454,218 @@ "enum": ["random"], "description": "Reuse a randomly selected provider until it is rate limited, then switch to another available provider." }, + { + "$ref": "#/components/schemas/WebSearch.ID" + } + ] + } + }, + "required": ["provider"], + "additionalProperties": false + }, + "ConflictErrorEncoded": { + "type": "object", + "properties": { + "_tag": { + "type": "string", + "enum": ["ConflictError"] + }, + "message": { + "type": "string" + }, + "resource": { + "anyOf": [ { "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": ["_tag", "message"], + "additionalProperties": false + }, + "Connection.CredentialInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["credential"] + }, + "id": { + "$ref": "#/components/schemas/Credential.ID" + }, + "label": { + "type": "string" + }, + "method": { + "type": "string", + "enum": ["key", "oauth"] + }, + "status": { + "$ref": "#/components/schemas/Connection.Status" + } + }, + "required": ["type", "id", "label", "method"], + "additionalProperties": false + }, + "Connection.EnvInfo": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["env"] + }, + "name": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/Connection.Status" + } + }, + "required": ["type", "name"], + "additionalProperties": false + }, + "Connection.Info": { + "anyOf": [ + { + "$ref": "#/components/schemas/Connection.CredentialInfo" + }, + { + "$ref": "#/components/schemas/Connection.EnvInfo" + } + ] + }, + "Connection.Status": { + "type": "object", + "properties": { + "status": { + "anyOf": [ + { + "type": "string", + "enum": ["needs_auth"] } ] + }, + "message": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": ["status", "message"], + "additionalProperties": false + }, + "Credential.CreateInput": { + "type": "object", + "properties": { + "id": { + "$ref": "#/components/schemas/Credential.ID" + }, + "integrationID": { + "$ref": "#/components/schemas/Integration.ID" + }, + "label": { + "type": "string" + }, + "value": { + "$ref": "#/components/schemas/Credential.Value" + }, + "activate": { + "type": "boolean" } }, - "required": ["provider"], + "required": ["integrationID", "value"], "additionalProperties": false }, - "ConflictErrorEncoded": { + "Credential.Entry": { "type": "object", "properties": { - "_tag": { - "type": "string", - "enum": ["ConflictError"] + "id": { + "$ref": "#/components/schemas/Credential.ID" }, - "message": { + "integrationID": { + "$ref": "#/components/schemas/Integration.ID" + }, + "label": { "type": "string" }, - "resource": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ] + "active": { + "type": "boolean" + }, + "value": { + "$ref": "#/components/schemas/Credential.Value" } }, - "required": ["_tag", "message"], + "required": ["id", "integrationID", "label", "active", "value"], "additionalProperties": false }, - "Connection.CredentialInfo": { + "Credential.ID": { + "type": "string" + }, + "Credential.Key": { "type": "object", "properties": { "type": { "type": "string", - "enum": ["credential"] + "enum": ["key"] }, - "id": { + "key": { "type": "string" }, - "label": { - "type": "string" + "metadata": { + "type": "object" }, - "method": { - "type": "string", - "enum": ["key", "oauth"] + "configuration": { + "$ref": "#/components/schemas/Form.Answer_1" } }, - "required": ["type", "id", "label", "method"], + "required": ["type", "key"], "additionalProperties": false }, - "Connection.EnvInfo": { + "Credential.OAuth": { "type": "object", "properties": { "type": { "type": "string", - "enum": ["env"] + "enum": ["oauth"] }, - "name": { + "methodID": { + "$ref": "#/components/schemas/Integration.MethodID" + }, + "refresh": { + "type": "string" + }, + "access": { "type": "string" + }, + "expires": { + "type": "integer", + "minimum": 0 + }, + "metadata": { + "type": "object" } }, - "required": ["type", "name"], + "required": ["type", "methodID", "refresh", "access", "expires"], "additionalProperties": false }, - "Connection.Info": { + "Credential.Value": { "anyOf": [ { - "$ref": "#/components/schemas/Connection.CredentialInfo" + "$ref": "#/components/schemas/Credential.OAuth" }, { - "$ref": "#/components/schemas/Connection.EnvInfo" + "$ref": "#/components/schemas/Credential.Key" } ] }, + "Event.SeqEncoded": { + "type": "string" + }, "FileDiff.Info": { "type": "object", "properties": { @@ -13706,7 +13712,7 @@ "type": "object", "properties": { "path": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "type": { "type": "string", @@ -13720,7 +13726,7 @@ "type": "object", "properties": { "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["path"], @@ -13746,6 +13752,12 @@ "$ref": "#/components/schemas/Form.Value" } }, + "Form.Answer_1": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Form.Value" + } + }, "Form.BooleanField": { "type": "object", "properties": { @@ -13787,8 +13799,7 @@ "id": { "anyOf": [ { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, { "type": "null" @@ -13812,8 +13823,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "sessionID": { "type": "string" @@ -13915,12 +13925,15 @@ "$ref": "#/components/schemas/Form.Field" } }, + "Form.ID": { + "type": "string", + "pattern": "^frm_" + }, "Form.Info": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^frm_" + "$ref": "#/components/schemas/Form.ID" }, "sessionID": { "type": "string" @@ -14402,7 +14415,6 @@ }, "InstructionEntry.Key": { "type": "string", - "pattern": "^[a-z0-9][a-z0-9._-]*$", "description": "Instruction entry key (lowercase alphanumerics plus . _ -)" }, "InstructionEntryValueTooLargeErrorEncoded": { @@ -14429,7 +14441,7 @@ "type": "object", "properties": { "attemptID": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "url": { "type": "string" @@ -14474,6 +14486,9 @@ "required": ["attemptID", "url", "instructions", "mode", "time"], "additionalProperties": false }, + "Integration.AttemptID": { + "type": "string" + }, "Integration.AttemptStatus": { "anyOf": [ { @@ -14645,7 +14660,7 @@ "type": "object", "properties": { "attemptID": { - "type": "string" + "$ref": "#/components/schemas/Integration.AttemptID" }, "time": { "type": "object", @@ -14854,7 +14869,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "type": { "type": "string", @@ -14890,11 +14905,14 @@ "required": ["type", "names"], "additionalProperties": false }, + "Integration.ID": { + "type": "string" + }, "Integration.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "name": { "type": "string" @@ -14951,11 +14969,14 @@ } ] }, + "Integration.MethodID": { + "type": "string" + }, "Integration.OAuthMethod": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Integration.MethodID" }, "type": { "type": "string", @@ -15080,19 +15101,19 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "project": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["id", "directory", "canonical"], @@ -15106,7 +15127,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["directory"], @@ -15343,7 +15364,7 @@ ] }, "integrationID": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" } }, "required": ["name", "status"], @@ -15533,23 +15554,29 @@ "required": ["input", "output", "cache"], "additionalProperties": false }, + "Model.Family": { + "type": "string" + }, + "Model.ID": { + "type": "string" + }, "Model.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "modelID": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "family": { - "type": "string" + "$ref": "#/components/schemas/Model.Family" }, "name": { "type": "string" @@ -15655,13 +15682,13 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.ID" }, "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "variant": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" } }, "required": ["id", "providerID"], @@ -15685,7 +15712,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Model.VariantID" }, "settings": { "$ref": "#/components/schemas/Model.Settings" @@ -15703,16 +15730,46 @@ "required": ["id"], "additionalProperties": false }, + "Model.VariantID": { + "type": "string" + }, "Money.USD": { "type": "number" }, "Money.USDPerMillionTokens": { "type": "number" }, + "PairingCode": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "expires_in": { + "type": "integer" + } + }, + "required": ["code", "expires_in"], + "additionalProperties": false + }, + "PairingSession": { + "type": "object", + "properties": { + "token": { + "type": "string" + } + }, + "required": ["token"], + "additionalProperties": false + }, "Permission.Effect": { "type": "string", "enum": ["allow", "deny", "ask"] }, + "Permission.ID": { + "type": "string", + "pattern": "^per" + }, "Permission.Reply": { "type": "string", "enum": ["once", "always", "reject"] @@ -15721,12 +15778,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^per" + "$ref": "#/components/schemas/Permission.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "action": { "type": "string" @@ -15816,14 +15871,17 @@ "required": ["_tag", "requestID", "message"], "additionalProperties": false }, + "PermissionSaved.ID": { + "type": "string" + }, "PermissionSaved.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/PermissionSaved.ID" }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "action": { "type": "string" @@ -15922,8 +15980,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -15953,8 +16010,7 @@ "minimum": 0 }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "foregroundProcess": { "anyOf": [ @@ -16019,8 +16075,7 @@ "type": "object", "properties": { "ptyID": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -16151,11 +16206,14 @@ }, "additionalProperties": false }, + "Plugin.ID": { + "type": "string" + }, "Plugin.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Plugin.ID" }, "source": { "$ref": "#/components/schemas/Plugin.Source" @@ -16271,10 +16329,10 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "vcs": { "$ref": "#/components/schemas/Project.Vcs" @@ -16311,6 +16369,9 @@ }, "additionalProperties": false }, + "Project.ID": { + "type": "string" + }, "Project.Icon": { "type": "object", "properties": { @@ -16346,8 +16407,7 @@ "additionalProperties": false }, "Project.Vcs": { - "type": "string", - "pattern": "^[a-z][a-z0-9._-]*$" + "type": "string" }, "ProjectNotFoundErrorEncoded": { "type": "object", @@ -16380,8 +16440,7 @@ "additionalProperties": false }, "Prompt.Base64": { - "type": "string", - "pattern": "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" + "type": "string" }, "Prompt.FileAttachment": { "type": "object", @@ -16457,10 +16516,10 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "text": { "type": "string" @@ -16495,7 +16554,7 @@ "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "mention": { "$ref": "#/components/schemas/Prompt.Mention" @@ -16530,17 +16589,20 @@ } ] }, + "Provider.ID": { + "type": "string" + }, "Provider.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "canonical": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "integrationID": { - "type": "string" + "$ref": "#/components/schemas/Integration.ID" }, "name": { "type": "string" @@ -16643,8 +16705,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^pty" + "$ref": "#/components/schemas/PtyID" }, "title": { "type": "string" @@ -16677,6 +16738,10 @@ "required": ["id", "title", "command", "args", "cwd", "status", "pid"], "additionalProperties": false }, + "PtyID": { + "type": "string", + "pattern": "^pty" + }, "PtyNotFoundErrorEncoded": { "type": "object", "properties": { @@ -16732,7 +16797,7 @@ "type": "string" }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "description": { "type": "string" @@ -16755,7 +16820,7 @@ "enum": ["local"] }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["type", "path"], @@ -16771,6 +16836,9 @@ } ] }, + "RelativePath": { + "type": "string" + }, "Rpc.Input": { "type": "object", "properties": { @@ -16900,8 +16968,7 @@ "enum": ["before"] }, "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" } }, "required": ["type", "messageID"], @@ -16915,8 +16982,7 @@ "enum": ["through"] }, "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" } }, "required": ["type", "messageID"], @@ -16928,12 +16994,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -16960,14 +17024,9 @@ "additionalProperties": false }, "Session.Inbox.CompactionPayload": { - "anyOf": [ - { - "type": "object" - }, - { - "type": "array" - } - ] + "not": { + "type": "null" + } }, "Session.Inbox.Delivery": { "type": "string", @@ -16993,12 +17052,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17028,10 +17085,10 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "location": { "$ref": "#/components/schemas/Location.PublicRef" @@ -17044,12 +17101,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17095,12 +17150,10 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "time": { "type": "object", @@ -17161,19 +17214,16 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "parentID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "fork": { "type": "object", "properties": { "sessionID": { - "type": "string", - "pattern": "^ses" + "$ref": "#/components/schemas/SessionID" }, "boundary": { "$ref": "#/components/schemas/Session.ForkBoundary" @@ -17183,10 +17233,10 @@ "additionalProperties": false }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -17227,7 +17277,7 @@ "type": "string" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "metadata": { "$ref": "#/components/schemas/Session.Metadata" @@ -17249,8 +17299,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17270,10 +17319,10 @@ "enum": ["agent-switched"] }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "previous": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" } }, "required": ["id", "time", "type", "agent"], @@ -17283,8 +17332,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17310,7 +17358,7 @@ "enum": ["assistant"] }, "agent": { - "type": "string" + "$ref": "#/components/schemas/Agent.ID" }, "model": { "$ref": "#/components/schemas/Model.Ref" @@ -17335,15 +17383,15 @@ "type": "object", "properties": { "start": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "end": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "files": { "type": "array", "items": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" } } }, @@ -17518,8 +17566,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17575,8 +17622,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17620,8 +17666,7 @@ "enum": ["compaction"] }, "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17654,12 +17699,15 @@ "required": ["type", "id", "time", "status", "reason", "summary", "recent"], "additionalProperties": false }, + "Session.Message.ID": { + "type": "string", + "pattern": "^msg_" + }, "Session.Message.Idle": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17727,8 +17775,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17748,10 +17795,10 @@ "enum": ["location-switched"] }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" }, "location": { "$ref": "#/components/schemas/Location.PublicRef" @@ -17765,10 +17812,10 @@ "$ref": "#/components/schemas/Location.PublicRef" }, "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "subpath": { - "type": "string" + "$ref": "#/components/schemas/RelativePath" } }, "required": ["location"], @@ -17787,8 +17834,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17839,8 +17885,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17863,8 +17908,7 @@ "enum": ["shell"] }, "shellID": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "command": { "type": "string" @@ -17913,8 +17957,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17934,10 +17977,10 @@ "enum": ["skill"] }, "skill": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "text": { "type": "string" @@ -17950,8 +17993,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -17984,8 +18026,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -18110,8 +18151,7 @@ "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "metadata": { "type": "object" @@ -18177,7 +18217,7 @@ "type": "object", "properties": { "providerID": { - "type": "string" + "$ref": "#/components/schemas/Provider.ID" }, "provider": { "type": "string" @@ -18202,14 +18242,13 @@ "type": "object", "properties": { "messageID": { - "type": "string", - "pattern": "^msg_" + "$ref": "#/components/schemas/Session.Message.ID" }, "partID": { "type": "string" }, "snapshot": { - "type": "string" + "$ref": "#/components/schemas/Snapshot.ID" }, "files": { "type": "array", @@ -18234,6 +18273,16 @@ "type": "integer", "minimum": 100, "maximum": 599 + }, + "response": { + "type": "object", + "properties": { + "body": { + "type": "string" + } + }, + "required": ["body"], + "additionalProperties": false } }, "required": ["type", "message"], @@ -18284,6 +18333,10 @@ "required": ["data"], "additionalProperties": false }, + "SessionID": { + "type": "string", + "pattern": "^ses" + }, "SessionInterruptResponse": { "type": "object", "properties": { @@ -18584,6 +18637,9 @@ "required": ["info", "messages"], "additionalProperties": false }, + "SessionsCursor": { + "type": "string" + }, "SessionsResponse": { "type": "object", "properties": { @@ -18599,7 +18655,7 @@ "previous": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SessionsCursor" }, { "type": "null" @@ -18609,7 +18665,7 @@ "next": { "anyOf": [ { - "type": "string" + "$ref": "#/components/schemas/SessionsCursor" }, { "type": "null" @@ -18623,12 +18679,15 @@ "required": ["data", "cursor"], "additionalProperties": false }, + "Shell.ID": { + "type": "string", + "pattern": "^sh_" + }, "Shell.Info": { "type": "object", "properties": { "id": { - "type": "string", - "pattern": "^sh_" + "$ref": "#/components/schemas/Shell.ID" }, "status": { "type": "string", @@ -18653,6 +18712,9 @@ "exit": { "type": "number" }, + "signal": { + "type": "string" + }, "metadata": { "type": "object" }, @@ -18691,14 +18753,17 @@ "required": ["_tag", "id", "message"], "additionalProperties": false }, + "Skill.ID": { + "type": "string" + }, "Skill.Info": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "name": { - "type": "string" + "$ref": "#/components/schemas/Skill.Name" }, "description": { "type": "string" @@ -18707,7 +18772,7 @@ "type": "boolean" }, "path": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "content": { "type": "string" @@ -18716,6 +18781,9 @@ "required": ["id", "name", "path", "content"], "additionalProperties": false }, + "Skill.Name": { + "type": "string" + }, "SkillNotFoundErrorEncoded": { "type": "object", "properties": { @@ -18724,7 +18792,7 @@ "enum": ["SkillNotFoundError"] }, "skill": { - "type": "string" + "$ref": "#/components/schemas/Skill.ID" }, "message": { "type": "string" @@ -18733,6 +18801,9 @@ "required": ["_tag", "skill", "message"], "additionalProperties": false }, + "Snapshot.ID": { + "type": "string" + }, "TokenUsage.Info": { "type": "object", "properties": { @@ -18929,11 +19000,14 @@ "type": "string", "enum": ["working", "branch", "committed"] }, + "WebSearch.ID": { + "type": "string" + }, "WebSearch.Provider": { "type": "object", "properties": { "id": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" }, "name": { "type": "string" @@ -18946,7 +19020,7 @@ "type": "object", "properties": { "providerID": { - "type": "string" + "$ref": "#/components/schemas/WebSearch.ID" }, "results": { "type": "array", @@ -18987,16 +19061,16 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "from": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "branch": { "type": "string" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "name": { "type": "string" @@ -19009,7 +19083,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "strategy": { "type": "string" @@ -19022,7 +19096,7 @@ "type": "object", "properties": { "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" } }, "required": ["directory"], @@ -19038,10 +19112,10 @@ "type": "object", "properties": { "projectID": { - "type": "string" + "$ref": "#/components/schemas/Project.ID" }, "directory": { - "type": "string" + "$ref": "#/components/schemas/AbsolutePath" }, "force": { "type": "boolean" diff --git a/services/www/src/docs/content/build/client/effect.mdx b/services/www/src/docs/content/build/client/effect.mdx index 560030d72089..75b53998f2f6 100644 --- a/services/www/src/docs/content/build/client/effect.mdx +++ b/services/www/src/docs/content/build/client/effect.mdx @@ -16,7 +16,7 @@ Create a client with the server URL, then call methods grouped by API resource. ```ts import { AbsolutePath, Location, OpenCode } from "@opencode/client/effect" import { Effect } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" const program = Effect.gen(function* () { const client = yield* OpenCode.make({ baseUrl: "http://localhost:4096" }) @@ -40,7 +40,7 @@ normal Effect interruption for cancellation. RPC methods additionally accept per-call location, header, and signal options. ```ts -import { HttpClient, HttpClientRequest } from "effect/unstable/http" +import { HttpClient, HttpClientRequest } from "effect/http" const httpClient = yield * HttpClient.HttpClient const client = @@ -123,7 +123,7 @@ import { NodeFileSystem } from "@effect/platform-node" import { OpenCode } from "@opencode/client/effect" import { Service } from "@opencode/client/effect/service" import { Effect } from "effect" -import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http" +import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http" const program = Effect.gen(function* () { const endpoint = yield* Service.ensure() diff --git a/services/www/src/docs/content/build/plugins/effect/rpc.mdx b/services/www/src/docs/content/build/plugins/effect/rpc.mdx index 51073744aed2..9234b292972b 100644 --- a/services/www/src/docs/content/build/plugins/effect/rpc.mdx +++ b/services/www/src/docs/content/build/plugins/effect/rpc.mdx @@ -122,7 +122,7 @@ Create the Effect client, then create the RPC subclient: ```ts import { OpenCode } from "@opencode/client/effect" import { Effect } from "effect" -import { FetchHttpClient } from "effect/unstable/http" +import { FetchHttpClient } from "effect/http" import { Acme } from "opencode-acme-plugin/rpc" const program = Effect.gen(function* () {