UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

201 lines (199 loc) 7.79 kB
import "./paths-BDd7_JUB.js"; import "./agent-scope-CrgUOY3f.js"; import { R as theme, c as defaultRuntime } from "./subsystem-46MXi6Ip.js"; import "./utils-Dg0Xbl6w.js"; import "./exec-CTo4hK94.js"; import "./model-selection-Cp1maz7B.js"; import "./github-copilot-token-VZsS4013.js"; import "./boolean-CE7i9tBR.js"; import "./env-DOcCob95.js"; import { r as loadConfig } from "./config-qgIz1lbh.js"; import "./manifest-registry-BFpLJJDB.js"; import { n as pickPrimaryTailnetIPv6, t as pickPrimaryTailnetIPv4 } from "./tailnet-Bk5cGmwE.js"; import { t as formatDocsLink } from "./links-C9fyAH-V.js"; import { t as renderTable } from "./table-DuNe7Qes.js"; import { n as resolveWideAreaDiscoveryDomain, t as getWideAreaZonePath } from "./widearea-dns-BIhjVRG1.js"; import path from "node:path"; import fs from "node:fs"; import { spawnSync } from "node:child_process"; //#region src/cli/dns-cli.ts function run(cmd, args, opts) { const res = spawnSync(cmd, args, { encoding: "utf-8", stdio: opts?.inherit ? "inherit" : "pipe" }); if (res.error) throw res.error; if (!opts?.allowFailure && res.status !== 0) { const errText = typeof res.stderr === "string" && res.stderr.trim() ? res.stderr.trim() : `exit ${res.status ?? "unknown"}`; throw new Error(`${cmd} ${args.join(" ")} failed: ${errText}`); } return typeof res.stdout === "string" ? res.stdout : ""; } function writeFileSudoIfNeeded(filePath, content) { try { fs.writeFileSync(filePath, content, "utf-8"); return; } catch (err) { const code = err.code; if (code !== "EACCES" && code !== "EPERM") throw err instanceof Error ? err : new Error(String(err)); } const res = spawnSync("sudo", ["tee", filePath], { input: content, encoding: "utf-8", stdio: [ "pipe", "ignore", "inherit" ] }); if (res.error) throw res.error; if (res.status !== 0) throw new Error(`sudo tee ${filePath} failed: exit ${res.status ?? "unknown"}`); } function mkdirSudoIfNeeded(dirPath) { try { fs.mkdirSync(dirPath, { recursive: true }); return; } catch (err) { const code = err.code; if (code !== "EACCES" && code !== "EPERM") throw err instanceof Error ? err : new Error(String(err)); } run("sudo", [ "mkdir", "-p", dirPath ], { inherit: true }); } function zoneFileNeedsBootstrap(zonePath) { if (!fs.existsSync(zonePath)) return true; try { const content = fs.readFileSync(zonePath, "utf-8"); return !/\bSOA\b/.test(content) || !/\bNS\b/.test(content); } catch { return true; } } function detectBrewPrefix() { const prefix = run("brew", ["--prefix"]).trim(); if (!prefix) throw new Error("failed to resolve Homebrew prefix"); return prefix; } function ensureImportLine(corefilePath, importGlob) { const existing = fs.readFileSync(corefilePath, "utf-8"); if (existing.includes(importGlob)) return false; writeFileSudoIfNeeded(corefilePath, `${existing.replace(/\s*$/, "")}\n\nimport ${importGlob}\n`); return true; } function registerDnsCli(program) { program.command("dns").description("DNS helpers for wide-area discovery (Tailscale + CoreDNS)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dns", "docs.openclaw.ai/cli/dns")}\n`).command("setup").description("Set up CoreDNS to serve your discovery domain for unicast DNS-SD (Wide-Area Bonjour)").option("--domain <domain>", "Wide-area discovery domain (e.g. openclaw.internal)").option("--apply", "Install/update CoreDNS config and (re)start the service (requires sudo)", false).action(async (opts) => { const cfg = loadConfig(); const tailnetIPv4 = pickPrimaryTailnetIPv4(); const tailnetIPv6 = pickPrimaryTailnetIPv6(); const wideAreaDomain = resolveWideAreaDiscoveryDomain({ configDomain: opts.domain ?? cfg.discovery?.wideArea?.domain }); if (!wideAreaDomain) throw new Error("No wide-area domain configured. Set discovery.wideArea.domain or pass --domain."); const zonePath = getWideAreaZonePath(wideAreaDomain); const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1); defaultRuntime.log(theme.heading("DNS setup")); defaultRuntime.log(renderTable({ width: tableWidth, columns: [{ key: "Key", header: "Key", minWidth: 18 }, { key: "Value", header: "Value", minWidth: 24, flex: true }], rows: [ { Key: "Domain", Value: wideAreaDomain }, { Key: "Zone file", Value: zonePath }, { Key: "Tailnet IP", Value: `${tailnetIPv4 ?? "—"}${tailnetIPv6 ? ` (v6 ${tailnetIPv6})` : ""}` } ] }).trimEnd()); defaultRuntime.log(""); defaultRuntime.log(theme.heading("Recommended ~/.openclaw/openclaw.json:")); defaultRuntime.log(JSON.stringify({ gateway: { bind: "auto" }, discovery: { wideArea: { enabled: true, domain: wideAreaDomain } } }, null, 2)); defaultRuntime.log(""); defaultRuntime.log(theme.heading("Tailscale admin (DNS → Nameservers):")); defaultRuntime.log(theme.muted(`- Add nameserver: ${tailnetIPv4 ?? "<this machine's tailnet IPv4>"}`)); defaultRuntime.log(theme.muted(`- Restrict to domain (Split DNS): ${wideAreaDomain.replace(/\.$/, "")}`)); if (!opts.apply) { defaultRuntime.log(""); defaultRuntime.log(theme.muted("Run with --apply to install CoreDNS and configure it.")); return; } if (process.platform !== "darwin") throw new Error("dns setup is currently supported on macOS only"); if (!tailnetIPv4 && !tailnetIPv6) throw new Error("no tailnet IP detected; ensure Tailscale is running on this machine"); const prefix = detectBrewPrefix(); const etcDir = path.join(prefix, "etc", "coredns"); const corefilePath = path.join(etcDir, "Corefile"); const confDir = path.join(etcDir, "conf.d"); const importGlob = path.join(confDir, "*.server"); const serverPath = path.join(confDir, `${wideAreaDomain.replace(/\.$/, "")}.server`); run("brew", ["list", "coredns"], { allowFailure: true }); run("brew", ["install", "coredns"], { inherit: true, allowFailure: true }); mkdirSudoIfNeeded(confDir); if (!fs.existsSync(corefilePath)) writeFileSudoIfNeeded(corefilePath, `import ${importGlob}\n`); else ensureImportLine(corefilePath, importGlob); const bindArgs = [tailnetIPv4, tailnetIPv6].filter((v) => Boolean(v?.trim())); writeFileSudoIfNeeded(serverPath, [ `${wideAreaDomain.replace(/\.$/, "")}:53 {`, ` bind ${bindArgs.join(" ")}`, ` file ${zonePath} {`, ` reload 10s`, ` }`, ` errors`, ` log`, `}`, `` ].join("\n")); await fs.promises.mkdir(path.dirname(zonePath), { recursive: true }); if (zoneFileNeedsBootstrap(zonePath)) { const serial = `${(/* @__PURE__ */ new Date()).getUTCFullYear()}${String((/* @__PURE__ */ new Date()).getUTCMonth() + 1).padStart(2, "0")}${String((/* @__PURE__ */ new Date()).getUTCDate()).padStart(2, "0")}01`; const zoneLines = [ `; created by openclaw dns setup (will be overwritten by the gateway when wide-area discovery is enabled)`, `$ORIGIN ${wideAreaDomain}`, `$TTL 60`, `@ IN SOA ns1 hostmaster ${serial} 7200 3600 1209600 60`, `@ IN NS ns1`, tailnetIPv4 ? `ns1 IN A ${tailnetIPv4}` : null, tailnetIPv6 ? `ns1 IN AAAA ${tailnetIPv6}` : null, `` ].filter((line) => Boolean(line)); fs.writeFileSync(zonePath, zoneLines.join("\n"), "utf-8"); } defaultRuntime.log(""); defaultRuntime.log(theme.heading("Starting CoreDNS (sudo)…")); run("sudo", [ "brew", "services", "restart", "coredns" ], { inherit: true }); if (cfg.discovery?.wideArea?.enabled !== true) { defaultRuntime.log(""); defaultRuntime.log(theme.muted("Note: enable discovery.wideArea.enabled in ~/.openclaw/openclaw.json on the gateway and restart the gateway so it writes the DNS-SD zone.")); } }); } //#endregion export { registerDnsCli };