UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

773 lines (753 loc) 26.8 kB
import { t as __exportAll } from "./rolldown-runtime-Cbj13DAv.js"; import { g as resolveStateDir } from "./paths-scjhy7N2.js"; import { t as isTruthyEnvValue } from "./env-0_mKbEWW.js"; import { r as resolveActionArgs } from "./helpers-5yebzF4C.js"; import os from "node:os"; import path from "node:path"; import fs from "node:fs/promises"; import { Option } from "commander"; //#region src/cli/argv.ts const HELP_FLAGS = new Set(["-h", "--help"]); const VERSION_FLAGS = new Set([ "-v", "-V", "--version" ]); const FLAG_TERMINATOR = "--"; function hasHelpOrVersion(argv) { return argv.some((arg) => HELP_FLAGS.has(arg) || VERSION_FLAGS.has(arg)); } function isValueToken(arg) { if (!arg) return false; if (arg === FLAG_TERMINATOR) return false; if (!arg.startsWith("-")) return true; return /^-\d+(?:\.\d+)?$/.test(arg); } function parsePositiveInt(value) { const parsed = Number.parseInt(value, 10); if (Number.isNaN(parsed) || parsed <= 0) return; return parsed; } function hasFlag(argv, name) { const args = argv.slice(2); for (const arg of args) { if (arg === FLAG_TERMINATOR) break; if (arg === name) return true; } return false; } function getFlagValue(argv, name) { const args = argv.slice(2); for (let i = 0; i < args.length; i += 1) { const arg = args[i]; if (arg === FLAG_TERMINATOR) break; if (arg === name) { const next = args[i + 1]; return isValueToken(next) ? next : null; } if (arg.startsWith(`${name}=`)) { const value = arg.slice(name.length + 1); return value ? value : null; } } } function getVerboseFlag(argv, options) { if (hasFlag(argv, "--verbose")) return true; if (options?.includeDebug && hasFlag(argv, "--debug")) return true; return false; } function getPositiveIntFlagValue(argv, name) { const raw = getFlagValue(argv, name); if (raw === null || raw === void 0) return raw; return parsePositiveInt(raw); } function getCommandPath(argv, depth = 2) { const args = argv.slice(2); const path = []; for (let i = 0; i < args.length; i += 1) { const arg = args[i]; if (!arg) continue; if (arg === "--") break; if (arg.startsWith("-")) continue; path.push(arg); if (path.length >= depth) break; } return path; } function getPrimaryCommand(argv) { const [primary] = getCommandPath(argv, 1); return primary ?? null; } function buildParseArgv(params) { const baseArgv = params.rawArgs && params.rawArgs.length > 0 ? params.rawArgs : params.fallbackArgv && params.fallbackArgv.length > 0 ? params.fallbackArgv : process.argv; const programName = params.programName ?? ""; const normalizedArgv = programName && baseArgv[0] === programName ? baseArgv.slice(1) : baseArgv[0]?.endsWith("openclaw") ? baseArgv.slice(1) : baseArgv; const executable = (normalizedArgv[0]?.split(/[/\\]/).pop() ?? "").toLowerCase(); if (normalizedArgv.length >= 2 && (isNodeExecutable(executable) || isBunExecutable(executable))) return normalizedArgv; return [ "node", programName || "openclaw", ...normalizedArgv ]; } const nodeExecutablePattern = /^node-\d+(?:\.\d+)*(?:\.exe)?$/; function isNodeExecutable(executable) { return executable === "node" || executable === "node.exe" || executable === "nodejs" || executable === "nodejs.exe" || nodeExecutablePattern.test(executable); } function isBunExecutable(executable) { return executable === "bun" || executable === "bun.exe"; } //#endregion //#region src/cli/program/register.subclis.ts const shouldRegisterPrimaryOnly = (argv) => { if (isTruthyEnvValue(process.env.OPENCLAW_DISABLE_LAZY_SUBCOMMANDS)) return false; if (hasHelpOrVersion(argv)) return false; return true; }; const shouldEagerRegisterSubcommands = (_argv) => { return isTruthyEnvValue(process.env.OPENCLAW_DISABLE_LAZY_SUBCOMMANDS); }; const loadConfig = async () => { return (await import("./config-CAuZ-EkU.js").then((n) => n.t)).loadConfig(); }; const entries = [ { name: "acp", description: "Agent Control Protocol tools", register: async (program) => { (await import("./acp-cli-BwcHtBDk.js")).registerAcpCli(program); } }, { name: "gateway", description: "Gateway control", register: async (program) => { (await import("./gateway-cli-ape0pnBU.js")).registerGatewayCli(program); } }, { name: "daemon", description: "Gateway service (legacy alias)", register: async (program) => { (await import("./daemon-cli-B6aLZ8OE.js").then((n) => n.t)).registerDaemonCli(program); } }, { name: "logs", description: "Gateway logs", register: async (program) => { (await import("./logs-cli-5L3NxTsc.js")).registerLogsCli(program); } }, { name: "system", description: "System events, heartbeat, and presence", register: async (program) => { (await import("./system-cli-SJLtqI47.js")).registerSystemCli(program); } }, { name: "models", description: "Model configuration", register: async (program) => { (await import("./models-cli-EhrWjNLH.js")).registerModelsCli(program); } }, { name: "approvals", description: "Exec approvals", register: async (program) => { (await import("./exec-approvals-cli-DzLp5G7t.js")).registerExecApprovalsCli(program); } }, { name: "nodes", description: "Node commands", register: async (program) => { (await import("./nodes-cli-Bc5K-0Lt.js")).registerNodesCli(program); } }, { name: "devices", description: "Device pairing + token management", register: async (program) => { (await import("./devices-cli-Cm0ENrXH.js")).registerDevicesCli(program); } }, { name: "node", description: "Node control", register: async (program) => { (await import("./node-cli-2oYmIWJt.js")).registerNodeCli(program); } }, { name: "sandbox", description: "Sandbox tools", register: async (program) => { (await import("./sandbox-cli-C0_Hrk7i.js")).registerSandboxCli(program); } }, { name: "tui", description: "Terminal UI", register: async (program) => { (await import("./tui-cli-DRSIBDgZ.js")).registerTuiCli(program); } }, { name: "cron", description: "Cron scheduler", register: async (program) => { (await import("./cron-cli-Ys53MyTg.js")).registerCronCli(program); } }, { name: "dns", description: "DNS helpers", register: async (program) => { (await import("./dns-cli-BRkJGLqK.js")).registerDnsCli(program); } }, { name: "docs", description: "Docs helpers", register: async (program) => { (await import("./docs-cli-Bh1Coji2.js")).registerDocsCli(program); } }, { name: "hooks", description: "Hooks tooling", register: async (program) => { (await import("./hooks-cli-BMu_-4Ru.js")).registerHooksCli(program); } }, { name: "webhooks", description: "Webhook helpers", register: async (program) => { (await import("./webhooks-cli-ZAn97osC.js")).registerWebhooksCli(program); } }, { name: "pairing", description: "Pairing helpers", register: async (program) => { const { registerPluginCliCommands } = await import("./cli-DD5dW58-.js"); registerPluginCliCommands(program, await loadConfig()); (await import("./pairing-cli-i7wiTmYC.js")).registerPairingCli(program); } }, { name: "plugins", description: "Plugin management", register: async (program) => { (await import("./plugins-cli-CGfxctIx.js")).registerPluginsCli(program); const { registerPluginCliCommands } = await import("./cli-DD5dW58-.js"); registerPluginCliCommands(program, await loadConfig()); } }, { name: "channels", description: "Channel management", register: async (program) => { (await import("./channels-cli-PPk5wwuy.js")).registerChannelsCli(program); } }, { name: "directory", description: "Directory commands", register: async (program) => { (await import("./directory-cli-CTtv_AB7.js")).registerDirectoryCli(program); } }, { name: "security", description: "Security helpers", register: async (program) => { (await import("./security-cli-CybLT9XS.js")).registerSecurityCli(program); } }, { name: "skills", description: "Skills management", register: async (program) => { (await import("./skills-cli-C1yJvIkL.js")).registerSkillsCli(program); } }, { name: "update", description: "CLI update helpers", register: async (program) => { (await import("./update-cli-OAcZiYuA.js")).registerUpdateCli(program); } }, { name: "completion", description: "Generate shell completion script", register: async (program) => { (await Promise.resolve().then(() => completion_cli_exports)).registerCompletionCli(program); } } ]; function getSubCliEntries() { return entries; } function removeCommand(program, command) { const commands = program.commands; const index = commands.indexOf(command); if (index >= 0) commands.splice(index, 1); } async function registerSubCliByName(program, name) { const entry = entries.find((candidate) => candidate.name === name); if (!entry) return false; const existing = program.commands.find((cmd) => cmd.name() === entry.name); if (existing) removeCommand(program, existing); await entry.register(program); return true; } function registerLazyCommand(program, entry) { const placeholder = program.command(entry.name).description(entry.description); placeholder.allowUnknownOption(true); placeholder.allowExcessArguments(true); placeholder.action(async (...actionArgs) => { removeCommand(program, placeholder); await entry.register(program); const actionCommand = actionArgs.at(-1); const rawArgs = (actionCommand?.parent ?? program).rawArgs; const actionArgsList = resolveActionArgs(actionCommand); const fallbackArgv = actionCommand?.name() ? [actionCommand.name(), ...actionArgsList] : actionArgsList; const parseArgv = buildParseArgv({ programName: program.name(), rawArgs, fallbackArgv }); await program.parseAsync(parseArgv); }); } function registerSubCliCommands(program, argv = process.argv) { if (shouldEagerRegisterSubcommands(argv)) { for (const entry of entries) entry.register(program); return; } const primary = getPrimaryCommand(argv); if (primary && shouldRegisterPrimaryOnly(argv)) { const entry = entries.find((candidate) => candidate.name === primary); if (entry) { registerLazyCommand(program, entry); return; } } for (const candidate of entries) registerLazyCommand(program, candidate); } //#endregion //#region src/cli/completion-cli.ts var completion_cli_exports = /* @__PURE__ */ __exportAll({ completionCacheExists: () => completionCacheExists, installCompletion: () => installCompletion, isCompletionInstalled: () => isCompletionInstalled, registerCompletionCli: () => registerCompletionCli, resolveCompletionCachePath: () => resolveCompletionCachePath, resolveShellFromEnv: () => resolveShellFromEnv, usesSlowDynamicCompletion: () => usesSlowDynamicCompletion }); const COMPLETION_SHELLS = [ "zsh", "bash", "powershell", "fish" ]; function isCompletionShell(value) { return COMPLETION_SHELLS.includes(value); } function resolveShellFromEnv(env = process.env) { const shellPath = env.SHELL?.trim() ?? ""; const shellName = shellPath ? path.basename(shellPath).toLowerCase() : ""; if (shellName === "zsh") return "zsh"; if (shellName === "bash") return "bash"; if (shellName === "fish") return "fish"; if (shellName === "pwsh" || shellName === "powershell") return "powershell"; return "zsh"; } function sanitizeCompletionBasename(value) { const trimmed = value.trim(); if (!trimmed) return "openclaw"; return trimmed.replace(/[^a-zA-Z0-9._-]/g, "-"); } function resolveCompletionCacheDir(env = process.env) { const stateDir = resolveStateDir(env, os.homedir); return path.join(stateDir, "completions"); } function resolveCompletionCachePath(shell, binName) { const basename = sanitizeCompletionBasename(binName); const extension = shell === "powershell" ? "ps1" : shell === "fish" ? "fish" : shell === "bash" ? "bash" : "zsh"; return path.join(resolveCompletionCacheDir(), `${basename}.${extension}`); } /** Check if the completion cache file exists for the given shell. */ async function completionCacheExists(shell, binName = "openclaw") { return pathExists(resolveCompletionCachePath(shell, binName)); } function getCompletionScript(shell, program) { if (shell === "zsh") return generateZshCompletion(program); if (shell === "bash") return generateBashCompletion(program); if (shell === "powershell") return generatePowerShellCompletion(program); return generateFishCompletion(program); } async function writeCompletionCache(params) { const cacheDir = resolveCompletionCacheDir(); await fs.mkdir(cacheDir, { recursive: true }); for (const shell of params.shells) { const script = getCompletionScript(shell, params.program); const targetPath = resolveCompletionCachePath(shell, params.binName); await fs.writeFile(targetPath, script, "utf-8"); } } async function pathExists(targetPath) { try { await fs.access(targetPath); return true; } catch { return false; } } function formatCompletionSourceLine(shell, binName, cachePath) { if (shell === "fish") return `source "${cachePath}"`; return `source "${cachePath}"`; } function isCompletionProfileHeader(line) { return line.trim() === "# OpenClaw Completion"; } function isCompletionProfileLine(line, binName, cachePath) { if (line.includes(`${binName} completion`)) return true; if (cachePath && line.includes(cachePath)) return true; return false; } /** Check if a line uses the slow dynamic completion pattern (source <(...)) */ function isSlowDynamicCompletionLine(line, binName) { return line.includes(`<(${binName} completion`) || line.includes(`${binName} completion`) && line.includes("| source"); } function updateCompletionProfile(content, binName, cachePath, sourceLine) { const lines = content.split("\n"); const filtered = []; let hadExisting = false; for (let i = 0; i < lines.length; i += 1) { const line = lines[i] ?? ""; if (isCompletionProfileHeader(line)) { hadExisting = true; i += 1; continue; } if (isCompletionProfileLine(line, binName, cachePath)) { hadExisting = true; continue; } filtered.push(line); } const trimmed = filtered.join("\n").trimEnd(); const block = `# OpenClaw Completion\n${sourceLine}`; const next = trimmed ? `${trimmed}\n\n${block}\n` : `${block}\n`; return { next, changed: next !== content, hadExisting }; } function getShellProfilePath(shell) { const home = process.env.HOME || os.homedir(); if (shell === "zsh") return path.join(home, ".zshrc"); if (shell === "bash") return path.join(home, ".bashrc"); if (shell === "fish") return path.join(home, ".config", "fish", "config.fish"); if (process.platform === "win32") return path.join(process.env.USERPROFILE || home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1"); return path.join(home, ".config", "powershell", "Microsoft.PowerShell_profile.ps1"); } async function isCompletionInstalled(shell, binName = "openclaw") { const profilePath = getShellProfilePath(shell); if (!await pathExists(profilePath)) return false; const cachePathCandidate = resolveCompletionCachePath(shell, binName); const cachedPath = await pathExists(cachePathCandidate) ? cachePathCandidate : null; return (await fs.readFile(profilePath, "utf-8")).split("\n").some((line) => isCompletionProfileHeader(line) || isCompletionProfileLine(line, binName, cachedPath)); } /** * Check if the profile uses the slow dynamic completion pattern. * Returns true if profile has `source <(openclaw completion ...)` instead of cached file. */ async function usesSlowDynamicCompletion(shell, binName = "openclaw") { const profilePath = getShellProfilePath(shell); if (!await pathExists(profilePath)) return false; const cachePath = resolveCompletionCachePath(shell, binName); const lines = (await fs.readFile(profilePath, "utf-8")).split("\n"); for (const line of lines) if (isSlowDynamicCompletionLine(line, binName) && !line.includes(cachePath)) return true; return false; } function registerCompletionCli(program) { program.command("completion").description("Generate shell completion script").addOption(new Option("-s, --shell <shell>", "Shell to generate completion for (default: zsh)").choices(COMPLETION_SHELLS)).option("-i, --install", "Install completion script to shell profile").option("--write-state", "Write completion scripts to $OPENCLAW_STATE_DIR/completions (no stdout)").option("-y, --yes", "Skip confirmation (non-interactive)", false).action(async (options) => { const shell = options.shell ?? "zsh"; const entries = getSubCliEntries(); for (const entry of entries) { if (entry.name === "completion") continue; await registerSubCliByName(program, entry.name); } if (options.writeState) await writeCompletionCache({ program, shells: options.shell ? [shell] : [...COMPLETION_SHELLS], binName: program.name() }); if (options.install) { await installCompletion(options.shell ?? resolveShellFromEnv(), Boolean(options.yes), program.name()); return; } if (options.writeState) return; if (!isCompletionShell(shell)) throw new Error(`Unsupported shell: ${shell}`); const script = getCompletionScript(shell, program); console.log(script); }); } async function installCompletion(shell, yes, binName = "openclaw") { const home = process.env.HOME || os.homedir(); let profilePath = ""; let sourceLine = ""; if (!isCompletionShell(shell)) { console.error(`Automated installation not supported for ${shell} yet.`); return; } const cachePath = resolveCompletionCachePath(shell, binName); if (!await pathExists(cachePath)) { console.error(`Completion cache not found at ${cachePath}. Run \`${binName} completion --write-state\` first.`); return; } if (shell === "zsh") { profilePath = path.join(home, ".zshrc"); sourceLine = formatCompletionSourceLine("zsh", binName, cachePath); } else if (shell === "bash") { profilePath = path.join(home, ".bashrc"); try { await fs.access(profilePath); } catch { profilePath = path.join(home, ".bash_profile"); } sourceLine = formatCompletionSourceLine("bash", binName, cachePath); } else if (shell === "fish") { profilePath = path.join(home, ".config", "fish", "config.fish"); sourceLine = formatCompletionSourceLine("fish", binName, cachePath); } else { console.error(`Automated installation not supported for ${shell} yet.`); return; } try { try { await fs.access(profilePath); } catch { if (!yes) console.warn(`Profile not found at ${profilePath}. Created a new one.`); await fs.mkdir(path.dirname(profilePath), { recursive: true }); await fs.writeFile(profilePath, "", "utf-8"); } const update = updateCompletionProfile(await fs.readFile(profilePath, "utf-8"), binName, cachePath, sourceLine); if (!update.changed) { if (!yes) console.log(`Completion already installed in ${profilePath}`); return; } if (!yes) { const action = update.hadExisting ? "Updating" : "Installing"; console.log(`${action} completion in ${profilePath}...`); } await fs.writeFile(profilePath, update.next, "utf-8"); if (!yes) console.log(`Completion installed. Restart your shell or run: source ${profilePath}`); } catch (err) { console.error(`Failed to install completion: ${err}`); } } function generateZshCompletion(program) { const rootCmd = program.name(); return ` #compdef ${rootCmd} _${rootCmd}_root_completion() { local -a commands local -a options _arguments -C \\ ${generateZshArgs(program)} \\ ${generateZshSubcmdList(program)} \\ "*::arg:->args" case $state in (args) case $line[1] in ${program.commands.map((cmd) => `(${cmd.name()}) _${rootCmd}_${cmd.name().replace(/-/g, "_")} ;;`).join("\n ")} esac ;; esac } ${generateZshSubcommands(program, rootCmd)} compdef _${rootCmd}_root_completion ${rootCmd} `; } function generateZshArgs(cmd) { return (cmd.options || []).map((opt) => { const flags = opt.flags.split(/[ ,|]+/); const name = flags.find((f) => f.startsWith("--")) || flags[0]; const short = flags.find((f) => f.startsWith("-") && !f.startsWith("--")); const desc = opt.description.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/'/g, "'\\''").replace(/\[/g, "\\[").replace(/\]/g, "\\]"); if (short) return `"(${name} ${short})"{${name},${short}}"[${desc}]"`; return `"${name}[${desc}]"`; }).join(" \\\n "); } function generateZshSubcmdList(cmd) { return `"1: :_values 'command' ${cmd.commands.map((c) => { const desc = c.description().replace(/\\/g, "\\\\").replace(/'/g, "'\\''").replace(/\[/g, "\\[").replace(/\]/g, "\\]"); return `'${c.name()}[${desc}]'`; }).join(" ")}"`; } function generateZshSubcommands(program, prefix) { let script = ""; for (const cmd of program.commands) { const cmdName = cmd.name(); const funcName = `_${prefix}_${cmdName.replace(/-/g, "_")}`; script += generateZshSubcommands(cmd, `${prefix}_${cmdName.replace(/-/g, "_")}`); const subCommands = cmd.commands; if (subCommands.length > 0) script += ` ${funcName}() { local -a commands local -a options _arguments -C \\ ${generateZshArgs(cmd)} \\ ${generateZshSubcmdList(cmd)} \\ "*::arg:->args" case $state in (args) case $line[1] in ${subCommands.map((sub) => `(${sub.name()}) ${funcName}_${sub.name().replace(/-/g, "_")} ;;`).join("\n ")} esac ;; esac } `; else script += ` ${funcName}() { _arguments -C \\ ${generateZshArgs(cmd)} } `; } return script; } function generateBashCompletion(program) { const rootCmd = program.name(); return ` _${rootCmd}_completion() { local cur prev opts COMPREPLY=() cur="\${COMP_WORDS[COMP_CWORD]}" prev="\${COMP_WORDS[COMP_CWORD-1]}" # Simple top-level completion for now opts="${program.commands.map((c) => c.name()).join(" ")} ${program.options.map((o) => o.flags.split(" ")[0]).join(" ")}" case "\${prev}" in ${program.commands.map((cmd) => generateBashSubcommand(cmd)).join("\n ")} esac if [[ \${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) ) return 0 fi COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) ) } complete -F _${rootCmd}_completion ${rootCmd} `; } function generateBashSubcommand(cmd) { return `${cmd.name()}) opts="${cmd.commands.map((c) => c.name()).join(" ")} ${cmd.options.map((o) => o.flags.split(" ")[0]).join(" ")}" COMPREPLY=( $(compgen -W "\${opts}" -- \${cur}) ) return 0 ;;`; } function generatePowerShellCompletion(program) { const rootCmd = program.name(); const visit = (cmd, parents) => { const cmdName = cmd.name(); const fullPath = [...parents, cmdName].join(" "); let script = ""; const subCommands = cmd.commands.map((c) => c.name()); const options = cmd.options.map((o) => o.flags.split(/[ ,|]+/)[0]); const allCompletions = [...subCommands, ...options].map((s) => `'${s}'`).join(","); if (allCompletions.length > 0) script += ` if ($commandPath -eq '${fullPath}') { $completions = @(${allCompletions}) $completions | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_) } } `; for (const sub of cmd.commands) script += visit(sub, [...parents, cmdName]); return script; }; const rootBody = visit(program, []); return ` Register-ArgumentCompleter -Native -CommandName ${rootCmd} -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) $commandElements = $commandAst.CommandElements $commandPath = "" # Reconstruct command path (simple approximation) # Skip the executable name for ($i = 1; $i -lt $commandElements.Count; $i++) { $element = $commandElements[$i].Extent.Text if ($element -like "-*") { break } if ($i -eq $commandElements.Count - 1 -and $wordToComplete -ne "") { break } # Don't include current word being typed $commandPath += "$element " } $commandPath = $commandPath.Trim() # Root command if ($commandPath -eq "") { $completions = @(${program.commands.map((c) => `'${c.name()}'`).join(",")}, ${program.options.map((o) => `'${o.flags.split(" ")[0]}'`).join(",")}) $completions | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_) } } ${rootBody} } `; } function generateFishCompletion(program) { const rootCmd = program.name(); let script = ""; const visit = (cmd, parents) => { const cmdName = cmd.name(); const fullPath = [...parents]; if (parents.length > 0) fullPath.push(cmdName); if (parents.length === 0) { for (const sub of cmd.commands) { const desc = sub.description().replace(/'/g, "'\\''"); script += `complete -c ${rootCmd} -n "__fish_use_subcommand" -a "${sub.name()}" -d '${desc}'\n`; } for (const opt of cmd.options) { const flags = opt.flags.split(/[ ,|]+/); const long = flags.find((f) => f.startsWith("--"))?.replace(/^--/, ""); const short = flags.find((f) => f.startsWith("-") && !f.startsWith("--"))?.replace(/^-/, ""); const desc = opt.description.replace(/'/g, "'\\''"); let line = `complete -c ${rootCmd} -n "__fish_use_subcommand"`; if (short) line += ` -s ${short}`; if (long) line += ` -l ${long}`; line += ` -d '${desc}'\n`; script += line; } } else { for (const sub of cmd.commands) { const desc = sub.description().replace(/'/g, "'\\''"); script += `complete -c ${rootCmd} -n "__fish_seen_subcommand_from ${cmdName}" -a "${sub.name()}" -d '${desc}'\n`; } for (const opt of cmd.options) { const flags = opt.flags.split(/[ ,|]+/); const long = flags.find((f) => f.startsWith("--"))?.replace(/^--/, ""); const short = flags.find((f) => f.startsWith("-") && !f.startsWith("--"))?.replace(/^-/, ""); const desc = opt.description.replace(/'/g, "'\\''"); let line = `complete -c ${rootCmd} -n "__fish_seen_subcommand_from ${cmdName}"`; if (short) line += ` -s ${short}`; if (long) line += ` -l ${long}`; line += ` -d '${desc}'\n`; script += line; } } for (const sub of cmd.commands) visit(sub, [...parents, cmdName]); }; visit(program, []); return script; } //#endregion export { resolveCompletionCachePath as a, registerSubCliCommands as c, getPositiveIntFlagValue as d, getVerboseFlag as f, isCompletionInstalled as i, getCommandPath as l, hasHelpOrVersion as m, completion_cli_exports as n, resolveShellFromEnv as o, hasFlag as p, installCompletion as r, usesSlowDynamicCompletion as s, completionCacheExists as t, getFlagValue as u };