diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts index 02ad0d3b33..8bb5dc522a 100644 --- a/packages/opencode/src/session/todo.ts +++ b/packages/opencode/src/session/todo.ts @@ -1,6 +1,8 @@ import { BusEvent } from "@/bus/bus-event" import { Bus } from "@/bus" +import { makeRuntime } from "@/effect/run-service" import { SessionID } from "./schema" +import { Effect, Layer, ServiceMap } from "effect" import z from "zod" import { Database, eq, asc } from "../storage/db" import { TodoTable } from "./session.sql" @@ -25,33 +27,69 @@ export namespace Todo { ), } - export function update(input: { sessionID: SessionID; todos: Info[] }) { - Database.transaction((db) => { - db.delete(TodoTable).where(eq(TodoTable.session_id, input.sessionID)).run() - if (input.todos.length === 0) return - db.insert(TodoTable) - .values( - input.todos.map((todo, position) => ({ - session_id: input.sessionID, - content: todo.content, - status: todo.status, - priority: todo.priority, - position, - })), - ) - .run() - }) - Bus.publish(Event.Updated, input) + export interface Interface { + readonly update: (input: { sessionID: SessionID; todos: Info[] }) => Effect.Effect + readonly get: (sessionID: SessionID) => Effect.Effect } - export function get(sessionID: SessionID) { - const rows = Database.use((db) => - db.select().from(TodoTable).where(eq(TodoTable.session_id, sessionID)).orderBy(asc(TodoTable.position)).all(), - ) - return rows.map((row) => ({ - content: row.content, - status: row.status, - priority: row.priority, - })) + export class Service extends ServiceMap.Service()("@opencode/SessionTodo") {} + + export const layer = Layer.effect( + Service, + Effect.gen(function* () { + const bus = yield* Bus.Service + + const update = Effect.fn("Todo.update")(function* (input: { sessionID: SessionID; todos: Info[] }) { + yield* Effect.sync(() => + Database.transaction((db) => { + db.delete(TodoTable).where(eq(TodoTable.session_id, input.sessionID)).run() + if (input.todos.length === 0) return + db.insert(TodoTable) + .values( + input.todos.map((todo, position) => ({ + session_id: input.sessionID, + content: todo.content, + status: todo.status, + priority: todo.priority, + position, + })), + ) + .run() + }), + ) + yield* bus.publish(Event.Updated, input) + }) + + const get = Effect.fn("Todo.get")(function* (sessionID: SessionID) { + const rows = yield* Effect.sync(() => + Database.use((db) => + db + .select() + .from(TodoTable) + .where(eq(TodoTable.session_id, sessionID)) + .orderBy(asc(TodoTable.position)) + .all(), + ), + ) + return rows.map((row) => ({ + content: row.content, + status: row.status, + priority: row.priority, + })) + }) + + return Service.of({ update, get }) + }), + ) + + const defaultLayer = layer.pipe(Layer.provide(Bus.layer)) + const { runPromise } = makeRuntime(Service, defaultLayer) + + export async function update(input: { sessionID: SessionID; todos: Info[] }) { + return runPromise((svc) => svc.update(input)) + } + + export async function get(sessionID: SessionID) { + return runPromise((svc) => svc.get(sessionID)) } } diff --git a/packages/opencode/src/tool/todo.ts b/packages/opencode/src/tool/todo.ts index 53b687b1d1..a5e56cb23e 100644 --- a/packages/opencode/src/tool/todo.ts +++ b/packages/opencode/src/tool/todo.ts @@ -16,7 +16,7 @@ export const TodoWriteTool = Tool.define("todowrite", { metadata: {}, }) - Todo.update({ + await Todo.update({ sessionID: ctx.sessionID, todos: params.todos, })