refactor: split oversized catalog and protocol helpers (#106476)

This commit is contained in:
Peter Steinberger
2026-07-13 11:10:42 -04:00
committed by GitHub
parent 4a7f8c5215
commit 2626e97b4c
4 changed files with 87 additions and 79 deletions
@@ -0,0 +1,16 @@
import { createHash } from "node:crypto";
export const CLAUDE_LOCAL_SESSION_HOST_ID = "gateway:local";
const CLAUDE_ADOPTED_SESSION_KEY_PREFIX = "plugin:anthropic:catalog-adopt:claude:";
export function adoptedSourceKey(hostId: string, threadId: string): string {
return `${hostId}\0${threadId}`;
}
export function adoptedSessionKey(hostId: string, threadId: string): string {
// Local rows hash threadId alone: adopted keys minted before node support
// must stay stable, or existing adopted sessions would orphan/duplicate.
const source =
hostId === CLAUDE_LOCAL_SESSION_HOST_ID ? threadId : adoptedSourceKey(hostId, threadId);
return `${CLAUDE_ADOPTED_SESSION_KEY_PREFIX}${createHash("sha256").update(source).digest("hex")}`;
}
+5 -16
View File
@@ -1,4 +1,3 @@
import { createHash } from "node:crypto";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
@@ -19,6 +18,11 @@ export const CLAUDE_SESSIONS_LIST_COMMAND = "anthropic.claude.sessions.list.v1";
export const CLAUDE_SESSION_READ_COMMAND = "anthropic.claude.sessions.read.v1";
export const CLAUDE_CLI_NODE_RUN_COMMAND = "agent.cli.claude.run.v1";
import { CLAUDE_CLI_BACKEND_ID, CLAUDE_CLI_DEFAULT_MODEL_REF } from "./cli-constants.js";
import {
adoptedSessionKey,
adoptedSourceKey,
CLAUDE_LOCAL_SESSION_HOST_ID,
} from "./session-catalog-adoption.js";
import {
collectTranscriptText,
parseTranscriptLine,
@@ -27,7 +31,6 @@ import {
export type { ClaudeTranscriptItem } from "./session-catalog-transcript.js";
const CLAUDE_LOCAL_SESSION_HOST_ID = "gateway:local";
const DEFAULT_PAGE_LIMIT = 50;
const MAX_PAGE_LIMIT = 100;
const DEFAULT_TRANSCRIPT_LIMIT = 20;
@@ -46,8 +49,6 @@ const MAX_TRANSCRIPT_SCAN_BYTES = 64 * 1024 * 1024;
const MAX_TRANSCRIPT_PAGE_BYTES = 20 * 1024 * 1024;
const NODE_INVOKE_TIMEOUT_MS = 30_000;
const CLAUDE_ADOPTED_SESSION_KEY_PREFIX = "plugin:anthropic:catalog-adopt:claude:";
const CLAUDE_HISTORY_IMPORT_MAX_ITEMS = 200;
const CLAUDE_HISTORY_IMPORT_MAX_BYTES = 512 * 1024;
@@ -1063,18 +1064,6 @@ async function readClaudeSessionTranscript(params: {
};
}
function adoptedSourceKey(hostId: string, threadId: string): string {
return `${hostId}\0${threadId}`;
}
function adoptedSessionKey(hostId: string, threadId: string): string {
// Local rows hash threadId alone: adopted keys minted before node support
// must stay stable, or existing adopted sessions would orphan/duplicate.
const source =
hostId === CLAUDE_LOCAL_SESSION_HOST_ID ? threadId : adoptedSourceKey(hostId, threadId);
return `${CLAUDE_ADOPTED_SESSION_KEY_PREFIX}${createHash("sha256").update(source).digest("hex")}`;
}
function currentConfig(api: OpenClawPluginApi): OpenClawConfig {
return (api.runtime.config?.current?.() as OpenClawConfig | undefined) ?? api.config;
}
+2 -63
View File
@@ -7,10 +7,10 @@ export {
type ClawHubTrustErrorCode,
type ClawHubTrustErrorDetails,
} from "./clawhub-trust-error-details.js";
import type { Static, TSchema } from "typebox";
import { Compile, type Validator as TypeBoxValidator } from "typebox/compile";
import type { ValidationError } from "./validation-errors.js";
export { formatValidationErrors, type ValidationError } from "./validation-errors.js";
import { lazyCompile } from "./protocol-validator.js";
export type { ProtocolValidator } from "./protocol-validator.js";
export * from "./schema/worker-inference.js";
export type {
SessionCatalog,
@@ -492,67 +492,6 @@ import {
FsListDirResultSchema,
} from "./schema.js";
/** Runtime validator shape shared by gateway clients and server handlers. */
export type ProtocolValidator<T = unknown> = ((data: unknown) => data is T) & {
errors: ValidationError[] | null; // Ajv-style last validation errors.
/** Original schema used by the validator, exposed for diagnostics/tests. */
schema: unknown;
};
// Defer TypeBox compilation because this module is common on startup paths.
function lazyCompile<const Schema extends TSchema>(
schema: Schema,
precheck?: (data: unknown) => ValidationError | undefined,
): ProtocolValidator<Static<Schema>>;
// Keep compact hand-authored public types where schema-derived declarations are intentionally avoided.
function lazyCompile<T>(
schema: TSchema,
precheck?: (data: unknown) => ValidationError | undefined,
): ProtocolValidator<T>;
function lazyCompile<T = unknown>(
schema: TSchema,
precheck?: (data: unknown) => ValidationError | undefined,
): ProtocolValidator<T> {
let compiled: TypeBoxValidator | undefined;
let errors: ValidationError[] | null = null;
const getCompiled = () => {
compiled ??= Compile(schema as never);
return compiled;
};
const validate = ((data: unknown): data is T => {
const precheckError = precheck?.(data);
if (precheckError) {
errors = [precheckError];
return false;
}
const current = getCompiled();
const valid = current.Check(data);
errors = valid ? null : ([...current.Errors(data)] as ValidationError[]);
return valid;
}) as ProtocolValidator<T>;
Object.defineProperties(validate, {
errors: {
configurable: true,
enumerable: true,
get: () => errors,
set: (nextErrors: ValidationError[] | null | undefined) => {
// Preserve Ajv-compatible mutability for callers/tests that clear errors.
errors = nextErrors ?? null;
},
},
schema: {
configurable: true,
enumerable: true,
get: () => schema,
},
});
return validate;
}
// Validator names mirror schemas so callers can pair them with wire contracts.
export const validateCommandsListParams = lazyCompile(CommandsListParamsSchema);
export const validateConnectParams = lazyCompile(ConnectParamsSchema);
@@ -0,0 +1,64 @@
import type { Static, TSchema } from "typebox";
import { Compile, type Validator as TypeBoxValidator } from "typebox/compile";
import type { ValidationError } from "./validation-errors.js";
/** Runtime validator shape shared by gateway clients and server handlers. */
export type ProtocolValidator<T = unknown> = ((data: unknown) => data is T) & {
errors: ValidationError[] | null; // Ajv-style last validation errors.
/** Original schema used by the validator, exposed for diagnostics/tests. */
schema: unknown;
};
// Defer TypeBox compilation because the protocol entrypoint is common on startup paths.
export function lazyCompile<const Schema extends TSchema>(
schema: Schema,
precheck?: (data: unknown) => ValidationError | undefined,
): ProtocolValidator<Static<Schema>>;
// Keep compact hand-authored public types where schema-derived declarations are intentionally avoided.
export function lazyCompile<T>(
schema: TSchema,
precheck?: (data: unknown) => ValidationError | undefined,
): ProtocolValidator<T>;
export function lazyCompile<T = unknown>(
schema: TSchema,
precheck?: (data: unknown) => ValidationError | undefined,
): ProtocolValidator<T> {
let compiled: TypeBoxValidator | undefined;
let errors: ValidationError[] | null = null;
const getCompiled = () => {
compiled ??= Compile(schema as never);
return compiled;
};
const validate = ((data: unknown): data is T => {
const precheckError = precheck?.(data);
if (precheckError) {
errors = [precheckError];
return false;
}
const current = getCompiled();
const valid = current.Check(data);
errors = valid ? null : ([...current.Errors(data)] as ValidationError[]);
return valid;
}) as ProtocolValidator<T>;
Object.defineProperties(validate, {
errors: {
configurable: true,
enumerable: true,
get: () => errors,
set: (nextErrors: ValidationError[] | null | undefined) => {
// Preserve Ajv-compatible mutability for callers/tests that clear errors.
errors = nextErrors ?? null;
},
},
schema: {
configurable: true,
enumerable: true,
get: () => schema,
},
});
return validate;
}