UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

188 lines (186 loc) 6.65 kB
import { J as resolveOAuthDir, w as shouldLogVerbose, x as logVerbose } from "./entry.js"; import path from "node:path"; import os from "node:os"; import fs from "node:fs"; //#region src/utils.ts async function ensureDir(dir) { await fs.promises.mkdir(dir, { recursive: true }); } function clampNumber(value, min, max) { return Math.max(min, Math.min(max, value)); } function clampInt(value, min, max) { return clampNumber(Math.floor(value), min, max); } function normalizeE164(number) { const digits = number.replace(/^whatsapp:/, "").trim().replace(/[^\d+]/g, ""); if (digits.startsWith("+")) return `+${digits.slice(1)}`; return `+${digits}`; } /** * "Self-chat mode" heuristic (single phone): the gateway is logged in as the owner's own WhatsApp account, * and `channels.whatsapp.allowFrom` includes that same number. Used to avoid side-effects that make no sense when the * "bot" and the human are the same WhatsApp identity (e.g. auto read receipts, @mention JID triggers). */ function isSelfChatMode(selfE164, allowFrom) { if (!selfE164) return false; if (!Array.isArray(allowFrom) || allowFrom.length === 0) return false; const normalizedSelf = normalizeE164(selfE164); return allowFrom.some((n) => { if (n === "*") return false; try { return normalizeE164(String(n)) === normalizedSelf; } catch { return false; } }); } function toWhatsappJid(number) { const withoutPrefix = number.replace(/^whatsapp:/, "").trim(); if (withoutPrefix.includes("@")) return withoutPrefix; return `${normalizeE164(withoutPrefix).replace(/\D/g, "")}@s.whatsapp.net`; } function resolveLidMappingDirs(opts) { const dirs = /* @__PURE__ */ new Set(); const addDir = (dir) => { if (!dir) return; dirs.add(resolveUserPath(dir)); }; addDir(opts?.authDir); for (const dir of opts?.lidMappingDirs ?? []) addDir(dir); addDir(resolveOAuthDir()); addDir(path.join(CONFIG_DIR, "credentials")); return [...dirs]; } function readLidReverseMapping(lid, opts) { const mappingFilename = `lid-mapping-${lid}_reverse.json`; const mappingDirs = resolveLidMappingDirs(opts); for (const dir of mappingDirs) { const mappingPath = path.join(dir, mappingFilename); try { const data = fs.readFileSync(mappingPath, "utf8"); const phone = JSON.parse(data); if (phone === null || phone === void 0) continue; return normalizeE164(String(phone)); } catch {} } return null; } function jidToE164(jid, opts) { const match = jid.match(/^(\d+)(?::\d+)?@(s\.whatsapp\.net|hosted)$/); if (match) return `+${match[1]}`; const lidMatch = jid.match(/^(\d+)(?::\d+)?@(lid|hosted\.lid)$/); if (lidMatch) { const lid = lidMatch[1]; const phone = readLidReverseMapping(lid, opts); if (phone) return phone; if (opts?.logMissing ?? shouldLogVerbose()) logVerbose(`LID mapping not found for ${lid}; skipping inbound message`); } return null; } async function resolveJidToE164(jid, opts) { if (!jid) return null; const direct = jidToE164(jid, opts); if (direct) return direct; if (!/(@lid|@hosted\.lid)$/.test(jid)) return null; if (!opts?.lidLookup?.getPNForLID) return null; try { const pnJid = await opts.lidLookup.getPNForLID(jid); if (!pnJid) return null; return jidToE164(pnJid, opts); } catch (err) { if (shouldLogVerbose()) logVerbose(`LID mapping lookup failed for ${jid}: ${String(err)}`); return null; } } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function isHighSurrogate(codeUnit) { return codeUnit >= 55296 && codeUnit <= 56319; } function isLowSurrogate(codeUnit) { return codeUnit >= 56320 && codeUnit <= 57343; } function sliceUtf16Safe(input, start, end) { const len = input.length; let from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len); let to = end === void 0 ? len : end < 0 ? Math.max(len + end, 0) : Math.min(end, len); if (to < from) { const tmp = from; from = to; to = tmp; } if (from > 0 && from < len) { if (isLowSurrogate(input.charCodeAt(from)) && isHighSurrogate(input.charCodeAt(from - 1))) from += 1; } if (to > 0 && to < len) { if (isHighSurrogate(input.charCodeAt(to - 1)) && isLowSurrogate(input.charCodeAt(to))) to -= 1; } return input.slice(from, to); } function truncateUtf16Safe(input, maxLen) { const limit = Math.max(0, Math.floor(maxLen)); if (input.length <= limit) return input; return sliceUtf16Safe(input, 0, limit); } function resolveUserPath(input) { const trimmed = input.trim(); if (!trimmed) return trimmed; if (trimmed.startsWith("~")) { const expanded = trimmed.replace(/^~(?=$|[\\/])/, os.homedir()); return path.resolve(expanded); } return path.resolve(trimmed); } function resolveConfigDir(env = process.env, homedir = os.homedir) { const override = env.OPENCLAW_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim(); if (override) return resolveUserPath(override); const newDir = path.join(homedir(), ".openclaw"); try { if (fs.existsSync(newDir)) return newDir; } catch {} return newDir; } function resolveHomeDir() { const envHome = process.env.HOME?.trim(); if (envHome) return envHome; const envProfile = process.env.USERPROFILE?.trim(); if (envProfile) return envProfile; try { const home = os.homedir(); return home?.trim() ? home : void 0; } catch { return; } } function shortenHomePath(input) { if (!input) return input; const home = resolveHomeDir(); if (!home) return input; if (input === home) return "~"; if (input.startsWith(`${home}/`)) return `~${input.slice(home.length)}`; return input; } function shortenHomeInString(input) { if (!input) return input; const home = resolveHomeDir(); if (!home) return input; return input.split(home).join("~"); } function displayPath(input) { return shortenHomePath(input); } function displayString(input) { return shortenHomeInString(input); } function formatTerminalLink(label, url, opts) { const esc = "\x1B"; const safeLabel = label.replaceAll(esc, ""); const safeUrl = url.replaceAll(esc, ""); if (!(opts?.force === true ? true : opts?.force === false ? false : Boolean(process.stdout.isTTY))) return opts?.fallback ?? `${safeLabel} (${safeUrl})`; return `\u001b]8;;${safeUrl}\u0007${safeLabel}\u001b]8;;\u0007`; } const CONFIG_DIR = resolveConfigDir(); //#endregion export { sleep as _, displayString as a, truncateUtf16Safe as b, isSelfChatMode as c, resolveConfigDir as d, resolveHomeDir as f, shortenHomePath as g, shortenHomeInString as h, displayPath as i, jidToE164 as l, resolveUserPath as m, clampInt as n, ensureDir as o, resolveJidToE164 as p, clampNumber as r, formatTerminalLink as s, CONFIG_DIR as t, normalizeE164 as u, sliceUtf16Safe as v, toWhatsappJid as y };