Files
openclaw/extensions/workboard/index.ts
T
Peter Steinberger b5b17c654b fix: keep Workboard visible in the sidebar (#125473)
* fix(ui): keep workboard in sidebar navigation

* test(ui): align workboard navigation ownership

* fix(ui): preserve saved workboard sidebar slots

* test(ui): shrink assertion safety baseline

* fix(plugins): bind native routes to bundled owners

* refactor(plugins): isolate native route policy
2026-08-17 18:44:39 -07:00

119 lines
3.8 KiB
TypeScript

// Workboard plugin entrypoint registers its OpenClaw integration.
import { definePluginEntry } from "./api.js";
import { registerWorkboardGatewayMethods } from "./runtime-api.js";
import { createWorkboardAutomationNudgeService } from "./src/automation-nudge.js";
import { createWorkboardChangeEventService } from "./src/change-events.js";
import { registerWorkboardCommand } from "./src/command.js";
import { cleanupWorkboardRunWorktree } from "./src/dispatcher-workspace.js";
import {
createWorkboardLifecycleService,
readWorkboardLifecycleSessions,
syncWorkboardAgentEnded,
syncWorkboardSubagentEnded,
} from "./src/lifecycle-sync.js";
import { WorkboardStore } from "./src/store.js";
import { createWorkboardTools } from "./src/tools.js";
import {
guardWorkboardToolsForWorkspaceAccess,
WORKBOARD_TOOL_NAMES,
} from "./src/workspace-access.js";
export default definePluginEntry({
id: "workboard",
name: "Workboard",
description: "Dashboard workboard for agent-owned issues and sessions.",
register(api) {
const store = WorkboardStore.openSqlite();
const automationNudge = createWorkboardAutomationNudgeService({
store,
gateway: api.runtime.gateway,
});
const lifecycleSync = createWorkboardLifecycleService({
store,
readSessions: async (options) =>
await readWorkboardLifecycleSessions(api.runtime.gateway, options),
});
api.session.controls.registerControlUiDescriptor({
surface: "tab",
id: "workboard",
label: "Workboard",
placement: "route:workboard",
icon: "kanban",
group: "control",
requiredScopes: ["operator.read"],
});
api.session.controls.registerControlUiDescriptor({
surface: "widget",
id: "board",
label: "Workboard board",
requiredScopes: ["operator.read"],
});
api.session.controls.registerControlUiDescriptor({
surface: "widget",
id: "card",
label: "Workboard card",
requiredScopes: ["operator.write"],
});
api.session.controls.registerControlUiDescriptor({
surface: "widget",
id: "mini",
label: "Workboard summary",
requiredScopes: ["operator.read"],
});
registerWorkboardGatewayMethods({ api, store });
registerWorkboardCommand({ api, store });
api.registerService(createWorkboardChangeEventService(store));
api.registerService(automationNudge);
api.registerService(lifecycleSync);
api.on("gateway_start", () => lifecycleSync.onGatewayStart());
api.on("gateway_stop", () => lifecycleSync.onGatewayStop());
api.on("subagent_ended", async (event) => {
await Promise.all([
syncWorkboardSubagentEnded({ store, event, onMatched: automationNudge.nudge }),
event.runId
? cleanupWorkboardRunWorktree({
store,
worktrees: api.runtime.worktrees,
runId: event.runId,
})
: undefined,
]);
});
api.on("agent_end", async (event, context) => {
await syncWorkboardAgentEnded({
store,
event,
context,
onMatched: automationNudge.nudge,
});
});
api.registerCli(
async ({ program }) => {
const { registerWorkboardCli } = await import("./src/cli.js");
registerWorkboardCli({ program, store });
},
{
descriptors: [
{
name: "workboard",
description: "Manage Workboard cards and worker dispatch",
hasSubcommands: true,
},
],
},
);
api.registerTool(
(context) =>
guardWorkboardToolsForWorkspaceAccess(
createWorkboardTools({ api, context, store }),
context,
api.runtime.sandbox.resolveWorkspaceAuthority,
),
{
names: [...WORKBOARD_TOOL_NAMES],
optional: true,
},
);
},
});