refactor: add typed gateway startup hook guard (openclaw#20569) thanks @mcaxtr

This commit is contained in:
Gustavo Madeira Santana
2026-02-19 00:48:48 -05:00
parent 2c463d5842
commit ca2d77978d
3 changed files with 46 additions and 15 deletions

View File

@@ -1,35 +1,28 @@
import { listAgentIds, resolveAgentWorkspaceDir } from "../../../agents/agent-scope.js";
import type { CliDeps } from "../../../cli/deps.js";
import { createDefaultDeps } from "../../../cli/deps.js";
import type { OpenClawConfig } from "../../../config/config.js";
import { runBootOnce } from "../../../gateway/boot.js";
import { createSubsystemLogger } from "../../../logging/subsystem.js";
import type { HookHandler } from "../../hooks.js";
type BootHookContext = {
cfg?: OpenClawConfig;
workspaceDir?: string;
deps?: CliDeps;
};
import { isGatewayStartupEvent } from "../../internal-hooks.js";
const log = createSubsystemLogger("hooks/boot-md");
const runBootChecklist: HookHandler = async (event) => {
if (event.type !== "gateway" || event.action !== "startup") {
if (!isGatewayStartupEvent(event)) {
return;
}
const context = (event.context ?? {}) as BootHookContext;
if (!context.cfg) {
if (!event.context.cfg) {
return;
}
const deps = context.deps ?? createDefaultDeps();
const agentIds = listAgentIds(context.cfg);
const cfg = event.context.cfg;
const deps = event.context.deps ?? createDefaultDeps();
const agentIds = listAgentIds(cfg);
for (const agentId of agentIds) {
const workspaceDir = resolveAgentWorkspaceDir(context.cfg, agentId);
const result = await runBootOnce({ cfg: context.cfg, deps, workspaceDir, agentId });
const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId);
const result = await runBootOnce({ cfg, deps, workspaceDir, agentId });
if (result.status === "failed") {
log.warn("boot-md failed for agent startup run", {
agentId,

View File

@@ -4,12 +4,14 @@ import {
createInternalHookEvent,
getRegisteredEventKeys,
isAgentBootstrapEvent,
isGatewayStartupEvent,
isMessageReceivedEvent,
isMessageSentEvent,
registerInternalHook,
triggerInternalHook,
unregisterInternalHook,
type AgentBootstrapHookContext,
type GatewayStartupHookContext,
type MessageReceivedHookContext,
type MessageSentHookContext,
} from "./internal-hooks.js";
@@ -185,6 +187,21 @@ describe("hooks", () => {
});
});
describe("isGatewayStartupEvent", () => {
it("returns true for gateway:startup events with expected context", () => {
const context: GatewayStartupHookContext = {
cfg: {},
};
const event = createInternalHookEvent("gateway", "startup", "gateway:startup", context);
expect(isGatewayStartupEvent(event)).toBe(true);
});
it("returns false for non-startup gateway events", () => {
const event = createInternalHookEvent("gateway", "shutdown", "gateway:shutdown", {});
expect(isGatewayStartupEvent(event)).toBe(false);
});
});
describe("isMessageReceivedEvent", () => {
it("returns true for message:received events with expected context", () => {
const context: MessageReceivedHookContext = {

View File

@@ -6,6 +6,7 @@
*/
import type { WorkspaceBootstrapFile } from "../agents/workspace.js";
import type { CliDeps } from "../cli/deps.js";
import type { OpenClawConfig } from "../config/config.js";
export type InternalHookEventType = "command" | "session" | "agent" | "gateway" | "message";
@@ -25,6 +26,18 @@ export type AgentBootstrapHookEvent = InternalHookEvent & {
context: AgentBootstrapHookContext;
};
export type GatewayStartupHookContext = {
cfg?: OpenClawConfig;
deps?: CliDeps;
workspaceDir?: string;
};
export type GatewayStartupHookEvent = InternalHookEvent & {
type: "gateway";
action: "startup";
context: GatewayStartupHookContext;
};
// ============================================================================
// Message Hook Events
// ============================================================================
@@ -234,6 +247,14 @@ export function isAgentBootstrapEvent(event: InternalHookEvent): event is AgentB
return Array.isArray(context.bootstrapFiles);
}
export function isGatewayStartupEvent(event: InternalHookEvent): event is GatewayStartupHookEvent {
if (event.type !== "gateway" || event.action !== "startup") {
return false;
}
const context = event.context as GatewayStartupHookContext | null;
return Boolean(context && typeof context === "object");
}
export function isMessageReceivedEvent(
event: InternalHookEvent,
): event is MessageReceivedHookEvent {