|
1 | | -import { Effect, Layer, LayerMap, ServiceMap } from "effect" |
2 | | -import { registerDisposer } from "./instance-registry" |
3 | | -import { InstanceContext } from "./instance-context" |
4 | | -import { ProviderAuthService } from "@/provider/auth-service" |
5 | | -import { QuestionService } from "@/question/service" |
6 | | -import { PermissionService } from "@/permission/service" |
7 | | -import { FileWatcherService } from "@/file/watcher" |
8 | | -import { VcsService } from "@/project/vcs" |
9 | | -import { FileTimeService } from "@/file/time" |
10 | | -import { FormatService } from "@/format" |
11 | | -import { FileService } from "@/file" |
12 | | -import { SkillService } from "@/skill/skill" |
13 | | -import { Instance } from "@/project/instance" |
| 1 | +import { Effect, Layer, LayerMap, ServiceMap } from "effect"; |
| 2 | +import { FileService } from "@/file"; |
| 3 | +import { FileTimeService } from "@/file/time"; |
| 4 | +import { FileWatcherService } from "@/file/watcher"; |
| 5 | +import { FormatService } from "@/format"; |
| 6 | +import { PermissionService } from "@/permission/service"; |
| 7 | +import { Instance } from "@/project/instance"; |
| 8 | +import { VcsService } from "@/project/vcs"; |
| 9 | +import { ProviderAuthService } from "@/provider/auth-service"; |
| 10 | +import { QuestionService } from "@/question/service"; |
| 11 | +import { SkillService } from "@/skill/skill"; |
| 12 | +import { SnapshotService } from "@/snapshot"; |
| 13 | +import { InstanceContext } from "./instance-context"; |
| 14 | +import { registerDisposer } from "./instance-registry"; |
14 | 15 |
|
15 | | -export { InstanceContext } from "./instance-context" |
| 16 | +export { InstanceContext } from "./instance-context"; |
16 | 17 |
|
17 | 18 | export type InstanceServices = |
18 | | - | QuestionService |
19 | | - | PermissionService |
20 | | - | ProviderAuthService |
21 | | - | FileWatcherService |
22 | | - | VcsService |
23 | | - | FileTimeService |
24 | | - | FormatService |
25 | | - | FileService |
26 | | - | SkillService |
| 19 | + | QuestionService |
| 20 | + | PermissionService |
| 21 | + | ProviderAuthService |
| 22 | + | FileWatcherService |
| 23 | + | VcsService |
| 24 | + | FileTimeService |
| 25 | + | FormatService |
| 26 | + | FileService |
| 27 | + | SkillService |
| 28 | + | SnapshotService; |
27 | 29 |
|
28 | | -function lookup(directory: string) { |
29 | | - const project = Instance.project |
30 | | - const ctx = Layer.sync(InstanceContext, () => InstanceContext.of({ directory, project })) |
31 | | - return Layer.mergeAll( |
32 | | - Layer.fresh(QuestionService.layer), |
33 | | - Layer.fresh(PermissionService.layer), |
34 | | - Layer.fresh(ProviderAuthService.layer), |
35 | | - Layer.fresh(FileWatcherService.layer).pipe(Layer.orDie), |
36 | | - Layer.fresh(VcsService.layer), |
37 | | - Layer.fresh(FileTimeService.layer).pipe(Layer.orDie), |
38 | | - Layer.fresh(FormatService.layer), |
39 | | - Layer.fresh(FileService.layer), |
40 | | - Layer.fresh(SkillService.layer), |
41 | | - ).pipe(Layer.provide(ctx)) |
| 30 | +// NOTE: LayerMap only passes the key (directory string) to lookup, but we need |
| 31 | +// the full instance context (directory, worktree, project). We read from the |
| 32 | +// legacy Instance ALS here, which is safe because lookup is only triggered via |
| 33 | +// runPromiseInstance -> Instances.get, which always runs inside Instance.provide. |
| 34 | +// This should go away once the old Instance type is removed and lookup can load |
| 35 | +// the full context directly. |
| 36 | +function lookup(_key: string) { |
| 37 | + const ctx = Layer.sync(InstanceContext, () => |
| 38 | + InstanceContext.of(Instance.current), |
| 39 | + ); |
| 40 | + return Layer.mergeAll( |
| 41 | + Layer.fresh(QuestionService.layer), |
| 42 | + Layer.fresh(PermissionService.layer), |
| 43 | + Layer.fresh(ProviderAuthService.layer), |
| 44 | + Layer.fresh(FileWatcherService.layer).pipe(Layer.orDie), |
| 45 | + Layer.fresh(VcsService.layer), |
| 46 | + Layer.fresh(FileTimeService.layer).pipe(Layer.orDie), |
| 47 | + Layer.fresh(FormatService.layer), |
| 48 | + Layer.fresh(FileService.layer), |
| 49 | + Layer.fresh(SkillService.layer), |
| 50 | + Layer.fresh(SnapshotService.layer), |
| 51 | + ).pipe(Layer.provide(ctx)); |
42 | 52 | } |
43 | 53 |
|
44 | | -export class Instances extends ServiceMap.Service<Instances, LayerMap.LayerMap<string, InstanceServices>>()( |
45 | | - "opencode/Instances", |
46 | | -) { |
47 | | - static readonly layer = Layer.effect( |
48 | | - Instances, |
49 | | - Effect.gen(function* () { |
50 | | - const layerMap = yield* LayerMap.make(lookup, { idleTimeToLive: Infinity }) |
51 | | - const unregister = registerDisposer((directory) => Effect.runPromise(layerMap.invalidate(directory))) |
52 | | - yield* Effect.addFinalizer(() => Effect.sync(unregister)) |
53 | | - return Instances.of(layerMap) |
54 | | - }), |
55 | | - ) |
| 54 | +export class Instances extends ServiceMap.Service< |
| 55 | + Instances, |
| 56 | + LayerMap.LayerMap<string, InstanceServices> |
| 57 | +>()("opencode/Instances") { |
| 58 | + static readonly layer = Layer.effect( |
| 59 | + Instances, |
| 60 | + Effect.gen(function* () { |
| 61 | + const layerMap = yield* LayerMap.make(lookup, { |
| 62 | + idleTimeToLive: Infinity, |
| 63 | + }); |
| 64 | + const unregister = registerDisposer((directory) => |
| 65 | + Effect.runPromise(layerMap.invalidate(directory)), |
| 66 | + ); |
| 67 | + yield* Effect.addFinalizer(() => Effect.sync(unregister)); |
| 68 | + return Instances.of(layerMap); |
| 69 | + }), |
| 70 | + ); |
56 | 71 |
|
57 | | - static get(directory: string): Layer.Layer<InstanceServices, never, Instances> { |
58 | | - return Layer.unwrap(Instances.use((map) => Effect.succeed(map.get(directory)))) |
59 | | - } |
| 72 | + static get( |
| 73 | + directory: string, |
| 74 | + ): Layer.Layer<InstanceServices, never, Instances> { |
| 75 | + return Layer.unwrap( |
| 76 | + Instances.use((map) => Effect.succeed(map.get(directory))), |
| 77 | + ); |
| 78 | + } |
60 | 79 |
|
61 | | - static invalidate(directory: string): Effect.Effect<void, never, Instances> { |
62 | | - return Instances.use((map) => map.invalidate(directory)) |
63 | | - } |
| 80 | + static invalidate(directory: string): Effect.Effect<void, never, Instances> { |
| 81 | + return Instances.use((map) => map.invalidate(directory)); |
| 82 | + } |
64 | 83 | } |
0 commit comments