mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
fix: Regenerage sdk and port tests to new v1.4.4 style
This commit is contained in:
@@ -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<Action> {
|
||||
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<boolean> {
|
||||
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<boolean> {
|
||||
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<void> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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* (
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1286,6 +1286,9 @@ export type GlobalEvent = {
|
||||
| EventTodoUpdated
|
||||
| EventSessionStatus
|
||||
| EventSessionIdle
|
||||
| EventSuggestionShown
|
||||
| EventSuggestionAccepted
|
||||
| EventSuggestionDismissed
|
||||
| EventSessionCompacted
|
||||
| EventCommandExecuted
|
||||
| EventVcsBranchUpdated
|
||||
|
||||
Reference in New Issue
Block a user