From 3c7b0a7d3c87fe99630581ac55e2e8223afb4d20 Mon Sep 17 00:00:00 2001 From: Johnny Amancio Date: Fri, 17 Apr 2026 12:47:27 +0200 Subject: [PATCH] fix: Regenerage sdk and port tests to new v1.4.4 style --- .../opencode/src/kilocode/suggestion/index.ts | 33 +++---- packages/opencode/src/tool/registry.ts | 6 ++ .../test/kilocode/read-directory.test.ts | 8 +- .../test/kilocode/suggestion/tool.test.ts | 97 ++++++++++++------- packages/opencode/test/tool/registry.test.ts | 4 +- packages/sdk/js/src/v2/gen/types.gen.ts | 3 + 6 files changed, 91 insertions(+), 60 deletions(-) diff --git a/packages/opencode/src/kilocode/suggestion/index.ts b/packages/opencode/src/kilocode/suggestion/index.ts index 0c1473f924e..57eebd70125 100644 --- a/packages/opencode/src/kilocode/suggestion/index.ts +++ b/packages/opencode/src/kilocode/suggestion/index.ts @@ -1,7 +1,6 @@ import { Bus } from "../../bus" import { BusEvent } from "../../bus/bus-event" import { Identifier } from "../../id/id" -import { Instance } from "../../project/instance" import { Log } from "../../util/log" import z from "zod" @@ -73,20 +72,16 @@ export namespace Suggestion { ), } - const state = Instance.state(async () => { - const pending: Record< - string, - { - info: Request - resolve: (action: Action) => void - reject: (error: any) => void - } - > = {} - - return { - pending, + // kilocode_change - Instance.state() removed in v1.4.4; use module-level state + // (request IDs are globally unique so instance scoping is not needed) + const pending: Record< + string, + { + info: Request + resolve: (action: Action) => void + reject: (error: any) => void } - }) + > = {} export async function show(input: { sessionID: string @@ -95,7 +90,7 @@ export namespace Suggestion { blocking?: boolean tool?: { messageID: string; callID: string } }): Promise { - const s = await state() + const s = { pending } const id = Identifier.ascending("suggestion") log.info("shown", { id, actions: input.actions.length }) @@ -119,7 +114,7 @@ export namespace Suggestion { } export async function accept(input: { requestID: string; index: number }): Promise { - const s = await state() + const s = { pending } const existing = s.pending[input.requestID] if (!existing) { log.warn("accept for unknown request", { requestID: input.requestID }) @@ -150,7 +145,7 @@ export namespace Suggestion { } export async function dismiss(requestID: string): Promise { - const s = await state() + const s = { pending } const existing = s.pending[requestID] if (!existing) { log.warn("dismiss for unknown request", { requestID }) @@ -176,7 +171,7 @@ export namespace Suggestion { } export async function dismissAll(sessionID: string): Promise { - const s = await state() + const s = { pending } for (const [id, entry] of Object.entries(s.pending)) { if (entry.info.sessionID !== sessionID) continue delete s.pending[id] @@ -190,6 +185,6 @@ export namespace Suggestion { } export async function list() { - return state().then((state) => Object.values(state.pending).map((item) => item.info)) + return Object.values(pending).map((item) => item.info) } } diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index a7a290acd65..cb5d689dcbc 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -23,6 +23,7 @@ import { ProviderID, type ModelID } from "../provider/schema" import { WebSearchTool } from "./websearch" import { CodeSearchTool } from "./codesearch" import { KiloToolRegistry } from "../kilocode/tool/registry" // kilocode_change +import { makeRuntime } from "@/effect/run-service" // kilocode_change import { Flag } from "@/flag/flag" import { Log } from "@/util/log" import { LspTool } from "./lsp" @@ -334,4 +335,9 @@ export namespace ToolRegistry { Layer.provide(Truncate.defaultLayer), ), ) + + // kilocode_change start + const { runPromise } = makeRuntime(Service, defaultLayer) + export const ids = () => runPromise((svc) => svc.ids()) + // kilocode_change end } diff --git a/packages/opencode/test/kilocode/read-directory.test.ts b/packages/opencode/test/kilocode/read-directory.test.ts index ca40c3b25d1..eb024fc9e91 100644 --- a/packages/opencode/test/kilocode/read-directory.test.ts +++ b/packages/opencode/test/kilocode/read-directory.test.ts @@ -8,6 +8,7 @@ import { AppFileSystem } from "../../src/filesystem" import { FileTime } from "../../src/file/time" import { LSP } from "../../src/lsp" import { Instruction } from "../../src/session/instruction" +import { Truncate } from "../../src/tool/truncate" import { MessageID, SessionID } from "../../src/session/schema" import { ReadTool } from "../../src/tool/read" import { Tool } from "../../src/tool/tool" @@ -22,7 +23,7 @@ const baseCtx = { abort: AbortSignal.any([]), messages: [], metadata: () => {}, - ask: async () => {}, + ask: () => Effect.void, } const expandCtx = { ...baseCtx, extra: { includeDirectoryFiles: true } } @@ -35,12 +36,13 @@ const it = testEffect( FileTime.defaultLayer, Instruction.defaultLayer, LSP.defaultLayer, + Truncate.defaultLayer, ), ) const init = Effect.fn("ReadDirectoryTest.init")(function* () { const info = yield* ReadTool - return yield* Effect.promise(() => info.init()) + return yield* Tool.init(info) }) const run = Effect.fn("ReadDirectoryTest.run")(function* ( @@ -48,7 +50,7 @@ const run = Effect.fn("ReadDirectoryTest.run")(function* ( ctx = expandCtx, ) { const tool = yield* init() - return yield* Effect.promise(() => tool.execute(args, ctx)) + return yield* tool.execute(args, ctx as any) }) const exec = Effect.fn("ReadDirectoryTest.exec")(function* ( diff --git a/packages/opencode/test/kilocode/suggestion/tool.test.ts b/packages/opencode/test/kilocode/suggestion/tool.test.ts index 74311ca5c7a..e4d3e671a0e 100644 --- a/packages/opencode/test/kilocode/suggestion/tool.test.ts +++ b/packages/opencode/test/kilocode/suggestion/tool.test.ts @@ -1,7 +1,22 @@ import { afterEach, beforeEach, describe, expect, test, spyOn } from "bun:test" +import { Effect, Layer, ManagedRuntime } from "effect" import { Command } from "../../../src/command" import { Suggestion } from "../../../src/kilocode/suggestion" import { SuggestTool } from "../../../src/kilocode/suggestion/tool" +import { Tool } from "../../../src/tool/tool" +import { Truncate } from "../../../src/tool/truncate" +import { Agent } from "../../../src/agent/agent" + +const toolRuntime = ManagedRuntime.make(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer)) + +async function initTool() { + return toolRuntime.runPromise( + Effect.gen(function* () { + const info = yield* SuggestTool + return yield* Tool.init(info) + }), + ) +} const ctx = { sessionID: "ses_test", @@ -23,7 +38,7 @@ const ctx = { }, ], metadata: () => {}, - ask: async () => {}, + ask: () => Effect.void, } describe("tool.suggest", () => { @@ -41,15 +56,17 @@ describe("tool.suggest", () => { }) test("returns dismissal result when suggestion is dismissed", async () => { - const tool = await SuggestTool.init() + const tool = await initTool() show.mockRejectedValueOnce(new Suggestion.DismissedError()) - const result = await tool.execute( - { - suggest: "Run review?", - actions: [{ label: "Start", prompt: "/local-review-uncommitted" }], - }, - ctx as any, + const result = await toolRuntime.runPromise( + tool.execute( + { + suggest: "Run review?", + actions: [{ label: "Start", prompt: "/local-review-uncommitted" }], + }, + ctx as any, + ), ) expect(result.title).toBe("Suggestion dismissed") @@ -58,7 +75,7 @@ describe("tool.suggest", () => { }) test("resolves command template for slash-command action prompt", async () => { - const tool = await SuggestTool.init() + const tool = await initTool() show.mockResolvedValueOnce({ label: "Start review", description: "Run a local review now", @@ -71,12 +88,14 @@ describe("tool.suggest", () => { hints: [], }) - const result = await tool.execute( - { - suggest: "Run review?", - actions: [{ label: "Start review", prompt: "/local-review-uncommitted" }], - }, - ctx as any, + const result = await toolRuntime.runPromise( + tool.execute( + { + suggest: "Run review?", + actions: [{ label: "Start review", prompt: "/local-review-uncommitted" }], + }, + ctx as any, + ), ) expect(result.title).toBe("User accepted: Start review") @@ -92,18 +111,20 @@ describe("tool.suggest", () => { }) test("returns plain-text prompt directly for non-command actions", async () => { - const tool = await SuggestTool.init() + const tool = await initTool() show.mockResolvedValueOnce({ label: "Run tests", prompt: "Run the test suite and fix any failures", }) - const result = await tool.execute( - { - suggest: "Tests might need running", - actions: [{ label: "Run tests", prompt: "Run the test suite and fix any failures" }], - }, - ctx as any, + const result = await toolRuntime.runPromise( + tool.execute( + { + suggest: "Tests might need running", + actions: [{ label: "Run tests", prompt: "Run the test suite and fix any failures" }], + }, + ctx as any, + ), ) expect(result.title).toBe("User accepted: Run tests") @@ -114,19 +135,21 @@ describe("tool.suggest", () => { }) test("falls back to raw prompt when command is not found", async () => { - const tool = await SuggestTool.init() + const tool = await initTool() show.mockResolvedValueOnce({ label: "Unknown cmd", prompt: "/nonexistent-command", }) cmdGet.mockResolvedValueOnce(undefined) - const result = await tool.execute( - { - suggest: "Try this?", - actions: [{ label: "Unknown cmd", prompt: "/nonexistent-command" }], - }, - ctx as any, + const result = await toolRuntime.runPromise( + tool.execute( + { + suggest: "Try this?", + actions: [{ label: "Unknown cmd", prompt: "/nonexistent-command" }], + }, + ctx as any, + ), ) expect(result.title).toBe("User accepted: Unknown cmd") @@ -135,7 +158,7 @@ describe("tool.suggest", () => { }) test("falls back to raw prompt when template resolution fails", async () => { - const tool = await SuggestTool.init() + const tool = await initTool() show.mockResolvedValueOnce({ label: "Start review", prompt: "/local-review-uncommitted", @@ -147,12 +170,14 @@ describe("tool.suggest", () => { hints: [], }) - const result = await tool.execute( - { - suggest: "Run review?", - actions: [{ label: "Start review", prompt: "/local-review-uncommitted" }], - }, - ctx as any, + const result = await toolRuntime.runPromise( + tool.execute( + { + suggest: "Run review?", + actions: [{ label: "Start review", prompt: "/local-review-uncommitted" }], + }, + ctx as any, + ), ) expect(result.title).toBe("User accepted: Start review") diff --git a/packages/opencode/test/tool/registry.test.ts b/packages/opencode/test/tool/registry.test.ts index bff38e08e79..40d63a05f98 100644 --- a/packages/opencode/test/tool/registry.test.ts +++ b/packages/opencode/test/tool/registry.test.ts @@ -1,11 +1,11 @@ -import { afterEach, describe, expect } from "bun:test" +import { afterEach, describe, expect, test } from "bun:test" import path from "path" import fs from "fs/promises" import { Effect, Layer } from "effect" import { Instance } from "../../src/project/instance" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import { ToolRegistry } from "../../src/tool/registry" -import { provideTmpdirInstance } from "../fixture/fixture" +import { provideTmpdirInstance, tmpdir } from "../fixture/fixture" import { testEffect } from "../lib/effect" const node = CrossSpawnSpawner.defaultLayer diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 496c86c402a..83824960942 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1286,6 +1286,9 @@ export type GlobalEvent = { | EventTodoUpdated | EventSessionStatus | EventSessionIdle + | EventSuggestionShown + | EventSuggestionAccepted + | EventSuggestionDismissed | EventSessionCompacted | EventCommandExecuted | EventVcsBranchUpdated