| |
| |
| |
| |
| |
| |
|
|
| import type { WorkspaceBootstrapFile } from "../agents/workspace.js"; |
| import type { OpenClawConfig } from "../config/config.js"; |
|
|
| export type InternalHookEventType = "command" | "session" | "agent" | "gateway"; |
|
|
| export type AgentBootstrapHookContext = { |
| workspaceDir: string; |
| bootstrapFiles: WorkspaceBootstrapFile[]; |
| cfg?: OpenClawConfig; |
| sessionKey?: string; |
| sessionId?: string; |
| agentId?: string; |
| }; |
|
|
| export type AgentBootstrapHookEvent = InternalHookEvent & { |
| type: "agent"; |
| action: "bootstrap"; |
| context: AgentBootstrapHookContext; |
| }; |
|
|
| export interface InternalHookEvent { |
| |
| type: InternalHookEventType; |
| |
| action: string; |
| |
| sessionKey: string; |
| |
| context: Record<string, unknown>; |
| |
| timestamp: Date; |
| |
| messages: string[]; |
| } |
|
|
| export type InternalHookHandler = (event: InternalHookEvent) => Promise<void> | void; |
|
|
| |
| const handlers = new Map<string, InternalHookHandler[]>(); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function registerInternalHook(eventKey: string, handler: InternalHookHandler): void { |
| if (!handlers.has(eventKey)) { |
| handlers.set(eventKey, []); |
| } |
| handlers.get(eventKey)!.push(handler); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function unregisterInternalHook(eventKey: string, handler: InternalHookHandler): void { |
| const eventHandlers = handlers.get(eventKey); |
| if (!eventHandlers) { |
| return; |
| } |
|
|
| const index = eventHandlers.indexOf(handler); |
| if (index !== -1) { |
| eventHandlers.splice(index, 1); |
| } |
|
|
| |
| if (eventHandlers.length === 0) { |
| handlers.delete(eventKey); |
| } |
| } |
|
|
| |
| |
| |
| export function clearInternalHooks(): void { |
| handlers.clear(); |
| } |
|
|
| |
| |
| |
| export function getRegisteredEventKeys(): string[] { |
| return Array.from(handlers.keys()); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export async function triggerInternalHook(event: InternalHookEvent): Promise<void> { |
| const typeHandlers = handlers.get(event.type) ?? []; |
| const specificHandlers = handlers.get(`${event.type}:${event.action}`) ?? []; |
|
|
| const allHandlers = [...typeHandlers, ...specificHandlers]; |
|
|
| if (allHandlers.length === 0) { |
| return; |
| } |
|
|
| for (const handler of allHandlers) { |
| try { |
| await handler(event); |
| } catch (err) { |
| console.error( |
| `Hook error [${event.type}:${event.action}]:`, |
| err instanceof Error ? err.message : String(err), |
| ); |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| export function createInternalHookEvent( |
| type: InternalHookEventType, |
| action: string, |
| sessionKey: string, |
| context: Record<string, unknown> = {}, |
| ): InternalHookEvent { |
| return { |
| type, |
| action, |
| sessionKey, |
| context, |
| timestamp: new Date(), |
| messages: [], |
| }; |
| } |
|
|
| export function isAgentBootstrapEvent(event: InternalHookEvent): event is AgentBootstrapHookEvent { |
| if (event.type !== "agent" || event.action !== "bootstrap") { |
| return false; |
| } |
| const context = event.context as Partial<AgentBootstrapHookContext> | null; |
| if (!context || typeof context !== "object") { |
| return false; |
| } |
| if (typeof context.workspaceDir !== "string") { |
| return false; |
| } |
| return Array.isArray(context.bootstrapFiles); |
| } |
|
|