feat(core): manage configurable plugin generations

This commit is contained in:
Dax Raad 2026-07-05 15:51:15 -04:00
commit a9b7bd9e2f
83 changed files with 1116 additions and 819 deletions

View file

@ -26,21 +26,32 @@ export interface Transformable<DraftApi> {
readonly reload: Reload
}
const CurrentBatch = Context.Reference<Set<Reload> | undefined>("@opencode/State/CurrentBatch", {
type Batch = {
active: boolean
readonly reloads: Set<Reload>
}
const CurrentBatch = Context.Reference<Batch | undefined>("@opencode/State/CurrentBatch", {
defaultValue: () => undefined,
})
export function batch<A, E, R>(effect: Effect.Effect<A, E, R>) {
return Effect.gen(function* () {
const current = yield* CurrentBatch
if (current) return yield* effect
const reloads = new Set<Reload>()
const result = yield* effect.pipe(Effect.provideService(CurrentBatch, reloads))
yield* Effect.forEach(reloads, (reload) => reload(), { discard: true })
return result
if (current?.active) return yield* effect
const batch: Batch = { active: true, reloads: new Set() }
const exit = yield* effect.pipe(Effect.provideService(CurrentBatch, batch), Effect.exit)
batch.active = false
yield* Effect.forEach(batch.reloads, (reload) => reload(), { discard: true })
return yield* exit
})
}
export const inherit = Effect.fnUntraced(function* () {
const batch = yield* CurrentBatch
return <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.provideService(effect, CurrentBatch, batch)
})
export interface Options<State, DraftApi> {
/** Creates the base value for initial state and every scoped-transform reload. */
readonly initial: () => State
@ -100,8 +111,8 @@ export function create<State, DraftApi>(options: Options<State, DraftApi>): Inte
transforms = transforms.filter((item) => item !== transform)
return Effect.gen(function* () {
const batch = yield* CurrentBatch
if (batch) {
batch.add(reload)
if (batch?.active) {
batch.reloads.add(reload)
return
}
yield* materialize()
@ -116,7 +127,7 @@ export function create<State, DraftApi>(options: Options<State, DraftApi>): Inte
)
yield* Scope.addFinalizer(scope, dispose)
const batch = yield* CurrentBatch
if (batch) batch.add(reload)
if (batch?.active) batch.reloads.add(reload)
else yield* reload()
return { dispose }
}),