Spaces:
Paused
Paused
File size: 4,778 Bytes
fb4d8fe | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | import JSON5 from "json5";
import type {
OpenClawHookMetadata,
HookEntry,
HookInstallSpec,
HookInvocationPolicy,
ParsedHookFrontmatter,
} from "./types.js";
import { LEGACY_MANIFEST_KEYS, MANIFEST_KEY } from "../compat/legacy-names.js";
import { parseFrontmatterBlock } from "../markdown/frontmatter.js";
import { parseBooleanValue } from "../utils/boolean.js";
export function parseFrontmatter(content: string): ParsedHookFrontmatter {
return parseFrontmatterBlock(content);
}
function normalizeStringList(input: unknown): string[] {
if (!input) {
return [];
}
if (Array.isArray(input)) {
return input.map((value) => String(value).trim()).filter(Boolean);
}
if (typeof input === "string") {
return input
.split(",")
.map((value) => value.trim())
.filter(Boolean);
}
return [];
}
function parseInstallSpec(input: unknown): HookInstallSpec | undefined {
if (!input || typeof input !== "object") {
return undefined;
}
const raw = input as Record<string, unknown>;
const kindRaw =
typeof raw.kind === "string" ? raw.kind : typeof raw.type === "string" ? raw.type : "";
const kind = kindRaw.trim().toLowerCase();
if (kind !== "bundled" && kind !== "npm" && kind !== "git") {
return undefined;
}
const spec: HookInstallSpec = {
kind: kind,
};
if (typeof raw.id === "string") {
spec.id = raw.id;
}
if (typeof raw.label === "string") {
spec.label = raw.label;
}
const bins = normalizeStringList(raw.bins);
if (bins.length > 0) {
spec.bins = bins;
}
if (typeof raw.package === "string") {
spec.package = raw.package;
}
if (typeof raw.repository === "string") {
spec.repository = raw.repository;
}
return spec;
}
function getFrontmatterValue(frontmatter: ParsedHookFrontmatter, key: string): string | undefined {
const raw = frontmatter[key];
return typeof raw === "string" ? raw : undefined;
}
function parseFrontmatterBool(value: string | undefined, fallback: boolean): boolean {
const parsed = parseBooleanValue(value);
return parsed === undefined ? fallback : parsed;
}
export function resolveOpenClawMetadata(
frontmatter: ParsedHookFrontmatter,
): OpenClawHookMetadata | undefined {
const raw = getFrontmatterValue(frontmatter, "metadata");
if (!raw) {
return undefined;
}
try {
const parsed = JSON5.parse(raw);
if (!parsed || typeof parsed !== "object") {
return undefined;
}
const metadataRawCandidates = [MANIFEST_KEY, ...LEGACY_MANIFEST_KEYS];
let metadataRaw: unknown;
for (const key of metadataRawCandidates) {
const candidate = parsed[key];
if (candidate && typeof candidate === "object") {
metadataRaw = candidate;
break;
}
}
if (!metadataRaw || typeof metadataRaw !== "object") {
return undefined;
}
const metadataObj = metadataRaw as Record<string, unknown>;
const requiresRaw =
typeof metadataObj.requires === "object" && metadataObj.requires !== null
? (metadataObj.requires as Record<string, unknown>)
: undefined;
const installRaw = Array.isArray(metadataObj.install) ? (metadataObj.install as unknown[]) : [];
const install = installRaw
.map((entry) => parseInstallSpec(entry))
.filter((entry): entry is HookInstallSpec => Boolean(entry));
const osRaw = normalizeStringList(metadataObj.os);
const eventsRaw = normalizeStringList(metadataObj.events);
return {
always: typeof metadataObj.always === "boolean" ? metadataObj.always : undefined,
emoji: typeof metadataObj.emoji === "string" ? metadataObj.emoji : undefined,
homepage: typeof metadataObj.homepage === "string" ? metadataObj.homepage : undefined,
hookKey: typeof metadataObj.hookKey === "string" ? metadataObj.hookKey : undefined,
export: typeof metadataObj.export === "string" ? metadataObj.export : undefined,
os: osRaw.length > 0 ? osRaw : undefined,
events: eventsRaw.length > 0 ? eventsRaw : [],
requires: requiresRaw
? {
bins: normalizeStringList(requiresRaw.bins),
anyBins: normalizeStringList(requiresRaw.anyBins),
env: normalizeStringList(requiresRaw.env),
config: normalizeStringList(requiresRaw.config),
}
: undefined,
install: install.length > 0 ? install : undefined,
};
} catch {
return undefined;
}
}
export function resolveHookInvocationPolicy(
frontmatter: ParsedHookFrontmatter,
): HookInvocationPolicy {
return {
enabled: parseFrontmatterBool(getFrontmatterValue(frontmatter, "enabled"), true),
};
}
export function resolveHookKey(hookName: string, entry?: HookEntry): string {
return entry?.metadata?.hookKey ?? hookName;
}
|