UNPKG

@sethdouglasford/claude-flow

Version:

Claude Code Flow - Advanced AI-powered development workflows with SPARC methodology

1,467 lines (1,461 loc) 5.03 MB
#!/usr/bin/env node var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from3, except, desc) => { if (from3 && typeof from3 === "object" || typeof from3 === "function") { for (let key of __getOwnPropNames(from3)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from3[key], enumerable: !(desc = __getOwnPropDesc(from3, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // dist/core/logger.js var import_node_fs, path, import_node_buffer, import_node_process, LogLevel, Logger, logger2; var init_logger = __esm({ "dist/core/logger.js"() { import_node_fs = require("node:fs"); path = __toESM(require("node:path"), 1); import_node_buffer = require("node:buffer"); import_node_process = __toESM(require("node:process"), 1); (function(LogLevel2) { LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG"; LogLevel2[LogLevel2["INFO"] = 1] = "INFO"; LogLevel2[LogLevel2["WARN"] = 2] = "WARN"; LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR"; })(LogLevel || (LogLevel = {})); Logger = class _Logger { static instance; config; context; fileHandle; currentFileSize = 0; currentFileIndex = 0; isClosing = false; constructor(config = { level: "info", format: "text", destination: "console" }, context = {}) { if ((config.destination === "file" || config.destination === "both") && !config.filePath) { throw new Error("File path required for file logging"); } this.config = config; this.context = context; } /** * Gets the singleton instance of the logger */ static getInstance(config) { if (!_Logger.instance) { if (!config) { const isTestEnv = import_node_process.default.env.CLAUDE_FLOW_ENV === "test"; if (isTestEnv) { throw new Error("Logger configuration required for initialization"); } config = { level: "info", format: "text", destination: "console" }; } _Logger.instance = new _Logger(config); } return _Logger.instance; } /** * Updates logger configuration */ async configure(config) { this.config = config; if (this.fileHandle && config.destination !== "file" && config.destination !== "both") { await this.fileHandle.close(); delete this.fileHandle; } } debug(message, meta) { this.log(LogLevel.DEBUG, message, meta); } info(message, meta) { this.log(LogLevel.INFO, message, meta); } warn(message, meta) { this.log(LogLevel.WARN, message, meta); } error(message, error3) { this.log(LogLevel.ERROR, message, void 0, error3); } /** * Creates a child logger with additional context */ child(context) { return new _Logger(this.config, { ...this.context, ...context }); } /** * Properly close the logger and release resources */ async close() { this.isClosing = true; if (this.fileHandle) { try { await this.fileHandle.close(); } catch (error3) { console.error("Error closing log file handle:", error3); } finally { delete this.fileHandle; } } } log(level, message, data, error3) { if (!this.shouldLog(level)) { return; } const entry = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), level: LogLevel[level], message, context: this.context, data, error: error3 }; const formatted = this.format(entry); if (this.config.destination === "console" || this.config.destination === "both") { this.writeToConsole(level, formatted); } if (this.config.destination === "file" || this.config.destination === "both") { void this.writeToFile(formatted); } } shouldLog(level) { const configLevel = LogLevel[this.config.level.toUpperCase()]; return level >= configLevel; } format(entry) { if (this.config.format === "json") { const jsonEntry = { ...entry }; if (jsonEntry.error instanceof Error) { jsonEntry.error = { name: jsonEntry.error.name, message: jsonEntry.error.message, stack: jsonEntry.error.stack }; } return JSON.stringify(jsonEntry); } const contextStr = Object.keys(entry.context).length > 0 ? ` ${JSON.stringify(entry.context)}` : ""; const dataStr = entry.data !== void 0 ? ` ${JSON.stringify(entry.data)}` : ""; const errorStr = entry.error !== void 0 ? entry.error instanceof Error ? ` Error: ${entry.error.message} Stack: ${entry.error.stack}` : ` Error: ${JSON.stringify(entry.error)}` : ""; return `[${entry.timestamp}] ${entry.level} ${entry.message}${contextStr}${dataStr}${errorStr}`; } writeToConsole(level, message) { switch (level) { case LogLevel.DEBUG: console.debug(message); break; case LogLevel.INFO: console.info(message); break; case LogLevel.WARN: console.warn(message); break; case LogLevel.ERROR: console.error(message); break; } } async writeToFile(message) { if (!this.config.filePath || this.isClosing) { return; } try { if (await this.shouldRotate()) { await this.rotate(); } if (!this.fileHandle) { this.fileHandle = await import_node_fs.promises.open(this.config.filePath, "a"); } const data = import_node_buffer.Buffer.from(`${message} `, "utf8"); await this.fileHandle.write(data); this.currentFileSize += data.length; } catch (error3) { console.error("Failed to write to log file:", error3); } } async shouldRotate() { if (!this.config.maxFileSize || !this.config.filePath) { return false; } try { const stat = await import_node_fs.promises.stat(this.config.filePath); return stat.size >= this.config.maxFileSize; } catch { return false; } } async rotate() { if (!this.config.filePath || !this.config.maxFiles) { return; } if (this.fileHandle) { await this.fileHandle.close(); delete this.fileHandle; } const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"); const rotatedPath = `${this.config.filePath}.${timestamp}`; await import_node_fs.promises.rename(this.config.filePath, rotatedPath); await this.cleanupOldFiles(); this.currentFileSize = 0; } async cleanupOldFiles() { if (!this.config.filePath || !this.config.maxFiles) { return; } const dir = path.dirname(this.config.filePath); const baseFileName = path.basename(this.config.filePath); try { const entries = await import_node_fs.promises.readdir(dir, { withFileTypes: true }); const files = []; for (const entry of entries) { if (entry.isFile() && entry.name.startsWith(`${baseFileName}.`)) { files.push(entry.name); } } files.sort().reverse(); const filesToRemove = files.slice(this.config.maxFiles - 1); for (const file of filesToRemove) { await import_node_fs.promises.unlink(path.join(dir, file)); } } catch (error3) { console.error("Failed to cleanup old log files:", error3); } } }; logger2 = Logger.getInstance(); } }); // dist/config/config-manager.js function isSEA() { if (process.isSEA) { return true; } const { execPath } = process; const isNodeBinary = execPath.includes("node") && !execPath.includes("claude-flow"); return !isNodeBinary; } function getDefaultMemoryBackend() { if (isSEA()) { return "markdown"; } return "hybrid"; } var import_fs, import_path, import_os, DEFAULT_CONFIG, ConfigError, ConfigManager, configManager; var init_config_manager = __esm({ "dist/config/config-manager.js"() { import_fs = require("fs"); import_path = __toESM(require("path"), 1); import_os = __toESM(require("os"), 1); DEFAULT_CONFIG = { orchestrator: { maxConcurrentAgents: 10, taskQueueSize: 100, healthCheckInterval: 3e4, shutdownTimeout: 3e4 }, terminal: { type: "auto", poolSize: 5, recycleAfter: 10, healthCheckInterval: 6e4, commandTimeout: 3e5 }, memory: { backend: "hybrid", // Will be overridden in createDefaultConfig for SEA cacheSizeMB: 100, syncInterval: 5e3, conflictResolution: "crdt", retentionDays: 30 }, coordination: { maxRetries: 3, retryDelay: 1e3, deadlockDetection: true, resourceTimeout: 6e4, messageTimeout: 3e4 }, mcp: { transport: "stdio", port: 3e3, tlsEnabled: false }, logging: { level: "info", format: "json", destination: "console" } }; ConfigError = class extends Error { constructor(message) { super(message); this.name = "ConfigError"; } }; ConfigManager = class _ConfigManager { static instance; config; configPath; userConfigDir; constructor() { this.config = this.deepClone(DEFAULT_CONFIG); this.userConfigDir = import_path.default.join(import_os.default.homedir(), ".claude-flow"); } /** * Gets the singleton instance */ static getInstance() { if (!_ConfigManager.instance) { _ConfigManager.instance = new _ConfigManager(); } return _ConfigManager.instance; } /** * Initialize configuration from file or create default */ async init(configPath = "claude-flow.config.json") { try { await this.load(configPath); console.log(`\u2705 Configuration loaded from: ${configPath}`); } catch (error3) { await this.createDefaultConfig(configPath); console.log(`\u2705 Default configuration created: ${configPath}`); } } /** * Creates a default configuration file */ async createDefaultConfig(configPath) { const config = this.deepClone(DEFAULT_CONFIG); const defaultBackend = getDefaultMemoryBackend(); if (defaultBackend !== config.memory.backend) { config.memory.backend = defaultBackend; console.log(`\u2139\uFE0F Using ${defaultBackend} backend for SEA (Single Executable) compatibility`); } const content = JSON.stringify(config, null, 2); await import_fs.promises.writeFile(configPath, content, "utf8"); this.configPath = configPath; } /** * Loads configuration from file */ async load(configPath) { if (configPath) { this.configPath = configPath; } if (!this.configPath) { throw new ConfigError("No configuration file path specified"); } try { const content = await import_fs.promises.readFile(this.configPath, "utf8"); const fileConfig = JSON.parse(content); this.config = this.deepMerge(DEFAULT_CONFIG, fileConfig); this.loadFromEnv(); this.validate(this.config); return this.config; } catch (error3) { if (error3.code === "ENOENT") { throw new ConfigError(`Configuration file not found: ${this.configPath}`); } throw new ConfigError(`Failed to load configuration: ${error3.message}`); } } /** * Shows current configuration */ show() { return this.deepClone(this.config); } /** * Gets a configuration value by path */ get(path10) { const keys = path10.split("."); let current = this.config; for (const key of keys) { if (current && typeof current === "object" && key in current) { current = current[key]; } else { return void 0; } } return current; } /** * Sets a configuration value by path */ set(path10, value) { const keys = path10.split("."); let current = this.config; for (let i3 = 0; i3 < keys.length - 1; i3++) { const key = keys[i3]; if (!(key in current)) { current[key] = {}; } current = current[key]; } const lastKey = keys[keys.length - 1]; current[lastKey] = value; this.validate(this.config); } /** * Saves current configuration to file */ async save(configPath) { const savePath = configPath || this.configPath; if (!savePath) { throw new ConfigError("No configuration file path specified"); } const content = JSON.stringify(this.config, null, 2); await import_fs.promises.writeFile(savePath, content, "utf8"); } /** * Validates the configuration */ validate(config) { if (config.orchestrator.maxConcurrentAgents < 1 || config.orchestrator.maxConcurrentAgents > 100) { throw new ConfigError("orchestrator.maxConcurrentAgents must be between 1 and 100"); } if (config.orchestrator.taskQueueSize < 1 || config.orchestrator.taskQueueSize > 1e4) { throw new ConfigError("orchestrator.taskQueueSize must be between 1 and 10000"); } if (!["auto", "vscode", "native"].includes(config.terminal.type)) { throw new ConfigError("terminal.type must be one of: auto, vscode, native"); } if (config.terminal.poolSize < 1 || config.terminal.poolSize > 50) { throw new ConfigError("terminal.poolSize must be between 1 and 50"); } if (!["sqlite", "markdown", "hybrid"].includes(config.memory.backend)) { throw new ConfigError("memory.backend must be one of: sqlite, markdown, hybrid"); } if (config.memory.cacheSizeMB < 1 || config.memory.cacheSizeMB > 1e4) { throw new ConfigError("memory.cacheSizeMB must be between 1 and 10000"); } if (config.coordination.maxRetries < 0 || config.coordination.maxRetries > 100) { throw new ConfigError("coordination.maxRetries must be between 0 and 100"); } if (!["stdio", "http", "websocket"].includes(config.mcp.transport)) { throw new ConfigError("mcp.transport must be one of: stdio, http, websocket"); } if (config.mcp.port < 1 || config.mcp.port > 65535) { throw new ConfigError("mcp.port must be between 1 and 65535"); } if (!["debug", "info", "warn", "error"].includes(config.logging.level)) { throw new ConfigError("logging.level must be one of: debug, info, warn, error"); } if (!["json", "text"].includes(config.logging.format)) { throw new ConfigError("logging.format must be one of: json, text"); } if (!["console", "file"].includes(config.logging.destination)) { throw new ConfigError("logging.destination must be one of: console, file"); } } /** * Loads configuration from environment variables */ loadFromEnv() { const maxAgents = process.env.CLAUDE_FLOW_MAX_AGENTS; if (maxAgents) { this.config.orchestrator.maxConcurrentAgents = parseInt(maxAgents, 10); } const terminalType = process.env.CLAUDE_FLOW_TERMINAL_TYPE; if (terminalType === "vscode" || terminalType === "native" || terminalType === "auto") { this.config.terminal.type = terminalType; } const memoryBackend = process.env.CLAUDE_FLOW_MEMORY_BACKEND; if (memoryBackend === "sqlite" || memoryBackend === "markdown" || memoryBackend === "hybrid") { this.config.memory.backend = memoryBackend; } const mcpTransport = process.env.CLAUDE_FLOW_MCP_TRANSPORT; if (mcpTransport === "stdio" || mcpTransport === "http" || mcpTransport === "websocket") { this.config.mcp.transport = mcpTransport; } const mcpPort = process.env.CLAUDE_FLOW_MCP_PORT; if (mcpPort) { this.config.mcp.port = parseInt(mcpPort, 10); } const logLevel = process.env.CLAUDE_FLOW_LOG_LEVEL; if (logLevel === "debug" || logLevel === "info" || logLevel === "warn" || logLevel === "error") { this.config.logging.level = logLevel; } } /** * Deep clone helper */ deepClone(obj) { return JSON.parse(JSON.stringify(obj)); } /** * Deep merge helper */ deepMerge(target, source) { const result = this.deepClone(target); if (source.orchestrator) { result.orchestrator = { ...result.orchestrator, ...source.orchestrator }; } if (source.terminal) { result.terminal = { ...result.terminal, ...source.terminal }; } if (source.memory) { result.memory = { ...result.memory, ...source.memory }; } if (source.coordination) { result.coordination = { ...result.coordination, ...source.coordination }; } if (source.mcp) { result.mcp = { ...result.mcp, ...source.mcp }; } if (source.logging) { result.logging = { ...result.logging, ...source.logging }; } return result; } /** * Gets available configuration templates */ getAvailableTemplates() { return ["minimal", "default", "development", "production"]; } /** * Creates a configuration from a template */ createTemplate(templateName) { const templates = { minimal: { orchestrator: { maxConcurrentAgents: 5, taskQueueSize: 50, healthCheckInterval: 6e4, shutdownTimeout: 1e4 }, terminal: { type: "auto", poolSize: 2, recycleAfter: 5, healthCheckInterval: 12e4, commandTimeout: 3e5 } }, development: { logging: { level: "debug", format: "text", destination: "console" }, orchestrator: { maxConcurrentAgents: 20, taskQueueSize: 200, healthCheckInterval: 15e3, shutdownTimeout: 5e3 } }, production: { logging: { level: "warn", format: "json", destination: "file" }, memory: { backend: "markdown", cacheSizeMB: 500, syncInterval: 1e4, conflictResolution: "timestamp", retentionDays: 90 } } }; const template = templates[templateName] || {}; return this.deepMerge(DEFAULT_CONFIG, template); } /** * Gets format parsers for different config file formats */ getFormatParsers() { return { json: { stringify: (obj) => JSON.stringify(obj, null, 2), parse: (str) => JSON.parse(str) }, yaml: { stringify: (obj) => { return this.toYAML(obj); }, parse: (str) => { throw new Error("YAML parsing not implemented"); } }, toml: { stringify: (obj) => { throw new Error("TOML stringification not implemented"); }, parse: (str) => { throw new Error("TOML parsing not implemented"); } } }; } /** * Validates a configuration file */ async validateFile(configPath) { const errors = []; try { const content = await import_fs.promises.readFile(configPath, "utf8"); const config = JSON.parse(content); try { this.validate(config); } catch (error3) { errors.push(error3.message); } if (!config.orchestrator) { errors.push("Missing required section: orchestrator"); } if (!config.terminal) { errors.push("Missing required section: terminal"); } if (!config.memory) { errors.push("Missing required section: memory"); } return { valid: errors.length === 0, errors }; } catch (error3) { errors.push(`Failed to read or parse file: ${error3.message}`); return { valid: false, errors }; } } /** * Backs up the current configuration */ async backup(backupPath) { const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"); const backupFile = backupPath || import_path.default.join(this.userConfigDir, `backup-${timestamp}.json`); await import_fs.promises.mkdir(import_path.default.dirname(backupFile), { recursive: true }); await import_fs.promises.writeFile(backupFile, JSON.stringify(this.config, null, 2), "utf8"); return backupFile; } /** * Restores configuration from a backup */ async restore(backupPath) { const content = await import_fs.promises.readFile(backupPath, "utf8"); const backupConfig = JSON.parse(content); this.validate(backupConfig); this.config = backupConfig; if (this.configPath) { await this.save(); } } /** * Gets configuration path history */ getPathHistory() { return this.configPath ? [this.configPath] : []; } /** * Gets configuration change history */ getChangeHistory() { return []; } /** * Simple YAML converter (basic implementation) */ toYAML(obj, indent = 0) { const spaces = " ".repeat(indent); let result = ""; for (const [key, value] of Object.entries(obj)) { if (typeof value === "object" && value !== null && !Array.isArray(value)) { result += `${spaces}${key}: ${this.toYAML(value, indent + 1)}`; } else if (Array.isArray(value)) { result += `${spaces}${key}: `; value.forEach((item) => { result += `${spaces} - ${JSON.stringify(item)} `; }); } else { result += `${spaces}${key}: ${JSON.stringify(value)} `; } } return result; } }; configManager = ConfigManager.getInstance(); } }); // node_modules/commander/lib/error.js var require_error = __commonJS({ "node_modules/commander/lib/error.js"(exports2) { var CommanderError2 = class extends Error { /** * Constructs the CommanderError class * @param {number} exitCode suggested exit code which could be used with process.exit * @param {string} code an id string representing the error * @param {string} message human-readable description of the error * @constructor */ constructor(exitCode, code, message) { super(message); Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; this.code = code; this.exitCode = exitCode; this.nestedError = void 0; } }; var InvalidArgumentError2 = class extends CommanderError2 { /** * Constructs the InvalidArgumentError class * @param {string} [message] explanation of why argument is invalid * @constructor */ constructor(message) { super(1, "commander.invalidArgument", message); Error.captureStackTrace(this, this.constructor); this.name = this.constructor.name; } }; exports2.CommanderError = CommanderError2; exports2.InvalidArgumentError = InvalidArgumentError2; } }); // node_modules/commander/lib/argument.js var require_argument = __commonJS({ "node_modules/commander/lib/argument.js"(exports2) { var { InvalidArgumentError: InvalidArgumentError2 } = require_error(); var Argument2 = class { /** * Initialize a new command argument with the given name and description. * The default is that the argument is required, and you can explicitly * indicate this with <> around the name. Put [] around the name for an optional argument. * * @param {string} name * @param {string} [description] */ constructor(name, description) { this.description = description || ""; this.variadic = false; this.parseArg = void 0; this.defaultValue = void 0; this.defaultValueDescription = void 0; this.argChoices = void 0; switch (name[0]) { case "<": this.required = true; this._name = name.slice(1, -1); break; case "[": this.required = false; this._name = name.slice(1, -1); break; default: this.required = true; this._name = name; break; } if (this._name.length > 3 && this._name.slice(-3) === "...") { this.variadic = true; this._name = this._name.slice(0, -3); } } /** * Return argument name. * * @return {string} */ name() { return this._name; } /** * @api private */ _concatValue(value, previous) { if (previous === this.defaultValue || !Array.isArray(previous)) { return [value]; } return previous.concat(value); } /** * Set the default value, and optionally supply the description to be displayed in the help. * * @param {*} value * @param {string} [description] * @return {Argument} */ default(value, description) { this.defaultValue = value; this.defaultValueDescription = description; return this; } /** * Set the custom handler for processing CLI command arguments into argument values. * * @param {Function} [fn] * @return {Argument} */ argParser(fn) { this.parseArg = fn; return this; } /** * Only allow argument value to be one of choices. * * @param {string[]} values * @return {Argument} */ choices(values) { this.argChoices = values.slice(); this.parseArg = (arg, previous) => { if (!this.argChoices.includes(arg)) { throw new InvalidArgumentError2(`Allowed choices are ${this.argChoices.join(", ")}.`); } if (this.variadic) { return this._concatValue(arg, previous); } return arg; }; return this; } /** * Make argument required. */ argRequired() { this.required = true; return this; } /** * Make argument optional. */ argOptional() { this.required = false; return this; } }; function humanReadableArgName(arg) { const nameOutput = arg.name() + (arg.variadic === true ? "..." : ""); return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]"; } exports2.Argument = Argument2; exports2.humanReadableArgName = humanReadableArgName; } }); // node_modules/commander/lib/help.js var require_help = __commonJS({ "node_modules/commander/lib/help.js"(exports2) { var { humanReadableArgName } = require_argument(); var Help2 = class { constructor() { this.helpWidth = void 0; this.sortSubcommands = false; this.sortOptions = false; this.showGlobalOptions = false; } /** * Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one. * * @param {Command} cmd * @returns {Command[]} */ visibleCommands(cmd) { const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden); if (cmd._hasImplicitHelpCommand()) { const [, helpName, helpArgs] = cmd._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/); const helpCommand2 = cmd.createCommand(helpName).helpOption(false); helpCommand2.description(cmd._helpCommandDescription); if (helpArgs) helpCommand2.arguments(helpArgs); visibleCommands.push(helpCommand2); } if (this.sortSubcommands) { visibleCommands.sort((a3, b3) => { return a3.name().localeCompare(b3.name()); }); } return visibleCommands; } /** * Compare options for sort. * * @param {Option} a * @param {Option} b * @returns number */ compareOptions(a3, b3) { const getSortKey = (option) => { return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, ""); }; return getSortKey(a3).localeCompare(getSortKey(b3)); } /** * Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one. * * @param {Command} cmd * @returns {Option[]} */ visibleOptions(cmd) { const visibleOptions = cmd.options.filter((option) => !option.hidden); const showShortHelpFlag = cmd._hasHelpOption && cmd._helpShortFlag && !cmd._findOption(cmd._helpShortFlag); const showLongHelpFlag = cmd._hasHelpOption && !cmd._findOption(cmd._helpLongFlag); if (showShortHelpFlag || showLongHelpFlag) { let helpOption; if (!showShortHelpFlag) { helpOption = cmd.createOption(cmd._helpLongFlag, cmd._helpDescription); } else if (!showLongHelpFlag) { helpOption = cmd.createOption(cmd._helpShortFlag, cmd._helpDescription); } else { helpOption = cmd.createOption(cmd._helpFlags, cmd._helpDescription); } visibleOptions.push(helpOption); } if (this.sortOptions) { visibleOptions.sort(this.compareOptions); } return visibleOptions; } /** * Get an array of the visible global options. (Not including help.) * * @param {Command} cmd * @returns {Option[]} */ visibleGlobalOptions(cmd) { if (!this.showGlobalOptions) return []; const globalOptions = []; for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) { const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden); globalOptions.push(...visibleOptions); } if (this.sortOptions) { globalOptions.sort(this.compareOptions); } return globalOptions; } /** * Get an array of the arguments if any have a description. * * @param {Command} cmd * @returns {Argument[]} */ visibleArguments(cmd) { if (cmd._argsDescription) { cmd.registeredArguments.forEach((argument) => { argument.description = argument.description || cmd._argsDescription[argument.name()] || ""; }); } if (cmd.registeredArguments.find((argument) => argument.description)) { return cmd.registeredArguments; } return []; } /** * Get the command term to show in the list of subcommands. * * @param {Command} cmd * @returns {string} */ subcommandTerm(cmd) { const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" "); return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option (args ? " " + args : ""); } /** * Get the option term to show in the list of options. * * @param {Option} option * @returns {string} */ optionTerm(option) { return option.flags; } /** * Get the argument term to show in the list of arguments. * * @param {Argument} argument * @returns {string} */ argumentTerm(argument) { return argument.name(); } /** * Get the longest command term length. * * @param {Command} cmd * @param {Help} helper * @returns {number} */ longestSubcommandTermLength(cmd, helper) { return helper.visibleCommands(cmd).reduce((max, command) => { return Math.max(max, helper.subcommandTerm(command).length); }, 0); } /** * Get the longest option term length. * * @param {Command} cmd * @param {Help} helper * @returns {number} */ longestOptionTermLength(cmd, helper) { return helper.visibleOptions(cmd).reduce((max, option) => { return Math.max(max, helper.optionTerm(option).length); }, 0); } /** * Get the longest global option term length. * * @param {Command} cmd * @param {Help} helper * @returns {number} */ longestGlobalOptionTermLength(cmd, helper) { return helper.visibleGlobalOptions(cmd).reduce((max, option) => { return Math.max(max, helper.optionTerm(option).length); }, 0); } /** * Get the longest argument term length. * * @param {Command} cmd * @param {Help} helper * @returns {number} */ longestArgumentTermLength(cmd, helper) { return helper.visibleArguments(cmd).reduce((max, argument) => { return Math.max(max, helper.argumentTerm(argument).length); }, 0); } /** * Get the command usage to be displayed at the top of the built-in help. * * @param {Command} cmd * @returns {string} */ commandUsage(cmd) { let cmdName = cmd._name; if (cmd._aliases[0]) { cmdName = cmdName + "|" + cmd._aliases[0]; } let ancestorCmdNames = ""; for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) { ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames; } return ancestorCmdNames + cmdName + " " + cmd.usage(); } /** * Get the description for the command. * * @param {Command} cmd * @returns {string} */ commandDescription(cmd) { return cmd.description(); } /** * Get the subcommand summary to show in the list of subcommands. * (Fallback to description for backwards compatibility.) * * @param {Command} cmd * @returns {string} */ subcommandDescription(cmd) { return cmd.summary() || cmd.description(); } /** * Get the option description to show in the list of options. * * @param {Option} option * @return {string} */ optionDescription(option) { const extraInfo = []; if (option.argChoices) { extraInfo.push( // use stringify to match the display of the default value `choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}` ); } if (option.defaultValue !== void 0) { const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean"; if (showDefault) { extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`); } } if (option.presetArg !== void 0 && option.optional) { extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`); } if (option.envVar !== void 0) { extraInfo.push(`env: ${option.envVar}`); } if (extraInfo.length > 0) { return `${option.description} (${extraInfo.join(", ")})`; } return option.description; } /** * Get the argument description to show in the list of arguments. * * @param {Argument} argument * @return {string} */ argumentDescription(argument) { const extraInfo = []; if (argument.argChoices) { extraInfo.push( // use stringify to match the display of the default value `choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}` ); } if (argument.defaultValue !== void 0) { extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`); } if (extraInfo.length > 0) { const extraDescripton = `(${extraInfo.join(", ")})`; if (argument.description) { return `${argument.description} ${extraDescripton}`; } return extraDescripton; } return argument.description; } /** * Generate the built-in help text. * * @param {Command} cmd * @param {Help} helper * @returns {string} */ formatHelp(cmd, helper) { const termWidth = helper.padWidth(cmd, helper); const helpWidth = helper.helpWidth || 80; const itemIndentWidth = 2; const itemSeparatorWidth = 2; function formatItem(term, description) { if (description) { const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`; return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth); } return term; } function formatList(textArray) { return textArray.join("\n").replace(/^/gm, " ".repeat(itemIndentWidth)); } let output = [`Usage: ${helper.commandUsage(cmd)}`, ""]; const commandDescription = helper.commandDescription(cmd); if (commandDescription.length > 0) { output = output.concat([helper.wrap(commandDescription, helpWidth, 0), ""]); } const argumentList = helper.visibleArguments(cmd).map((argument) => { return formatItem(helper.argumentTerm(argument), helper.argumentDescription(argument)); }); if (argumentList.length > 0) { output = output.concat(["Arguments:", formatList(argumentList), ""]); } const optionList = helper.visibleOptions(cmd).map((option) => { return formatItem(helper.optionTerm(option), helper.optionDescription(option)); }); if (optionList.length > 0) { output = output.concat(["Options:", formatList(optionList), ""]); } if (this.showGlobalOptions) { const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => { return formatItem(helper.optionTerm(option), helper.optionDescription(option)); }); if (globalOptionList.length > 0) { output = output.concat(["Global Options:", formatList(globalOptionList), ""]); } } const commandList = helper.visibleCommands(cmd).map((cmd2) => { return formatItem(helper.subcommandTerm(cmd2), helper.subcommandDescription(cmd2)); }); if (commandList.length > 0) { output = output.concat(["Commands:", formatList(commandList), ""]); } return output.join("\n"); } /** * Calculate the pad width from the maximum term length. * * @param {Command} cmd * @param {Help} helper * @returns {number} */ padWidth(cmd, helper) { return Math.max( helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper) ); } /** * Wrap the given string to width characters per line, with lines after the first indented. * Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted. * * @param {string} str * @param {number} width * @param {number} indent * @param {number} [minColumnWidth=40] * @return {string} * */ wrap(str, width, indent, minColumnWidth = 40) { const indents = " \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF"; const manualIndent = new RegExp(`[\\n][${indents}]+`); if (str.match(manualIndent)) return str; const columnWidth = width - indent; if (columnWidth < minColumnWidth) return str; const leadingStr = str.slice(0, indent); const columnText = str.slice(indent).replace("\r\n", "\n"); const indentString = " ".repeat(indent); const zeroWidthSpace = "\u200B"; const breaks = `\\s${zeroWidthSpace}`; const regex = new RegExp(` |.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`, "g"); const lines = columnText.match(regex) || []; return leadingStr + lines.map((line, i3) => { if (line === "\n") return ""; return (i3 > 0 ? indentString : "") + line.trimEnd(); }).join("\n"); } }; exports2.Help = Help2; } }); // node_modules/commander/lib/option.js var require_option = __commonJS({ "node_modules/commander/lib/option.js"(exports2) { var { InvalidArgumentError: InvalidArgumentError2 } = require_error(); var Option2 = class { /** * Initialize a new `Option` with the given `flags` and `description`. * * @param {string} flags * @param {string} [description] */ constructor(flags, description) { this.flags = flags; this.description = description || ""; this.required = flags.includes("<"); this.optional = flags.includes("["); this.variadic = /\w\.\.\.[>\]]$/.test(flags); this.mandatory = false; const optionFlags = splitOptionFlags(flags); this.short = optionFlags.shortFlag; this.long = optionFlags.longFlag; this.negate = false; if (this.long) { this.negate = this.long.startsWith("--no-"); } this.defaultValue = void 0; this.defaultValueDescription = void 0; this.presetArg = void 0; this.envVar = void 0; this.parseArg = void 0; this.hidden = false; this.argChoices = void 0; this.conflictsWith = []; this.implied = void 0; } /** * Set the default value, and optionally supply the description to be displayed in the help. * * @param {*} value * @param {string} [description] * @return {Option} */ default(value, description) { this.defaultValue = value; this.defaultValueDescription = description; return this; } /** * Preset to use when option used without option-argument, especially optional but also boolean and negated. * The custom processing (parseArg) is called. * * @example * new Option('--color').default('GREYSCALE').preset('RGB'); * new Option('--donate [amount]').preset('20').argParser(parseFloat); * * @param {*} arg * @return {Option} */ preset(arg) { this.presetArg = arg; return this; } /** * Add option name(s) that conflict with this option. * An error will be displayed if conflicting options are found during parsing. * * @example * new Option('--rgb').conflicts('cmyk'); * new Option('--js').conflicts(['ts', 'jsx']); * * @param {string | string[]} names * @return {Option} */ conflicts(names) { this.conflictsWith = this.conflictsWith.concat(names); return this; } /** * Specify implied option values for when this option is set and the implied options are not. * * The custom processing (parseArg) is not called on the implied values. * * @example * program * .addOption(new Option('--log', 'write logging information to file')) * .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' })); * * @param {Object} impliedOptionValues * @return {Option} */ implies(impliedOptionValues) { let newImplied = impliedOptionValues; if (typeof impliedOptionValues === "string") { newImplied = { [impliedOptionValues]: true }; } this.implied = Object.assign(this.implied || {}, newImplied); return this; } /** * Set environment variable to check for option value. * * An environment variable is only used if when processed the current option value is * undefined, or the source of the current value is 'default' or 'config' or 'env'. * * @param {string} name * @return {Option} */ env(name) { this.envVar = name; return this; } /** * Set the custom handler for processing CLI option arguments into option values. * * @param {Function} [fn] * @return {Option} */ argParser(fn) { this.parseArg = fn; return this; } /** * Whether the option is mandatory and must have a value after parsing. * * @param {boolean} [mandatory=true] * @return {Option} */ makeOptionMandatory(mandatory = true) { this.mandatory = !!mandatory; return this; } /** * Hide option in help. * * @param {boolean} [hide=true] * @return {Option} */ hideHelp(hide = true) { this.hidden = !!hide; return this; } /** * @api private */ _concatValue(value, previous) { if (previous === this.defaultValue || !Array.isArray(previous)) { return [value]; } return previous.concat(value); } /** * Only allow option value to be one of choices. * * @param {string[]} values * @return {Option} */ choices(values) { this.argChoices = values.slice(); this.parseArg = (arg, previous) => { if (!this.argChoices.includes(arg)) { throw new InvalidArgumentError2(`Allowed choices are ${this.argChoices.join(", ")}.`); } if (this.variadic) { return this._concatValue(arg, previous); } return arg; }; return this; } /** * Return option name. * * @return {string} */ name() { if (this.long) { return this.long.replace(/^--/, ""); } return this.short.replace(/^-/, ""); } /** * Return option name, in a camelcase format that can be used * as a object attribute key. * * @return {string} * @api private */ attributeName() { return camelcase(this.name().replace(/^no-/, "")); } /** * Check if `arg` matches the short or long flag. * * @param {string} arg * @return {boolean} * @api private */ is(arg) { ret