fix(plugin): dispatch openclaw lifecycle events from handlers
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { describe, expect, mock, spyOn, test } from "bun:test"
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
|
||||
import type { OhMyOpenCodeConfig } from "../config"
|
||||
import * as openclawRuntimeDispatch from "../openclaw/runtime-dispatch"
|
||||
import type { ToolsRecord } from "./types"
|
||||
import { createToolRegistry, trimToolsToCap } from "./tool-registry"
|
||||
|
||||
const fakeTool = tool({
|
||||
description: "test tool",
|
||||
@@ -12,6 +13,58 @@ const fakeTool = tool({
|
||||
},
|
||||
})
|
||||
|
||||
const delegateTaskTool = tool({
|
||||
description: "task tool",
|
||||
args: {},
|
||||
async execute(): Promise<string> {
|
||||
return "ok"
|
||||
},
|
||||
})
|
||||
|
||||
const syncSessionCreatedCallbacks: Array<
|
||||
((event: { sessionID: string; parentID: string; title: string }) => Promise<void>) | undefined
|
||||
> = []
|
||||
|
||||
mock.module("../tools", () => ({
|
||||
builtinTools: { bash: fakeTool, read: fakeTool },
|
||||
createBackgroundTools: mock(() => ({})),
|
||||
createCallOmoAgent: mock(() => fakeTool),
|
||||
createLookAt: mock(() => fakeTool),
|
||||
createSkillMcpTool: mock(() => fakeTool),
|
||||
createSkillTool: mock(() => fakeTool),
|
||||
createGrepTools: mock(() => ({})),
|
||||
createGlobTools: mock(() => ({})),
|
||||
createAstGrepTools: mock(() => ({})),
|
||||
createSessionManagerTools: mock(() => ({})),
|
||||
createDelegateTask: mock((options: { onSyncSessionCreated?: typeof syncSessionCreatedCallbacks[number] }) => {
|
||||
syncSessionCreatedCallbacks.push(options.onSyncSessionCreated)
|
||||
return delegateTaskTool
|
||||
}),
|
||||
discoverCommandsSync: mock(() => []),
|
||||
interactive_bash: fakeTool,
|
||||
createTaskCreateTool: mock(() => fakeTool),
|
||||
createTaskGetTool: mock(() => fakeTool),
|
||||
createTaskList: mock(() => fakeTool),
|
||||
createTaskUpdateTool: mock(() => fakeTool),
|
||||
createHashlineEditTool: mock(() => fakeTool),
|
||||
}))
|
||||
|
||||
const trackedPaneBySession = new Map<string, string>()
|
||||
|
||||
const { createToolRegistry, trimToolsToCap } = await import("./tool-registry")
|
||||
const dispatchOpenClawEvent = spyOn(openclawRuntimeDispatch, "dispatchOpenClawEvent")
|
||||
|
||||
function createPluginConfig(overrides: Partial<OhMyOpenCodeConfig> = {}): OhMyOpenCodeConfig {
|
||||
return {
|
||||
git_master: {
|
||||
commit_footer: false,
|
||||
include_co_authored_by: false,
|
||||
git_env_prefix: "",
|
||||
},
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
describe("#given tool trimming prioritization", () => {
|
||||
test("#when max_tools trims a hashline edit registration named edit #then edit is removed before higher-priority tools", () => {
|
||||
const filteredTools = {
|
||||
@@ -30,9 +83,11 @@ describe("#given tool trimming prioritization", () => {
|
||||
|
||||
describe("#given task_system configuration", () => {
|
||||
test("#when task_system is omitted #then task tools are not registered by default", () => {
|
||||
syncSessionCreatedCallbacks.length = 0
|
||||
|
||||
const result = createToolRegistry({
|
||||
ctx: { directory: "/tmp" } as Parameters<typeof createToolRegistry>[0]["ctx"],
|
||||
pluginConfig: {},
|
||||
pluginConfig: createPluginConfig(),
|
||||
managers: {
|
||||
backgroundManager: {},
|
||||
tmuxSessionManager: {},
|
||||
@@ -55,11 +110,13 @@ describe("#given task_system configuration", () => {
|
||||
})
|
||||
|
||||
test("#when task_system is enabled #then task tools are registered", () => {
|
||||
syncSessionCreatedCallbacks.length = 0
|
||||
|
||||
const result = createToolRegistry({
|
||||
ctx: { directory: "/tmp" } as Parameters<typeof createToolRegistry>[0]["ctx"],
|
||||
pluginConfig: {
|
||||
pluginConfig: createPluginConfig({
|
||||
experimental: { task_system: true },
|
||||
},
|
||||
}),
|
||||
managers: {
|
||||
backgroundManager: {},
|
||||
tmuxSessionManager: {},
|
||||
@@ -84,9 +141,11 @@ describe("#given task_system configuration", () => {
|
||||
|
||||
describe("#given tmux integration is disabled", () => {
|
||||
test("#when system tmux is available #then interactive_bash remains registered", () => {
|
||||
syncSessionCreatedCallbacks.length = 0
|
||||
|
||||
const result = createToolRegistry({
|
||||
ctx: { directory: "/tmp" } as Parameters<typeof createToolRegistry>[0]["ctx"],
|
||||
pluginConfig: {
|
||||
pluginConfig: createPluginConfig({
|
||||
tmux: {
|
||||
enabled: false,
|
||||
layout: "main-vertical",
|
||||
@@ -95,7 +154,7 @@ describe("#given tmux integration is disabled", () => {
|
||||
agent_pane_min_width: 40,
|
||||
isolation: "inline",
|
||||
},
|
||||
},
|
||||
}),
|
||||
managers: {
|
||||
backgroundManager: {},
|
||||
tmuxSessionManager: {},
|
||||
@@ -115,9 +174,11 @@ describe("#given tmux integration is disabled", () => {
|
||||
})
|
||||
|
||||
test("#when system tmux is unavailable #then interactive_bash is not registered", () => {
|
||||
syncSessionCreatedCallbacks.length = 0
|
||||
|
||||
const result = createToolRegistry({
|
||||
ctx: { directory: "/tmp" } as Parameters<typeof createToolRegistry>[0]["ctx"],
|
||||
pluginConfig: {
|
||||
pluginConfig: createPluginConfig({
|
||||
tmux: {
|
||||
enabled: false,
|
||||
layout: "main-vertical",
|
||||
@@ -126,7 +187,7 @@ describe("#given tmux integration is disabled", () => {
|
||||
agent_pane_min_width: 40,
|
||||
isolation: "inline",
|
||||
},
|
||||
},
|
||||
}),
|
||||
managers: {
|
||||
backgroundManager: {},
|
||||
tmuxSessionManager: {},
|
||||
@@ -145,3 +206,64 @@ describe("#given tmux integration is disabled", () => {
|
||||
expect(result.filteredTools).not.toHaveProperty("interactive_bash")
|
||||
})
|
||||
})
|
||||
|
||||
describe("#given openclaw is enabled for sync task sessions", () => {
|
||||
test("#when the sync session-created callback runs #then it dispatches openclaw with the tracked pane id", async () => {
|
||||
syncSessionCreatedCallbacks.length = 0
|
||||
dispatchOpenClawEvent.mockReset()
|
||||
trackedPaneBySession.clear()
|
||||
|
||||
const tmuxSessionManager = {
|
||||
async onSessionCreated(event: { properties?: { info?: { id?: string } } }): Promise<void> {
|
||||
const sessionID = event.properties?.info?.id
|
||||
if (sessionID) {
|
||||
trackedPaneBySession.set(sessionID, `%pane-${sessionID}`)
|
||||
}
|
||||
},
|
||||
getTrackedPaneId(sessionID: string): string | undefined {
|
||||
return trackedPaneBySession.get(sessionID)
|
||||
},
|
||||
}
|
||||
|
||||
const openclawConfig = {
|
||||
enabled: true,
|
||||
gateways: {},
|
||||
hooks: {},
|
||||
}
|
||||
|
||||
createToolRegistry({
|
||||
ctx: { directory: "/tmp/project" } as Parameters<typeof createToolRegistry>[0]["ctx"],
|
||||
pluginConfig: createPluginConfig({ openclaw: openclawConfig }),
|
||||
managers: {
|
||||
backgroundManager: {},
|
||||
tmuxSessionManager,
|
||||
skillMcpManager: {},
|
||||
} as Parameters<typeof createToolRegistry>[0]["managers"],
|
||||
skillContext: {
|
||||
mergedSkills: [],
|
||||
availableSkills: [],
|
||||
browserProvider: "playwright",
|
||||
disabledSkills: new Set(),
|
||||
},
|
||||
availableCategories: [],
|
||||
})
|
||||
|
||||
const onSyncSessionCreated = syncSessionCreatedCallbacks[syncSessionCreatedCallbacks.length - 1]
|
||||
await onSyncSessionCreated?.({
|
||||
sessionID: "ses-sync-1",
|
||||
parentID: "ses-parent",
|
||||
title: "sync task",
|
||||
})
|
||||
|
||||
expect(dispatchOpenClawEvent).toHaveBeenCalledTimes(1)
|
||||
expect(dispatchOpenClawEvent).toHaveBeenCalledWith({
|
||||
config: openclawConfig,
|
||||
rawEvent: "session.created",
|
||||
context: {
|
||||
sessionId: "ses-sync-1",
|
||||
projectPath: "/tmp/project",
|
||||
tmuxPaneId: "%pane-ses-sync-1",
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user