summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-10 23:06:28 -0400
committerGitHub <[email protected]>2026-04-10 23:06:28 -0400
commit9581bf06709195368bc3220294c36f3527dbc5c6 (patch)
tree3ae9b93ee3be9ac07eab9f0b80bf2b9e429f8765
parentaf8aff37889c059e38ccf2e18e10ee156bf0eea1 (diff)
downloadopencode-9581bf06709195368bc3220294c36f3527dbc5c6.tar.gz
opencode-9581bf06709195368bc3220294c36f3527dbc5c6.zip
refactor(effect): upgrade opencode to beta.46 context APIs (#21977)
-rw-r--r--bun.lock22
-rw-r--r--package.json4
-rw-r--r--packages/opencode/package.json2
-rw-r--r--packages/opencode/specs/effect-migration.md2
-rw-r--r--packages/opencode/src/account/index.ts4
-rw-r--r--packages/opencode/src/account/repo.ts4
-rw-r--r--packages/opencode/src/account/schema.ts32
-rw-r--r--packages/opencode/src/agent/agent.ts4
-rw-r--r--packages/opencode/src/auth/index.ts4
-rw-r--r--packages/opencode/src/bus/index.ts4
-rw-r--r--packages/opencode/src/command/index.ts7
-rw-r--r--packages/opencode/src/config/config.ts4
-rw-r--r--packages/opencode/src/control-plane/schema.ts3
-rw-r--r--packages/opencode/src/control-plane/workspace-context.ts4
-rw-r--r--packages/opencode/src/effect/cross-spawn-spawner.ts13
-rw-r--r--packages/opencode/src/effect/instance-ref.ts6
-rw-r--r--packages/opencode/src/effect/instance-state.ts8
-rw-r--r--packages/opencode/src/effect/run-service.ts8
-rw-r--r--packages/opencode/src/file/index.ts4
-rw-r--r--packages/opencode/src/file/ripgrep.ts4
-rw-r--r--packages/opencode/src/file/time.ts4
-rw-r--r--packages/opencode/src/file/watcher.ts4
-rw-r--r--packages/opencode/src/filesystem/index.ts4
-rw-r--r--packages/opencode/src/format/index.ts4
-rw-r--r--packages/opencode/src/git/index.ts4
-rw-r--r--packages/opencode/src/installation/index.ts4
-rw-r--r--packages/opencode/src/lsp/index.ts4
-rw-r--r--packages/opencode/src/mcp/auth.ts4
-rw-r--r--packages/opencode/src/mcp/index.ts4
-rw-r--r--packages/opencode/src/permission/index.ts4
-rw-r--r--packages/opencode/src/permission/schema.ts6
-rw-r--r--packages/opencode/src/plugin/index.ts4
-rw-r--r--packages/opencode/src/project/instance.ts4
-rw-r--r--packages/opencode/src/project/project.ts4
-rw-r--r--packages/opencode/src/project/schema.ts3
-rw-r--r--packages/opencode/src/project/vcs.ts4
-rw-r--r--packages/opencode/src/provider/auth.ts4
-rw-r--r--packages/opencode/src/provider/provider.ts4
-rw-r--r--packages/opencode/src/provider/schema.ts24
-rw-r--r--packages/opencode/src/pty/index.ts4
-rw-r--r--packages/opencode/src/pty/schema.ts3
-rw-r--r--packages/opencode/src/question/index.ts4
-rw-r--r--packages/opencode/src/question/schema.ts6
-rw-r--r--packages/opencode/src/session/compaction.ts4
-rw-r--r--packages/opencode/src/session/index.ts4
-rw-r--r--packages/opencode/src/session/instruction.ts4
-rw-r--r--packages/opencode/src/session/llm.ts4
-rw-r--r--packages/opencode/src/session/processor.ts4
-rw-r--r--packages/opencode/src/session/prompt.ts4
-rw-r--r--packages/opencode/src/session/revert.ts4
-rw-r--r--packages/opencode/src/session/run-state.ts4
-rw-r--r--packages/opencode/src/session/schema.ts9
-rw-r--r--packages/opencode/src/session/status.ts4
-rw-r--r--packages/opencode/src/session/summary.ts4
-rw-r--r--packages/opencode/src/session/todo.ts4
-rw-r--r--packages/opencode/src/share/session.ts4
-rw-r--r--packages/opencode/src/share/share-next.ts4
-rw-r--r--packages/opencode/src/skill/discovery.ts4
-rw-r--r--packages/opencode/src/skill/index.ts4
-rw-r--r--packages/opencode/src/snapshot/index.ts4
-rw-r--r--packages/opencode/src/storage/db.ts8
-rw-r--r--packages/opencode/src/storage/storage.ts4
-rw-r--r--packages/opencode/src/sync/schema.ts3
-rw-r--r--packages/opencode/src/tool/registry.ts4
-rw-r--r--packages/opencode/src/tool/schema.ts3
-rw-r--r--packages/opencode/src/tool/truncate.ts4
-rw-r--r--packages/opencode/src/util/local-context.ts (renamed from packages/opencode/src/util/context.ts)2
-rw-r--r--packages/opencode/src/util/schema.ts10
-rw-r--r--packages/opencode/src/worktree/index.ts4
-rw-r--r--packages/opencode/test/effect/instance-state.test.ts14
-rw-r--r--packages/opencode/test/effect/run-service.test.ts8
-rw-r--r--packages/opencode/test/fixture/fixture.ts4
-rw-r--r--packages/opencode/test/installation/installation.test.ts1
-rw-r--r--packages/opencode/test/lib/llm-server.ts4
-rw-r--r--packages/opencode/test/project/project.test.ts1
75 files changed, 195 insertions, 209 deletions
diff --git a/bun.lock b/bun.lock
index deeda0646..3d6bf4f0f 100644
--- a/bun.lock
+++ b/bun.lock
@@ -413,7 +413,7 @@
},
"devDependencies": {
"@babel/core": "7.28.4",
- "@effect/language-service": "0.79.0",
+ "@effect/language-service": "0.84.2",
"@octokit/webhooks-types": "7.6.1",
"@opencode-ai/script": "workspace:*",
"@parcel/watcher-darwin-arm64": "2.5.1",
@@ -641,7 +641,7 @@
},
"catalog": {
"@cloudflare/workers-types": "4.20251008.0",
- "@effect/platform-node": "4.0.0-beta.43",
+ "@effect/platform-node": "4.0.0-beta.46",
"@hono/zod-validator": "0.4.2",
"@kobalte/core": "0.13.11",
"@lydell/node-pty": "1.2.0-beta.10",
@@ -668,7 +668,7 @@
"dompurify": "3.3.1",
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
- "effect": "4.0.0-beta.43",
+ "effect": "4.0.0-beta.46",
"fuzzysort": "3.1.0",
"hono": "4.10.7",
"hono-openapi": "1.1.2",
@@ -1025,11 +1025,11 @@
"@drizzle-team/brocli": ["@drizzle-team/[email protected]", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="],
- "@effect/language-service": ["@effect/[email protected]", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-DEmIOsg1GjjP6s9HXH1oJrW+gDmzkhVv9WOZl6to5eNyyCrjz1S2PDqQ7aYrW/HuifhfwI5Bik1pK4pj7Z+lrg=="],
+ "@effect/language-service": ["@effect/[email protected]", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-l04qNxpiA8rY5yXWckRPJ7Mk5MNerXuNymSFf+IdflfI5i8jgL1bpBNLuP6ijg7wgjdHc/KmTnCj2kT0SCntuA=="],
- "@effect/platform-node": ["@effect/[email protected]", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.43", "mime": "^4.1.0", "undici": "^7.24.0" }, "peerDependencies": { "effect": "^4.0.0-beta.43", "ioredis": "^5.7.0" } }, "sha512-Uq6E1rjaIpjHauzjwoB2HzAg3battYt2Boy8XO50GoHiWCXKE6WapYZ0/AnaBx5v5qg2sOfqpuiLsUf9ZgxOkA=="],
+ "@effect/platform-node": ["@effect/[email protected]", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.46", "mime": "^4.1.0", "undici": "^7.24.0" }, "peerDependencies": { "effect": "^4.0.0-beta.46", "ioredis": "^5.7.0" } }, "sha512-6AFRKjJO95dFl5lK/YnJi04uePjQDFi3+K1aXwcz/EfVlRwJ4+lg5O4vbievfKL/hnfcShVp3/eXnNS9tvlMZQ=="],
- "@effect/platform-node-shared": ["@effect/[email protected]", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.43" } }, "sha512-A9q0GEb61pYcQ06Dr6gXj1nKlDI3KHsar1sk3qb1ZY+kVSR64tBAylI8zGon23KY+NPtTUj/sEIToB7jc3Qt5w=="],
+ "@effect/platform-node-shared": ["@effect/[email protected]", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.46" } }, "sha512-Yzci82XbZ1W3tuiownsJawrJZTGeTrTZKLD0uxdBWCBzlVyqDwoSwRwO5qh33DurJj9B7iS8MDf14fpGRBPNGQ=="],
"@electron/asar": ["@electron/[email protected]", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="],
@@ -2889,7 +2889,7 @@
"ee-first": ["[email protected]", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
- "effect": ["[email protected]", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-AJYyDimIwJOn87uUz/JzmgDc5GfjxJbXvEbTvNzMa+M3Uer344bLo/O5mMRkqc1vBleA+Ygs4+dbE3QsqOkKTQ=="],
+ "effect": ["[email protected]", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-3f6gXvvUMtEueCRY0tU76Vq2Pej1SAwwE+s0Owd5nD53yS5n4RZhUA1rlCGFuSbQFA225pGy8vO72+lpvu7u5A=="],
"ejs": ["[email protected]", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
@@ -5509,6 +5509,10 @@
"@solidjs/start/vite-plugin-solid": ["[email protected]", "", { "dependencies": { "@babel/core": "^7.23.3", "@types/babel__core": "^7.20.4", "babel-preset-solid": "^1.8.4", "merge-anything": "^5.1.7", "solid-refresh": "^0.6.3", "vitefu": "^1.0.4" }, "peerDependencies": { "@testing-library/jest-dom": "^5.16.6 || ^5.17.0 || ^6.*", "solid-js": "^1.7.2", "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["@testing-library/jest-dom"] }, "sha512-YMZCXsLw9kyuvQFEdwLP27fuTQJLmjNoHy90AOJnbRuJ6DwShUxKFo38gdFrWn9v11hnGicKCZEaeI/TFs6JKw=="],
+ "@standard-community/standard-json/effect": ["[email protected]", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-AJYyDimIwJOn87uUz/JzmgDc5GfjxJbXvEbTvNzMa+M3Uer344bLo/O5mMRkqc1vBleA+Ygs4+dbE3QsqOkKTQ=="],
+
+ "@standard-community/standard-openapi/effect": ["[email protected]", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-AJYyDimIwJOn87uUz/JzmgDc5GfjxJbXvEbTvNzMa+M3Uer344bLo/O5mMRkqc1vBleA+Ygs4+dbE3QsqOkKTQ=="],
+
"@tailwindcss/oxide/detect-libc": ["[email protected]", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/[email protected]", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
@@ -6435,6 +6439,10 @@
"@solidjs/start/shiki/@shikijs/types": ["@shikijs/[email protected]", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="],
+ "@standard-community/standard-json/effect/@standard-schema/spec": ["@standard-schema/[email protected]", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
+
+ "@standard-community/standard-openapi/effect/@standard-schema/spec": ["@standard-schema/[email protected]", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
+
"@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/[email protected]", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
"@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/[email protected]", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="],
diff --git a/package.json b/package.json
index c0d3a568f..922133b40 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
"packages/slack"
],
"catalog": {
- "@effect/platform-node": "4.0.0-beta.43",
+ "@effect/platform-node": "4.0.0-beta.46",
"@types/bun": "1.3.11",
"@types/cross-spawn": "6.0.6",
"@octokit/rest": "22.0.0",
@@ -47,7 +47,7 @@
"dompurify": "3.3.1",
"drizzle-kit": "1.0.0-beta.19-d95b7a4",
"drizzle-orm": "1.0.0-beta.19-d95b7a4",
- "effect": "4.0.0-beta.43",
+ "effect": "4.0.0-beta.46",
"ai": "6.0.149",
"cross-spawn": "7.0.6",
"hono": "4.10.7",
diff --git a/packages/opencode/package.json b/packages/opencode/package.json
index 7cce13190..9f428854a 100644
--- a/packages/opencode/package.json
+++ b/packages/opencode/package.json
@@ -43,7 +43,7 @@
},
"devDependencies": {
"@babel/core": "7.28.4",
- "@effect/language-service": "0.79.0",
+ "@effect/language-service": "0.84.2",
"@octokit/webhooks-types": "7.6.1",
"@opencode-ai/script": "workspace:*",
"@parcel/watcher-darwin-arm64": "2.5.1",
diff --git a/packages/opencode/specs/effect-migration.md b/packages/opencode/specs/effect-migration.md
index dacf55b07..8ada3f738 100644
--- a/packages/opencode/specs/effect-migration.md
+++ b/packages/opencode/specs/effect-migration.md
@@ -23,7 +23,7 @@ export namespace Foo {
readonly get: (id: FooID) => Effect.Effect<FooInfo, FooError>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Foo") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Foo") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/account/index.ts b/packages/opencode/src/account/index.ts
index 0aca85782..ad4d30863 100644
--- a/packages/opencode/src/account/index.ts
+++ b/packages/opencode/src/account/index.ts
@@ -1,4 +1,4 @@
-import { Cache, Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, ServiceMap } from "effect"
+import { Cache, Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, Context } from "effect"
import {
FetchHttpClient,
HttpClient,
@@ -181,7 +181,7 @@ export namespace Account {
readonly poll: (input: Login) => Effect.Effect<PollResult, AccountError>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Account") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Account") {}
export const layer: Layer.Layer<Service, never, AccountRepo | HttpClient.HttpClient> = Layer.effect(
Service,
diff --git a/packages/opencode/src/account/repo.ts b/packages/opencode/src/account/repo.ts
index 4dbb9cab4..b2b084c08 100644
--- a/packages/opencode/src/account/repo.ts
+++ b/packages/opencode/src/account/repo.ts
@@ -1,5 +1,5 @@
import { eq } from "drizzle-orm"
-import { Effect, Layer, Option, Schema, ServiceMap } from "effect"
+import { Effect, Layer, Option, Schema, Context } from "effect"
import { Database } from "@/storage/db"
import { AccountStateTable, AccountTable } from "./account.sql"
@@ -38,7 +38,7 @@ export namespace AccountRepo {
}
}
-export class AccountRepo extends ServiceMap.Service<AccountRepo, AccountRepo.Service>()("@opencode/AccountRepo") {
+export class AccountRepo extends Context.Service<AccountRepo, AccountRepo.Service>()("@opencode/AccountRepo") {
static readonly layer: Layer.Layer<AccountRepo> = Layer.effect(
AccountRepo,
Effect.gen(function* () {
diff --git a/packages/opencode/src/account/schema.ts b/packages/opencode/src/account/schema.ts
index f8b3c2cf9..222296ff1 100644
--- a/packages/opencode/src/account/schema.ts
+++ b/packages/opencode/src/account/schema.ts
@@ -1,42 +1,22 @@
import { Schema } from "effect"
import type * as HttpClientError from "effect/unstable/http/HttpClientError"
-import { withStatics } from "@/util/schema"
-
-export const AccountID = Schema.String.pipe(
- Schema.brand("AccountID"),
- withStatics((s) => ({ make: (id: string) => s.makeUnsafe(id) })),
-)
+export const AccountID = Schema.String.pipe(Schema.brand("AccountID"))
export type AccountID = Schema.Schema.Type<typeof AccountID>
-export const OrgID = Schema.String.pipe(
- Schema.brand("OrgID"),
- withStatics((s) => ({ make: (id: string) => s.makeUnsafe(id) })),
-)
+export const OrgID = Schema.String.pipe(Schema.brand("OrgID"))
export type OrgID = Schema.Schema.Type<typeof OrgID>
-export const AccessToken = Schema.String.pipe(
- Schema.brand("AccessToken"),
- withStatics((s) => ({ make: (token: string) => s.makeUnsafe(token) })),
-)
+export const AccessToken = Schema.String.pipe(Schema.brand("AccessToken"))
export type AccessToken = Schema.Schema.Type<typeof AccessToken>
-export const RefreshToken = Schema.String.pipe(
- Schema.brand("RefreshToken"),
- withStatics((s) => ({ make: (token: string) => s.makeUnsafe(token) })),
-)
+export const RefreshToken = Schema.String.pipe(Schema.brand("RefreshToken"))
export type RefreshToken = Schema.Schema.Type<typeof RefreshToken>
-export const DeviceCode = Schema.String.pipe(
- Schema.brand("DeviceCode"),
- withStatics((s) => ({ make: (code: string) => s.makeUnsafe(code) })),
-)
+export const DeviceCode = Schema.String.pipe(Schema.brand("DeviceCode"))
export type DeviceCode = Schema.Schema.Type<typeof DeviceCode>
-export const UserCode = Schema.String.pipe(
- Schema.brand("UserCode"),
- withStatics((s) => ({ make: (code: string) => s.makeUnsafe(code) })),
-)
+export const UserCode = Schema.String.pipe(Schema.brand("UserCode"))
export type UserCode = Schema.Schema.Type<typeof UserCode>
export class Info extends Schema.Class<Info>("Account")({
diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts
index 2a8bed092..93b393f13 100644
--- a/packages/opencode/src/agent/agent.ts
+++ b/packages/opencode/src/agent/agent.ts
@@ -19,7 +19,7 @@ import { Global } from "@/global"
import path from "path"
import { Plugin } from "@/plugin"
import { Skill } from "../skill"
-import { Effect, ServiceMap, Layer } from "effect"
+import { Effect, Context, Layer } from "effect"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
@@ -67,7 +67,7 @@ export namespace Agent {
type State = Omit<Interface, "generate">
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Agent") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Agent") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/auth/index.ts b/packages/opencode/src/auth/index.ts
index 2a9fb6c19..2e83fe287 100644
--- a/packages/opencode/src/auth/index.ts
+++ b/packages/opencode/src/auth/index.ts
@@ -1,5 +1,5 @@
import path from "path"
-import { Effect, Layer, Record, Result, Schema, ServiceMap } from "effect"
+import { Effect, Layer, Record, Result, Schema, Context } from "effect"
import { makeRuntime } from "@/effect/run-service"
import { zod } from "@/util/effect-zod"
import { Global } from "../global"
@@ -49,7 +49,7 @@ export namespace Auth {
readonly remove: (key: string) => Effect.Effect<void, AuthError>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Auth") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Auth") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/bus/index.ts b/packages/opencode/src/bus/index.ts
index 707c57c0c..0638777bd 100644
--- a/packages/opencode/src/bus/index.ts
+++ b/packages/opencode/src/bus/index.ts
@@ -1,5 +1,5 @@
import z from "zod"
-import { Effect, Exit, Layer, PubSub, Scope, ServiceMap, Stream } from "effect"
+import { Effect, Exit, Layer, PubSub, Scope, Context, Stream } from "effect"
import { EffectLogger } from "@/effect/logger"
import { Log } from "../util/log"
import { BusEvent } from "./bus-event"
@@ -42,7 +42,7 @@ export namespace Bus {
readonly subscribeAllCallback: (callback: (event: any) => unknown) => Effect.Effect<() => void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Bus") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Bus") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts
index 4c08dbbb3..0c5ef67f4 100644
--- a/packages/opencode/src/command/index.ts
+++ b/packages/opencode/src/command/index.ts
@@ -1,8 +1,9 @@
import { BusEvent } from "@/bus/bus-event"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
+import type { InstanceContext } from "@/project/instance"
import { SessionID, MessageID } from "@/session/schema"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { EffectLogger } from "@/effect/logger"
import z from "zod"
import { Config } from "../config/config"
@@ -71,7 +72,7 @@ export namespace Command {
readonly list: () => Effect.Effect<Info[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Command") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Command") {}
export const layer = Layer.effect(
Service,
@@ -80,7 +81,7 @@ export namespace Command {
const mcp = yield* MCP.Service
const skill = yield* Skill.Service
- const init = Effect.fn("Command.state")(function* (ctx) {
+ const init = Effect.fn("Command.state")(function* (ctx: InstanceContext) {
const cfg = yield* config.get()
const commands: Record<string, Info> = {}
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index eabf971f4..086d51abd 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -37,7 +37,7 @@ import type { ConsoleState } from "./console-state"
import { AppFileSystem } from "@/filesystem"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
-import { Duration, Effect, Layer, Option, ServiceMap } from "effect"
+import { Duration, Effect, Layer, Option, Context } from "effect"
import { Flock } from "@/util/flock"
import { isPathPluginSpec, parsePluginSpecifier, resolvePathPluginTarget } from "@/plugin/shared"
import { Npm } from "@/npm"
@@ -1127,7 +1127,7 @@ export namespace Config {
readonly waitForDependencies: () => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Config") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Config") {}
function globalConfigFile() {
const candidates = ["opencode.jsonc", "opencode.json", "config.json"].map((file) =>
diff --git a/packages/opencode/src/control-plane/schema.ts b/packages/opencode/src/control-plane/schema.ts
index 7618f46ad..7262a380b 100644
--- a/packages/opencode/src/control-plane/schema.ts
+++ b/packages/opencode/src/control-plane/schema.ts
@@ -10,8 +10,7 @@ export type WorkspaceID = typeof workspaceIdSchema.Type
export const WorkspaceID = workspaceIdSchema.pipe(
withStatics((schema: typeof workspaceIdSchema) => ({
- make: (id: string) => schema.makeUnsafe(id),
- ascending: (id?: string) => schema.makeUnsafe(Identifier.ascending("workspace", id)),
+ ascending: (id?: string) => schema.make(Identifier.ascending("workspace", id)),
zod: Identifier.schema("workspace").pipe(z.custom<WorkspaceID>()),
})),
)
diff --git a/packages/opencode/src/control-plane/workspace-context.ts b/packages/opencode/src/control-plane/workspace-context.ts
index 37204d17d..173ec6178 100644
--- a/packages/opencode/src/control-plane/workspace-context.ts
+++ b/packages/opencode/src/control-plane/workspace-context.ts
@@ -1,11 +1,11 @@
-import { Context } from "../util/context"
+import { LocalContext } from "../util/local-context"
import type { WorkspaceID } from "../control-plane/schema"
export interface WorkspaceContext {
workspaceID: string
}
-const context = Context.create<WorkspaceContext>("instance")
+const context = LocalContext.create<WorkspaceContext>("instance")
export const WorkspaceContext = {
async provide<R>(input: { workspaceID: WorkspaceID; fn: () => R }): Promise<R> {
diff --git a/packages/opencode/src/effect/cross-spawn-spawner.ts b/packages/opencode/src/effect/cross-spawn-spawner.ts
index 76982a613..5e25263a0 100644
--- a/packages/opencode/src/effect/cross-spawn-spawner.ts
+++ b/packages/opencode/src/effect/cross-spawn-spawner.ts
@@ -402,6 +402,7 @@ export const make = Effect.gen(function* () {
const fd = yield* setupFds(command, proc, extra)
const out = setupOutput(command, proc, sout, serr)
+ let ref = true
return makeHandle({
pid: ProcessId(proc.pid!),
stdin: yield* setupStdin(command, proc, sin),
@@ -432,6 +433,18 @@ export const make = Effect.gen(function* () {
orElse: () => send("SIGKILL").pipe(Effect.andThen(Deferred.await(signal)), Effect.asVoid),
})
},
+ unref: Effect.sync(() => {
+ if (ref) {
+ proc.unref()
+ ref = false
+ }
+ return Effect.sync(() => {
+ if (!ref) {
+ proc.ref()
+ ref = true
+ }
+ })
+ }),
})
}
case "PipedCommand": {
diff --git a/packages/opencode/src/effect/instance-ref.ts b/packages/opencode/src/effect/instance-ref.ts
index 07a510a4f..301316c77 100644
--- a/packages/opencode/src/effect/instance-ref.ts
+++ b/packages/opencode/src/effect/instance-ref.ts
@@ -1,10 +1,10 @@
-import { ServiceMap } from "effect"
+import { Context } from "effect"
import type { InstanceContext } from "@/project/instance"
-export const InstanceRef = ServiceMap.Reference<InstanceContext | undefined>("~opencode/InstanceRef", {
+export const InstanceRef = Context.Reference<InstanceContext | undefined>("~opencode/InstanceRef", {
defaultValue: () => undefined,
})
-export const WorkspaceRef = ServiceMap.Reference<string | undefined>("~opencode/WorkspaceRef", {
+export const WorkspaceRef = Context.Reference<string | undefined>("~opencode/WorkspaceRef", {
defaultValue: () => undefined,
})
diff --git a/packages/opencode/src/effect/instance-state.ts b/packages/opencode/src/effect/instance-state.ts
index a73ca17c5..b3392d156 100644
--- a/packages/opencode/src/effect/instance-state.ts
+++ b/packages/opencode/src/effect/instance-state.ts
@@ -1,7 +1,7 @@
-import { Effect, Fiber, ScopedCache, Scope, ServiceMap } from "effect"
+import { Effect, Fiber, ScopedCache, Scope, Context } from "effect"
import { EffectLogger } from "@/effect/logger"
import { Instance, type InstanceContext } from "@/project/instance"
-import { Context } from "@/util/context"
+import { LocalContext } from "@/util/local-context"
import { InstanceRef, WorkspaceRef } from "./instance-ref"
import { registerDisposer } from "./instance-registry"
import { WorkspaceContext } from "@/control-plane/workspace-context"
@@ -18,10 +18,10 @@ export namespace InstanceState {
try {
return Instance.bind(fn)
} catch (err) {
- if (!(err instanceof Context.NotFound)) throw err
+ if (!(err instanceof LocalContext.NotFound)) throw err
}
const fiber = Fiber.getCurrent()
- const ctx = fiber ? ServiceMap.getReferenceUnsafe(fiber.services, InstanceRef) : undefined
+ const ctx = fiber ? Context.getReferenceUnsafe(fiber.context, InstanceRef) : undefined
if (!ctx) return fn
return ((...args: any[]) => Instance.restore(ctx, () => fn(...args))) as F
}
diff --git a/packages/opencode/src/effect/run-service.ts b/packages/opencode/src/effect/run-service.ts
index 7dffa8cae..532278612 100644
--- a/packages/opencode/src/effect/run-service.ts
+++ b/packages/opencode/src/effect/run-service.ts
@@ -1,7 +1,7 @@
import { Effect, Layer, ManagedRuntime } from "effect"
-import * as ServiceMap from "effect/ServiceMap"
+import * as Context from "effect/Context"
import { Instance } from "@/project/instance"
-import { Context } from "@/util/context"
+import { LocalContext } from "@/util/local-context"
import { InstanceRef, WorkspaceRef } from "./instance-ref"
import { Observability } from "./oltp"
import { WorkspaceContext } from "@/control-plane/workspace-context"
@@ -14,12 +14,12 @@ export function attach<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A
const workspaceID = WorkspaceContext.workspaceID
return effect.pipe(Effect.provideService(InstanceRef, ctx), Effect.provideService(WorkspaceRef, workspaceID))
} catch (err) {
- if (!(err instanceof Context.NotFound)) throw err
+ if (!(err instanceof LocalContext.NotFound)) throw err
}
return effect
}
-export function makeRuntime<I, S, E>(service: ServiceMap.Service<I, S>, layer: Layer.Layer<I, E>) {
+export function makeRuntime<I, S, E>(service: Context.Service<I, S>, layer: Layer.Layer<I, E>) {
let rt: ManagedRuntime.ManagedRuntime<I, E> | undefined
const getRuntime = () => (rt ??= ManagedRuntime.make(Layer.merge(layer, Observability.layer), { memoMap }))
diff --git a/packages/opencode/src/file/index.ts b/packages/opencode/src/file/index.ts
index 47d15fbb0..80ed2b7ef 100644
--- a/packages/opencode/src/file/index.ts
+++ b/packages/opencode/src/file/index.ts
@@ -3,7 +3,7 @@ import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
import { AppFileSystem } from "@/filesystem"
import { Git } from "@/git"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { formatPatch, structuredPatch } from "diff"
import fuzzysort from "fuzzysort"
import ignore from "ignore"
@@ -337,7 +337,7 @@ export namespace File {
}) => Effect.Effect<string[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/File") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/File") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts
index 4f02c97b1..4d0fc5598 100644
--- a/packages/opencode/src/file/ripgrep.ts
+++ b/packages/opencode/src/file/ripgrep.ts
@@ -3,7 +3,7 @@ import path from "path"
import { Global } from "../global"
import fs from "fs/promises"
import z from "zod"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import * as Stream from "effect/Stream"
import { ChildProcess } from "effect/unstable/process"
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
@@ -291,7 +291,7 @@ export namespace Ripgrep {
}) => Stream.Stream<string, PlatformError>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Ripgrep") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Ripgrep") {}
export const layer: Layer.Layer<Service, never, ChildProcessSpawner | AppFileSystem.Service> = Layer.effect(
Service,
diff --git a/packages/opencode/src/file/time.ts b/packages/opencode/src/file/time.ts
index 6af71e91a..05a70f80e 100644
--- a/packages/opencode/src/file/time.ts
+++ b/packages/opencode/src/file/time.ts
@@ -1,4 +1,4 @@
-import { DateTime, Effect, Layer, Option, Semaphore, ServiceMap } from "effect"
+import { DateTime, Effect, Layer, Option, Semaphore, Context } from "effect"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
import { AppFileSystem } from "@/filesystem"
@@ -37,7 +37,7 @@ export namespace FileTime {
readonly withLock: <T>(filepath: string, fn: () => Effect.Effect<T>) => Effect.Effect<T>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/FileTime") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/FileTime") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/file/watcher.ts b/packages/opencode/src/file/watcher.ts
index dd8b5798c..609543fb0 100644
--- a/packages/opencode/src/file/watcher.ts
+++ b/packages/opencode/src/file/watcher.ts
@@ -1,4 +1,4 @@
-import { Cause, Effect, Layer, Scope, ServiceMap } from "effect"
+import { Cause, Effect, Layer, Scope, Context } from "effect"
// @ts-ignore
import { createWrapper } from "@parcel/watcher/wrapper"
import type ParcelWatcher from "@parcel/watcher"
@@ -65,7 +65,7 @@ export namespace FileWatcher {
readonly init: () => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/FileWatcher") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/FileWatcher") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/filesystem/index.ts b/packages/opencode/src/filesystem/index.ts
index 01fdcd2e5..2c3964ec2 100644
--- a/packages/opencode/src/filesystem/index.ts
+++ b/packages/opencode/src/filesystem/index.ts
@@ -3,7 +3,7 @@ import { dirname, join, relative, resolve as pathResolve } from "path"
import { realpathSync } from "fs"
import * as NFS from "fs/promises"
import { lookup } from "mime-types"
-import { Effect, FileSystem, Layer, Schema, ServiceMap } from "effect"
+import { Effect, FileSystem, Layer, Schema, Context } from "effect"
import type { PlatformError } from "effect/PlatformError"
import { Glob } from "../util/glob"
@@ -36,7 +36,7 @@ export namespace AppFileSystem {
readonly globMatch: (pattern: string, filepath: string) => boolean
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/FileSystem") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/FileSystem") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/format/index.ts b/packages/opencode/src/format/index.ts
index 56df63cf9..36844d351 100644
--- a/packages/opencode/src/format/index.ts
+++ b/packages/opencode/src/format/index.ts
@@ -1,4 +1,4 @@
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
import { InstanceState } from "@/effect/instance-state"
@@ -31,7 +31,7 @@ export namespace Format {
readonly file: (filepath: string) => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Format") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Format") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/git/index.ts b/packages/opencode/src/git/index.ts
index 10c96d560..de84fdd74 100644
--- a/packages/opencode/src/git/index.ts
+++ b/packages/opencode/src/git/index.ts
@@ -1,5 +1,5 @@
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
-import { Effect, Layer, ServiceMap, Stream } from "effect"
+import { Effect, Layer, Context, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { makeRuntime } from "@/effect/run-service"
@@ -80,7 +80,7 @@ export namespace Git {
return "modified"
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Git") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Git") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts
index f4cd4d09f..06b673217 100644
--- a/packages/opencode/src/installation/index.ts
+++ b/packages/opencode/src/installation/index.ts
@@ -1,4 +1,4 @@
-import { Effect, Layer, Schema, ServiceMap, Stream } from "effect"
+import { Effect, Layer, Schema, Context, Stream } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
import { makeRuntime } from "@/effect/run-service"
@@ -91,7 +91,7 @@ export namespace Installation {
readonly upgrade: (method: Method, target: string) => Effect.Effect<void, UpgradeFailedError>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Installation") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Installation") {}
export const layer: Layer.Layer<Service, never, HttpClient.HttpClient | ChildProcessSpawner.ChildProcessSpawner> =
Layer.effect(
diff --git a/packages/opencode/src/lsp/index.ts b/packages/opencode/src/lsp/index.ts
index 793a4475d..8e34a8854 100644
--- a/packages/opencode/src/lsp/index.ts
+++ b/packages/opencode/src/lsp/index.ts
@@ -11,7 +11,7 @@ import { Instance } from "../project/instance"
import { Flag } from "@/flag/flag"
import { Process } from "../util/process"
import { spawn as lspspawn } from "./launch"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
@@ -156,7 +156,7 @@ export namespace LSP {
readonly outgoingCalls: (input: LocInput) => Effect.Effect<any[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/LSP") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/LSP") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/mcp/auth.ts b/packages/opencode/src/mcp/auth.ts
index e9c3db8a9..7f33f32b8 100644
--- a/packages/opencode/src/mcp/auth.ts
+++ b/packages/opencode/src/mcp/auth.ts
@@ -1,7 +1,7 @@
import path from "path"
import z from "zod"
import { Global } from "../global"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { AppFileSystem } from "@/filesystem"
import { makeRuntime } from "@/effect/run-service"
@@ -49,7 +49,7 @@ export namespace McpAuth {
readonly isTokenExpired: (mcpName: string) => Effect.Effect<boolean | null>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/McpAuth") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/McpAuth") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts
index c175ea19e..696a662c1 100644
--- a/packages/opencode/src/mcp/index.ts
+++ b/packages/opencode/src/mcp/index.ts
@@ -24,7 +24,7 @@ import { BusEvent } from "../bus/bus-event"
import { Bus } from "@/bus"
import { TuiEvent } from "@/cli/cmd/tui/event"
import open from "open"
-import { Effect, Exit, Layer, Option, ServiceMap, Stream } from "effect"
+import { Effect, Exit, Layer, Option, Context, Stream } from "effect"
import { EffectLogger } from "@/effect/logger"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
@@ -240,7 +240,7 @@ export namespace MCP {
readonly getAuthStatus: (mcpName: string) => Effect.Effect<AuthStatus>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/MCP") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/MCP") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts
index b2cc0f9bb..a45aaf59d 100644
--- a/packages/opencode/src/permission/index.ts
+++ b/packages/opencode/src/permission/index.ts
@@ -10,7 +10,7 @@ import { PermissionTable } from "@/session/session.sql"
import { Database, eq } from "@/storage/db"
import { Log } from "@/util/log"
import { Wildcard } from "@/util/wildcard"
-import { Deferred, Effect, Layer, Schema, ServiceMap } from "effect"
+import { Deferred, Effect, Layer, Schema, Context } from "effect"
import os from "os"
import z from "zod"
import { evaluate as evalRule } from "./evaluate"
@@ -135,7 +135,7 @@ export namespace Permission {
return evalRule(permission, pattern, ...rulesets)
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Permission") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Permission") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/permission/schema.ts b/packages/opencode/src/permission/schema.ts
index bfa2b4957..2f1190a23 100644
--- a/packages/opencode/src/permission/schema.ts
+++ b/packages/opencode/src/permission/schema.ts
@@ -5,12 +5,8 @@ import { Identifier } from "@/id/id"
import { Newtype } from "@/util/schema"
export class PermissionID extends Newtype<PermissionID>()("PermissionID", Schema.String) {
- static make(id: string): PermissionID {
- return this.makeUnsafe(id)
- }
-
static ascending(id?: string): PermissionID {
- return this.makeUnsafe(Identifier.ascending("permission", id))
+ return this.make(Identifier.ascending("permission", id))
}
static readonly zod = Identifier.schema("permission") as unknown as z.ZodType<PermissionID>
diff --git a/packages/opencode/src/plugin/index.ts b/packages/opencode/src/plugin/index.ts
index ae75bc6a1..5de77aee3 100644
--- a/packages/opencode/src/plugin/index.ts
+++ b/packages/opencode/src/plugin/index.ts
@@ -11,7 +11,7 @@ import { CopilotAuthPlugin } from "./github-copilot/copilot"
import { gitlabAuthPlugin as GitlabAuthPlugin } from "opencode-gitlab-auth"
import { PoeAuthPlugin } from "opencode-poe-auth"
import { CloudflareAIGatewayAuthPlugin, CloudflareWorkersAuthPlugin } from "./cloudflare"
-import { Effect, Layer, ServiceMap, Stream } from "effect"
+import { Effect, Layer, Context, Stream } from "effect"
import { EffectLogger } from "@/effect/logger"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
@@ -45,7 +45,7 @@ export namespace Plugin {
readonly init: () => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Plugin") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Plugin") {}
// Built-in plugins that are directly imported (not installed from npm)
const INTERNAL_PLUGINS: PluginInstance[] = [
diff --git a/packages/opencode/src/project/instance.ts b/packages/opencode/src/project/instance.ts
index 60665a99a..8d2d51db6 100644
--- a/packages/opencode/src/project/instance.ts
+++ b/packages/opencode/src/project/instance.ts
@@ -3,7 +3,7 @@ import { disposeInstance } from "@/effect/instance-registry"
import { Filesystem } from "@/util/filesystem"
import { iife } from "@/util/iife"
import { Log } from "@/util/log"
-import { Context } from "../util/context"
+import { LocalContext } from "../util/local-context"
import { Project } from "./project"
import { WorkspaceContext } from "@/control-plane/workspace-context"
import { State } from "./state"
@@ -14,7 +14,7 @@ export interface InstanceContext {
project: Project.Info
}
-const context = Context.create<InstanceContext>("instance")
+const context = LocalContext.create<InstanceContext>("instance")
const cache = new Map<string, Promise<InstanceContext>>()
const disposal = {
diff --git a/packages/opencode/src/project/project.ts b/packages/opencode/src/project/project.ts
index 8db8df5d5..df07ca221 100644
--- a/packages/opencode/src/project/project.ts
+++ b/packages/opencode/src/project/project.ts
@@ -8,7 +8,7 @@ import { BusEvent } from "@/bus/bus-event"
import { GlobalBus } from "@/bus/global"
import { which } from "../util/which"
import { ProjectID } from "./schema"
-import { Effect, Layer, Path, Scope, ServiceMap, Stream } from "effect"
+import { Effect, Layer, Path, Scope, Context, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { NodeFileSystem, NodePath } from "@effect/platform-node"
import { makeRuntime } from "@/effect/run-service"
@@ -100,7 +100,7 @@ export namespace Project {
readonly removeSandbox: (id: ProjectID, directory: string) => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Project") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Project") {}
type GitResult = { code: number; text: string; stderr: string }
diff --git a/packages/opencode/src/project/schema.ts b/packages/opencode/src/project/schema.ts
index e904ff5a8..d10c82e2c 100644
--- a/packages/opencode/src/project/schema.ts
+++ b/packages/opencode/src/project/schema.ts
@@ -9,8 +9,7 @@ export type ProjectID = typeof projectIdSchema.Type
export const ProjectID = projectIdSchema.pipe(
withStatics((schema: typeof projectIdSchema) => ({
- global: schema.makeUnsafe("global"),
- make: (id: string) => schema.makeUnsafe(id),
+ global: schema.make("global"),
zod: z.string().pipe(z.custom<ProjectID>()),
})),
)
diff --git a/packages/opencode/src/project/vcs.ts b/packages/opencode/src/project/vcs.ts
index 0e430d41b..1b1f21f90 100644
--- a/packages/opencode/src/project/vcs.ts
+++ b/packages/opencode/src/project/vcs.ts
@@ -1,4 +1,4 @@
-import { Effect, Layer, ServiceMap, Stream } from "effect"
+import { Effect, Layer, Context, Stream } from "effect"
import { formatPatch, structuredPatch } from "diff"
import path from "path"
import { Bus } from "@/bus"
@@ -151,7 +151,7 @@ export namespace Vcs {
root: Git.Base | undefined
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Vcs") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Vcs") {}
export const layer: Layer.Layer<Service, never, AppFileSystem.Service | Git.Service | Bus.Service> = Layer.effect(
Service,
diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts
index 38ef4b11f..3823baf13 100644
--- a/packages/opencode/src/provider/auth.ts
+++ b/packages/opencode/src/provider/auth.ts
@@ -5,7 +5,7 @@ import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
import { Plugin } from "../plugin"
import { ProviderID } from "./schema"
-import { Array as Arr, Effect, Layer, Record, Result, ServiceMap } from "effect"
+import { Array as Arr, Effect, Layer, Record, Result, Context } from "effect"
import z from "zod"
export namespace ProviderAuth {
@@ -109,7 +109,7 @@ export namespace ProviderAuth {
pending: Map<ProviderID, AuthOAuthResult>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/ProviderAuth") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/ProviderAuth") {}
export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> = Layer.effect(
Service,
diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts
index 858306b62..e401a067c 100644
--- a/packages/opencode/src/provider/provider.ts
+++ b/packages/opencode/src/provider/provider.ts
@@ -19,7 +19,7 @@ import { iife } from "@/util/iife"
import { Global } from "../global"
import path from "path"
import { Filesystem } from "../util/filesystem"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { EffectLogger } from "@/effect/logger"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
@@ -925,7 +925,7 @@ export namespace Provider {
varsLoaders: Record<string, CustomVarsLoader>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Provider") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Provider") {}
function cost(c: ModelsDev.Model["cost"]): Model["cost"] {
const result: Model["cost"] = {
diff --git a/packages/opencode/src/provider/schema.ts b/packages/opencode/src/provider/schema.ts
index 71c8a1029..4490ca289 100644
--- a/packages/opencode/src/provider/schema.ts
+++ b/packages/opencode/src/provider/schema.ts
@@ -9,20 +9,19 @@ export type ProviderID = typeof providerIdSchema.Type
export const ProviderID = providerIdSchema.pipe(
withStatics((schema: typeof providerIdSchema) => ({
- make: (id: string) => schema.makeUnsafe(id),
zod: z.string().pipe(z.custom<ProviderID>()),
// Well-known providers
- opencode: schema.makeUnsafe("opencode"),
- anthropic: schema.makeUnsafe("anthropic"),
- openai: schema.makeUnsafe("openai"),
- google: schema.makeUnsafe("google"),
- googleVertex: schema.makeUnsafe("google-vertex"),
- githubCopilot: schema.makeUnsafe("github-copilot"),
- amazonBedrock: schema.makeUnsafe("amazon-bedrock"),
- azure: schema.makeUnsafe("azure"),
- openrouter: schema.makeUnsafe("openrouter"),
- mistral: schema.makeUnsafe("mistral"),
- gitlab: schema.makeUnsafe("gitlab"),
+ opencode: schema.make("opencode"),
+ anthropic: schema.make("anthropic"),
+ openai: schema.make("openai"),
+ google: schema.make("google"),
+ googleVertex: schema.make("google-vertex"),
+ githubCopilot: schema.make("github-copilot"),
+ amazonBedrock: schema.make("amazon-bedrock"),
+ azure: schema.make("azure"),
+ openrouter: schema.make("openrouter"),
+ mistral: schema.make("mistral"),
+ gitlab: schema.make("gitlab"),
})),
)
@@ -32,7 +31,6 @@ export type ModelID = typeof modelIdSchema.Type
export const ModelID = modelIdSchema.pipe(
withStatics((schema: typeof modelIdSchema) => ({
- make: (id: string) => schema.makeUnsafe(id),
zod: z.string().pipe(z.custom<ModelID>()),
})),
)
diff --git a/packages/opencode/src/pty/index.ts b/packages/opencode/src/pty/index.ts
index 0358c72e8..a563bb954 100644
--- a/packages/opencode/src/pty/index.ts
+++ b/packages/opencode/src/pty/index.ts
@@ -10,7 +10,7 @@ import { lazy } from "@opencode-ai/util/lazy"
import { Shell } from "@/shell/shell"
import { Plugin } from "@/plugin"
import { PtyID } from "./schema"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { EffectLogger } from "@/effect/logger"
export namespace Pty {
@@ -113,7 +113,7 @@ export namespace Pty {
) => Effect.Effect<{ onMessage: (message: string | ArrayBuffer) => void; onClose: () => void } | undefined>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Pty") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Pty") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/pty/schema.ts b/packages/opencode/src/pty/schema.ts
index 47b3196f0..deb498891 100644
--- a/packages/opencode/src/pty/schema.ts
+++ b/packages/opencode/src/pty/schema.ts
@@ -10,8 +10,7 @@ export type PtyID = typeof ptyIdSchema.Type
export const PtyID = ptyIdSchema.pipe(
withStatics((schema: typeof ptyIdSchema) => ({
- make: (id: string) => schema.makeUnsafe(id),
- ascending: (id?: string) => schema.makeUnsafe(Identifier.ascending("pty", id)),
+ ascending: (id?: string) => schema.make(Identifier.ascending("pty", id)),
zod: Identifier.schema("pty").pipe(z.custom<PtyID>()),
})),
)
diff --git a/packages/opencode/src/question/index.ts b/packages/opencode/src/question/index.ts
index 615c699ce..ca83bb7b2 100644
--- a/packages/opencode/src/question/index.ts
+++ b/packages/opencode/src/question/index.ts
@@ -1,4 +1,4 @@
-import { Deferred, Effect, Layer, Schema, ServiceMap } from "effect"
+import { Deferred, Effect, Layer, Schema, Context } from "effect"
import { Bus } from "@/bus"
import { BusEvent } from "@/bus/bus-event"
import { InstanceState } from "@/effect/instance-state"
@@ -104,7 +104,7 @@ export namespace Question {
readonly list: () => Effect.Effect<Request[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Question") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Question") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/question/schema.ts b/packages/opencode/src/question/schema.ts
index 38b930af1..e5a0496c9 100644
--- a/packages/opencode/src/question/schema.ts
+++ b/packages/opencode/src/question/schema.ts
@@ -5,12 +5,8 @@ import { Identifier } from "@/id/id"
import { Newtype } from "@/util/schema"
export class QuestionID extends Newtype<QuestionID>()("QuestionID", Schema.String) {
- static make(id: string): QuestionID {
- return this.makeUnsafe(id)
- }
-
static ascending(id?: string): QuestionID {
- return this.makeUnsafe(Identifier.ascending("question", id))
+ return this.make(Identifier.ascending("question", id))
}
static readonly zod = Identifier.schema("question") as unknown as z.ZodType<QuestionID>
diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts
index 937aa7132..b280971c7 100644
--- a/packages/opencode/src/session/compaction.ts
+++ b/packages/opencode/src/session/compaction.ts
@@ -15,7 +15,7 @@ import { Plugin } from "@/plugin"
import { Config } from "@/config/config"
import { NotFoundError } from "@/storage/db"
import { ModelID, ProviderID } from "@/provider/schema"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { makeRuntime } from "@/effect/run-service"
import { InstanceState } from "@/effect/instance-state"
import { isOverflow as overflow } from "./overflow"
@@ -58,7 +58,7 @@ export namespace SessionCompaction {
}) => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionCompaction") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionCompaction") {}
export const layer: Layer.Layer<
Service,
diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts
index ba073cb1a..d28a1988d 100644
--- a/packages/opencode/src/session/index.ts
+++ b/packages/opencode/src/session/index.ts
@@ -29,7 +29,7 @@ import type { Provider } from "@/provider/provider"
import { Permission } from "@/permission"
import { Global } from "@/global"
import type { LanguageModelV2Usage } from "@ai-sdk/provider"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { makeRuntime } from "@/effect/run-service"
export namespace Session {
@@ -354,7 +354,7 @@ export namespace Session {
}) => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Session") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Session") {}
type Patch = z.infer<typeof Event.Updated.schema>["info"]
diff --git a/packages/opencode/src/session/instruction.ts b/packages/opencode/src/session/instruction.ts
index fc90093e9..9b01c9524 100644
--- a/packages/opencode/src/session/instruction.ts
+++ b/packages/opencode/src/session/instruction.ts
@@ -1,6 +1,6 @@
import os from "os"
import path from "path"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http"
import { Config } from "@/config/config"
import { InstanceState } from "@/effect/instance-state"
@@ -64,7 +64,7 @@ export namespace Instruction {
) => Effect.Effect<{ filepath: string; content: string }[], AppFileSystem.Error>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Instruction") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Instruction") {}
export const layer: Layer.Layer<Service, never, AppFileSystem.Service | Config.Service | HttpClient.HttpClient> =
Layer.effect(
diff --git a/packages/opencode/src/session/llm.ts b/packages/opencode/src/session/llm.ts
index 22fc9b1d5..f6e5c9a3f 100644
--- a/packages/opencode/src/session/llm.ts
+++ b/packages/opencode/src/session/llm.ts
@@ -1,6 +1,6 @@
import { Provider } from "@/provider/provider"
import { Log } from "@/util/log"
-import { Cause, Effect, Layer, Record, ServiceMap } from "effect"
+import { Cause, Effect, Layer, Record, Context } from "effect"
import * as Queue from "effect/Queue"
import * as Stream from "effect/Stream"
import { streamText, wrapLanguageModel, type ModelMessage, type Tool, tool, jsonSchema } from "ai"
@@ -51,7 +51,7 @@ export namespace LLM {
readonly stream: (input: StreamInput) => Stream.Stream<Event, unknown>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/LLM") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/LLM") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts
index d507eb675..be0977c1d 100644
--- a/packages/opencode/src/session/processor.ts
+++ b/packages/opencode/src/session/processor.ts
@@ -1,4 +1,4 @@
-import { Cause, Deferred, Effect, Layer, ServiceMap } from "effect"
+import { Cause, Deferred, Effect, Layer, Context } from "effect"
import * as Stream from "effect/Stream"
import { Agent } from "@/agent/agent"
import { Bus } from "@/bus"
@@ -76,7 +76,7 @@ export namespace SessionProcessor {
type StreamEvent = Event
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionProcessor") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionProcessor") {}
export const layer: Layer.Layer<
Service,
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index a1bdcb1b9..384147a12 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -43,7 +43,7 @@ import { AppFileSystem } from "@/filesystem"
import { Truncate } from "@/tool/truncate"
import { decodeDataUrl } from "@/util/data-url"
import { Process } from "@/util/process"
-import { Cause, Effect, Exit, Layer, Option, Scope, ServiceMap } from "effect"
+import { Cause, Effect, Exit, Layer, Option, Scope, Context } from "effect"
import { EffectLogger } from "@/effect/logger"
import { InstanceState } from "@/effect/instance-state"
import { makeRuntime } from "@/effect/run-service"
@@ -76,7 +76,7 @@ export namespace SessionPrompt {
readonly resolvePromptParts: (template: string) => Effect.Effect<PromptInput["parts"]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionPrompt") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionPrompt") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/session/revert.ts b/packages/opencode/src/session/revert.ts
index 1216362ca..416b8555d 100644
--- a/packages/opencode/src/session/revert.ts
+++ b/packages/opencode/src/session/revert.ts
@@ -1,5 +1,5 @@
import z from "zod"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { makeRuntime } from "@/effect/run-service"
import { Bus } from "../bus"
import { Snapshot } from "../snapshot"
@@ -29,7 +29,7 @@ export namespace SessionRevert {
readonly cleanup: (session: Session.Info) => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionRevert") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionRevert") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/session/run-state.ts b/packages/opencode/src/session/run-state.ts
index 3c2022bd0..2c570f520 100644
--- a/packages/opencode/src/session/run-state.ts
+++ b/packages/opencode/src/session/run-state.ts
@@ -1,7 +1,7 @@
import { InstanceState } from "@/effect/instance-state"
import { Runner } from "@/effect/runner"
import { makeRuntime } from "@/effect/run-service"
-import { Effect, Layer, Scope, ServiceMap } from "effect"
+import { Effect, Layer, Scope, Context } from "effect"
import { Session } from "."
import { MessageV2 } from "./message-v2"
import { SessionID } from "./schema"
@@ -23,7 +23,7 @@ export namespace SessionRunState {
) => Effect.Effect<MessageV2.WithParts>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionRunState") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionRunState") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/session/schema.ts b/packages/opencode/src/session/schema.ts
index 540643c49..856ab3114 100644
--- a/packages/opencode/src/session/schema.ts
+++ b/packages/opencode/src/session/schema.ts
@@ -7,8 +7,7 @@ import { withStatics } from "@/util/schema"
export const SessionID = Schema.String.pipe(
Schema.brand("SessionID"),
withStatics((s) => ({
- make: (id: string) => s.makeUnsafe(id),
- descending: (id?: string) => s.makeUnsafe(Identifier.descending("session", id)),
+ descending: (id?: string) => s.make(Identifier.descending("session", id)),
zod: Identifier.schema("session").pipe(z.custom<Schema.Schema.Type<typeof s>>()),
})),
)
@@ -18,8 +17,7 @@ export type SessionID = Schema.Schema.Type<typeof SessionID>
export const MessageID = Schema.String.pipe(
Schema.brand("MessageID"),
withStatics((s) => ({
- make: (id: string) => s.makeUnsafe(id),
- ascending: (id?: string) => s.makeUnsafe(Identifier.ascending("message", id)),
+ ascending: (id?: string) => s.make(Identifier.ascending("message", id)),
zod: Identifier.schema("message").pipe(z.custom<Schema.Schema.Type<typeof s>>()),
})),
)
@@ -29,8 +27,7 @@ export type MessageID = Schema.Schema.Type<typeof MessageID>
export const PartID = Schema.String.pipe(
Schema.brand("PartID"),
withStatics((s) => ({
- make: (id: string) => s.makeUnsafe(id),
- ascending: (id?: string) => s.makeUnsafe(Identifier.ascending("part", id)),
+ ascending: (id?: string) => s.make(Identifier.ascending("part", id)),
zod: Identifier.schema("part").pipe(z.custom<Schema.Schema.Type<typeof s>>()),
})),
)
diff --git a/packages/opencode/src/session/status.ts b/packages/opencode/src/session/status.ts
index d54d8b795..5800cb732 100644
--- a/packages/opencode/src/session/status.ts
+++ b/packages/opencode/src/session/status.ts
@@ -2,7 +2,7 @@ import { BusEvent } from "@/bus/bus-event"
import { Bus } from "@/bus"
import { InstanceState } from "@/effect/instance-state"
import { SessionID } from "./schema"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import z from "zod"
export namespace SessionStatus {
@@ -49,7 +49,7 @@ export namespace SessionStatus {
readonly set: (sessionID: SessionID, status: Info) => Effect.Effect<void>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionStatus") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionStatus") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/session/summary.ts b/packages/opencode/src/session/summary.ts
index 2f07a0f5d..498288d61 100644
--- a/packages/opencode/src/session/summary.ts
+++ b/packages/opencode/src/session/summary.ts
@@ -1,5 +1,5 @@
import z from "zod"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { makeRuntime } from "@/effect/run-service"
import { Bus } from "@/bus"
import { Snapshot } from "@/snapshot"
@@ -71,7 +71,7 @@ export namespace SessionSummary {
readonly computeDiff: (input: { messages: MessageV2.WithParts[] }) => Effect.Effect<Snapshot.FileDiff[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionSummary") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionSummary") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts
index a7aa49aa3..1fd9cbaa5 100644
--- a/packages/opencode/src/session/todo.ts
+++ b/packages/opencode/src/session/todo.ts
@@ -1,7 +1,7 @@
import { BusEvent } from "@/bus/bus-event"
import { Bus } from "@/bus"
import { SessionID } from "./schema"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import z from "zod"
import { Database, eq, asc } from "../storage/db"
import { TodoTable } from "./session.sql"
@@ -31,7 +31,7 @@ export namespace Todo {
readonly get: (sessionID: SessionID) => Effect.Effect<Info[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionTodo") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionTodo") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/share/session.ts b/packages/opencode/src/share/session.ts
index 1446b5bb4..f98bf14cb 100644
--- a/packages/opencode/src/share/session.ts
+++ b/packages/opencode/src/share/session.ts
@@ -3,7 +3,7 @@ import { Session } from "@/session"
import { SessionID } from "@/session/schema"
import { SyncEvent } from "@/sync"
import { fn } from "@/util/fn"
-import { Effect, Layer, Scope, ServiceMap } from "effect"
+import { Effect, Layer, Scope, Context } from "effect"
import { Config } from "../config/config"
import { Flag } from "../flag/flag"
import { ShareNext } from "./share-next"
@@ -15,7 +15,7 @@ export namespace SessionShare {
readonly unshare: (sessionID: SessionID) => Effect.Effect<void, unknown>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SessionShare") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SessionShare") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts
index 11fc08e24..ad247f546 100644
--- a/packages/opencode/src/share/share-next.ts
+++ b/packages/opencode/src/share/share-next.ts
@@ -1,5 +1,5 @@
import type * as SDK from "@opencode-ai/sdk/v2"
-import { Effect, Exit, Layer, Option, Schema, Scope, ServiceMap, Stream } from "effect"
+import { Effect, Exit, Layer, Option, Schema, Scope, Context, Stream } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import { Account } from "@/account"
import { Bus } from "@/bus"
@@ -73,7 +73,7 @@ export namespace ShareNext {
readonly remove: (sessionID: SessionID) => Effect.Effect<void, unknown>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/ShareNext") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/ShareNext") {}
const db = <T>(fn: (d: Parameters<typeof Database.use>[0] extends (trx: infer D) => any ? D : never) => T) =>
Effect.sync(() => Database.use(fn))
diff --git a/packages/opencode/src/skill/discovery.ts b/packages/opencode/src/skill/discovery.ts
index e10397503..0bc3ee629 100644
--- a/packages/opencode/src/skill/discovery.ts
+++ b/packages/opencode/src/skill/discovery.ts
@@ -1,5 +1,5 @@
import { NodePath } from "@effect/platform-node"
-import { Effect, Layer, Path, Schema, ServiceMap } from "effect"
+import { Effect, Layer, Path, Schema, Context } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
import { withTransientReadRetry } from "@/util/effect-http-client"
import { AppFileSystem } from "@/filesystem"
@@ -23,7 +23,7 @@ export namespace Discovery {
readonly pull: (url: string) => Effect.Effect<string[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/SkillDiscovery") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/SkillDiscovery") {}
export const layer: Layer.Layer<Service, never, AppFileSystem.Service | Path.Path | HttpClient.HttpClient> =
Layer.effect(
diff --git a/packages/opencode/src/skill/index.ts b/packages/opencode/src/skill/index.ts
index cde36dd52..be74c0b34 100644
--- a/packages/opencode/src/skill/index.ts
+++ b/packages/opencode/src/skill/index.ts
@@ -2,7 +2,7 @@ import os from "os"
import path from "path"
import { pathToFileURL } from "url"
import z from "zod"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { NamedError } from "@opencode-ai/util/error"
import type { Agent } from "@/agent/agent"
import { Bus } from "@/bus"
@@ -187,7 +187,7 @@ export namespace Skill {
log.info("init", { count: Object.keys(state.skills).length })
})
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Skill") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Skill") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts
index 569c834bf..834cdde25 100644
--- a/packages/opencode/src/snapshot/index.ts
+++ b/packages/opencode/src/snapshot/index.ts
@@ -1,4 +1,4 @@
-import { Cause, Duration, Effect, Layer, Schedule, Semaphore, ServiceMap, Stream } from "effect"
+import { Cause, Duration, Effect, Layer, Schedule, Semaphore, Context, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { formatPatch, structuredPatch } from "diff"
import path from "path"
@@ -57,7 +57,7 @@ export namespace Snapshot {
readonly diffFull: (from: string, to: string) => Effect.Effect<Snapshot.FileDiff[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Snapshot") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Snapshot") {}
export const layer: Layer.Layer<
Service,
diff --git a/packages/opencode/src/storage/db.ts b/packages/opencode/src/storage/db.ts
index 78320ac0a..a7dbf9380 100644
--- a/packages/opencode/src/storage/db.ts
+++ b/packages/opencode/src/storage/db.ts
@@ -2,7 +2,7 @@ import { type SQLiteBunDatabase } from "drizzle-orm/bun-sqlite"
import { migrate } from "drizzle-orm/bun-sqlite/migrator"
import { type SQLiteTransaction } from "drizzle-orm/sqlite-core"
export * from "drizzle-orm"
-import { Context } from "../util/context"
+import { LocalContext } from "../util/local-context"
import { lazy } from "../util/lazy"
import { Global } from "../global"
import { Log } from "../util/log"
@@ -122,7 +122,7 @@ export namespace Database {
export type TxOrDb = Transaction | Client
- const ctx = Context.create<{
+ const ctx = LocalContext.create<{
tx: TxOrDb
effects: (() => void | Promise<void>)[]
}>("database")
@@ -131,7 +131,7 @@ export namespace Database {
try {
return callback(ctx.use().tx)
} catch (err) {
- if (err instanceof Context.NotFound) {
+ if (err instanceof LocalContext.NotFound) {
const effects: (() => void | Promise<void>)[] = []
const result = ctx.provide({ effects, tx: Client() }, () => callback(Client()))
for (const effect of effects) effect()
@@ -161,7 +161,7 @@ export namespace Database {
try {
return callback(ctx.use().tx)
} catch (err) {
- if (err instanceof Context.NotFound) {
+ if (err instanceof LocalContext.NotFound) {
const effects: (() => void | Promise<void>)[] = []
const txCallback = InstanceState.bind((tx: TxOrDb) => ctx.provide({ tx, effects }, () => callback(tx)))
const result = Client().transaction(txCallback, { behavior: options?.behavior })
diff --git a/packages/opencode/src/storage/storage.ts b/packages/opencode/src/storage/storage.ts
index c8fc59c14..a123cd664 100644
--- a/packages/opencode/src/storage/storage.ts
+++ b/packages/opencode/src/storage/storage.ts
@@ -4,7 +4,7 @@ import { Global } from "../global"
import { NamedError } from "@opencode-ai/util/error"
import z from "zod"
import { AppFileSystem } from "@/filesystem"
-import { Effect, Exit, Layer, Option, RcMap, Schema, ServiceMap, TxReentrantLock } from "effect"
+import { Effect, Exit, Layer, Option, RcMap, Schema, Context, TxReentrantLock } from "effect"
import { Git } from "@/git"
export namespace Storage {
@@ -65,7 +65,7 @@ export namespace Storage {
readonly list: (prefix: string[]) => Effect.Effect<string[][], AppFileSystem.Error>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Storage") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Storage") {}
function file(dir: string, key: string[]) {
return path.join(dir, ...key) + ".json"
diff --git a/packages/opencode/src/sync/schema.ts b/packages/opencode/src/sync/schema.ts
index 8e734e598..5cec8b1f7 100644
--- a/packages/opencode/src/sync/schema.ts
+++ b/packages/opencode/src/sync/schema.ts
@@ -7,8 +7,7 @@ import { withStatics } from "@/util/schema"
export const EventID = Schema.String.pipe(
Schema.brand("EventID"),
withStatics((s) => ({
- make: (id: string) => s.makeUnsafe(id),
- ascending: (id?: string) => s.makeUnsafe(Identifier.ascending("event", id)),
+ ascending: (id?: string) => s.make(Identifier.ascending("event", id)),
zod: Identifier.schema("event").pipe(z.custom<Schema.Schema.Type<typeof s>>()),
})),
)
diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts
index c2577a505..0cd6d312f 100644
--- a/packages/opencode/src/tool/registry.ts
+++ b/packages/opencode/src/tool/registry.ts
@@ -29,7 +29,7 @@ import { ApplyPatchTool } from "./apply_patch"
import { Glob } from "../util/glob"
import path from "path"
import { pathToFileURL } from "url"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { EffectLogger } from "@/effect/logger"
import { FetchHttpClient, HttpClient } from "effect/unstable/http"
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
@@ -74,7 +74,7 @@ export namespace ToolRegistry {
}) => Effect.Effect<Tool.Def[]>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/ToolRegistry") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/ToolRegistry") {}
export const layer: Layer.Layer<
Service,
diff --git a/packages/opencode/src/tool/schema.ts b/packages/opencode/src/tool/schema.ts
index 93f0f9a71..823bb0aed 100644
--- a/packages/opencode/src/tool/schema.ts
+++ b/packages/opencode/src/tool/schema.ts
@@ -10,8 +10,7 @@ export type ToolID = typeof toolIdSchema.Type
export const ToolID = toolIdSchema.pipe(
withStatics((schema: typeof toolIdSchema) => ({
- make: (id: string) => schema.makeUnsafe(id),
- ascending: (id?: string) => schema.makeUnsafe(Identifier.ascending("tool", id)),
+ ascending: (id?: string) => schema.make(Identifier.ascending("tool", id)),
zod: Identifier.schema("tool").pipe(z.custom<ToolID>()),
})),
)
diff --git a/packages/opencode/src/tool/truncate.ts b/packages/opencode/src/tool/truncate.ts
index 5cddacefc..716929cc6 100644
--- a/packages/opencode/src/tool/truncate.ts
+++ b/packages/opencode/src/tool/truncate.ts
@@ -1,5 +1,5 @@
import { NodePath } from "@effect/platform-node"
-import { Cause, Duration, Effect, Layer, Schedule, ServiceMap } from "effect"
+import { Cause, Duration, Effect, Layer, Schedule, Context } from "effect"
import path from "path"
import type { Agent } from "../agent/agent"
import { makeRuntime } from "@/effect/run-service"
@@ -41,7 +41,7 @@ export namespace Truncate {
readonly output: (text: string, options?: Options, agent?: Agent.Info) => Effect.Effect<Result>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Truncate") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Truncate") {}
export const layer = Layer.effect(
Service,
diff --git a/packages/opencode/src/util/context.ts b/packages/opencode/src/util/local-context.ts
index 46bbf4608..26f88ab09 100644
--- a/packages/opencode/src/util/context.ts
+++ b/packages/opencode/src/util/local-context.ts
@@ -1,6 +1,6 @@
import { AsyncLocalStorage } from "async_hooks"
-export namespace Context {
+export namespace LocalContext {
export class NotFound extends Error {
constructor(public override readonly name: string) {
super(`No context found for ${name}`)
diff --git a/packages/opencode/src/util/schema.ts b/packages/opencode/src/util/schema.ts
index 6a88dba53..405f6a718 100644
--- a/packages/opencode/src/util/schema.ts
+++ b/packages/opencode/src/util/schema.ts
@@ -6,7 +6,7 @@ import { Schema } from "effect"
* @example
* export const Foo = fooSchema.pipe(
* withStatics((schema) => ({
- * zero: schema.makeUnsafe(0),
+ * zero: schema.make(0),
* from: Schema.decodeUnknownOption(schema),
* }))
* )
@@ -26,7 +26,7 @@ type NewtypeBrand<Tag extends string> = { readonly [NewtypeBrand]: Tag }
* @example
* class QuestionID extends Newtype<QuestionID>()("QuestionID", Schema.String) {
* static make(id: string): QuestionID {
- * return this.makeUnsafe(id)
+ * return this.make(id)
* }
* }
*
@@ -39,7 +39,7 @@ export function Newtype<Self>() {
abstract class Base {
declare readonly [NewtypeBrand]: Tag
- static makeUnsafe(value: Schema.Schema.Type<S>): Self {
+ static make(value: Schema.Schema.Type<S>): Self {
return value as unknown as Self
}
}
@@ -47,7 +47,7 @@ export function Newtype<Self>() {
Object.setPrototypeOf(Base, schema)
return Base as unknown as (abstract new (_: never) => Branded) & {
- readonly makeUnsafe: (value: Schema.Schema.Type<S>) => Self
- } & Omit<Schema.Opaque<Self, S, {}>, "makeUnsafe">
+ readonly make: (value: Schema.Schema.Type<S>) => Self
+ } & Omit<Schema.Opaque<Self, S, {}>, "make">
}
}
diff --git a/packages/opencode/src/worktree/index.ts b/packages/opencode/src/worktree/index.ts
index dc1548300..f4ec0af83 100644
--- a/packages/opencode/src/worktree/index.ts
+++ b/packages/opencode/src/worktree/index.ts
@@ -13,7 +13,7 @@ import { errorMessage } from "../util/error"
import { BusEvent } from "@/bus/bus-event"
import { GlobalBus } from "@/bus/global"
import { Git } from "@/git"
-import { Effect, Layer, Path, Scope, ServiceMap, Stream } from "effect"
+import { Effect, Layer, Path, Scope, Context, Stream } from "effect"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { NodePath } from "@effect/platform-node"
import { AppFileSystem } from "@/filesystem"
@@ -164,7 +164,7 @@ export namespace Worktree {
readonly reset: (input: ResetInput) => Effect.Effect<boolean>
}
- export class Service extends ServiceMap.Service<Service, Interface>()("@opencode/Worktree") {}
+ export class Service extends Context.Service<Service, Interface>()("@opencode/Worktree") {}
type GitResult = { code: number; text: string; stderr: string }
diff --git a/packages/opencode/test/effect/instance-state.test.ts b/packages/opencode/test/effect/instance-state.test.ts
index 914753312..813ca344a 100644
--- a/packages/opencode/test/effect/instance-state.test.ts
+++ b/packages/opencode/test/effect/instance-state.test.ts
@@ -1,5 +1,5 @@
import { afterEach, expect, test } from "bun:test"
-import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, ServiceMap } from "effect"
+import { Cause, Deferred, Duration, Effect, Exit, Fiber, Layer, ManagedRuntime, Context } from "effect"
import { InstanceState } from "../../src/effect/instance-state"
import { InstanceRef } from "../../src/effect/instance-ref"
import { Instance } from "../../src/project/instance"
@@ -122,7 +122,7 @@ test("InstanceState.get reads the current directory lazily", async () => {
readonly get: () => Effect.Effect<string>
}
- class Test extends ServiceMap.Service<Test, Api>()("@test/InstanceStateLazy") {
+ class Test extends Context.Service<Test, Api>()("@test/InstanceStateLazy") {
static readonly layer = Layer.effect(
Test,
Effect.gen(function* () {
@@ -166,7 +166,7 @@ test("InstanceState preserves directory across async boundaries", async () => {
readonly get: () => Effect.Effect<{ directory: string; worktree: string; project: string }>
}
- class Test extends ServiceMap.Service<Test, Api>()("@test/InstanceStateAsync") {
+ class Test extends Context.Service<Test, Api>()("@test/InstanceStateAsync") {
static readonly layer = Layer.effect(
Test,
Effect.gen(function* () {
@@ -234,7 +234,7 @@ test("InstanceState survives high-contention concurrent access", async () => {
readonly get: () => Effect.Effect<string>
}
- class Test extends ServiceMap.Service<Test, Api>()("@test/HighContention") {
+ class Test extends Context.Service<Test, Api>()("@test/HighContention") {
static readonly layer = Layer.effect(
Test,
Effect.gen(function* () {
@@ -284,7 +284,7 @@ test("InstanceState correct after interleaved init and dispose", async () => {
readonly get: () => Effect.Effect<string>
}
- class Test extends ServiceMap.Service<Test, Api>()("@test/InterleavedDispose") {
+ class Test extends Context.Service<Test, Api>()("@test/InterleavedDispose") {
static readonly layer = Layer.effect(
Test,
Effect.gen(function* () {
@@ -391,7 +391,7 @@ test("InstanceState survives deferred resume from the same instance context", as
readonly get: (gate: Deferred.Deferred<void>) => Effect.Effect<string>
}
- class Test extends ServiceMap.Service<Test, Api>()("@test/DeferredResume") {
+ class Test extends Context.Service<Test, Api>()("@test/DeferredResume") {
static readonly layer = Layer.effect(
Test,
Effect.gen(function* () {
@@ -438,7 +438,7 @@ test("InstanceState survives deferred resume outside ALS when InstanceRef is set
readonly get: (gate: Deferred.Deferred<void>) => Effect.Effect<string>
}
- class Test extends ServiceMap.Service<Test, Api>()("@test/DeferredResumeOutside") {
+ class Test extends Context.Service<Test, Api>()("@test/DeferredResumeOutside") {
static readonly layer = Layer.effect(
Test,
Effect.gen(function* () {
diff --git a/packages/opencode/test/effect/run-service.test.ts b/packages/opencode/test/effect/run-service.test.ts
index b2004fb66..b5f1a1d09 100644
--- a/packages/opencode/test/effect/run-service.test.ts
+++ b/packages/opencode/test/effect/run-service.test.ts
@@ -1,8 +1,8 @@
import { expect, test } from "bun:test"
-import { Effect, Layer, ServiceMap } from "effect"
+import { Effect, Layer, Context } from "effect"
import { makeRuntime } from "../../src/effect/run-service"
-class Shared extends ServiceMap.Service<Shared, { readonly id: number }>()("@test/Shared") {}
+class Shared extends Context.Service<Shared, { readonly id: number }>()("@test/Shared") {}
test("makeRuntime shares dependent layers through the shared memo map", async () => {
let n = 0
@@ -15,7 +15,7 @@ test("makeRuntime shares dependent layers through the shared memo map", async ()
}),
)
- class One extends ServiceMap.Service<One, { readonly get: () => Effect.Effect<number> }>()("@test/One") {}
+ class One extends Context.Service<One, { readonly get: () => Effect.Effect<number> }>()("@test/One") {}
const one = Layer.effect(
One,
Effect.gen(function* () {
@@ -26,7 +26,7 @@ test("makeRuntime shares dependent layers through the shared memo map", async ()
}),
).pipe(Layer.provide(shared))
- class Two extends ServiceMap.Service<Two, { readonly get: () => Effect.Effect<number> }>()("@test/Two") {}
+ class Two extends Context.Service<Two, { readonly get: () => Effect.Effect<number> }>()("@test/Two") {}
const two = Layer.effect(
Two,
Effect.gen(function* () {
diff --git a/packages/opencode/test/fixture/fixture.ts b/packages/opencode/test/fixture/fixture.ts
index 03713d879..797054354 100644
--- a/packages/opencode/test/fixture/fixture.ts
+++ b/packages/opencode/test/fixture/fixture.ts
@@ -2,7 +2,7 @@ import { $ } from "bun"
import * as fs from "fs/promises"
import os from "os"
import path from "path"
-import { Effect, ServiceMap } from "effect"
+import { Effect, Context } from "effect"
import type * as PlatformError from "effect/PlatformError"
import type * as Scope from "effect/Scope"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
@@ -123,7 +123,7 @@ export function tmpdirScoped(options?: { git?: boolean; config?: Partial<Config.
export const provideInstance =
(directory: string) =>
<A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
- Effect.servicesWith((services: ServiceMap.ServiceMap<R>) =>
+ Effect.contextWith((services: Context.Context<R>) =>
Effect.promise<A>(async () =>
Instance.provide({
directory,
diff --git a/packages/opencode/test/installation/installation.test.ts b/packages/opencode/test/installation/installation.test.ts
index b05c31029..2b04c3858 100644
--- a/packages/opencode/test/installation/installation.test.ts
+++ b/packages/opencode/test/installation/installation.test.ts
@@ -27,6 +27,7 @@ function mockSpawner(handler: (cmd: string, args: readonly string[]) => string =
all: Stream.empty,
getInputFd: () => ({ [Symbol.for("effect/Sink/TypeId")]: Symbol.for("effect/Sink/TypeId") }) as any,
getOutputFd: () => Stream.empty,
+ unref: Effect.succeed(Effect.void),
}),
)
})
diff --git a/packages/opencode/test/lib/llm-server.ts b/packages/opencode/test/lib/llm-server.ts
index fbad6ac14..2e2a2ea89 100644
--- a/packages/opencode/test/lib/llm-server.ts
+++ b/packages/opencode/test/lib/llm-server.ts
@@ -1,6 +1,6 @@
import { NodeHttpServer, NodeHttpServerRequest } from "@effect/platform-node"
import * as Http from "node:http"
-import { Deferred, Effect, Layer, ServiceMap, Stream } from "effect"
+import { Deferred, Effect, Layer, Context, Stream } from "effect"
import * as HttpServer from "effect/unstable/http/HttpServer"
import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
@@ -650,7 +650,7 @@ namespace TestLLMServer {
}
}
-export class TestLLMServer extends ServiceMap.Service<TestLLMServer, TestLLMServer.Service>()("@test/LLMServer") {
+export class TestLLMServer extends Context.Service<TestLLMServer, TestLLMServer.Service>()("@test/LLMServer") {
static readonly layer = Layer.effect(
TestLLMServer,
Effect.gen(function* () {
diff --git a/packages/opencode/test/project/project.test.ts b/packages/opencode/test/project/project.test.ts
index 988ae2742..93d97e6a4 100644
--- a/packages/opencode/test/project/project.test.ts
+++ b/packages/opencode/test/project/project.test.ts
@@ -41,6 +41,7 @@ function mockGitFailure(failArg: string) {
all: Stream.empty,
getInputFd: () => ({ [Symbol.for("effect/Sink/TypeId")]: Symbol.for("effect/Sink/TypeId") }) as any,
getOutputFd: () => Stream.empty,
+ unref: Effect.succeed(Effect.void),
})
}
return yield* real.spawn(command)