mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-17 02:41:41 +00:00
* fix(skills): refresh persisted snapshots after restart Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: Oleksandr Zakotyanskyi <28755978+fif911@users.noreply.github.com> Co-authored-by: Stephan Kadauke <10904538+skadauke@users.noreply.github.com> * fix(clownfish): address review for ghcrawl-156600-autonomous-smoke (1) Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: Oleksandr Zakotyanskyi <28755978+fif911@users.noreply.github.com> Co-authored-by: Stephan Kadauke <10904538+skadauke@users.noreply.github.com> --------- Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com> Co-authored-by: Stephan Kadauke <10904538+skadauke@users.noreply.github.com>
92 lines
2.9 KiB
TypeScript
92 lines
2.9 KiB
TypeScript
// Skill refresh state types describe change notifications emitted by runtime reloads.
|
|
export type SkillsChangeEvent = {
|
|
workspaceDir?: string;
|
|
reason: "watch" | "watch-targets" | "manual" | "remote-node" | "config-change" | "workshop";
|
|
changedPath?: string;
|
|
};
|
|
|
|
const listeners = new Set<(event: SkillsChangeEvent) => void>();
|
|
const workspaceVersions = new Map<string, number>();
|
|
const INITIAL_SKILLS_SNAPSHOT_VERSION = Date.now();
|
|
let globalVersion = INITIAL_SKILLS_SNAPSHOT_VERSION;
|
|
let listenerErrorHandler: ((err: unknown) => void) | undefined;
|
|
|
|
function bumpVersion(current: number): number {
|
|
const now = Date.now();
|
|
return now <= current ? current + 1 : now;
|
|
}
|
|
|
|
function emit(event: SkillsChangeEvent) {
|
|
for (const listener of listeners) {
|
|
try {
|
|
listener(event);
|
|
} catch (err) {
|
|
listenerErrorHandler?.(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function setSkillsChangeListenerErrorHandler(handler?: (err: unknown) => void): void {
|
|
listenerErrorHandler = handler;
|
|
}
|
|
|
|
export function registerSkillsChangeListener(listener: (event: SkillsChangeEvent) => void) {
|
|
listeners.add(listener);
|
|
return () => {
|
|
listeners.delete(listener);
|
|
};
|
|
}
|
|
|
|
export function bumpSkillsSnapshotVersion(params?: {
|
|
workspaceDir?: string;
|
|
reason?: SkillsChangeEvent["reason"];
|
|
changedPath?: string;
|
|
}): number {
|
|
const reason = params?.reason ?? "manual";
|
|
const changedPath = params?.changedPath;
|
|
if (params?.workspaceDir) {
|
|
const current = Math.max(globalVersion, workspaceVersions.get(params.workspaceDir) ?? 0);
|
|
const next = bumpVersion(current);
|
|
workspaceVersions.set(params.workspaceDir, next);
|
|
emit({ workspaceDir: params.workspaceDir, reason, changedPath });
|
|
return next;
|
|
}
|
|
globalVersion = bumpVersion(globalVersion);
|
|
emit({ reason, changedPath });
|
|
return globalVersion;
|
|
}
|
|
|
|
export function getSkillsSnapshotVersion(workspaceDir?: string): number {
|
|
if (!workspaceDir) {
|
|
return globalVersion;
|
|
}
|
|
const local = workspaceVersions.get(workspaceDir) ?? 0;
|
|
return Math.max(globalVersion, local);
|
|
}
|
|
|
|
export function clearSkillsSnapshotVersionForWorkspace(workspaceDir: string): void {
|
|
const local = workspaceVersions.get(workspaceDir);
|
|
if (typeof local === "number" && local > globalVersion) {
|
|
// Keep pending workspace invalidation visible after dropping the workspace
|
|
// key; otherwise teardown can hide a skill change from cached snapshots.
|
|
globalVersion = local;
|
|
}
|
|
workspaceVersions.delete(workspaceDir);
|
|
}
|
|
|
|
export function shouldRefreshSnapshotForVersion(
|
|
cachedVersion?: number,
|
|
nextVersion?: number,
|
|
): boolean {
|
|
const cached = typeof cachedVersion === "number" ? cachedVersion : 0;
|
|
const next = typeof nextVersion === "number" ? nextVersion : 0;
|
|
return next === 0 ? cached > 0 : cached < next;
|
|
}
|
|
|
|
export function resetSkillsRefreshStateForTest(): void {
|
|
listeners.clear();
|
|
workspaceVersions.clear();
|
|
globalVersion = INITIAL_SKILLS_SNAPSHOT_VERSION;
|
|
listenerErrorHandler = undefined;
|
|
}
|