refactor: add plugin sdk runtime scaffolding
This commit is contained in:
96
src/plugins/runtime/index.ts
Normal file
96
src/plugins/runtime/index.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
import { chunkMarkdownText, resolveTextChunkLimit } from "../../auto-reply/chunk.js";
|
||||
import { hasControlCommand } from "../../auto-reply/command-detection.js";
|
||||
import { createInboundDebouncer, resolveInboundDebounceMs } from "../../auto-reply/inbound-debounce.js";
|
||||
import { buildMentionRegexes, matchesMentionPatterns } from "../../auto-reply/reply/mentions.js";
|
||||
import { dispatchReplyWithBufferedBlockDispatcher } from "../../auto-reply/reply/provider-dispatcher.js";
|
||||
import { createReplyDispatcherWithTyping } from "../../auto-reply/reply/reply-dispatcher.js";
|
||||
import { resolveCommandAuthorizedFromAuthorizers } from "../../channels/command-gating.js";
|
||||
import { resolveChannelGroupPolicy, resolveChannelGroupRequireMention } from "../../config/group-policy.js";
|
||||
import { resolveStateDir } from "../../config/paths.js";
|
||||
import { shouldLogVerbose } from "../../globals.js";
|
||||
import { getChildLogger } from "../../logging.js";
|
||||
import { fetchRemoteMedia } from "../../media/fetch.js";
|
||||
import { saveMediaBuffer } from "../../media/store.js";
|
||||
import { buildPairingReply } from "../../pairing/pairing-messages.js";
|
||||
import { readChannelAllowFromStore, upsertChannelPairingRequest } from "../../pairing/pairing-store.js";
|
||||
import { resolveAgentRoute } from "../../routing/resolve-route.js";
|
||||
|
||||
import type { PluginRuntime } from "./types.js";
|
||||
|
||||
let cachedVersion: string | null = null;
|
||||
|
||||
function resolveVersion(): string {
|
||||
if (cachedVersion) return cachedVersion;
|
||||
try {
|
||||
const require = createRequire(import.meta.url);
|
||||
const pkg = require("../../../package.json") as { version?: string };
|
||||
cachedVersion = pkg.version ?? "unknown";
|
||||
return cachedVersion;
|
||||
} catch {
|
||||
cachedVersion = "unknown";
|
||||
return cachedVersion;
|
||||
}
|
||||
}
|
||||
|
||||
export function createPluginRuntime(): PluginRuntime {
|
||||
return {
|
||||
version: resolveVersion(),
|
||||
channel: {
|
||||
text: {
|
||||
chunkMarkdownText,
|
||||
resolveTextChunkLimit,
|
||||
hasControlCommand,
|
||||
},
|
||||
reply: {
|
||||
dispatchReplyWithBufferedBlockDispatcher,
|
||||
createReplyDispatcherWithTyping,
|
||||
},
|
||||
routing: {
|
||||
resolveAgentRoute,
|
||||
},
|
||||
pairing: {
|
||||
buildPairingReply,
|
||||
readAllowFromStore: readChannelAllowFromStore,
|
||||
upsertPairingRequest: upsertChannelPairingRequest,
|
||||
},
|
||||
media: {
|
||||
fetchRemoteMedia,
|
||||
saveMediaBuffer,
|
||||
},
|
||||
mentions: {
|
||||
buildMentionRegexes,
|
||||
matchesMentionPatterns,
|
||||
},
|
||||
groups: {
|
||||
resolveGroupPolicy: resolveChannelGroupPolicy,
|
||||
resolveRequireMention: resolveChannelGroupRequireMention,
|
||||
},
|
||||
debounce: {
|
||||
createInboundDebouncer,
|
||||
resolveInboundDebounceMs,
|
||||
},
|
||||
commands: {
|
||||
resolveCommandAuthorizedFromAuthorizers,
|
||||
},
|
||||
},
|
||||
logging: {
|
||||
shouldLogVerbose,
|
||||
getChildLogger: (bindings, opts) => {
|
||||
const logger = getChildLogger(bindings, opts);
|
||||
return {
|
||||
debug: (message) => logger.debug?.(message),
|
||||
info: (message) => logger.info(message),
|
||||
warn: (message) => logger.warn(message),
|
||||
error: (message) => logger.error(message),
|
||||
};
|
||||
},
|
||||
},
|
||||
state: {
|
||||
resolveStateDir,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export type { PluginRuntime } from "./types.js";
|
||||
103
src/plugins/runtime/types.ts
Normal file
103
src/plugins/runtime/types.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import type { ClawdbotConfig } from "../../config/config.js";
|
||||
|
||||
export type RuntimeLogger = {
|
||||
debug?: (message: string) => void;
|
||||
info: (message: string) => void;
|
||||
warn: (message: string) => void;
|
||||
error: (message: string) => void;
|
||||
};
|
||||
|
||||
export type PluginRuntime = {
|
||||
version: string;
|
||||
channel: {
|
||||
text: {
|
||||
chunkMarkdownText: (text: string, limit: number) => string[];
|
||||
resolveTextChunkLimit: (cfg: ClawdbotConfig, channel: string, accountId?: string) => number;
|
||||
hasControlCommand: (text: string, cfg: ClawdbotConfig) => boolean;
|
||||
};
|
||||
reply: {
|
||||
dispatchReplyWithBufferedBlockDispatcher: (params: {
|
||||
ctx: unknown;
|
||||
cfg: unknown;
|
||||
dispatcherOptions: {
|
||||
deliver: (payload: { text?: string; mediaUrls?: string[]; mediaUrl?: string }) => void | Promise<void>;
|
||||
onError?: (err: unknown, info: { kind: string }) => void;
|
||||
};
|
||||
}) => Promise<void>;
|
||||
createReplyDispatcherWithTyping: (...args: unknown[]) => unknown;
|
||||
};
|
||||
routing: {
|
||||
resolveAgentRoute: (params: {
|
||||
cfg: unknown;
|
||||
channel: string;
|
||||
accountId: string;
|
||||
peer: { kind: "dm" | "group" | "channel"; id: string };
|
||||
}) => { sessionKey: string; accountId: string };
|
||||
};
|
||||
pairing: {
|
||||
buildPairingReply: (params: { channel: string; idLine: string; code: string }) => string;
|
||||
readAllowFromStore: (channel: string) => Promise<string[]>;
|
||||
upsertPairingRequest: (params: {
|
||||
channel: string;
|
||||
id: string;
|
||||
meta?: { name?: string };
|
||||
}) => Promise<{ code: string; created: boolean }>;
|
||||
};
|
||||
media: {
|
||||
fetchRemoteMedia: (params: { url: string }) => Promise<{ buffer: Buffer; contentType?: string }>;
|
||||
saveMediaBuffer: (
|
||||
buffer: Uint8Array,
|
||||
contentType: string | undefined,
|
||||
direction: "inbound" | "outbound",
|
||||
maxBytes: number,
|
||||
) => Promise<{ path: string; contentType?: string }>;
|
||||
};
|
||||
mentions: {
|
||||
buildMentionRegexes: (cfg: ClawdbotConfig, agentId?: string) => RegExp[];
|
||||
matchesMentionPatterns: (text: string, regexes: RegExp[]) => boolean;
|
||||
};
|
||||
groups: {
|
||||
resolveGroupPolicy: (
|
||||
cfg: ClawdbotConfig,
|
||||
channel: string,
|
||||
accountId: string,
|
||||
groupId: string,
|
||||
) => {
|
||||
allowlistEnabled: boolean;
|
||||
allowed: boolean;
|
||||
groupConfig?: unknown;
|
||||
defaultConfig?: unknown;
|
||||
};
|
||||
resolveRequireMention: (
|
||||
cfg: ClawdbotConfig,
|
||||
channel: string,
|
||||
accountId: string,
|
||||
groupId: string,
|
||||
override?: boolean,
|
||||
) => boolean;
|
||||
};
|
||||
debounce: {
|
||||
createInboundDebouncer: <T>(opts: {
|
||||
debounceMs: number;
|
||||
buildKey: (value: T) => string | null;
|
||||
shouldDebounce: (value: T) => boolean;
|
||||
onFlush: (entries: T[]) => Promise<void>;
|
||||
onError?: (err: unknown) => void;
|
||||
}) => { push: (value: T) => void; flush: () => Promise<void> };
|
||||
resolveInboundDebounceMs: (cfg: ClawdbotConfig, channel: string) => number;
|
||||
};
|
||||
commands: {
|
||||
resolveCommandAuthorizedFromAuthorizers: (params: {
|
||||
useAccessGroups: boolean;
|
||||
authorizers: Array<{ configured: boolean; allowed: boolean }>;
|
||||
}) => boolean;
|
||||
};
|
||||
};
|
||||
logging: {
|
||||
shouldLogVerbose: () => boolean;
|
||||
getChildLogger: (bindings?: Record<string, unknown>, opts?: { level?: string }) => RuntimeLogger;
|
||||
};
|
||||
state: {
|
||||
resolveStateDir: (cfg: ClawdbotConfig) => string;
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user