mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-31 22:32:28 +00:00
refactor(snapshot): effectify SnapshotService (#17878)
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import { ServiceMap } from "effect"
|
||||
import type { Project } from "@/project/project"
|
||||
import { ServiceMap } from "effect";
|
||||
import type { Project } from "@/project/project";
|
||||
|
||||
export declare namespace InstanceContext {
|
||||
export interface Shape {
|
||||
readonly directory: string
|
||||
readonly project: Project.Info
|
||||
}
|
||||
export interface Shape {
|
||||
readonly directory: string;
|
||||
readonly worktree: string;
|
||||
readonly project: Project.Info;
|
||||
}
|
||||
}
|
||||
|
||||
export class InstanceContext extends ServiceMap.Service<InstanceContext, InstanceContext.Shape>()(
|
||||
"opencode/InstanceContext",
|
||||
) {}
|
||||
export class InstanceContext extends ServiceMap.Service<
|
||||
InstanceContext,
|
||||
InstanceContext.Shape
|
||||
>()("opencode/InstanceContext") {}
|
||||
|
||||
@@ -1,64 +1,83 @@
|
||||
import { Effect, Layer, LayerMap, ServiceMap } from "effect"
|
||||
import { registerDisposer } from "./instance-registry"
|
||||
import { InstanceContext } from "./instance-context"
|
||||
import { ProviderAuthService } from "@/provider/auth-service"
|
||||
import { QuestionService } from "@/question/service"
|
||||
import { PermissionService } from "@/permission/service"
|
||||
import { FileWatcherService } from "@/file/watcher"
|
||||
import { VcsService } from "@/project/vcs"
|
||||
import { FileTimeService } from "@/file/time"
|
||||
import { FormatService } from "@/format"
|
||||
import { FileService } from "@/file"
|
||||
import { SkillService } from "@/skill/skill"
|
||||
import { Instance } from "@/project/instance"
|
||||
import { Effect, Layer, LayerMap, ServiceMap } from "effect";
|
||||
import { FileService } from "@/file";
|
||||
import { FileTimeService } from "@/file/time";
|
||||
import { FileWatcherService } from "@/file/watcher";
|
||||
import { FormatService } from "@/format";
|
||||
import { PermissionService } from "@/permission/service";
|
||||
import { Instance } from "@/project/instance";
|
||||
import { VcsService } from "@/project/vcs";
|
||||
import { ProviderAuthService } from "@/provider/auth-service";
|
||||
import { QuestionService } from "@/question/service";
|
||||
import { SkillService } from "@/skill/skill";
|
||||
import { SnapshotService } from "@/snapshot";
|
||||
import { InstanceContext } from "./instance-context";
|
||||
import { registerDisposer } from "./instance-registry";
|
||||
|
||||
export { InstanceContext } from "./instance-context"
|
||||
export { InstanceContext } from "./instance-context";
|
||||
|
||||
export type InstanceServices =
|
||||
| QuestionService
|
||||
| PermissionService
|
||||
| ProviderAuthService
|
||||
| FileWatcherService
|
||||
| VcsService
|
||||
| FileTimeService
|
||||
| FormatService
|
||||
| FileService
|
||||
| SkillService
|
||||
| QuestionService
|
||||
| PermissionService
|
||||
| ProviderAuthService
|
||||
| FileWatcherService
|
||||
| VcsService
|
||||
| FileTimeService
|
||||
| FormatService
|
||||
| FileService
|
||||
| SkillService
|
||||
| SnapshotService;
|
||||
|
||||
function lookup(directory: string) {
|
||||
const project = Instance.project
|
||||
const ctx = Layer.sync(InstanceContext, () => InstanceContext.of({ directory, project }))
|
||||
return Layer.mergeAll(
|
||||
Layer.fresh(QuestionService.layer),
|
||||
Layer.fresh(PermissionService.layer),
|
||||
Layer.fresh(ProviderAuthService.layer),
|
||||
Layer.fresh(FileWatcherService.layer).pipe(Layer.orDie),
|
||||
Layer.fresh(VcsService.layer),
|
||||
Layer.fresh(FileTimeService.layer).pipe(Layer.orDie),
|
||||
Layer.fresh(FormatService.layer),
|
||||
Layer.fresh(FileService.layer),
|
||||
Layer.fresh(SkillService.layer),
|
||||
).pipe(Layer.provide(ctx))
|
||||
// NOTE: LayerMap only passes the key (directory string) to lookup, but we need
|
||||
// the full instance context (directory, worktree, project). We read from the
|
||||
// legacy Instance ALS here, which is safe because lookup is only triggered via
|
||||
// runPromiseInstance -> Instances.get, which always runs inside Instance.provide.
|
||||
// This should go away once the old Instance type is removed and lookup can load
|
||||
// the full context directly.
|
||||
function lookup(_key: string) {
|
||||
const ctx = Layer.sync(InstanceContext, () =>
|
||||
InstanceContext.of(Instance.current),
|
||||
);
|
||||
return Layer.mergeAll(
|
||||
Layer.fresh(QuestionService.layer),
|
||||
Layer.fresh(PermissionService.layer),
|
||||
Layer.fresh(ProviderAuthService.layer),
|
||||
Layer.fresh(FileWatcherService.layer).pipe(Layer.orDie),
|
||||
Layer.fresh(VcsService.layer),
|
||||
Layer.fresh(FileTimeService.layer).pipe(Layer.orDie),
|
||||
Layer.fresh(FormatService.layer),
|
||||
Layer.fresh(FileService.layer),
|
||||
Layer.fresh(SkillService.layer),
|
||||
Layer.fresh(SnapshotService.layer),
|
||||
).pipe(Layer.provide(ctx));
|
||||
}
|
||||
|
||||
export class Instances extends ServiceMap.Service<Instances, LayerMap.LayerMap<string, InstanceServices>>()(
|
||||
"opencode/Instances",
|
||||
) {
|
||||
static readonly layer = Layer.effect(
|
||||
Instances,
|
||||
Effect.gen(function* () {
|
||||
const layerMap = yield* LayerMap.make(lookup, { idleTimeToLive: Infinity })
|
||||
const unregister = registerDisposer((directory) => Effect.runPromise(layerMap.invalidate(directory)))
|
||||
yield* Effect.addFinalizer(() => Effect.sync(unregister))
|
||||
return Instances.of(layerMap)
|
||||
}),
|
||||
)
|
||||
export class Instances extends ServiceMap.Service<
|
||||
Instances,
|
||||
LayerMap.LayerMap<string, InstanceServices>
|
||||
>()("opencode/Instances") {
|
||||
static readonly layer = Layer.effect(
|
||||
Instances,
|
||||
Effect.gen(function* () {
|
||||
const layerMap = yield* LayerMap.make(lookup, {
|
||||
idleTimeToLive: Infinity,
|
||||
});
|
||||
const unregister = registerDisposer((directory) =>
|
||||
Effect.runPromise(layerMap.invalidate(directory)),
|
||||
);
|
||||
yield* Effect.addFinalizer(() => Effect.sync(unregister));
|
||||
return Instances.of(layerMap);
|
||||
}),
|
||||
);
|
||||
|
||||
static get(directory: string): Layer.Layer<InstanceServices, never, Instances> {
|
||||
return Layer.unwrap(Instances.use((map) => Effect.succeed(map.get(directory))))
|
||||
}
|
||||
static get(
|
||||
directory: string,
|
||||
): Layer.Layer<InstanceServices, never, Instances> {
|
||||
return Layer.unwrap(
|
||||
Instances.use((map) => Effect.succeed(map.get(directory))),
|
||||
);
|
||||
}
|
||||
|
||||
static invalidate(directory: string): Effect.Effect<void, never, Instances> {
|
||||
return Instances.use((map) => map.invalidate(directory))
|
||||
}
|
||||
static invalidate(directory: string): Effect.Effect<void, never, Instances> {
|
||||
return Instances.use((map) => map.invalidate(directory));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,3 +12,7 @@ export const runtime = ManagedRuntime.make(
|
||||
export function runPromiseInstance<A, E>(effect: Effect.Effect<A, E, InstanceServices>) {
|
||||
return runtime.runPromise(effect.pipe(Effect.provide(Instances.get(Instance.directory))))
|
||||
}
|
||||
|
||||
export function disposeRuntime() {
|
||||
return runtime.dispose()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user