@gguf/claw
Version:
Multi-channel AI gateway with extensible messaging integrations
595 lines (588 loc) • 21 kB
JavaScript
import { Dt as theme, Lt as isNixMode, Ut as resolveGatewayPort, Yt as resolveStateDir, _ as defaultRuntime, ct as shortenHomeInString, it as resolveHomeDir, ot as resolveUserPath, qt as resolveOAuthDir, zt as resolveConfigPath } from "./entry.js";
import "./auth-profiles-DFa1zzNy.js";
import { t as formatCliCommand } from "./command-format-D3syQOZg.js";
import "./exec-CBKBIMpA.js";
import { D as resolveDefaultAgentWorkspaceDir } from "./agent-scope-RzK9Zcks.js";
import "./github-copilot-token-DuFIqfeC.js";
import "./model-DY9t1aT6.js";
import "./pi-model-discovery-Do3xMEtM.js";
import "./frontmatter-D-YR-Ghi.js";
import "./skills-DJmGZazd.js";
import "./manifest-registry-DS2iK5AZ.js";
import "./skills-status-qrtSNHRV.js";
import { i as loadConfig, o as readConfigFileSnapshot } from "./config-B2kL1ciP.js";
import "./client-CDjZdZtI.js";
import "./call-DXhJGwEy.js";
import "./message-channel-CVHJDItx.js";
import "./pairing-token-Byh6drgn.js";
import "./subagent-registry-C7Edpn23.js";
import "./sessions-BD5dyLxb.js";
import "./tokens-D5RzuaYP.js";
import "./normalize-Db7Xtx2v.js";
import "./accounts-BpzwDfBB.js";
import "./bindings-KqaGKS1E.js";
import "./logging-CFvkxgcX.js";
import "./send-BFiRlO6V.js";
import "./plugins-RqhjLCb6.js";
import "./send-CWDtU8Gi.js";
import "./with-timeout-nVWy7PWz.js";
import "./deliver-CeVE1Jh-.js";
import "./diagnostic-774btyou.js";
import "./diagnostic-session-state-HO94DMou.js";
import "./accounts-B3D4iWUP.js";
import "./send-DCCBUsNn.js";
import "./image-ops-lDlFpoR2.js";
import "./pi-embedded-helpers-NVEtaJwl.js";
import "./sandbox-CO-R8v6J.js";
import "./common-DcSh1hZE.js";
import "./chrome-52ZF7gmE.js";
import "./tailscale-BzRVNhMW.js";
import "./auth-Dq2pFnjj.js";
import "./server-context-C1f7cijA.js";
import "./routes-BJmh1Ify.js";
import "./redact-C2s6sr73.js";
import "./errors-CFEPAPWc.js";
import "./fs-safe-3YwsxSr5.js";
import "./paths-CXKNzNjU.js";
import "./ssrf-Cv2DiHsm.js";
import "./store-e6fIrP17.js";
import "./ports-59j-bA53.js";
import "./trash-DVLJ0k6q.js";
import "./dock-BZuwgj1O.js";
import "./accounts-Jg3_1Y-r.js";
import "./paths-CXpciDEv.js";
import "./thinking-CJPPUYWd.js";
import "./models-config-5zJ39mUb.js";
import "./reply-prefix-DJOqzjBt.js";
import "./memory-cli-C3uas9sI.js";
import "./manager-D3ZmOwqt.js";
import "./gemini-auth-CdgAkz2K.js";
import "./sqlite-1-TCahE6.js";
import "./retry-BcjnIuo-.js";
import "./chunk-Z2NYDchs.js";
import "./markdown-tables-GCHx-nGT.js";
import "./fetch-guard-B5BAqVyD.js";
import "./local-roots-SkDT1Wv8.js";
import "./ir-DAwVi0a7.js";
import "./render-e7fENCYH.js";
import "./commands-registry-CRmMPJQ9.js";
import "./image-QGUQCdGh.js";
import "./tool-display-Cs1uRaRV.js";
import "./runner-D81xREgc.js";
import "./model-catalog-DLoDxnxL.js";
import "./session-utils-C3Oi9cXA.js";
import "./skill-commands-D2rmj6w8.js";
import "./workspace-dirs-BXftTDSV.js";
import "./pairing-store-CruPwgBw.js";
import "./fetch-vg2oFVIH.js";
import "./exec-approvals-BZA6z4HM.js";
import "./nodes-screen-x7YKy8Ay.js";
import "./session-cost-usage-CpxG9Mup.js";
import "./pi-tools.policy-DeRwGLEO.js";
import "./control-service-DGleRjGJ.js";
import "./stagger-CArN2YVJ.js";
import "./channel-selection-DoXlsBhe.js";
import "./send-C3RIrBTr.js";
import "./outbound-attachment-CdFWGHgJ.js";
import "./delivery-queue-DKdWlR61.js";
import "./send-0Nz3O9Jc.js";
import "./resolve-route-BONxzeyg.js";
import "./channel-activity-BYGpAtHP.js";
import "./tables-BrqD0SUa.js";
import "./proxy-DL3MD6-P.js";
import { t as formatDocsLink } from "./links-CW8Bx7rK.js";
import { n as runCommandWithRuntime } from "./cli-utils-CCaEbxAz.js";
import "./help-format-B0pWGnZs.js";
import "./progress-BAHiAaDW.js";
import "./replies-CuUAAFF2.js";
import { f as openUrl, g as resolveControlUiLinks, i as detectBrowserOpenSupport, o as formatControlUiSshHint } from "./onboard-helpers-CEx2tGVB.js";
import { n as stylePromptMessage, r as stylePromptTitle, t as stylePromptHint } from "./prompt-style-DwCXob2h.js";
import "./pairing-labels-DtxjElSq.js";
import { t as copyToClipboard } from "./clipboard-33311YqP.js";
import "./catalog-vmrRUSxJ.js";
import "./note-D3Xn5qjj.js";
import "./plugin-auto-enable-DR5UZ2Ky.js";
import "./channels-status-issues-DgVhydeW.js";
import "./register.subclis-CPEP_g__.js";
import "./command-registry-D81FNA9E.js";
import "./program-context--isQKnLs.js";
import "./completion-cli-D8CbjU3K.js";
import "./daemon-runtime-DL5x9CWn.js";
import "./runtime-guard-DcwOrtgH.js";
import "./systemd-BeKZd5oD.js";
import { t as resolveGatewayService } from "./service-CIkh5YiN.js";
import "./systemd-hints-DCQYuPQQ.js";
import "./diagnostics-CqIGmTJP.js";
import "./health-75545GOF.js";
import "./control-ui-assets-CwSEyfND.js";
import "./update-check-Cabl9Oh_.js";
import "./dm-policy-shared-BaTHScul.js";
import "./session-dirs-DzJ9UfQe.js";
import "./logging-BGewRZy0.js";
import "./doctor-config-flow-Cr5VX2mY.js";
import "./systemd-linger-CgYzp_8H.js";
import "./health-format-DkjSgkDx.js";
import { n as doctorCommand, t as selectStyled } from "./prompt-select-styled-BENoydGH.js";
import "./doctor-completion-CkzolxKG.js";
import path from "node:path";
import fs from "node:fs/promises";
import { cancel, confirm, isCancel, multiselect } from "@clack/prompts";
//#region src/commands/dashboard.ts
async function dashboardCommand(runtime = defaultRuntime, options = {}) {
const snapshot = await readConfigFileSnapshot();
const cfg = snapshot.valid ? snapshot.config : {};
const port = resolveGatewayPort(cfg);
const bind = cfg.gateway?.bind ?? "loopback";
const basePath = cfg.gateway?.controlUi?.basePath;
const customBindHost = cfg.gateway?.customBindHost;
const token = cfg.gateway?.auth?.token ?? process.env.OPENCLAW_GATEWAY_TOKEN ?? "";
const links = resolveControlUiLinks({
port,
bind: bind === "lan" ? "loopback" : bind,
customBindHost,
basePath
});
const dashboardUrl = token ? `${links.httpUrl}#token=${encodeURIComponent(token)}` : links.httpUrl;
runtime.log(`Dashboard URL: ${dashboardUrl}`);
const copied = await copyToClipboard(dashboardUrl).catch(() => false);
runtime.log(copied ? "Copied to clipboard." : "Copy to clipboard unavailable.");
let opened = false;
let hint;
if (!options.noOpen) {
if ((await detectBrowserOpenSupport()).ok) opened = await openUrl(dashboardUrl);
if (!opened) hint = formatControlUiSshHint({
port,
basePath,
token: token || void 0
});
} else hint = "Browser launch disabled (--no-open). Use the URL above.";
if (opened) runtime.log("Opened in your browser. Keep that tab to control OpenClaw.");
else if (hint) runtime.log(hint);
}
//#endregion
//#region src/commands/cleanup-utils.ts
function collectWorkspaceDirs(cfg) {
const dirs = /* @__PURE__ */ new Set();
const defaults = cfg?.agents?.defaults;
if (typeof defaults?.workspace === "string" && defaults.workspace.trim()) dirs.add(resolveUserPath(defaults.workspace));
const list = Array.isArray(cfg?.agents?.list) ? cfg?.agents?.list : [];
for (const agent of list) {
const workspace = agent.workspace;
if (typeof workspace === "string" && workspace.trim()) dirs.add(resolveUserPath(workspace));
}
if (dirs.size === 0) dirs.add(resolveDefaultAgentWorkspaceDir());
return [...dirs];
}
function buildCleanupPlan(params) {
return {
configInsideState: isPathWithin(params.configPath, params.stateDir),
oauthInsideState: isPathWithin(params.oauthDir, params.stateDir),
workspaceDirs: collectWorkspaceDirs(params.cfg)
};
}
function isPathWithin(child, parent) {
const relative = path.relative(parent, child);
return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
}
function isUnsafeRemovalTarget(target) {
if (!target.trim()) return true;
const resolved = path.resolve(target);
if (resolved === path.parse(resolved).root) return true;
const home = resolveHomeDir();
if (home && resolved === path.resolve(home)) return true;
return false;
}
async function removePath(target, runtime, opts) {
if (!target?.trim()) return {
ok: false,
skipped: true
};
const resolved = path.resolve(target);
const displayLabel = shortenHomeInString(opts?.label ?? resolved);
if (isUnsafeRemovalTarget(resolved)) {
runtime.error(`Refusing to remove unsafe path: ${displayLabel}`);
return { ok: false };
}
if (opts?.dryRun) {
runtime.log(`[dry-run] remove ${displayLabel}`);
return {
ok: true,
skipped: true
};
}
try {
await fs.rm(resolved, {
recursive: true,
force: true
});
runtime.log(`Removed ${displayLabel}`);
return { ok: true };
} catch (err) {
runtime.error(`Failed to remove ${displayLabel}: ${String(err)}`);
return { ok: false };
}
}
async function listAgentSessionDirs(stateDir) {
const root = path.join(stateDir, "agents");
try {
return (await fs.readdir(root, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => path.join(root, entry.name, "sessions"));
} catch {
return [];
}
}
//#endregion
//#region src/commands/cleanup-plan.ts
function resolveCleanupPlanFromDisk() {
const cfg = loadConfig();
const stateDir = resolveStateDir();
const configPath = resolveConfigPath();
const oauthDir = resolveOAuthDir();
return {
cfg,
stateDir,
configPath,
oauthDir,
...buildCleanupPlan({
cfg,
stateDir,
configPath,
oauthDir
})
};
}
//#endregion
//#region src/commands/reset.ts
async function stopGatewayIfRunning(runtime) {
if (isNixMode) return;
const service = resolveGatewayService();
let loaded = false;
try {
loaded = await service.isLoaded({ env: process.env });
} catch (err) {
runtime.error(`Gateway service check failed: ${String(err)}`);
return;
}
if (!loaded) return;
try {
await service.stop({
env: process.env,
stdout: process.stdout
});
} catch (err) {
runtime.error(`Gateway stop failed: ${String(err)}`);
}
}
async function resetCommand(runtime, opts) {
const interactive = !opts.nonInteractive;
if (!interactive && !opts.yes) {
runtime.error("Non-interactive mode requires --yes.");
runtime.exit(1);
return;
}
let scope = opts.scope;
if (!scope) {
if (!interactive) {
runtime.error("Non-interactive mode requires --scope.");
runtime.exit(1);
return;
}
const selection = await selectStyled({
message: "Reset scope",
options: [
{
value: "config",
label: "Config only",
hint: "openclaw.json"
},
{
value: "config+creds+sessions",
label: "Config + credentials + sessions",
hint: "keeps workspace + auth profiles"
},
{
value: "full",
label: "Full reset",
hint: "state dir + workspace"
}
],
initialValue: "config+creds+sessions"
});
if (isCancel(selection)) {
cancel(stylePromptTitle("Reset cancelled.") ?? "Reset cancelled.");
runtime.exit(0);
return;
}
scope = selection;
}
if (![
"config",
"config+creds+sessions",
"full"
].includes(scope)) {
runtime.error("Invalid --scope. Expected \"config\", \"config+creds+sessions\", or \"full\".");
runtime.exit(1);
return;
}
if (interactive && !opts.yes) {
const ok = await confirm({ message: stylePromptMessage(`Proceed with ${scope} reset?`) });
if (isCancel(ok) || !ok) {
cancel(stylePromptTitle("Reset cancelled.") ?? "Reset cancelled.");
runtime.exit(0);
return;
}
}
const dryRun = Boolean(opts.dryRun);
const { stateDir, configPath, oauthDir, configInsideState, oauthInsideState, workspaceDirs } = resolveCleanupPlanFromDisk();
if (scope !== "config") if (dryRun) runtime.log("[dry-run] stop gateway service");
else await stopGatewayIfRunning(runtime);
if (scope === "config") {
await removePath(configPath, runtime, {
dryRun,
label: configPath
});
return;
}
if (scope === "config+creds+sessions") {
await removePath(configPath, runtime, {
dryRun,
label: configPath
});
await removePath(oauthDir, runtime, {
dryRun,
label: oauthDir
});
const sessionDirs = await listAgentSessionDirs(stateDir);
for (const dir of sessionDirs) await removePath(dir, runtime, {
dryRun,
label: dir
});
runtime.log(`Next: ${formatCliCommand("openclaw onboard --install-daemon")}`);
return;
}
if (scope === "full") {
await removePath(stateDir, runtime, {
dryRun,
label: stateDir
});
if (!configInsideState) await removePath(configPath, runtime, {
dryRun,
label: configPath
});
if (!oauthInsideState) await removePath(oauthDir, runtime, {
dryRun,
label: oauthDir
});
for (const workspace of workspaceDirs) await removePath(workspace, runtime, {
dryRun,
label: workspace
});
runtime.log(`Next: ${formatCliCommand("openclaw onboard --install-daemon")}`);
return;
}
}
//#endregion
//#region src/commands/uninstall.ts
const multiselectStyled = (params) => multiselect({
...params,
message: stylePromptMessage(params.message),
options: params.options.map((opt) => opt.hint === void 0 ? opt : {
...opt,
hint: stylePromptHint(opt.hint)
})
});
function buildScopeSelection(opts) {
const hadExplicit = Boolean(opts.all || opts.service || opts.state || opts.workspace || opts.app);
const scopes = /* @__PURE__ */ new Set();
if (opts.all || opts.service) scopes.add("service");
if (opts.all || opts.state) scopes.add("state");
if (opts.all || opts.workspace) scopes.add("workspace");
if (opts.all || opts.app) scopes.add("app");
return {
scopes,
hadExplicit
};
}
async function stopAndUninstallService(runtime) {
if (isNixMode) {
runtime.error("Nix mode detected; service uninstall is disabled.");
return false;
}
const service = resolveGatewayService();
let loaded = false;
try {
loaded = await service.isLoaded({ env: process.env });
} catch (err) {
runtime.error(`Gateway service check failed: ${String(err)}`);
return false;
}
if (!loaded) {
runtime.log(`Gateway service ${service.notLoadedText}.`);
return true;
}
try {
await service.stop({
env: process.env,
stdout: process.stdout
});
} catch (err) {
runtime.error(`Gateway stop failed: ${String(err)}`);
}
try {
await service.uninstall({
env: process.env,
stdout: process.stdout
});
return true;
} catch (err) {
runtime.error(`Gateway uninstall failed: ${String(err)}`);
return false;
}
}
async function removeMacApp(runtime, dryRun) {
if (process.platform !== "darwin") return;
await removePath("/Applications/OpenClaw.app", runtime, {
dryRun,
label: "/Applications/OpenClaw.app"
});
}
async function uninstallCommand(runtime, opts) {
const { scopes, hadExplicit } = buildScopeSelection(opts);
const interactive = !opts.nonInteractive;
if (!interactive && !opts.yes) {
runtime.error("Non-interactive mode requires --yes.");
runtime.exit(1);
return;
}
if (!hadExplicit) {
if (!interactive) {
runtime.error("Non-interactive mode requires explicit scopes (use --all).");
runtime.exit(1);
return;
}
const selection = await multiselectStyled({
message: "Uninstall which components?",
options: [
{
value: "service",
label: "Gateway service",
hint: "launchd / systemd / schtasks"
},
{
value: "state",
label: "State + config",
hint: "~/.openclaw"
},
{
value: "workspace",
label: "Workspace",
hint: "agent files"
},
{
value: "app",
label: "macOS app",
hint: "/Applications/OpenClaw.app"
}
],
initialValues: [
"service",
"state",
"workspace"
]
});
if (isCancel(selection)) {
cancel(stylePromptTitle("Uninstall cancelled.") ?? "Uninstall cancelled.");
runtime.exit(0);
return;
}
for (const value of selection) scopes.add(value);
}
if (scopes.size === 0) {
runtime.log("Nothing selected.");
return;
}
if (interactive && !opts.yes) {
const ok = await confirm({ message: stylePromptMessage("Proceed with uninstall?") });
if (isCancel(ok) || !ok) {
cancel(stylePromptTitle("Uninstall cancelled.") ?? "Uninstall cancelled.");
runtime.exit(0);
return;
}
}
const dryRun = Boolean(opts.dryRun);
const { stateDir, configPath, oauthDir, configInsideState, oauthInsideState, workspaceDirs } = resolveCleanupPlanFromDisk();
if (scopes.has("service")) if (dryRun) runtime.log("[dry-run] remove gateway service");
else await stopAndUninstallService(runtime);
if (scopes.has("state")) {
await removePath(stateDir, runtime, {
dryRun,
label: stateDir
});
if (!configInsideState) await removePath(configPath, runtime, {
dryRun,
label: configPath
});
if (!oauthInsideState) await removePath(oauthDir, runtime, {
dryRun,
label: oauthDir
});
}
if (scopes.has("workspace")) for (const workspace of workspaceDirs) await removePath(workspace, runtime, {
dryRun,
label: workspace
});
if (scopes.has("app")) await removeMacApp(runtime, dryRun);
runtime.log("CLI still installed. Remove via npm/pnpm if desired.");
if (scopes.has("state") && !scopes.has("workspace")) {
const home = resolveHomeDir();
if (home && workspaceDirs.some((dir) => dir.startsWith(path.resolve(home)))) runtime.log("Tip: workspaces were preserved. Re-run with --workspace to remove them.");
}
}
//#endregion
//#region src/cli/program/register.maintenance.ts
function registerMaintenanceCommands(program) {
program.command("doctor").description("Health checks + quick fixes for the gateway and channels").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/doctor", "docs.openclaw.ai/cli/doctor")}\n`).option("--no-workspace-suggestions", "Disable workspace memory system suggestions", false).option("--yes", "Accept defaults without prompting", false).option("--repair", "Apply recommended repairs without prompting", false).option("--fix", "Apply recommended repairs (alias for --repair)", false).option("--force", "Apply aggressive repairs (overwrites custom service config)", false).option("--non-interactive", "Run without prompts (safe migrations only)", false).option("--generate-gateway-token", "Generate and configure a gateway token", false).option("--deep", "Scan system services for extra gateway installs", false).action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
await doctorCommand(defaultRuntime, {
workspaceSuggestions: opts.workspaceSuggestions,
yes: Boolean(opts.yes),
repair: Boolean(opts.repair) || Boolean(opts.fix),
force: Boolean(opts.force),
nonInteractive: Boolean(opts.nonInteractive),
generateGatewayToken: Boolean(opts.generateGatewayToken),
deep: Boolean(opts.deep)
});
defaultRuntime.exit(0);
});
});
program.command("dashboard").description("Open the Control UI with your current token").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/dashboard", "docs.openclaw.ai/cli/dashboard")}\n`).option("--no-open", "Print URL but do not launch a browser", false).action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
await dashboardCommand(defaultRuntime, { noOpen: Boolean(opts.noOpen) });
});
});
program.command("reset").description("Reset local config/state (keeps the CLI installed)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/reset", "docs.openclaw.ai/cli/reset")}\n`).option("--scope <scope>", "config|config+creds+sessions|full (default: interactive prompt)").option("--yes", "Skip confirmation prompts", false).option("--non-interactive", "Disable prompts (requires --scope + --yes)", false).option("--dry-run", "Print actions without removing files", false).action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
await resetCommand(defaultRuntime, {
scope: opts.scope,
yes: Boolean(opts.yes),
nonInteractive: Boolean(opts.nonInteractive),
dryRun: Boolean(opts.dryRun)
});
});
});
program.command("uninstall").description("Uninstall the gateway service + local data (CLI remains)").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/uninstall", "docs.openclaw.ai/cli/uninstall")}\n`).option("--service", "Remove the gateway service", false).option("--state", "Remove state + config", false).option("--workspace", "Remove workspace dirs", false).option("--app", "Remove the macOS app", false).option("--all", "Remove service + state + workspace + app", false).option("--yes", "Skip confirmation prompts", false).option("--non-interactive", "Disable prompts (requires --yes)", false).option("--dry-run", "Print actions without removing files", false).action(async (opts) => {
await runCommandWithRuntime(defaultRuntime, async () => {
await uninstallCommand(defaultRuntime, {
service: Boolean(opts.service),
state: Boolean(opts.state),
workspace: Boolean(opts.workspace),
app: Boolean(opts.app),
all: Boolean(opts.all),
yes: Boolean(opts.yes),
nonInteractive: Boolean(opts.nonInteractive),
dryRun: Boolean(opts.dryRun)
});
});
});
}
//#endregion
export { registerMaintenanceCommands };