UNPKG

@mariozechner/pi-agent

Version:

General-purpose agent with tool calling and session persistence

158 lines 5.95 kB
import { homedir } from "os"; import { resolve } from "path"; export function parseArgs(defs, args) { const result = { _: [] }; const aliasMap = {}; // Build alias map and set defaults for (const [key, def] of Object.entries(defs)) { if (def.alias) { aliasMap[def.alias] = key; } if (def.default !== undefined) { result[key] = def.default; } else if (def.type === "flag" || def.type === "boolean") { result[key] = false; } } // Parse arguments for (let i = 0; i < args.length; i++) { const arg = args[i]; // Check if it's a flag if (arg.startsWith("--")) { const flagName = arg.slice(2); const key = aliasMap[flagName] || flagName; const def = defs[key]; if (!def) { // Unknown flag, add to positional args result._.push(arg); continue; } if (def.type === "flag") { // Simple on/off flag result[key] = true; } else if (i + 1 < args.length) { // Flag with value const value = args[++i]; let parsedValue; switch (def.type) { case "boolean": parsedValue = value === "true" || value === "1" || value === "yes"; break; case "int": parsedValue = parseInt(value, 10); if (Number.isNaN(parsedValue)) { throw new Error(`Invalid integer value for --${key}: ${value}`); } break; case "float": parsedValue = parseFloat(value); if (Number.isNaN(parsedValue)) { throw new Error(`Invalid float value for --${key}: ${value}`); } break; case "string": parsedValue = value; break; case "file": { // Resolve ~ to home directory and make absolute let path = value; if (path.startsWith("~")) { path = path.replace("~", homedir()); } parsedValue = resolve(path); break; } } // Validate against choices if specified if (def.choices) { const validValues = def.choices.map((c) => (typeof c === "string" ? c : c.value)); if (!validValues.includes(parsedValue)) { throw new Error(`Invalid value for --${key}: "${parsedValue}". Valid choices: ${validValues.join(", ")}`); } } result[key] = parsedValue; } else { throw new Error(`Flag --${key} requires a value`); } } else if (arg.startsWith("-") && arg.length === 2) { // Short flag like -h const flagChar = arg[1]; const key = aliasMap[flagChar] || flagChar; const def = defs[key]; if (!def) { result._.push(arg); continue; } if (def.type === "flag") { result[key] = true; } else { throw new Error(`Short flag -${flagChar} cannot have a value`); } } else { // Positional argument result._.push(arg); } } return result; } export function printHelp(defs, usage) { console.log(usage); console.log("\nOptions:"); for (const [key, def] of Object.entries(defs)) { let line = ` --${key}`; if (def.alias) { line += `, -${def.alias}`; } if (def.type !== "flag") { if (def.choices) { // Show choices instead of type const simpleChoices = def.choices.filter((c) => typeof c === "string"); if (simpleChoices.length === def.choices.length) { // All choices are simple strings line += ` <${simpleChoices.join("|")}>`; } else { // Has descriptions, just show the type const typeStr = def.type === "file" ? "path" : def.type; line += ` <${typeStr}>`; } } else { const typeStr = def.type === "file" ? "path" : def.type; line += ` <${typeStr}>`; } } if (def.description) { // Pad to align descriptions line = line.padEnd(30) + def.description; } if (def.default !== undefined && def.type !== "flag" && def.showDefault !== false) { if (typeof def.showDefault === "string") { line += ` (default: ${def.showDefault})`; } else { line += ` (default: ${def.default})`; } } console.log(line); // Print choices with descriptions if available if (def.choices) { const hasDescriptions = def.choices.some((c) => typeof c === "object" && c.description); if (hasDescriptions) { for (const choice of def.choices) { if (typeof choice === "object") { const choiceLine = ` ${choice.value}`.padEnd(30) + (choice.description || ""); console.log(choiceLine); } } } } } } //# sourceMappingURL=args.js.map