From d1f7df0b976e64d323366d47bedf8b9b027b5464 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sat, 21 Mar 2026 20:09:44 -0400 Subject: [PATCH] refactor(command): initialize state on first access --- packages/opencode/src/command/index.ts | 173 ++++++++++++------------- 1 file changed, 81 insertions(+), 92 deletions(-) diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts index f4bbdb48f2..ff93826103 100644 --- a/packages/opencode/src/command/index.ts +++ b/packages/opencode/src/command/index.ts @@ -2,7 +2,7 @@ import { BusEvent } from "@/bus/bus-event" import { InstanceState } from "@/effect/instance-state" import { makeRunPromise } from "@/effect/run-service" import { SessionID, MessageID } from "@/session/schema" -import { Effect, Fiber, Layer, ServiceMap } from "effect" +import { Effect, Layer, ServiceMap } from "effect" import z from "zod" import { Config } from "../config/config" import { MCP } from "../mcp" @@ -16,7 +16,6 @@ export namespace Command { type State = { commands: Record - load: Fiber.Fiber } export const Event = { @@ -76,107 +75,97 @@ export namespace Command { export const layer = Layer.effect( Service, Effect.gen(function* () { - const cache = yield* InstanceState.make( - Effect.fn("Command.state")(function* (ctx) { - const commands: Record = {} - const load = yield* Effect.fn("Command.load")(function* () { - yield* Effect.promise(async () => { - const cfg = await Config.get() + const init = Effect.fn("Command.state")(function* (ctx) { + const cfg = yield* Effect.promise(() => Config.get()) + const commands: Record = {} - commands[Default.INIT] = { - name: Default.INIT, - description: "create/update AGENTS.md", - source: "command", - get template() { - return PROMPT_INITIALIZE.replace("${path}", ctx.worktree) - }, - hints: hints(PROMPT_INITIALIZE), - } - commands[Default.REVIEW] = { - name: Default.REVIEW, - description: "review changes [commit|branch|pr], defaults to uncommitted", - source: "command", - get template() { - return PROMPT_REVIEW.replace("${path}", ctx.worktree) - }, - subtask: true, - hints: hints(PROMPT_REVIEW), - } + commands[Default.INIT] = { + name: Default.INIT, + description: "create/update AGENTS.md", + source: "command", + get template() { + return PROMPT_INITIALIZE.replace("${path}", ctx.worktree) + }, + hints: hints(PROMPT_INITIALIZE), + } + commands[Default.REVIEW] = { + name: Default.REVIEW, + description: "review changes [commit|branch|pr], defaults to uncommitted", + source: "command", + get template() { + return PROMPT_REVIEW.replace("${path}", ctx.worktree) + }, + subtask: true, + hints: hints(PROMPT_REVIEW), + } - for (const [name, command] of Object.entries(cfg.command ?? {})) { - commands[name] = { - name, - agent: command.agent, - model: command.model, - description: command.description, - source: "command", - get template() { - return command.template - }, - subtask: command.subtask, - hints: hints(command.template), - } - } - - for (const [name, prompt] of Object.entries(await MCP.prompts())) { - commands[name] = { - name, - source: "mcp", - description: prompt.description, - get template() { - return new Promise(async (resolve, reject) => { - const template = await MCP.getPrompt( - prompt.client, - prompt.name, - prompt.arguments - ? Object.fromEntries(prompt.arguments.map((argument, i) => [argument.name, `$${i + 1}`])) - : {}, - ).catch(reject) - resolve( - template?.messages - .map((message) => (message.content.type === "text" ? message.content.text : "")) - .join("\n") || "", - ) - }) - }, - hints: prompt.arguments?.map((_, i) => `$${i + 1}`) ?? [], - } - } - - for (const skill of await Skill.all()) { - if (commands[skill.name]) continue - commands[skill.name] = { - name: skill.name, - description: skill.description, - source: "skill", - get template() { - return skill.content - }, - hints: [], - } - } - }) - })().pipe( - Effect.catchCause((cause) => Effect.sync(() => log.error("init failed", { cause }))), - Effect.forkScoped, - ) - - return { - commands, - load, + for (const [name, command] of Object.entries(cfg.command ?? {})) { + commands[name] = { + name, + agent: command.agent, + model: command.model, + description: command.description, + source: "command", + get template() { + return command.template + }, + subtask: command.subtask, + hints: hints(command.template), } - }), - ) + } + + for (const [name, prompt] of Object.entries(yield* Effect.promise(() => MCP.prompts()))) { + commands[name] = { + name, + source: "mcp", + description: prompt.description, + get template() { + return new Promise(async (resolve, reject) => { + const template = await MCP.getPrompt( + prompt.client, + prompt.name, + prompt.arguments + ? Object.fromEntries(prompt.arguments.map((argument, i) => [argument.name, `$${i + 1}`])) + : {}, + ).catch(reject) + resolve( + template?.messages + .map((message) => (message.content.type === "text" ? message.content.text : "")) + .join("\n") || "", + ) + }) + }, + hints: prompt.arguments?.map((_, i) => `$${i + 1}`) ?? [], + } + } + + for (const skill of yield* Effect.promise(() => Skill.all())) { + if (commands[skill.name]) continue + commands[skill.name] = { + name: skill.name, + description: skill.description, + source: "skill", + get template() { + return skill.content + }, + hints: [], + } + } + + return { + commands, + } + }) + + const cache = yield* InstanceState.make((ctx) => init(ctx)) const get = Effect.fn("Command.get")(function* (name: string) { const state = yield* InstanceState.get(cache) - yield* Fiber.join(state.load) return state.commands[name] }) const list = Effect.fn("Command.list")(function* () { const state = yield* InstanceState.get(cache) - yield* Fiber.join(state.load) return Object.values(state.commands) })