From 59cc1ebc27819558bef10cee55affbc4578b562e Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 19 Mar 2026 16:01:48 -0400 Subject: [PATCH] use forkScoped + Fiber.join for lazy init (match old Instance.state behavior) --- packages/opencode/src/command/index.ts | 168 ++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts index 5ab0a0fe64..65c0925d72 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, Layer, ServiceMap } from "effect" +import { Effect, Fiber, Layer, ServiceMap } from "effect" import z from "zod" import { Config } from "../config/config" import PROMPT_INITIALIZE from "./template/initialize.txt" @@ -78,9 +78,17 @@ export namespace Command { const commands: Record = {} let task: Promise | undefined +<<<<<<< HEAD async function load() { const cfg = await Config.get() +||||||| parent of 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + const commands = yield* Effect.promise(async () => { + const cfg = await Config.get() +======= + const commands: Record = {} +>>>>>>> 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) +<<<<<<< HEAD commands[Default.INIT] = { name: Default.INIT, description: "create/update AGENTS.md", @@ -153,8 +161,68 @@ export namespace Command { hints: [], } } +||||||| parent of 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + const result: Record = { + [Default.INIT]: { + name: Default.INIT, + description: "create/update AGENTS.md", + source: "command", + get template() { + return PROMPT_INITIALIZE.replace("${path}", instance.worktree) + }, + hints: hints(PROMPT_INITIALIZE), + }, + [Default.REVIEW]: { + name: Default.REVIEW, + description: "review changes [commit|branch|pr], defaults to uncommitted", + source: "command", + get template() { + return PROMPT_REVIEW.replace("${path}", instance.worktree) + }, + subtask: true, + hints: hints(PROMPT_REVIEW), + }, + } + + for (const [name, command] of Object.entries(cfg.command ?? {})) { + result[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), +======= + const load = Effect.fn("Command.load")(function* () { + yield* Effect.promise(async () => { + const cfg = await Config.get() + + commands[Default.INIT] = { + name: Default.INIT, + description: "create/update AGENTS.md", + source: "command", + get template() { + return PROMPT_INITIALIZE.replace("${path}", instance.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}", instance.worktree) + }, + subtask: true, + hints: hints(PROMPT_REVIEW), +>>>>>>> 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) } +<<<<<<< HEAD return { commands, ensure: () => { @@ -166,20 +234,118 @@ export namespace Command { ) return task }, +||||||| parent of 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + // Add skills as invokable commands + for (const skill of await Skill.all()) { + // Skip if a command with this name already exists + if (result[skill.name]) continue + result[skill.name] = { + name: skill.name, + description: skill.description, + source: "skill", + get template() { + return skill.content + }, + hints: [], +======= + 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() { + // since a getter can't be async we need to manually return a promise here + return new Promise(async (resolve, reject) => { + const template = await MCP.getPrompt( + prompt.client, + prompt.name, + prompt.arguments + ? // substitute each argument with $1, $2, etc. + 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}`) ?? [], + } +>>>>>>> 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + } +<<<<<<< HEAD }), ) +||||||| parent of 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + } + + return result + }) +======= + + // Add skills as invokable commands + for (const skill of await Skill.all()) { + // Skip if a command with this name already exists + if (commands[skill.name]) continue + commands[skill.name] = { + name: skill.name, + description: skill.description, + source: "skill", + get template() { + return skill.content + }, + hints: [], + } + } + }) + }) +>>>>>>> 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + + const loadFiber = yield* load().pipe( + Effect.catchCause(() => Effect.void), + Effect.forkScoped, + ) const get = Effect.fn("Command.get")(function* (name: string) { +<<<<<<< HEAD const state = yield* InstanceState.get(cache) yield* Effect.promise(() => state.ensure()) return state.commands[name] +||||||| parent of 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + return commands[name] +======= + yield* Fiber.join(loadFiber) + return commands[name] +>>>>>>> 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) }) const list = Effect.fn("Command.list")(function* () { +<<<<<<< HEAD const state = yield* InstanceState.get(cache) yield* Effect.promise(() => state.ensure()) return Object.values(state.commands) +||||||| parent of 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) + return Object.values(commands) +======= + yield* Fiber.join(loadFiber) + return Object.values(commands) +>>>>>>> 8e11a46fe (use forkScoped + Fiber.join for lazy init (match old Instance.state behavior)) }) return Service.of({ get, list })