UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

101 lines (100 loc) 4.81 kB
import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString, s as normalizeOptionalLowercaseString } from "./string-coerce-mnp54Vah.js"; //#region src/shared/node-match.ts /** Normalizes human node names into stable lookup keys for fuzzy CLI/API matching. */ function normalizeNodeKey(value) { return normalizeLowercaseStringOrEmpty(value).replace(/[^a-z0-9]+/g, "-").replace(/^-+/, "").replace(/-+$/, ""); } function listKnownNodes(nodes) { return nodes.map((n) => n.displayName || n.remoteIp || n.nodeId).filter(Boolean).join(", "); } function formatNodeCandidateLabel(node) { const label = node.displayName || node.remoteIp || node.nodeId; const details = [`node=${node.nodeId}`]; const clientId = normalizeOptionalString(node.clientId); if (clientId) details.push(`client=${clientId}`); return `${label} [${details.join(", ")}]`; } function isCurrentOpenClawClient(clientId) { return (normalizeOptionalLowercaseString(clientId) ?? "").startsWith("openclaw-"); } function isLegacyClawdbotClient(clientId) { const normalized = normalizeOptionalLowercaseString(clientId) ?? ""; return normalized.startsWith("clawdbot-") || normalized.startsWith("moldbot-"); } function pickPreferredLegacyMigrationMatch(matches) { const current = matches.filter((match) => isCurrentOpenClawClient(match.clientId)); if (current.length !== 1) return; const legacyCount = matches.filter((match) => isLegacyClawdbotClient(match.clientId)).length; if (legacyCount === 0 || current.length + legacyCount !== matches.length) return; return current[0]; } function resolveMatchScore(node, query, queryNormalized) { if (node.nodeId === query) return 4e3; if (typeof node.remoteIp === "string" && node.remoteIp === query) return 3e3; const name = typeof node.displayName === "string" ? node.displayName : ""; if (name && normalizeNodeKey(name) === queryNormalized) return 2e3; if (query.length >= 6 && node.nodeId.startsWith(query)) return 1e3; return 0; } function scoreNodeCandidate(node, matchScore) { let score = matchScore; if (node.connected === true) score += 100; if (isCurrentOpenClawClient(node.clientId)) score += 10; else if (isLegacyClawdbotClient(node.clientId)) score -= 10; return score; } function resolveScoredMatches(nodes, query) { const trimmed = normalizeOptionalString(query); if (!trimmed) return []; const normalized = normalizeNodeKey(trimmed); return nodes.map((node) => { const matchScore = resolveMatchScore(node, trimmed, normalized); if (matchScore === 0) return null; return { node, matchScore, selectionScore: scoreNodeCandidate(node, matchScore) }; }).filter((entry) => entry !== null); } /** Resolves a single node id or throws an operator-readable unknown/ambiguous-node error. */ function resolveNodeIdFromCandidates(nodes, query) { const q = query.trim(); if (!q) throw new Error("node required"); const rawMatches = resolveScoredMatches(nodes, q); if (rawMatches.length === 1) return rawMatches[0]?.node.nodeId ?? ""; if (rawMatches.length === 0) { const known = listKnownNodes(nodes); throw new Error(`unknown node: ${q}${known ? ` (known: ${known})` : ""}`); } const topMatchScore = Math.max(...rawMatches.map((match) => match.matchScore)); const strongestMatches = rawMatches.filter((match) => match.matchScore === topMatchScore); if (strongestMatches.length === 1) return strongestMatches[0]?.node.nodeId ?? ""; const topSelectionScore = Math.max(...strongestMatches.map((match) => match.selectionScore)); const matches = strongestMatches.filter((match) => match.selectionScore === topSelectionScore); if (matches.length === 1) return matches[0]?.node.nodeId ?? ""; const preferred = pickPreferredLegacyMigrationMatch(matches.map((match) => match.node)); if (preferred) return preferred.nodeId; throw new Error(`ambiguous node: ${q} (matches: ${matches.map((match) => formatNodeCandidateLabel(match.node)).join(", ")})`); } //#endregion //#region src/shared/node-resolve.ts /** Resolves a user query to a node id, optionally using a caller-defined blank-query default. */ function resolveNodeIdFromNodeList(nodes, query, options = {}) { const q = normalizeOptionalString(query) ?? ""; if (!q) { if (options.allowDefault === true && options.pickDefaultNode) { const picked = options.pickDefaultNode(nodes); if (picked) return picked.nodeId; } throw new Error("node required"); } return resolveNodeIdFromCandidates(nodes, q); } /** Resolves a full node entry, preserving synthetic defaults returned by the picker. */ function resolveNodeFromNodeList(nodes, query, options = {}) { const nodeId = resolveNodeIdFromNodeList(nodes, query, options); return nodes.find((node) => node.nodeId === nodeId) ?? { nodeId }; } //#endregion export { resolveNodeIdFromNodeList as n, resolveNodeFromNodeList as t };