Files
openclaw/extensions/workboard/src/change-events.ts
Peter Steinberger 9d79d85f46 feat(workboard): refresh Control UI from live changes (#99051)
* feat(workboard): refresh control ui from live changes

* refactor(workboard): tighten live invalidation path

* chore(workboard): preserve locale catalog state

* refactor(gateway): keep broadcaster runtime object

* refactor(plugin-sdk): own gateway event types

* test(workboard): bind reconciliation mocks

* test(release): declare recovery helpers

* fix(workboard): cancel direct loads on teardown
2026-07-14 05:17:23 -07:00

44 lines
1.3 KiB
TypeScript

import type { WorkboardChange } from "@openclaw/workboard-contract";
import type { OpenClawPluginService } from "../api.js";
import type { WorkboardStore } from "./store.js";
const WORKBOARD_EXTERNAL_CHANGE_CHECK_MS = 1000;
export function createWorkboardChangeEventService(store: WorkboardStore): OpenClawPluginService {
let unsubscribe: (() => void) | undefined;
let timer: ReturnType<typeof setInterval> | undefined;
return {
id: "workboard-change-events",
start(ctx) {
const gatewayEvents = ctx.gatewayEvents;
if (!gatewayEvents) {
return;
}
const emit = (change: WorkboardChange) => {
gatewayEvents.emit("changed", change, {
scope: "operator.read",
});
};
unsubscribe = store.subscribeChanges(emit);
store.announceChangeEpoch();
timer = setInterval(() => {
try {
store.reconcileExternalChanges();
} catch (error) {
ctx.logger.warn(`workboard external change check failed: ${String(error)}`);
}
}, WORKBOARD_EXTERNAL_CHANGE_CHECK_MS);
timer.unref?.();
},
stop() {
unsubscribe?.();
unsubscribe = undefined;
if (timer) {
clearInterval(timer);
timer = undefined;
}
},
};
}