UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

443 lines (441 loc) 16.2 kB
import "./pi-embedded-helpers-CC00lEFI.js"; import "./reply-CoztdrN_.js"; import "./paths-BDd7_JUB.js"; import "./agent-scope-CrgUOY3f.js"; import { R as theme, c as defaultRuntime } from "./subsystem-46MXi6Ip.js"; import { _ as shortenHomePath, g as shortenHomeInString, h as resolveUserPath } from "./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, s as writeConfigFile } from "./config-qgIz1lbh.js"; import { u as applyExclusiveSlotSelection } from "./manifest-registry-BFpLJJDB.js"; import "./plugins-D1CxUobm.js"; import "./sandbox-BXUfp_qv.js"; import "./image-ClOB6QDJ.js"; import "./pi-model-discovery-DjGamP_B.js"; import "./chrome-D2LUApAY.js"; import "./skills-C4b1FA1e.js"; import "./routes-Ds-tIZFJ.js"; import "./server-context-D2cv-pIA.js"; import "./message-channel-CQGWXVL4.js"; import "./logging-BdnOSVPD.js"; import "./accounts-BlHoTziG.js"; import "./paths-50eo6DV6.js"; import "./redact-BKh-zp-c.js"; import "./tool-display-rIUh61kT.js"; import "./deliver-Bsvrattg.js"; import "./dispatcher-BNB5aCZ6.js"; import "./manager-BArueSTR.js"; import "./sqlite-Dz6S6ijV.js"; import "./channel-summary-C8GoEKgH.js"; import "./client-zqMhLTAX.js"; import "./call-CPBhMXxo.js"; import "./login-qr-C2H_iQJU.js"; import "./pairing-store-BnMngoWQ.js"; import { t as formatDocsLink } from "./links-C9fyAH-V.js"; import "./progress-uNDQDtGB.js"; import "./pi-tools.policy-DleRi9eC.js"; import "./prompt-style-gfROyHgB.js"; import "./pairing-labels-DK2aLSd2.js"; import "./control-service-BW5sW2U1.js"; import "./restart-sentinel-CdcBcziq.js"; import "./channel-selection-BCn8_qun.js"; import { i as resolveArchiveKind } from "./archive-BrH5WBhI.js"; import { n as installPluginFromNpmSpec, r as installPluginFromPath, t as recordPluginInstall } from "./installs-W4Pc1LJz.js"; import { t as renderTable } from "./table-DuNe7Qes.js"; import { t as buildPluginStatusReport } from "./status-PjegR5Cv.js"; import { n as updateNpmInstalledPlugins } from "./update-BDyA5Iqy.js"; import path from "node:path"; import fs from "node:fs"; //#region src/cli/plugins-cli.ts function formatPluginLine(plugin, verbose = false) { const status = plugin.status === "loaded" ? theme.success("loaded") : plugin.status === "disabled" ? theme.warn("disabled") : theme.error("error"); const name = theme.command(plugin.name || plugin.id); const idSuffix = plugin.name && plugin.name !== plugin.id ? theme.muted(` (${plugin.id})`) : ""; const desc = plugin.description ? theme.muted(plugin.description.length > 60 ? `${plugin.description.slice(0, 57)}...` : plugin.description) : theme.muted("(no description)"); if (!verbose) return `${name}${idSuffix} ${status} - ${desc}`; const parts = [ `${name}${idSuffix} ${status}`, ` source: ${theme.muted(shortenHomeInString(plugin.source))}`, ` origin: ${plugin.origin}` ]; if (plugin.version) parts.push(` version: ${plugin.version}`); if (plugin.providerIds.length > 0) parts.push(` providers: ${plugin.providerIds.join(", ")}`); if (plugin.error) parts.push(theme.error(` error: ${plugin.error}`)); return parts.join("\n"); } function applySlotSelectionForPlugin(config, pluginId) { const report = buildPluginStatusReport({ config }); const plugin = report.plugins.find((entry) => entry.id === pluginId); if (!plugin) return { config, warnings: [] }; const result = applyExclusiveSlotSelection({ config, selectedId: plugin.id, selectedKind: plugin.kind, registry: report }); return { config: result.config, warnings: result.warnings }; } function logSlotWarnings(warnings) { if (warnings.length === 0) return; for (const warning of warnings) defaultRuntime.log(theme.warn(warning)); } function registerPluginsCli(program) { const plugins = program.command("plugins").description("Manage OpenClaw plugins/extensions").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/plugins", "docs.openclaw.ai/cli/plugins")}\n`); plugins.command("list").description("List discovered plugins").option("--json", "Print JSON").option("--enabled", "Only show enabled plugins", false).option("--verbose", "Show detailed entries", false).action((opts) => { const report = buildPluginStatusReport(); const list = opts.enabled ? report.plugins.filter((p) => p.status === "loaded") : report.plugins; if (opts.json) { const payload = { workspaceDir: report.workspaceDir, plugins: list, diagnostics: report.diagnostics }; defaultRuntime.log(JSON.stringify(payload, null, 2)); return; } if (list.length === 0) { defaultRuntime.log(theme.muted("No plugins found.")); return; } const loaded = list.filter((p) => p.status === "loaded").length; defaultRuntime.log(`${theme.heading("Plugins")} ${theme.muted(`(${loaded}/${list.length} loaded)`)}`); if (!opts.verbose) { const tableWidth = Math.max(60, (process.stdout.columns ?? 120) - 1); const rows = list.map((plugin) => { const desc = plugin.description ? theme.muted(plugin.description) : ""; const sourceLine = desc ? `${plugin.source}\n${desc}` : plugin.source; return { Name: plugin.name || plugin.id, ID: plugin.name && plugin.name !== plugin.id ? plugin.id : "", Status: plugin.status === "loaded" ? theme.success("loaded") : plugin.status === "disabled" ? theme.warn("disabled") : theme.error("error"), Source: sourceLine, Version: plugin.version ?? "" }; }); defaultRuntime.log(renderTable({ width: tableWidth, columns: [ { key: "Name", header: "Name", minWidth: 14, flex: true }, { key: "ID", header: "ID", minWidth: 10, flex: true }, { key: "Status", header: "Status", minWidth: 10 }, { key: "Source", header: "Source", minWidth: 26, flex: true }, { key: "Version", header: "Version", minWidth: 8 } ], rows }).trimEnd()); return; } const lines = []; for (const plugin of list) { lines.push(formatPluginLine(plugin, true)); lines.push(""); } defaultRuntime.log(lines.join("\n").trim()); }); plugins.command("info").description("Show plugin details").argument("<id>", "Plugin id").option("--json", "Print JSON").action((id, opts) => { const plugin = buildPluginStatusReport().plugins.find((p) => p.id === id || p.name === id); if (!plugin) { defaultRuntime.error(`Plugin not found: ${id}`); process.exit(1); } const install = loadConfig().plugins?.installs?.[plugin.id]; if (opts.json) { defaultRuntime.log(JSON.stringify(plugin, null, 2)); return; } const lines = []; lines.push(theme.heading(plugin.name || plugin.id)); if (plugin.name && plugin.name !== plugin.id) lines.push(theme.muted(`id: ${plugin.id}`)); if (plugin.description) lines.push(plugin.description); lines.push(""); lines.push(`${theme.muted("Status:")} ${plugin.status}`); lines.push(`${theme.muted("Source:")} ${shortenHomeInString(plugin.source)}`); lines.push(`${theme.muted("Origin:")} ${plugin.origin}`); if (plugin.version) lines.push(`${theme.muted("Version:")} ${plugin.version}`); if (plugin.toolNames.length > 0) lines.push(`${theme.muted("Tools:")} ${plugin.toolNames.join(", ")}`); if (plugin.hookNames.length > 0) lines.push(`${theme.muted("Hooks:")} ${plugin.hookNames.join(", ")}`); if (plugin.gatewayMethods.length > 0) lines.push(`${theme.muted("Gateway methods:")} ${plugin.gatewayMethods.join(", ")}`); if (plugin.providerIds.length > 0) lines.push(`${theme.muted("Providers:")} ${plugin.providerIds.join(", ")}`); if (plugin.cliCommands.length > 0) lines.push(`${theme.muted("CLI commands:")} ${plugin.cliCommands.join(", ")}`); if (plugin.services.length > 0) lines.push(`${theme.muted("Services:")} ${plugin.services.join(", ")}`); if (plugin.error) lines.push(`${theme.error("Error:")} ${plugin.error}`); if (install) { lines.push(""); lines.push(`${theme.muted("Install:")} ${install.source}`); if (install.spec) lines.push(`${theme.muted("Spec:")} ${install.spec}`); if (install.sourcePath) lines.push(`${theme.muted("Source path:")} ${shortenHomePath(install.sourcePath)}`); if (install.installPath) lines.push(`${theme.muted("Install path:")} ${shortenHomePath(install.installPath)}`); if (install.version) lines.push(`${theme.muted("Recorded version:")} ${install.version}`); if (install.installedAt) lines.push(`${theme.muted("Installed at:")} ${install.installedAt}`); } defaultRuntime.log(lines.join("\n")); }); plugins.command("enable").description("Enable a plugin in config").argument("<id>", "Plugin id").action(async (id) => { const cfg = loadConfig(); let next = { ...cfg, plugins: { ...cfg.plugins, entries: { ...cfg.plugins?.entries, [id]: { ...(cfg.plugins?.entries)?.[id], enabled: true } } } }; const slotResult = applySlotSelectionForPlugin(next, id); next = slotResult.config; await writeConfigFile(next); logSlotWarnings(slotResult.warnings); defaultRuntime.log(`Enabled plugin "${id}". Restart the gateway to apply.`); }); plugins.command("disable").description("Disable a plugin in config").argument("<id>", "Plugin id").action(async (id) => { const cfg = loadConfig(); await writeConfigFile({ ...cfg, plugins: { ...cfg.plugins, entries: { ...cfg.plugins?.entries, [id]: { ...(cfg.plugins?.entries)?.[id], enabled: false } } } }); defaultRuntime.log(`Disabled plugin "${id}". Restart the gateway to apply.`); }); plugins.command("install").description("Install a plugin (path, archive, or npm spec)").argument("<path-or-spec>", "Path (.ts/.js/.zip/.tgz/.tar.gz) or an npm package spec").option("-l, --link", "Link a local path instead of copying", false).action(async (raw, opts) => { const resolved = resolveUserPath(raw); const cfg = loadConfig(); if (fs.existsSync(resolved)) { if (opts.link) { const existing = cfg.plugins?.load?.paths ?? []; const merged = Array.from(new Set([...existing, resolved])); const probe = await installPluginFromPath({ path: resolved, dryRun: true }); if (!probe.ok) { defaultRuntime.error(probe.error); process.exit(1); } let next = { ...cfg, plugins: { ...cfg.plugins, load: { ...cfg.plugins?.load, paths: merged }, entries: { ...cfg.plugins?.entries, [probe.pluginId]: { ...cfg.plugins?.entries?.[probe.pluginId], enabled: true } } } }; next = recordPluginInstall(next, { pluginId: probe.pluginId, source: "path", sourcePath: resolved, installPath: resolved, version: probe.version }); const slotResult = applySlotSelectionForPlugin(next, probe.pluginId); next = slotResult.config; await writeConfigFile(next); logSlotWarnings(slotResult.warnings); defaultRuntime.log(`Linked plugin path: ${shortenHomePath(resolved)}`); defaultRuntime.log(`Restart the gateway to load plugins.`); return; } const result = await installPluginFromPath({ path: resolved, logger: { info: (msg) => defaultRuntime.log(msg), warn: (msg) => defaultRuntime.log(theme.warn(msg)) } }); if (!result.ok) { defaultRuntime.error(result.error); process.exit(1); } let next = { ...cfg, plugins: { ...cfg.plugins, entries: { ...cfg.plugins?.entries, [result.pluginId]: { ...cfg.plugins?.entries?.[result.pluginId], enabled: true } } } }; const source = resolveArchiveKind(resolved) ? "archive" : "path"; next = recordPluginInstall(next, { pluginId: result.pluginId, source, sourcePath: resolved, installPath: result.targetDir, version: result.version }); const slotResult = applySlotSelectionForPlugin(next, result.pluginId); next = slotResult.config; await writeConfigFile(next); logSlotWarnings(slotResult.warnings); defaultRuntime.log(`Installed plugin: ${result.pluginId}`); defaultRuntime.log(`Restart the gateway to load plugins.`); return; } if (opts.link) { defaultRuntime.error("`--link` requires a local path."); process.exit(1); } if (raw.startsWith(".") || raw.startsWith("~") || path.isAbsolute(raw) || raw.endsWith(".ts") || raw.endsWith(".js") || raw.endsWith(".mjs") || raw.endsWith(".cjs") || raw.endsWith(".tgz") || raw.endsWith(".tar.gz") || raw.endsWith(".tar") || raw.endsWith(".zip")) { defaultRuntime.error(`Path not found: ${resolved}`); process.exit(1); } const result = await installPluginFromNpmSpec({ spec: raw, logger: { info: (msg) => defaultRuntime.log(msg), warn: (msg) => defaultRuntime.log(theme.warn(msg)) } }); if (!result.ok) { defaultRuntime.error(result.error); process.exit(1); } let next = { ...cfg, plugins: { ...cfg.plugins, entries: { ...cfg.plugins?.entries, [result.pluginId]: { ...cfg.plugins?.entries?.[result.pluginId], enabled: true } } } }; next = recordPluginInstall(next, { pluginId: result.pluginId, source: "npm", spec: raw, installPath: result.targetDir, version: result.version }); const slotResult = applySlotSelectionForPlugin(next, result.pluginId); next = slotResult.config; await writeConfigFile(next); logSlotWarnings(slotResult.warnings); defaultRuntime.log(`Installed plugin: ${result.pluginId}`); defaultRuntime.log(`Restart the gateway to load plugins.`); }); plugins.command("update").description("Update installed plugins (npm installs only)").argument("[id]", "Plugin id (omit with --all)").option("--all", "Update all tracked plugins", false).option("--dry-run", "Show what would change without writing", false).action(async (id, opts) => { const cfg = loadConfig(); const installs = cfg.plugins?.installs ?? {}; const targets = opts.all ? Object.keys(installs) : id ? [id] : []; if (targets.length === 0) { if (opts.all) { defaultRuntime.log("No npm-installed plugins to update."); return; } defaultRuntime.error("Provide a plugin id or use --all."); process.exit(1); } const result = await updateNpmInstalledPlugins({ config: cfg, pluginIds: targets, dryRun: opts.dryRun, logger: { info: (msg) => defaultRuntime.log(msg), warn: (msg) => defaultRuntime.log(theme.warn(msg)) } }); for (const outcome of result.outcomes) { if (outcome.status === "error") { defaultRuntime.log(theme.error(outcome.message)); continue; } if (outcome.status === "skipped") { defaultRuntime.log(theme.warn(outcome.message)); continue; } defaultRuntime.log(outcome.message); } if (!opts.dryRun && result.changed) { await writeConfigFile(result.config); defaultRuntime.log("Restart the gateway to load plugins."); } }); plugins.command("doctor").description("Report plugin load issues").action(() => { const report = buildPluginStatusReport(); const errors = report.plugins.filter((p) => p.status === "error"); const diags = report.diagnostics.filter((d) => d.level === "error"); if (errors.length === 0 && diags.length === 0) { defaultRuntime.log("No plugin issues detected."); return; } const lines = []; if (errors.length > 0) { lines.push(theme.error("Plugin errors:")); for (const entry of errors) lines.push(`- ${entry.id}: ${entry.error ?? "failed to load"} (${entry.source})`); } if (diags.length > 0) { if (lines.length > 0) lines.push(""); lines.push(theme.warn("Diagnostics:")); for (const diag of diags) { const target = diag.pluginId ? `${diag.pluginId}: ` : ""; lines.push(`- ${target}${diag.message}`); } } const docs = formatDocsLink("/plugin", "docs.openclaw.ai/plugin"); lines.push(""); lines.push(`${theme.muted("Docs:")} ${docs}`); defaultRuntime.log(lines.join("\n")); }); } //#endregion export { registerPluginsCli };