From 9581bf06709195368bc3220294c36f3527dbc5c6 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Fri, 10 Apr 2026 23:06:28 -0400 Subject: [PATCH] refactor(effect): upgrade opencode to beta.46 context APIs (#21977) --- bun.lock | 22 +++++++++---- package.json | 4 +-- packages/opencode/package.json | 2 +- packages/opencode/specs/effect-migration.md | 2 +- packages/opencode/src/account/index.ts | 4 +-- packages/opencode/src/account/repo.ts | 4 +-- packages/opencode/src/account/schema.ts | 32 ++++--------------- packages/opencode/src/agent/agent.ts | 4 +-- packages/opencode/src/auth/index.ts | 4 +-- packages/opencode/src/bus/index.ts | 4 +-- packages/opencode/src/command/index.ts | 7 ++-- packages/opencode/src/config/config.ts | 4 +-- packages/opencode/src/control-plane/schema.ts | 3 +- .../src/control-plane/workspace-context.ts | 4 +-- .../src/effect/cross-spawn-spawner.ts | 13 ++++++++ packages/opencode/src/effect/instance-ref.ts | 6 ++-- .../opencode/src/effect/instance-state.ts | 8 ++--- packages/opencode/src/effect/run-service.ts | 8 ++--- packages/opencode/src/file/index.ts | 4 +-- packages/opencode/src/file/ripgrep.ts | 4 +-- packages/opencode/src/file/time.ts | 4 +-- packages/opencode/src/file/watcher.ts | 4 +-- packages/opencode/src/filesystem/index.ts | 4 +-- packages/opencode/src/format/index.ts | 4 +-- packages/opencode/src/git/index.ts | 4 +-- packages/opencode/src/installation/index.ts | 4 +-- packages/opencode/src/lsp/index.ts | 4 +-- packages/opencode/src/mcp/auth.ts | 4 +-- packages/opencode/src/mcp/index.ts | 4 +-- packages/opencode/src/permission/index.ts | 4 +-- packages/opencode/src/permission/schema.ts | 6 +--- packages/opencode/src/plugin/index.ts | 4 +-- packages/opencode/src/project/instance.ts | 4 +-- packages/opencode/src/project/project.ts | 4 +-- packages/opencode/src/project/schema.ts | 3 +- packages/opencode/src/project/vcs.ts | 4 +-- packages/opencode/src/provider/auth.ts | 4 +-- packages/opencode/src/provider/provider.ts | 4 +-- packages/opencode/src/provider/schema.ts | 24 +++++++------- packages/opencode/src/pty/index.ts | 4 +-- packages/opencode/src/pty/schema.ts | 3 +- packages/opencode/src/question/index.ts | 4 +-- packages/opencode/src/question/schema.ts | 6 +--- packages/opencode/src/session/compaction.ts | 4 +-- packages/opencode/src/session/index.ts | 4 +-- packages/opencode/src/session/instruction.ts | 4 +-- packages/opencode/src/session/llm.ts | 4 +-- packages/opencode/src/session/processor.ts | 4 +-- packages/opencode/src/session/prompt.ts | 4 +-- packages/opencode/src/session/revert.ts | 4 +-- packages/opencode/src/session/run-state.ts | 4 +-- packages/opencode/src/session/schema.ts | 9 ++---- packages/opencode/src/session/status.ts | 4 +-- packages/opencode/src/session/summary.ts | 4 +-- packages/opencode/src/session/todo.ts | 4 +-- packages/opencode/src/share/session.ts | 4 +-- packages/opencode/src/share/share-next.ts | 4 +-- packages/opencode/src/skill/discovery.ts | 4 +-- packages/opencode/src/skill/index.ts | 4 +-- packages/opencode/src/snapshot/index.ts | 4 +-- packages/opencode/src/storage/db.ts | 8 ++--- packages/opencode/src/storage/storage.ts | 4 +-- packages/opencode/src/sync/schema.ts | 3 +- packages/opencode/src/tool/registry.ts | 4 +-- packages/opencode/src/tool/schema.ts | 3 +- packages/opencode/src/tool/truncate.ts | 4 +-- .../src/util/{context.ts => local-context.ts} | 2 +- packages/opencode/src/util/schema.ts | 10 +++--- packages/opencode/src/worktree/index.ts | 4 +-- .../test/effect/instance-state.test.ts | 14 ++++---- .../opencode/test/effect/run-service.test.ts | 8 ++--- packages/opencode/test/fixture/fixture.ts | 4 +-- .../test/installation/installation.test.ts | 1 + packages/opencode/test/lib/llm-server.ts | 4 +-- .../opencode/test/project/project.test.ts | 1 + 75 files changed, 195 insertions(+), 209 deletions(-) rename packages/opencode/src/util/{context.ts => local-context.ts} (94%) 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/brocli@0.11.0", "", {}, "sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg=="], - "@effect/language-service": ["@effect/language-service@0.79.0", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-DEmIOsg1GjjP6s9HXH1oJrW+gDmzkhVv9WOZl6to5eNyyCrjz1S2PDqQ7aYrW/HuifhfwI5Bik1pK4pj7Z+lrg=="], + "@effect/language-service": ["@effect/language-service@0.84.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-l04qNxpiA8rY5yXWckRPJ7Mk5MNerXuNymSFf+IdflfI5i8jgL1bpBNLuP6ijg7wgjdHc/KmTnCj2kT0SCntuA=="], - "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.43", "", { "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/platform-node@4.0.0-beta.46", "", { "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/platform-node-shared@4.0.0-beta.43", "", { "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/platform-node-shared@4.0.0-beta.46", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.46" } }, "sha512-Yzci82XbZ1W3tuiownsJawrJZTGeTrTZKLD0uxdBWCBzlVyqDwoSwRwO5qh33DurJj9B7iS8MDf14fpGRBPNGQ=="], "@electron/asar": ["@electron/asar@3.4.1", "", { "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": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "effect": ["effect@4.0.0-beta.43", "", { "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": ["effect@4.0.0-beta.46", "", { "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": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], @@ -5509,6 +5509,10 @@ "@solidjs/start/vite-plugin-solid": ["vite-plugin-solid@2.11.11", "", { "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": ["effect@4.0.0-beta.43", "", { "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": ["effect@4.0.0-beta.43", "", { "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": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.1", "", { "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/types@1.29.2", "", { "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/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@standard-community/standard-openapi/effect/@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@tailwindcss/oxide-wasm32-wasi/@napi-rs/wasm-runtime/@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], "@vitest/expect/@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "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 } - export class Service extends ServiceMap.Service()("@opencode/Foo") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Account") {} + export class Service extends Context.Service()("@opencode/Account") {} export const layer: Layer.Layer = 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()("@opencode/AccountRepo") { +export class AccountRepo extends Context.Service()("@opencode/AccountRepo") { static readonly layer: Layer.Layer = 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 -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 -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 -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 -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 -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 export class Info extends Schema.Class("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 - export class Service extends ServiceMap.Service()("@opencode/Agent") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Auth") {} + export class Service extends Context.Service()("@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()("@opencode/Bus") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Command") {} + export class Service extends Context.Service()("@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 = {} 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 } - export class Service extends ServiceMap.Service()("@opencode/Config") {} + export class Service extends Context.Service()("@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()), })), ) 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("instance") +const context = LocalContext.create("instance") export const WorkspaceContext = { async provide(input: { workspaceID: WorkspaceID; fn: () => R }): Promise { 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("~opencode/InstanceRef", { +export const InstanceRef = Context.Reference("~opencode/InstanceRef", { defaultValue: () => undefined, }) -export const WorkspaceRef = ServiceMap.Reference("~opencode/WorkspaceRef", { +export const WorkspaceRef = Context.Reference("~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(effect: Effect.Effect): Effect.Effect(service: ServiceMap.Service, layer: Layer.Layer) { +export function makeRuntime(service: Context.Service, layer: Layer.Layer) { let rt: ManagedRuntime.ManagedRuntime | 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 } - export class Service extends ServiceMap.Service()("@opencode/File") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Ripgrep") {} + export class Service extends Context.Service()("@opencode/Ripgrep") {} export const layer: Layer.Layer = 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: (filepath: string, fn: () => Effect.Effect) => Effect.Effect } - export class Service extends ServiceMap.Service()("@opencode/FileTime") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/FileWatcher") {} + export class Service extends Context.Service()("@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()("@opencode/FileSystem") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Format") {} + export class Service extends Context.Service()("@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()("@opencode/Git") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Installation") {} + export class Service extends Context.Service()("@opencode/Installation") {} export const layer: Layer.Layer = 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 } - export class Service extends ServiceMap.Service()("@opencode/LSP") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/McpAuth") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/MCP") {} + export class Service extends Context.Service()("@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()("@opencode/Permission") {} + export class Service extends Context.Service()("@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", 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 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 } - export class Service extends ServiceMap.Service()("@opencode/Plugin") {} + export class Service extends Context.Service()("@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("instance") +const context = LocalContext.create("instance") const cache = new Map>() 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 } - export class Service extends ServiceMap.Service()("@opencode/Project") {} + export class Service extends Context.Service()("@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()), })), ) 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()("@opencode/Vcs") {} + export class Service extends Context.Service()("@opencode/Vcs") {} export const layer: Layer.Layer = 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 } - export class Service extends ServiceMap.Service()("@opencode/ProviderAuth") {} + export class Service extends Context.Service()("@opencode/ProviderAuth") {} export const layer: Layer.Layer = 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 } - export class Service extends ServiceMap.Service()("@opencode/Provider") {} + export class Service extends Context.Service()("@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()), // 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()), })), ) 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()("@opencode/Pty") {} + export class Service extends Context.Service()("@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()), })), ) 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 } - export class Service extends ServiceMap.Service()("@opencode/Question") {} + export class Service extends Context.Service()("@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", 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 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 } - export class Service extends ServiceMap.Service()("@opencode/SessionCompaction") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Session") {} + export class Service extends Context.Service()("@opencode/Session") {} type Patch = z.infer["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()("@opencode/Instruction") {} + export class Service extends Context.Service()("@opencode/Instruction") {} export const layer: Layer.Layer = 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 } - export class Service extends ServiceMap.Service()("@opencode/LLM") {} + export class Service extends Context.Service()("@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()("@opencode/SessionProcessor") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/SessionPrompt") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/SessionRevert") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/SessionRunState") {} + export class Service extends Context.Service()("@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>()), })), ) @@ -18,8 +17,7 @@ export type SessionID = Schema.Schema.Type 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>()), })), ) @@ -29,8 +27,7 @@ export type MessageID = Schema.Schema.Type 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>()), })), ) 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 } - export class Service extends ServiceMap.Service()("@opencode/SessionStatus") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/SessionSummary") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/SessionTodo") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/SessionShare") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/ShareNext") {} + export class Service extends Context.Service()("@opencode/ShareNext") {} const db = (fn: (d: Parameters[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 } - export class Service extends ServiceMap.Service()("@opencode/SkillDiscovery") {} + export class Service extends Context.Service()("@opencode/SkillDiscovery") {} export const layer: Layer.Layer = 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()("@opencode/Skill") {} + export class Service extends Context.Service()("@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 } - export class Service extends ServiceMap.Service()("@opencode/Snapshot") {} + export class Service extends Context.Service()("@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)[] }>("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)[] = [] 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)[] = [] 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 } - export class Service extends ServiceMap.Service()("@opencode/Storage") {} + export class Service extends Context.Service()("@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>()), })), ) 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 } - export class Service extends ServiceMap.Service()("@opencode/ToolRegistry") {} + export class Service extends Context.Service()("@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()), })), ) 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 } - export class Service extends ServiceMap.Service()("@opencode/Truncate") {} + export class Service extends Context.Service()("@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 similarity index 94% rename from packages/opencode/src/util/context.ts rename to 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 = { readonly [NewtypeBrand]: Tag } * @example * class QuestionID extends Newtype()("QuestionID", Schema.String) { * static make(id: string): QuestionID { - * return this.makeUnsafe(id) + * return this.make(id) * } * } * @@ -39,7 +39,7 @@ export function Newtype() { abstract class Base { declare readonly [NewtypeBrand]: Tag - static makeUnsafe(value: Schema.Schema.Type): Self { + static make(value: Schema.Schema.Type): Self { return value as unknown as Self } } @@ -47,7 +47,7 @@ export function Newtype() { Object.setPrototypeOf(Base, schema) return Base as unknown as (abstract new (_: never) => Branded) & { - readonly makeUnsafe: (value: Schema.Schema.Type) => Self - } & Omit, "makeUnsafe"> + readonly make: (value: Schema.Schema.Type) => Self + } & Omit, "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 } - export class Service extends ServiceMap.Service()("@opencode/Worktree") {} + export class Service extends Context.Service()("@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 } - class Test extends ServiceMap.Service()("@test/InstanceStateLazy") { + class Test extends Context.Service()("@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/InstanceStateAsync") { + class Test extends Context.Service()("@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 } - class Test extends ServiceMap.Service()("@test/HighContention") { + class Test extends Context.Service()("@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 } - class Test extends ServiceMap.Service()("@test/InterleavedDispose") { + class Test extends Context.Service()("@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) => Effect.Effect } - class Test extends ServiceMap.Service()("@test/DeferredResume") { + class Test extends Context.Service()("@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) => Effect.Effect } - class Test extends ServiceMap.Service()("@test/DeferredResumeOutside") { + class Test extends Context.Service()("@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()("@test/Shared") {} +class Shared extends Context.Service()("@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 Effect.Effect }>()("@test/One") {} + class One extends Context.Service Effect.Effect }>()("@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 Effect.Effect }>()("@test/Two") {} + class Two extends Context.Service Effect.Effect }>()("@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 (self: Effect.Effect): Effect.Effect => - Effect.servicesWith((services: ServiceMap.ServiceMap) => + Effect.contextWith((services: Context.Context) => Effect.promise(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()("@test/LLMServer") { +export class TestLLMServer extends Context.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)