padrone 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +79 -0
- package/README.md +105 -284
- package/dist/{args-CVDbyyzG.mjs → args-D5PNDyNu.mjs} +41 -18
- package/dist/args-D5PNDyNu.mjs.map +1 -0
- package/dist/chunk-CjcI7cDX.mjs +15 -0
- package/dist/codegen/index.d.mts +28 -3
- package/dist/codegen/index.d.mts.map +1 -1
- package/dist/codegen/index.mjs +169 -19
- package/dist/codegen/index.mjs.map +1 -1
- package/dist/command-utils-B1D-HqCd.mjs +1117 -0
- package/dist/command-utils-B1D-HqCd.mjs.map +1 -0
- package/dist/completion.d.mts +1 -1
- package/dist/completion.d.mts.map +1 -1
- package/dist/completion.mjs +77 -29
- package/dist/completion.mjs.map +1 -1
- package/dist/docs/index.d.mts +22 -2
- package/dist/docs/index.d.mts.map +1 -1
- package/dist/docs/index.mjs +94 -7
- package/dist/docs/index.mjs.map +1 -1
- package/dist/errors-BiVrBgi6.mjs +114 -0
- package/dist/errors-BiVrBgi6.mjs.map +1 -0
- package/dist/{formatter-ClUK5hcQ.d.mts → formatter-DtHzbP22.d.mts} +34 -5
- package/dist/formatter-DtHzbP22.d.mts.map +1 -0
- package/dist/help-bbmu9-qd.mjs +735 -0
- package/dist/help-bbmu9-qd.mjs.map +1 -0
- package/dist/index.d.mts +32 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +493 -265
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-mLWIdUIu.mjs +379 -0
- package/dist/mcp-mLWIdUIu.mjs.map +1 -0
- package/dist/serve-B0u43DK7.mjs +404 -0
- package/dist/serve-B0u43DK7.mjs.map +1 -0
- package/dist/stream-BcC146Ud.mjs +56 -0
- package/dist/stream-BcC146Ud.mjs.map +1 -0
- package/dist/test.d.mts +1 -1
- package/dist/test.mjs +4 -15
- package/dist/test.mjs.map +1 -1
- package/dist/{types-DjIdJN5G.d.mts → types-Ch8Mk6Qb.d.mts} +310 -62
- package/dist/types-Ch8Mk6Qb.d.mts.map +1 -0
- package/dist/{update-check-EbNDkzyV.mjs → update-check-CFX1FV3v.mjs} +2 -2
- package/dist/{update-check-EbNDkzyV.mjs.map → update-check-CFX1FV3v.mjs.map} +1 -1
- package/dist/zod.d.mts +32 -0
- package/dist/zod.d.mts.map +1 -0
- package/dist/zod.mjs +50 -0
- package/dist/zod.mjs.map +1 -0
- package/package.json +10 -2
- package/src/args.ts +68 -40
- package/src/cli/docs.ts +1 -7
- package/src/cli/doctor.ts +195 -10
- package/src/cli/index.ts +1 -1
- package/src/cli/init.ts +2 -3
- package/src/cli/link.ts +2 -2
- package/src/codegen/discovery.ts +80 -28
- package/src/codegen/index.ts +2 -1
- package/src/codegen/parsers/bash.ts +179 -0
- package/src/codegen/schema-to-code.ts +2 -1
- package/src/colorizer.ts +126 -13
- package/src/command-utils.ts +380 -30
- package/src/completion.ts +120 -47
- package/src/create.ts +480 -128
- package/src/docs/index.ts +122 -8
- package/src/formatter.ts +171 -125
- package/src/help.ts +45 -12
- package/src/index.ts +29 -1
- package/src/interactive.ts +45 -4
- package/src/mcp.ts +390 -0
- package/src/repl-loop.ts +16 -3
- package/src/runtime.ts +195 -2
- package/src/serve.ts +442 -0
- package/src/stream.ts +75 -0
- package/src/test.ts +7 -16
- package/src/type-utils.ts +28 -4
- package/src/types.ts +212 -30
- package/src/wrap.ts +23 -25
- package/src/zod.ts +50 -0
- package/dist/args-CVDbyyzG.mjs.map +0 -1
- package/dist/chunk-y_GBKt04.mjs +0 -5
- package/dist/formatter-ClUK5hcQ.d.mts.map +0 -1
- package/dist/help-CcBe91bV.mjs +0 -1254
- package/dist/help-CcBe91bV.mjs.map +0 -1
- package/dist/types-DjIdJN5G.d.mts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-utils-B1D-HqCd.mjs","names":[],"sources":["../src/utils.ts","../src/runtime.ts","../src/command-utils.ts"],"sourcesContent":["import type { AnyPadroneCommand } from './types.ts';\n\nexport function getRootCommand(cmd: AnyPadroneCommand): AnyPadroneCommand {\n let current = cmd;\n while (current.parent) current = current.parent;\n return current;\n}\n\n/**\n * Attempts to get the version from various sources:\n * 1. Explicit version set on the command\n * 2. npm_package_version environment variable (set by npm/yarn/pnpm when running scripts)\n * 3. package.json in current or parent directories\n * @param explicitVersion - Version explicitly set via .version()\n * @returns The version string or '0.0.0' if not found\n */\nexport function getVersion(explicitVersion?: string): string {\n // 1. Use explicit version if provided\n if (explicitVersion) return explicitVersion;\n\n // 2. Check npm_package_version env var (set by npm/yarn/pnpm during script execution)\n if (typeof process !== 'undefined' && process.env?.npm_package_version) {\n return process.env.npm_package_version;\n }\n\n // 3. Try to read from package.json\n if (typeof process !== 'undefined') {\n try {\n const fs = require('node:fs');\n const path = require('node:path');\n let dir = process.cwd();\n\n // Walk up the directory tree looking for package.json\n for (let i = 0; i < 10; i++) {\n const pkgPath = path.join(dir, 'package.json');\n if (fs.existsSync(pkgPath)) {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\n if (pkg.version) return pkg.version;\n }\n const parentDir = path.dirname(dir);\n if (parentDir === dir) break; // Reached root\n dir = parentDir;\n }\n } catch {\n // Ignore errors (e.g., fs not available in browser)\n }\n }\n\n return '0.0.0';\n}\n\n/**\n * Loads and parses a config file from the given path.\n * Supports JSON, JSONC (JSON with comments), and attempts to parse other formats.\n * @param configPath - Path to the config file\n * @returns Parsed config data or undefined if loading fails\n */\nexport function loadConfigFile(configPath: string): Record<string, unknown> | undefined {\n if (typeof process === 'undefined') return undefined;\n\n try {\n const fs = require('node:fs');\n const path = require('node:path');\n\n // Resolve to absolute path\n const absolutePath = path.isAbsolute(configPath) ? configPath : path.resolve(process.cwd(), configPath);\n\n if (!fs.existsSync(absolutePath)) {\n console.error(`Config file not found: ${absolutePath}`);\n return undefined;\n }\n\n const getContent = () => fs.readFileSync(absolutePath, 'utf-8');\n const ext = path.extname(absolutePath).toLowerCase();\n\n if (ext === '.yaml' || ext === '.yml') {\n return Bun.YAML.parse(getContent()) as any;\n }\n\n if (ext === '.toml') {\n return Bun.TOML.parse(getContent()) as any;\n }\n\n if (ext === '.json') {\n if (Bun.JSONC) return Bun.JSONC.parse(getContent()) as any;\n try {\n return JSON.parse(getContent());\n } catch {\n return Bun.JSONC.parse(getContent()) as any;\n }\n }\n\n if (ext === '.jsonc') {\n return Bun.JSONC.parse(getContent()) as any;\n }\n\n if (ext === '.js' || ext === '.cjs' || ext === '.mjs' || ext === '.ts' || ext === '.cts' || ext === '.mts') {\n // For JS files, require them\n return require(absolutePath);\n }\n\n // For unknown extensions, try to parse as JSON\n try {\n return JSON.parse(getContent());\n } catch {\n console.error(`Unable to parse config file: ${absolutePath}`);\n return undefined;\n }\n } catch (error) {\n console.error(`Error loading config file: ${error}`);\n return undefined;\n }\n}\n\n/**\n * Searches for a config file from a list of possible file names.\n * Searches in the current working directory.\n * @param configFiles - Array of possible config file names to search for\n * @returns The path to the first found config file, or undefined if none found\n */\nexport function findConfigFile(configFiles: string[]): string | undefined {\n if (typeof process === 'undefined' || !configFiles?.length) return undefined;\n\n try {\n const fs = require('node:fs');\n const path = require('node:path');\n const cwd = process.cwd();\n\n for (const configFile of configFiles) {\n const configPath = path.isAbsolute(configFile) ? configFile : path.resolve(cwd, configFile);\n if (fs.existsSync(configPath)) {\n return configPath;\n }\n }\n } catch {\n // Ignore errors (e.g., fs not available in browser)\n }\n\n return undefined;\n}\n","import type { ColorConfig, ColorTheme } from './colorizer.ts';\nimport type { HelpFormat } from './formatter.ts';\nimport { findConfigFile, loadConfigFile } from './utils.ts';\n\n/**\n * A progress indicator instance (spinner, progress bar, etc).\n * Created by the runtime's `progress` factory and used to show loading state during command execution.\n */\nexport type PadroneProgressIndicator = {\n /** Update the displayed message. */\n update: (message: string) => void;\n /** Mark as succeeded and stop. Pass `null` to stop without rendering a final message. */\n succeed: (message?: string | null, options?: { indicator?: string }) => void;\n /** Mark as failed and stop. Pass `null` to stop without rendering a final message. */\n fail: (message?: string | null, options?: { indicator?: string }) => void;\n /** Stop without success/fail status. */\n stop: () => void;\n /** Temporarily hide the indicator so other output can be written cleanly. */\n pause: () => void;\n /** Redraw the indicator after a `pause()`. */\n resume: () => void;\n};\n\n/** Built-in spinner presets. */\nexport type PadroneSpinnerPreset = 'dots' | 'line' | 'arc' | 'bounce';\n\n/**\n * Spinner configuration for progress indicators.\n * - A preset name (e.g., `'dots'`) to use built-in frames.\n * - An object with custom `frames` and/or `interval`.\n * - `false` to disable the spinner animation (static text only).\n */\nexport type PadroneSpinnerConfig = PadroneSpinnerPreset | { frames?: string[]; interval?: number } | false;\n\n/**\n * Options passed to the runtime's `progress` factory.\n */\nexport type PadroneProgressOptions = {\n spinner?: PadroneSpinnerConfig;\n /** Character/string shown before the success message. Defaults to `'✔'`. */\n successIndicator?: string;\n /** Character/string shown before the error message. Defaults to `'✖'`. */\n errorIndicator?: string;\n};\n\n/**\n * Controls interactive prompting capability and default behavior at the runtime level.\n * - `'supported'` — capable; caller decides.\n * - `'unsupported'` — hard veto; nothing can override.\n * - `'forced'` — capable and forces prompts by default.\n * - `'disabled'` — capable but suppresses prompts by default.\n */\nexport type InteractiveMode = 'supported' | 'unsupported' | 'forced' | 'disabled';\n\n/**\n * Configuration passed to the runtime's `prompt` function for interactive field prompting.\n * The prompt type and choices are auto-detected from the field's JSON schema.\n */\nexport type InteractivePromptConfig = {\n /** The field name being prompted. */\n name: string;\n /** Human-readable message/label for the prompt, derived from the field's description or name. */\n message: string;\n /** The prompt type, auto-detected from the JSON schema. */\n type: 'input' | 'confirm' | 'select' | 'multiselect' | 'password';\n /** Available choices for select/multiselect prompts. */\n choices?: { label: string; value: unknown }[];\n /** Default value from the schema. */\n default?: unknown;\n};\n\n/**\n * Defines the execution context for a Padrone program.\n * Abstracts all environment-dependent I/O so the CLI framework\n * can run outside of a terminal (e.g., web UIs, chat interfaces, testing).\n *\n * All fields are optional — unspecified fields fall back to the Node.js/Bun defaults.\n */\nexport type PadroneRuntime = {\n /** Write normal output (replaces console.log). Receives the raw value — runtime handles formatting. */\n output?: (...args: unknown[]) => void;\n /** Write error output (replaces console.error). */\n error?: (text: string) => void;\n /** Return the raw CLI arguments (replaces process.argv.slice(2)). */\n argv?: () => string[];\n /** Return environment variables (replaces process.env). */\n env?: () => Record<string, string | undefined>;\n /** Default help output format. */\n format?: HelpFormat | 'auto';\n /** Color theme for ANSI/console help output. A theme name or partial color config. */\n theme?: ColorTheme | ColorConfig;\n /** Load and parse a config file by path. Return undefined if not found or unparsable. */\n loadConfigFile?: (path: string) => Record<string, unknown> | undefined;\n /** Find the first existing file from a list of candidate names. */\n findFile?: (names: string[]) => string | undefined;\n /**\n * Standard input abstraction. Provides methods to read piped data from stdin.\n * When not provided, defaults to reading from `process.stdin`.\n *\n * Used by commands that declare a `stdin` field in their arguments meta.\n * The framework reads stdin automatically during the validate phase and\n * injects the data into the specified argument field.\n */\n stdin?: {\n /** Whether stdin is a TTY (interactive terminal) vs a pipe/file. */\n isTTY?: boolean;\n /** Read all of stdin as a string. */\n text: () => Promise<string>;\n /** Async iterable of lines for streaming. */\n lines: () => AsyncIterable<string>;\n };\n /**\n * Controls interactive prompting capability and default behavior.\n * - `'supported'` — runtime can handle prompts; caller (flag/pref) decides whether to prompt. This is the default when `prompt` is provided.\n * - `'unsupported'` — runtime cannot handle prompts; hard veto that nothing can override.\n * - `'forced'` — runtime supports prompts and forces them by default (prompts even for provided values).\n * - `'disabled'` — runtime supports prompts but suppresses them by default.\n *\n * `'unsupported'` is the only immutable state. For the others, the `--interactive`/`-i` flag\n * and `cli()` preferences can override the default behavior.\n */\n interactive?: InteractiveMode;\n /**\n * Prompt the user for input. Called during `cli()` for fields marked as interactive.\n * When `interactive` is `true` and this is not provided, defaults to an Enquirer-based terminal prompt.\n */\n prompt?: (config: InteractivePromptConfig) => Promise<unknown>;\n /**\n * Create a progress indicator (spinner, progress bar, etc).\n * Used by commands that set `progress` in their config, or manually via `ctx.progress()` in actions.\n * When not provided, auto-progress is silently skipped and `ctx.progress()` returns a no-op indicator.\n */\n progress?: (message: string, options?: PadroneProgressOptions) => PadroneProgressIndicator;\n /**\n * Read a line of input from the user. Used by `repl()` for custom runtimes\n * (web UIs, chat interfaces, testing).\n * Returns the input string, `null` on EOF (e.g. Ctrl+D, closed connection),\n * or `REPL_SIGINT` when the user presses Ctrl+C.\n *\n * When not provided, `repl()` uses a built-in Node.js readline session\n * with command history (up/down arrows) and tab completion.\n */\n readLine?: (prompt: string) => Promise<string | typeof REPL_SIGINT | null>;\n};\n\n/**\n * Internal resolved runtime where all fields are guaranteed to be present.\n * The `prompt`, `interactive`, and `readLine` fields remain optional since not all runtimes provide them.\n */\nexport type ResolvedPadroneRuntime = Required<\n Omit<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin' | 'progress' | 'theme'>\n> &\n Pick<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin' | 'progress' | 'theme'>;\n\n/**\n * Default terminal prompt implementation powered by Enquirer.\n * Lazily imported to avoid loading Enquirer when not needed.\n */\nasync function defaultTerminalPrompt(config: InteractivePromptConfig): Promise<unknown> {\n const Enquirer = (await import('enquirer')).default;\n\n const question: Record<string, unknown> = {\n type: config.type,\n name: config.name,\n message: config.message,\n };\n\n if (config.default !== undefined) {\n question.initial = config.default;\n }\n\n if (config.choices) {\n question.choices = config.choices.map((c) => ({\n name: String(c.value),\n message: c.label,\n }));\n }\n\n const response = (await Enquirer.prompt(question as any)) as Record<string, unknown>;\n return response[config.name];\n}\n\n/**\n * Internal session config for the REPL's persistent readline interface.\n */\nexport type ReplSessionConfig = {\n completer?: (line: string) => [string[], string];\n history?: string[];\n};\n\n/**\n * Creates a persistent Node.js readline session for the REPL.\n * Enables up/down arrow history navigation and tab completion.\n * Used internally by `repl()` when no custom `readLine` is provided.\n */\n/**\n * Sentinel value returned by the terminal REPL session when Ctrl+C is pressed.\n * Distinguished from empty string (user pressed enter) and null (EOF/Ctrl+D).\n */\nexport const REPL_SIGINT = Symbol('REPL_SIGINT');\n\nexport function createTerminalReplSession(config: ReplSessionConfig) {\n // History accumulates across per-call interfaces, giving us\n // up/down arrow navigation without a persistent stdin listener\n // that would conflict with Enquirer or other stdin consumers.\n let history: string[] = config.history ? [...config.history] : [];\n let currentCompleter = config.completer;\n\n return {\n /** Update the tab completer (e.g. when REPL scope changes). Takes effect on the next question. */\n set completer(fn: ((line: string) => [string[], string]) | undefined) {\n currentCompleter = fn;\n },\n async question(prompt: string): Promise<string | typeof REPL_SIGINT | null> {\n const { createInterface } = await import('node:readline');\n const opts: Record<string, unknown> = {\n input: process.stdin,\n output: process.stdout,\n terminal: true,\n history: [...history],\n historySize: Math.max(history.length, 1000),\n };\n if (currentCompleter) {\n opts.completer = currentCompleter;\n }\n const rl = createInterface(opts as any);\n\n return new Promise((resolve) => {\n let resolved = false;\n const settle = (value: string | typeof REPL_SIGINT | null) => {\n if (resolved) return;\n resolved = true;\n rl.close();\n resolve(value);\n };\n\n rl.question(prompt, (answer) => {\n // Grab updated history (includes the new entry) before closing.\n if (Array.isArray((rl as any).history)) history = [...(rl as any).history];\n settle(answer);\n });\n // Ctrl+C: cancel current line, print newline, resolve SIGINT sentinel.\n rl.once('SIGINT', () => {\n process.stdout.write('\\n');\n settle(REPL_SIGINT);\n });\n // EOF (Ctrl+D) fires close without the question callback.\n rl.once('close', () => {\n // Write newline so zsh doesn't show '%' (partial-line indicator).\n process.stdout.write('\\n');\n settle(null);\n });\n });\n },\n close() {\n // No persistent interface to clean up.\n },\n };\n}\n\n/**\n * Auto-detect interactive mode when not explicitly set.\n * Returns 'disabled' in CI environments or non-TTY contexts, 'supported' otherwise.\n */\nfunction detectInteractiveMode(): InteractiveMode {\n if (typeof process === 'undefined') return 'disabled';\n if (process.env.CI || process.env.CONTINUOUS_INTEGRATION) return 'disabled';\n if (!process.stdout?.isTTY) return 'disabled';\n return 'supported';\n}\n\n/**\n * Creates the default Node.js/Bun runtime.\n */\n/**\n * Creates a default stdin reader from `process.stdin`.\n * Only created when a command actually declares a `stdin` meta field.\n */\nfunction createDefaultStdin(): NonNullable<PadroneRuntime['stdin']> {\n return {\n get isTTY() {\n // process.stdin.isTTY is `true` when interactive terminal, `undefined` when piped/redirected.\n // Node.js never sets it to `false` — it's either `true` or absent.\n if (typeof process === 'undefined') return true;\n return process.stdin?.isTTY === true;\n },\n async text() {\n if (typeof process === 'undefined') return '';\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);\n }\n return Buffer.concat(chunks).toString('utf-8');\n },\n async *lines() {\n if (typeof process === 'undefined') return;\n const { createInterface } = await import('node:readline');\n const rl = createInterface({ input: process.stdin });\n try {\n for await (const line of rl) {\n yield line;\n }\n } finally {\n rl.close();\n }\n },\n };\n}\n\nconst spinnerPresets: Record<PadroneSpinnerPreset, string[]> = {\n dots: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],\n line: ['-', '\\\\', '|', '/'],\n arc: ['◜', '◠', '◝', '◞', '◡', '◟'],\n bounce: ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'],\n};\n\nfunction resolveSpinnerConfig(config?: PadroneSpinnerConfig): { frames: string[]; interval: number; disabled: boolean } {\n if (config === false) return { frames: [], interval: 80, disabled: true };\n if (typeof config === 'string') return { frames: spinnerPresets[config], interval: 80, disabled: false };\n if (typeof config === 'object') {\n return {\n frames: config.frames ?? spinnerPresets.dots,\n interval: config.interval ?? 80,\n disabled: false,\n };\n }\n return { frames: spinnerPresets.dots, interval: 80, disabled: false };\n}\n\n/**\n * Creates a built-in terminal spinner. Returns a no-op indicator in non-TTY/CI environments.\n */\nfunction createTerminalSpinner(message: string, options?: PadroneProgressOptions): PadroneProgressIndicator {\n const { frames, interval, disabled: spinnerDisabled } = resolveSpinnerConfig(options?.spinner);\n const successIcon = options?.successIndicator ?? '✔';\n const errorIcon = options?.errorIndicator ?? '✖';\n\n const formatFinal = (icon: string, msg: string) => (icon ? `${icon} ${msg}\\n` : `${msg}\\n`);\n\n if (typeof process === 'undefined' || !process.stderr?.isTTY) {\n // Non-TTY: just log start/end, no animation\n return {\n update() {},\n succeed(msg, opts) {\n if (msg === null) return;\n const icon = opts?.indicator ?? successIcon;\n if (msg || message) process?.stderr?.write?.(formatFinal(icon, msg || message));\n },\n fail(msg, opts) {\n if (msg === null) return;\n const icon = opts?.indicator ?? errorIcon;\n if (msg || message) process?.stderr?.write?.(formatFinal(icon, msg || message));\n },\n stop() {},\n pause() {},\n resume() {},\n };\n }\n\n // If spinner is disabled and there's no message, nothing to render\n if (spinnerDisabled && !message) {\n return { update() {}, succeed() {}, fail() {}, stop() {}, pause() {}, resume() {} };\n }\n\n let frame = 0;\n let text = message;\n let stopped = false;\n let paused = false;\n\n const writeStderr = process.stderr.write.bind(process.stderr);\n const writeStdout = process.stdout.write.bind(process.stdout);\n const clearLine = () => writeStderr('\\x1b[2K\\r');\n\n const render = () => {\n if (paused || stopped) return;\n if (spinnerDisabled) {\n // Static text only, no spinner frames\n if (text) writeStderr(`\\x1b[2K\\r${text}`);\n } else {\n const prefix = frames[frame] ?? '';\n writeStderr(`\\x1b[2K\\r${text ? `${prefix} ${text}` : prefix}`);\n }\n };\n\n const timer = spinnerDisabled\n ? undefined\n : setInterval(() => {\n frame = (frame + 1) % frames.length;\n render();\n }, interval);\n\n render();\n\n const clear = () => {\n if (stopped) return;\n stopped = true;\n paused = false;\n if (timer) clearInterval(timer);\n clearLine();\n };\n\n return {\n update(msg) {\n if (stopped) return;\n text = msg;\n render();\n },\n succeed(msg, opts) {\n clear();\n if (msg === null) return;\n const finalMsg = msg ?? text;\n const icon = opts?.indicator ?? successIcon;\n if (finalMsg) writeStderr(formatFinal(icon, finalMsg));\n },\n fail(msg, opts) {\n clear();\n if (msg === null) return;\n const finalMsg = msg ?? text;\n const icon = opts?.indicator ?? errorIcon;\n if (finalMsg) writeStderr(formatFinal(icon, finalMsg));\n },\n stop() {\n clear();\n },\n pause() {\n if (stopped || paused) return;\n paused = true;\n clearLine();\n writeStdout('\\x1b[2K\\r');\n },\n resume() {\n if (stopped || !paused) return;\n paused = false;\n render();\n },\n };\n}\n\nexport function createDefaultRuntime(): ResolvedPadroneRuntime {\n return {\n output: (...args) => console.log(...args),\n error: (text) => console.error(text),\n argv: () => (typeof process !== 'undefined' ? process.argv.slice(2) : []),\n env: () => (typeof process !== 'undefined' ? (process.env as Record<string, string | undefined>) : {}),\n format: 'auto',\n loadConfigFile,\n findFile: findConfigFile,\n prompt: defaultTerminalPrompt,\n interactive: detectInteractiveMode(),\n progress: createTerminalSpinner,\n };\n}\n\n/**\n * Merges a partial runtime with the default runtime.\n */\n/**\n * Returns the stdin abstraction: custom runtime stdin > default process.stdin.\n * Returns `undefined` when no custom stdin is provided and process.stdin is not piped.\n */\nexport function resolveStdin(partial?: PadroneRuntime): NonNullable<PadroneRuntime['stdin']> | undefined {\n if (partial?.stdin) return partial.stdin;\n const defaultStdin = createDefaultStdin();\n // Only use default stdin if it's actually piped (isTTY === false).\n // This avoids accidentally blocking on stdin in tests/CI.\n if (defaultStdin.isTTY) return undefined;\n return defaultStdin;\n}\n\n/**\n * Like `resolveStdin`, but always returns a stdin source even when it's a TTY.\n * Used for async streams which support interactive (non-piped) input.\n */\nexport function resolveStdinAlways(partial?: PadroneRuntime): NonNullable<PadroneRuntime['stdin']> {\n if (partial?.stdin) return partial.stdin;\n return createDefaultStdin();\n}\n\nexport function resolveRuntime(partial?: PadroneRuntime): ResolvedPadroneRuntime {\n const defaults = createDefaultRuntime();\n if (!partial) return defaults;\n return {\n output: partial.output ?? defaults.output,\n error: partial.error ?? defaults.error,\n argv: partial.argv ?? defaults.argv,\n env: partial.env ?? defaults.env,\n format: partial.format ?? defaults.format,\n loadConfigFile: partial.loadConfigFile ?? defaults.loadConfigFile,\n findFile: partial.findFile ?? defaults.findFile,\n interactive: partial.interactive ?? defaults.interactive,\n prompt: partial.prompt ?? defaults.prompt,\n readLine: partial.readLine ?? defaults.readLine,\n progress: partial.progress ?? defaults.progress,\n stdin: partial.stdin,\n theme: partial.theme,\n };\n}\n","import { extractSchemaMetadata, JSON_SCHEMA_OPTS } from './args.ts';\nimport { type PadroneProgressIndicator, type ResolvedPadroneRuntime, resolveRuntime } from './runtime.ts';\nimport type { Thenable } from './type-utils.ts';\nimport type {\n AnyPadroneCommand,\n PadronePlugin,\n PadroneSchema,\n PluginErrorContext,\n PluginErrorResult,\n PluginShutdownContext,\n PluginStartContext,\n} from './types.ts';\n\n// ---------------------------------------------------------------------------\n// Lazy command resolution\n// ---------------------------------------------------------------------------\n\nexport const lazyResolver = Symbol('lazyResolver');\n\n/** Resolves a lazy command in place by calling its stored resolver. No-op if already resolved. */\nexport function resolveCommand(cmd: AnyPadroneCommand): AnyPadroneCommand {\n const resolver = (cmd as any)[lazyResolver];\n if (resolver) {\n delete (cmd as any)[lazyResolver];\n resolver(cmd);\n }\n return cmd;\n}\n\n/** Recursively resolves a command and all its descendants. */\nexport function resolveAllCommands(cmd: AnyPadroneCommand): void {\n resolveCommand(cmd);\n if (cmd.commands) {\n for (const sub of cmd.commands) resolveAllCommands(sub);\n }\n}\n\n/** Checks whether a value is a Padrone program/builder. */\nexport function isPadroneProgram(value: unknown): value is object {\n return !!value && typeof value === 'object' && commandSymbol in value;\n}\n\n/** Extracts the underlying command from a program/builder and resolves the full command tree. */\nexport function getCommand(program: object): AnyPadroneCommand {\n const cmd = commandSymbol in program ? ((program as any)[commandSymbol] as AnyPadroneCommand) : (program as AnyPadroneCommand);\n resolveAllCommands(cmd);\n return cmd;\n}\n\n/**\n * Brands a schema as async, signaling that its `validate()` may return a Promise.\n * When an async-branded schema is passed to `.arguments()`, `.configFile()`, or `.env()`,\n * the command's `parse()` and `cli()` will return Promises.\n *\n * @example\n * ```ts\n * const schema = asyncSchema(z.object({\n * name: z.string(),\n * }).check(async (data) => {\n * // async validation logic\n * }));\n *\n * const program = createPadrone('app')\n * .command('greet', (c) => c.arguments(schema).action((args) => args.name));\n *\n * // parse() now returns Promise<PadroneParseResult>\n * const result = await program.parse('greet --name world');\n * ```\n */\nexport function asyncSchema<T extends PadroneSchema>(schema: T): T & { '~async': true } {\n return Object.assign(schema, { '~async': true as const });\n}\n\nexport const commandSymbol = Symbol('padrone_command');\n\nexport const noop = <TRes>() => undefined as TRes;\n\n/** Config keys that are merged when overriding a command. */\nexport const configKeys = [\n 'title',\n 'description',\n 'version',\n 'deprecated',\n 'hidden',\n 'mutation',\n 'needsApproval',\n 'autoOutput',\n 'updateCheck',\n] as const;\n\n/**\n * Merges an existing command with an override.\n * - Config fields are shallow-merged (new overrides old).\n * - Action, arguments, meta, config schema, env schema are taken from the override if set.\n * - Subcommands are recursively merged by name.\n */\nexport function mergeCommands(existing: AnyPadroneCommand, override: AnyPadroneCommand): AnyPadroneCommand {\n resolveCommand(existing);\n resolveCommand(override);\n const merged: AnyPadroneCommand = { ...existing };\n\n // Merge config fields\n for (const key of configKeys) {\n if (override[key] !== undefined) (merged as any)[key] = override[key];\n }\n\n // Override fields: take from override if explicitly set (not inherited from existing via spread)\n if (override.action !== existing.action) merged.action = override.action;\n if (override.argsSchema !== existing.argsSchema) merged.argsSchema = override.argsSchema;\n if (override.meta !== existing.meta) merged.meta = override.meta;\n if (override.configSchema !== existing.configSchema) merged.configSchema = override.configSchema;\n if (override.envSchema !== existing.envSchema) merged.envSchema = override.envSchema;\n if (override.configFiles !== existing.configFiles) merged.configFiles = override.configFiles;\n if (override.isAsync !== existing.isAsync) merged.isAsync = override.isAsync || existing.isAsync;\n if (override.runtime !== existing.runtime) merged.runtime = override.runtime;\n if (override.plugins !== existing.plugins) merged.plugins = override.plugins;\n if (override.aliases !== existing.aliases) merged.aliases = override.aliases;\n if (override.progress !== existing.progress) merged.progress = override.progress;\n\n // Recursively merge subcommands by name\n if (override.commands) {\n const baseCommands = [...(existing.commands || [])];\n for (const overrideChild of override.commands) {\n const existingIndex = baseCommands.findIndex((c) => c.name === overrideChild.name);\n if (existingIndex >= 0) {\n baseCommands[existingIndex] = mergeCommands(baseCommands[existingIndex]!, overrideChild);\n } else {\n baseCommands.push(overrideChild);\n }\n }\n merged.commands = baseCommands;\n }\n\n return merged;\n}\n\n/**\n * Maps over a value that may or may not be a Promise.\n * If the value is a Promise, chains with `.then()`. Otherwise, calls the function synchronously.\n * This preserves sync behavior for sync schemas and async behavior for async schemas.\n */\nexport function thenMaybe<T, U>(value: T | Promise<T>, fn: (v: T) => U | Promise<U>): U | Promise<U> {\n if (value instanceof Promise) return value.then(fn);\n return fn(value);\n}\n\n/**\n * Makes a sync result object thenable by adding `.then()`, `.catch()`, and `.finally()` methods.\n * If the value is already a Promise, returns it as-is.\n * This allows users to write `await program.cli()` or `program.cli().then(...)` regardless of sync/async.\n *\n * The `.then()` resolves with a plain copy (without thenable methods) to avoid infinite\n * recursive unwrapping by the Promise resolution algorithm.\n */\nexport function makeThenable<T>(value: T | Promise<T>): Thenable<T> {\n if (value instanceof Promise) return value as any;\n if (value !== null && typeof value === 'object' && !('then' in value)) {\n const toPlain = () => {\n const plain = { ...value } as any;\n delete plain.then;\n delete plain.catch;\n delete plain.finally;\n return plain as T;\n };\n // biome-ignore lint/suspicious/noThenProperty: intentional thenable shim for sync results\n (value as any).then = (onfulfilled?: (v: T) => any, onrejected?: (reason: any) => any) => {\n try {\n const result = onfulfilled ? onfulfilled(toPlain()) : toPlain();\n return Promise.resolve(result);\n } catch (err) {\n if (onrejected) return Promise.resolve(onrejected(err));\n return Promise.reject(err);\n }\n };\n (value as any).catch = (onrejected?: (reason: any) => any) => (value as any).then(undefined, onrejected);\n (value as any).finally = (onfinally?: () => void) =>\n (value as any).then(\n (v: any) => {\n onfinally?.();\n return v;\n },\n (err: any) => {\n onfinally?.();\n throw err;\n },\n );\n }\n return value as any;\n}\n\n/**\n * Wraps a Promise to include a `drain()` method at the top level.\n * This allows `await promise.drain()` without first awaiting the promise.\n * Since cli/eval never reject, this just delegates to the resolved result's `drain()`.\n */\nexport function withPromiseDrain<T extends Promise<any>>(promise: T): T & { drain: () => Promise<any> } {\n (promise as any).drain = async () => {\n const resolved = await promise;\n return resolved.drain();\n };\n return promise as any;\n}\n\nexport function isIterator(value: unknown): value is Iterator<unknown> {\n return typeof value === 'object' && value !== null && Symbol.iterator in value && typeof (value as any)[Symbol.iterator] === 'function';\n}\n\nexport function isAsyncIterator(value: unknown): value is AsyncIterator<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n Symbol.asyncIterator in value &&\n typeof (value as any)[Symbol.asyncIterator] === 'function'\n );\n}\n\n/**\n * Writes a command's return value to output, handling promises, iterators, and async iterators.\n * Values are passed directly to the output function without stringification —\n * runtimes like Node/Bun already format objects via console.log.\n * Returns void or a Promise depending on whether async consumption is needed.\n */\nexport function outputValue(value: unknown, output: (...args: unknown[]) => void): void | Promise<void> {\n if (value == null) return;\n\n // Async iterator — consume and output each yielded value\n if (isAsyncIterator(value)) {\n return (async () => {\n const iter = (value as any)[Symbol.asyncIterator]();\n while (true) {\n const { done, value: item } = await iter.next();\n if (done) break;\n if (item != null) output(item);\n }\n })();\n }\n\n // Sync iterator (but not a plain string/array which also have Symbol.iterator)\n if (typeof value !== 'string' && !Array.isArray(value) && isIterator(value)) {\n const iter = (value as any)[Symbol.iterator]();\n while (true) {\n const { done, value: item } = iter.next();\n if (done) break;\n if (item != null) output(item);\n }\n return;\n }\n\n // Promise — await then output\n if (value instanceof Promise) {\n return value.then((resolved) => outputValue(resolved, output));\n }\n\n // Pass value directly — runtime handles formatting\n output(value);\n}\n\n/**\n * Resolves a result value by unwrapping Promises and collecting iterables into arrays.\n * This is the runtime counterpart of the `Drained<T>` type.\n */\nexport async function drainValue(value: unknown): Promise<unknown> {\n // Unwrap promises first\n if (value instanceof Promise) {\n return drainValue(await value);\n }\n\n // Async iterator — collect into array\n if (isAsyncIterator(value)) {\n const items: unknown[] = [];\n const iter = (value as any)[Symbol.asyncIterator]();\n while (true) {\n const { done, value: item } = await iter.next();\n if (done) break;\n items.push(item);\n }\n return items;\n }\n\n // Sync iterator (but not string/array)\n if (typeof value !== 'string' && !Array.isArray(value) && isIterator(value)) {\n const items: unknown[] = [];\n const iter = (value as any)[Symbol.iterator]();\n while (true) {\n const { done, value: item } = iter.next();\n if (done) break;\n items.push(item);\n }\n return items;\n }\n\n return value;\n}\n\n/**\n * Attaches a `drain()` method to a command result object.\n * If the result has an `error` field, `drain()` returns `{ error }`.\n * Otherwise, resolves the result (unwrapping Promises, collecting iterables), catches errors,\n * and returns a discriminated union `{ value } | { error }` that never throws.\n */\nexport function withDrain<T extends Record<string, unknown>>(obj: T): T & { drain: () => Promise<any> } {\n (obj as any).drain = async () => {\n if ('error' in obj && obj.error !== undefined) {\n return { error: obj.error };\n }\n try {\n const value = await drainValue(obj.result);\n return { value };\n } catch (err) {\n return { error: err };\n }\n };\n return obj as any;\n}\n\n/**\n * Creates an error command result with a `drain()` that returns the error.\n */\nexport function errorResult(error: unknown, partial?: { command?: unknown; args?: unknown; argsResult?: unknown }) {\n return withDrain({\n error,\n result: undefined,\n command: partial?.command,\n args: partial?.args,\n argsResult: partial?.argsResult,\n });\n}\n\n/**\n * Deduplicates plugins by `id`. When multiple plugins share the same `id`,\n * only the last one in the array is kept. Plugins without an `id` are always kept.\n */\nfunction deduplicatePlugins(plugins: PadronePlugin<any, any>[]): PadronePlugin<any, any>[] {\n // Fast path: no ids at all\n if (!plugins.some((p) => p.id)) return plugins;\n\n // Find the last index for each id\n const lastIndex = new Map<string, number>();\n for (let i = 0; i < plugins.length; i++) {\n const id = plugins[i]!.id;\n if (id) lastIndex.set(id, i);\n }\n\n return plugins.filter((p, i) => !p.id || lastIndex.get(p.id) === i);\n}\n\n/**\n * Runs a plugin chain for a given phase using the onion/middleware pattern.\n * Plugins are sorted by `order` (ascending, stable), then composed so that\n * the first plugin in sorted order is the outermost wrapper.\n * If no plugins handle this phase, `core` is called directly.\n */\nexport function runPluginChain<TCtx, TResult>(\n phase: 'start' | 'parse' | 'validate' | 'execute' | 'error' | 'shutdown',\n plugins: PadronePlugin<any, any>[],\n ctx: TCtx,\n core: () => TResult | Promise<TResult>,\n): TResult | Promise<TResult> {\n // Deduplicate by id (last wins), then filter to plugins that have a handler for this phase\n const deduped = deduplicatePlugins(plugins);\n const phasePlugins = deduped.filter((p) => p[phase]);\n if (phasePlugins.length === 0) return core();\n\n // Stable sort by order (lower = outermost). Equal order preserves registration order.\n phasePlugins.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n\n // Build chain from inside out: last plugin wraps core, first plugin is outermost\n let next = core;\n for (let i = phasePlugins.length - 1; i >= 0; i--) {\n const handler = phasePlugins[i]![phase]! as unknown as (\n ctx: TCtx,\n next: () => TResult | Promise<TResult>,\n ) => TResult | Promise<TResult>;\n const prevNext = next;\n next = () => handler(ctx, prevNext);\n }\n\n return next();\n}\n\n/**\n * Wraps a pipeline with start → error → shutdown lifecycle hooks.\n * - `start` plugins wrap the pipeline (onion pattern, root plugins only).\n * - On error: `error` plugins run (can transform/suppress the error).\n * - Always: `shutdown` plugins run (success or failure).\n */\nexport function wrapWithLifecycle<T>(\n plugins: PadronePlugin<any, any>[],\n command: AnyPadroneCommand,\n state: Record<string, unknown>,\n input: string | undefined,\n pipeline: () => T | Promise<T>,\n wrapErrorResult?: (result: unknown) => T,\n): T | Promise<T> {\n const hasStart = plugins.some((p) => p.start);\n const hasError = plugins.some((p) => p.error);\n const hasShutdown = plugins.some((p) => p.shutdown);\n\n const cleanupProgress = (error?: unknown, result?: unknown) => {\n const indicator = state._progress as PadroneProgressIndicator | undefined;\n if (indicator) {\n // If there's no progress config (lazy/manual indicator), just stop it silently\n const hasProgressConfig = '_progressMsg' in state;\n if (!hasProgressConfig) {\n indicator.stop();\n } else if (error !== undefined) {\n const fallback = error instanceof Error ? error.message : String(error);\n const { message: errorMsg, indicator: errorIcon } = resolveProgressMessage(state._progressError, error, fallback);\n indicator.fail(errorMsg, errorIcon !== undefined ? { indicator: errorIcon } : undefined);\n } else {\n const { message: successMsg, indicator: successIcon } = resolveProgressMessage(state._progressSuccess, result);\n indicator.succeed(successMsg, successIcon !== undefined ? { indicator: successIcon } : undefined);\n }\n (state._restoreOutput as (() => void) | undefined)?.();\n state._progress = undefined;\n state._restoreOutput = undefined;\n }\n };\n\n // Fast path: no lifecycle plugins — still need progress cleanup\n if (!hasStart && !hasError && !hasShutdown) {\n let result: T | Promise<T>;\n try {\n result = pipeline();\n } catch (e) {\n cleanupProgress(e);\n throw e;\n }\n if (result instanceof Promise) {\n return result.then(\n (r) => {\n cleanupProgress();\n return r;\n },\n (e) => {\n cleanupProgress(e);\n throw e;\n },\n );\n }\n cleanupProgress();\n return result;\n }\n\n const runShutdown = (error?: unknown, result?: unknown) => {\n cleanupProgress(error);\n if (!hasShutdown) return;\n const ctx: PluginShutdownContext = { command, state, error, result };\n return runPluginChain('shutdown', plugins, ctx, () => {});\n };\n\n const runError = (error: unknown): T | Promise<T> => {\n if (!hasError) {\n const s = runShutdown(error);\n if (s instanceof Promise)\n return s.then(() => {\n throw error;\n });\n throw error;\n }\n const ctx: PluginErrorContext = { command, state, error };\n const errorResult = runPluginChain('error', plugins, ctx, (): PluginErrorResult => ({ error }));\n return thenMaybe(errorResult, (er) => {\n if (er.error !== undefined) {\n const s = runShutdown(er.error);\n return thenMaybe(s as void | Promise<void>, () => {\n throw er.error;\n });\n }\n const wrapped = wrapErrorResult ? wrapErrorResult(er.result) : (er.result as T);\n const s = runShutdown(undefined, wrapped);\n return thenMaybe(s as void | Promise<void>, () => wrapped);\n });\n };\n\n const handleSuccess = (result: T): T | Promise<T> => {\n const s = runShutdown(undefined, result);\n if (s instanceof Promise) return s.then(() => result);\n return result;\n };\n\n // Run start phase wrapping the pipeline\n const startCtx: PluginStartContext = { command, state, input };\n let result: T | Promise<T>;\n try {\n result = (hasStart ? runPluginChain('start', plugins, startCtx, pipeline) : pipeline()) as T | Promise<T>;\n } catch (e) {\n return runError(e);\n }\n\n if (result instanceof Promise) {\n return result.then(handleSuccess, runError);\n }\n\n return handleSuccess(result);\n}\n\n/**\n * Resolves the runtime for a command by walking up the parent chain.\n * Returns a fully resolved runtime with all defaults filled in.\n */\nexport function getCommandRuntime(cmd: AnyPadroneCommand): ResolvedPadroneRuntime {\n let current: AnyPadroneCommand | undefined = cmd;\n while (current) {\n if (current.runtime) return resolveRuntime(current.runtime);\n current = current.parent;\n }\n return resolveRuntime();\n}\n\n/** No-op progress indicator returned when the runtime doesn't provide a `progress` factory. */\nconst noopIndicator: PadroneProgressIndicator = {\n update() {},\n succeed() {},\n fail() {},\n stop() {},\n pause() {},\n resume() {},\n};\n\n/** Creates a progress indicator from the runtime, or returns a no-op if unavailable. */\nexport function createProgress(\n runtime: ResolvedPadroneRuntime,\n message: string,\n options?: import('./runtime.ts').PadroneProgressOptions,\n): PadroneProgressIndicator {\n return runtime.progress?.(message, options) ?? noopIndicator;\n}\n\n/**\n * Creates a lazy progress indicator that defers real indicator creation until first use.\n * This allows `ctx.progress` to work even without `.progress()` config, as long as the\n * runtime provides a progress factory.\n */\nexport function createLazyIndicator(runtime: ResolvedPadroneRuntime, state: Record<string, unknown>): PadroneProgressIndicator {\n if (!runtime.progress) return noopIndicator;\n\n let real: PadroneProgressIndicator | undefined;\n const ensure = (message?: string) => {\n if (!real) {\n real = runtime.progress!(message ?? '', undefined);\n state._progress = real;\n }\n return real;\n };\n\n return {\n update(msg) {\n ensure(msg).update(msg);\n },\n succeed(msg) {\n if (real) real.succeed(msg);\n },\n fail(msg) {\n if (real) real.fail(msg);\n },\n stop() {\n if (real) real.stop();\n },\n pause() {\n if (real) real.pause();\n },\n resume() {\n if (real) real.resume();\n },\n };\n}\n\n/**\n * Resolves a progress message field (static or callback) into the arguments for succeed/fail.\n * Handles string, null, `{ message, indicator }` objects, and callback functions.\n */\nexport function resolveProgressMessage(\n field: unknown,\n value: unknown,\n fallback?: string,\n): { message: string | null | undefined; indicator?: string } {\n const raw = typeof field === 'function' ? (field as (v: unknown) => unknown)(value) : field;\n if (raw === undefined) return { message: fallback };\n if (raw === null || typeof raw === 'string') return { message: raw };\n if (typeof raw === 'object' && raw !== null) {\n const obj = raw as { message?: string | null; indicator?: string };\n return { message: obj.message, indicator: obj.indicator };\n }\n return { message: fallback };\n}\n\nexport { noopIndicator };\n\nexport function isAsyncBranded(schema: unknown): boolean {\n return !!schema && typeof schema === 'object' && '~async' in schema && (schema as any)['~async'] === true;\n}\n\nexport function hasInteractiveConfig(meta: unknown): boolean {\n if (!meta || typeof meta !== 'object') return false;\n const m = meta as Record<string, unknown>;\n return m.interactive === true || Array.isArray(m.interactive) || m.optionalInteractive === true || Array.isArray(m.optionalInteractive);\n}\n\nexport function warnIfUnexpectedAsync<T>(value: T, command: AnyPadroneCommand): T {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return value;\n if (value instanceof Promise && !command.isAsync) {\n const runtime = getCommandRuntime(command);\n runtime.error(\n `[padrone] Command \"${command.path || command.name}\" returned a Promise from validation, ` +\n `but was not marked as async. Use \\`.async()\\` on the builder or \\`asyncSchema()\\` to brand your schema. ` +\n `Without this, TypeScript will infer a sync return type and the result will be a Promise at runtime.`,\n );\n }\n return value;\n}\n\n/**\n * Recursively re-paths a command tree under a new parent path, updating parent references.\n */\nexport function repathCommandTree(\n cmd: AnyPadroneCommand,\n newName: string,\n parentPath: string,\n parent: AnyPadroneCommand,\n): AnyPadroneCommand {\n resolveCommand(cmd);\n const newPath = parentPath ? `${parentPath} ${newName}` : newName;\n const remounted: AnyPadroneCommand = {\n ...cmd,\n name: newName,\n path: newPath,\n parent,\n version: undefined,\n };\n\n if (cmd.commands?.length) {\n remounted.commands = cmd.commands.map((child) => repathCommandTree(child, child.name, newPath, remounted));\n }\n\n return remounted;\n}\n\n/**\n * Builds a completer function for the REPL from the command tree.\n * Completes command names, subcommand names, option names (--foo), and aliases (-f).\n * Also includes dot-prefixed built-in REPL commands (.exit, .clear, .scope, .help, .history).\n */\nexport function buildReplCompleter(\n rootCommand: AnyPadroneCommand,\n builtins: {\n inScope?: boolean;\n },\n): (line: string) => [string[], string] {\n resolveAllCommands(rootCommand);\n return (line: string): [string[], string] => {\n const trimmed = line.trimStart();\n const parts = trimmed.split(/\\s+/);\n const lastPart = parts[parts.length - 1] ?? '';\n\n // If we're completing a dot-command\n if (lastPart.startsWith('.')) {\n const dotCmds = ['.exit', '.clear', '.help', '.history'];\n if (rootCommand.commands?.some((c) => c.commands?.length) || builtins.inScope) dotCmds.push('.scope');\n const hits = dotCmds.filter((c) => c.startsWith(lastPart));\n return [hits.length ? hits : dotCmds, lastPart];\n }\n\n // If we're completing an option (starts with -)\n if (lastPart.startsWith('-')) {\n // Find which command we're in\n const commandParts = parts.slice(0, -1).filter((p) => !p.startsWith('-'));\n let targetCommand = rootCommand;\n for (const part of commandParts) {\n resolveCommand(targetCommand);\n const sub = targetCommand.commands?.find((c) => c.name === part || c.aliases?.includes(part));\n if (sub) {\n resolveCommand(sub);\n targetCommand = sub;\n } else break;\n }\n\n // Get options for this command\n const options: string[] = [];\n if (targetCommand.argsSchema) {\n try {\n const argsMeta = targetCommand.meta?.fields;\n const { flags, aliases } = extractSchemaMetadata(targetCommand.argsSchema, argsMeta, targetCommand.meta?.autoAlias);\n const jsonSchema = targetCommand.argsSchema['~standard'].jsonSchema.input(JSON_SCHEMA_OPTS) as Record<string, any>;\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n for (const key of Object.keys(jsonSchema.properties)) {\n options.push(`--${key}`);\n }\n for (const flag of Object.keys(flags)) {\n options.push(`-${flag}`);\n }\n for (const alias of Object.keys(aliases)) {\n options.push(`--${alias}`);\n }\n }\n } catch {\n // Ignore schema parsing errors\n }\n }\n // Add global flags\n options.push('--help', '-h');\n\n const hits = options.filter((o) => o.startsWith(lastPart));\n return [hits.length ? hits : options, lastPart];\n }\n\n // Completing command names\n const commandParts = parts.filter((p) => !p.startsWith('-'));\n // Walk into subcommands for all but the last token\n let targetCommand = rootCommand;\n for (let i = 0; i < commandParts.length - 1; i++) {\n resolveCommand(targetCommand);\n const sub = targetCommand.commands?.find((c) => c.name === commandParts[i] || c.aliases?.includes(commandParts[i]!));\n if (sub) {\n resolveCommand(sub);\n targetCommand = sub;\n } else break;\n }\n\n const candidates: string[] = [];\n\n // Add subcommand names and aliases\n if (targetCommand.commands) {\n for (const cmd of targetCommand.commands) {\n if (!cmd.hidden) {\n candidates.push(cmd.name);\n if (cmd.aliases) candidates.push(...cmd.aliases);\n }\n }\n }\n\n // Add dot-commands and `..` shorthand at the root level (relative to current scope)\n if (targetCommand === rootCommand) {\n candidates.push('.help', '.exit', '.clear', '.history');\n if (rootCommand.commands?.some((c) => c.commands?.length) || builtins.inScope) candidates.push('.scope');\n if (builtins.inScope) candidates.push('..');\n }\n\n const hits = candidates.filter((c) => c.startsWith(lastPart));\n return [hits.length ? hits : candidates, lastPart];\n };\n}\n\n/**\n * Computes the Levenshtein edit distance between two strings.\n */\nfunction levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n const dp: number[] = Array.from({ length: n + 1 }, (_, i) => i);\n\n for (let i = 1; i <= m; i++) {\n let prev = dp[0]!;\n dp[0] = i;\n for (let j = 1; j <= n; j++) {\n const temp = dp[j]!;\n dp[j] = a[i - 1] === b[j - 1] ? prev : 1 + Math.min(prev, dp[j]!, dp[j - 1]!);\n prev = temp;\n }\n }\n\n return dp[n]!;\n}\n\n/**\n * Finds the closest match from a list of candidates using Levenshtein distance.\n * Returns the suggestion string (e.g. 'Did you mean \"deploy\"?') or empty string if no good match.\n * Threshold: distance must be at most 40% of the longer string's length (min 1, max 3).\n */\nexport function suggestSimilar(input: string, candidates: string[]): string {\n if (candidates.length === 0) return '';\n\n const lower = input.toLowerCase();\n let bestDist = Infinity;\n let bestMatch = '';\n\n for (const candidate of candidates) {\n const dist = levenshtein(lower, candidate.toLowerCase());\n if (dist < bestDist) {\n bestDist = dist;\n bestMatch = candidate;\n }\n }\n\n const maxLen = Math.max(input.length, bestMatch.length);\n const threshold = Math.min(3, Math.max(1, Math.ceil(maxLen * 0.4)));\n\n if (bestDist > 0 && bestDist <= threshold) {\n return `Did you mean \"${bestMatch}\"?`;\n }\n\n return '';\n}\n\nexport function findCommandByName(name: string, commands?: AnyPadroneCommand[]): AnyPadroneCommand | undefined {\n if (!commands) return undefined;\n\n const foundByName = commands.find((cmd) => cmd.name === name);\n if (foundByName) return resolveCommand(foundByName);\n\n // Check for aliases\n const foundByAlias = commands.find((cmd) => cmd.aliases?.includes(name));\n if (foundByAlias) return resolveCommand(foundByAlias);\n\n for (const cmd of commands) {\n if (name.startsWith(`${cmd.name} `)) {\n resolveCommand(cmd);\n if (cmd.commands) {\n const subCommandName = name.slice(cmd.name.length + 1);\n const subCommand = findCommandByName(subCommandName, cmd.commands);\n if (subCommand) return subCommand;\n }\n }\n // Check aliases for nested commands\n if (cmd.aliases) {\n for (const alias of cmd.aliases) {\n if (name.startsWith(`${alias} `)) {\n resolveCommand(cmd);\n if (cmd.commands) {\n const subCommandName = name.slice(alias.length + 1);\n const subCommand = findCommandByName(subCommandName, cmd.commands);\n if (subCommand) return subCommand;\n }\n }\n }\n }\n }\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Shared utilities for MCP and serve\n// ---------------------------------------------------------------------------\n\nexport type CollectedEndpoint = { name: string; command: AnyPadroneCommand };\n\n/** Collect all actionable commands recursively. Hidden commands are excluded. */\nexport function collectEndpoints(commands: AnyPadroneCommand[] | undefined, prefix: string): CollectedEndpoint[] {\n if (!commands) return [];\n const endpoints: CollectedEndpoint[] = [];\n for (const cmd of commands) {\n resolveCommand(cmd);\n if (cmd.hidden) continue;\n const path = cmd.name ? (prefix ? `${prefix}.${cmd.name}` : cmd.name) : prefix;\n if (cmd.action || cmd.argsSchema) {\n endpoints.push({ name: path, command: cmd });\n }\n if (cmd.commands?.length) {\n endpoints.push(...collectEndpoints(cmd.commands, path));\n }\n }\n return endpoints;\n}\n\n/** Build the JSON Schema for a command's arguments. */\nexport function buildInputSchema(cmd: AnyPadroneCommand): Record<string, unknown> {\n if (!cmd.argsSchema) {\n return { type: 'object', additionalProperties: false };\n }\n try {\n return cmd.argsSchema['~standard'].jsonSchema.input(JSON_SCHEMA_OPTS) as Record<string, unknown>;\n } catch {\n return { type: 'object', additionalProperties: false };\n }\n}\n\n/** Serialize a record of args into CLI flag strings. */\nexport function serializeArgsToFlags(args: Record<string, unknown>): string[] {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(args)) {\n if (value === undefined) continue;\n if (typeof value === 'boolean') {\n parts.push(value ? `--${key}` : `--no-${key}`);\n } else if (Array.isArray(value)) {\n for (const v of value) parts.push(`--${key}=${String(v)}`);\n } else {\n const strVal = String(value);\n parts.push(strVal.includes(' ') ? `--${key}=\"${strVal}\"` : `--${key}=${strVal}`);\n }\n }\n return parts;\n}\n"],"mappings":"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"}
|
package/dist/completion.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion.d.mts","names":[],"sources":["../src/shell-utils.ts","../src/completion.ts"],"mappings":";;;KAAY,SAAA;;;AAAZ;;iBAMgB,WAAA,CAAA,GAAe,SAAA;AAAA,iBAmCf,SAAA,CAAU,KAAA,EAAO,SAAA,EAAW,IAAA;AAAA,iBAkB5B,YAAA,CAAa,GAAA;AArD7B;;;;AAAA,iBA6DgB,aAAA,CAAc,MAAA,UAAgB,OAAA,UAAiB,WAAA,UAAqB,SAAA;EAAsB,IAAA;EAAc,OAAA;AAAA;;;AAnExH;;;AAAA,
|
|
1
|
+
{"version":3,"file":"completion.d.mts","names":[],"sources":["../src/shell-utils.ts","../src/completion.ts"],"mappings":";;;KAAY,SAAA;;;AAAZ;;iBAMgB,WAAA,CAAA,GAAe,SAAA;AAAA,iBAmCf,SAAA,CAAU,KAAA,EAAO,SAAA,EAAW,IAAA;AAAA,iBAkB5B,YAAA,CAAa,GAAA;AArD7B;;;;AAAA,iBA6DgB,aAAA,CAAc,MAAA,UAAgB,OAAA,UAAiB,WAAA,UAAqB,SAAA;EAAsB,IAAA;EAAc,OAAA;AAAA;;;AAnExH;;;AAAA,iBC4FgB,sBAAA,CAAuB,OAAA,EAAS,iBAAA;;ADtFhD;;iBC+LgB,qBAAA,CAAsB,OAAA,EAAS,iBAAA;;;AD5J/C;iBCsOgB,sBAAA,CAAuB,OAAA,EAAS,iBAAA;;;;iBAoDhC,4BAAA,CAA6B,OAAA,EAAS,iBAAA;;;;iBAkEtC,kBAAA,CAAmB,OAAA,EAAS,iBAAA,EAAmB,KAAA,EAAO,SAAA;;;;iBAkBtD,gCAAA,CAAiC,WAAA,UAAqB,KAAA,EAAO,SAAA;ADpV7E;;;;AAAA,iBCsXgB,wBAAA,CAAyB,OAAA,EAAS,iBAAA,EAAmB,KAAA,GAAQ,SAAA;AAAA,UA0C5D,sBAAA;EDha8C;ECka7D,IAAA;EDlawG;ECoaxG,OAAA;AAAA;;;;;iBAOc,gBAAA,CAAiB,WAAA,UAAqB,KAAA,EAAO,SAAA,GAAY,sBAAA"}
|
package/dist/completion.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { n as __require } from "./chunk-CjcI7cDX.mjs";
|
|
2
|
+
import { a as extractSchemaMetadata, t as JSON_SCHEMA_OPTS } from "./args-D5PNDyNu.mjs";
|
|
3
3
|
//#region src/shell-utils.ts
|
|
4
4
|
/**
|
|
5
5
|
* Detects the current shell from environment variables and process info.
|
|
@@ -92,35 +92,55 @@ function extractArguments(cmd) {
|
|
|
92
92
|
try {
|
|
93
93
|
const argsMeta = cmd.meta?.fields;
|
|
94
94
|
const { aliases } = extractSchemaMetadata(cmd.argsSchema, argsMeta, cmd.meta?.autoAlias);
|
|
95
|
-
const
|
|
96
|
-
for (const [
|
|
97
|
-
const jsonSchema = cmd.argsSchema["~standard"].jsonSchema.input(
|
|
95
|
+
const argToAlias = {};
|
|
96
|
+
for (const [aliasName, argName] of Object.entries(aliases)) if (!argToAlias[argName]) argToAlias[argName] = aliasName;
|
|
97
|
+
const jsonSchema = cmd.argsSchema["~standard"].jsonSchema.input(JSON_SCHEMA_OPTS);
|
|
98
98
|
if (jsonSchema.type === "object" && jsonSchema.properties) for (const [key, prop] of Object.entries(jsonSchema.properties)) {
|
|
99
|
-
const
|
|
99
|
+
const enumValues = prop.enum ?? prop.items?.enum;
|
|
100
|
+
const optMeta = argsMeta?.[key];
|
|
100
101
|
argList.push({
|
|
101
102
|
name: key,
|
|
102
|
-
alias,
|
|
103
|
-
isBoolean: prop?.type === "boolean"
|
|
103
|
+
alias: argToAlias[key],
|
|
104
|
+
isBoolean: prop?.type === "boolean",
|
|
105
|
+
enum: enumValues,
|
|
106
|
+
description: optMeta?.description ?? prop.description
|
|
104
107
|
});
|
|
105
108
|
}
|
|
106
109
|
} catch {}
|
|
107
110
|
return argList;
|
|
108
111
|
}
|
|
109
112
|
/**
|
|
113
|
+
* Collects unique args across all commands, preserving first-seen enum values.
|
|
114
|
+
*/
|
|
115
|
+
function collectUniqueArgs(program, commands) {
|
|
116
|
+
const seen = /* @__PURE__ */ new Map();
|
|
117
|
+
for (const cmd of [program, ...commands]) for (const arg of extractArguments(cmd)) if (!seen.has(arg.name)) seen.set(arg.name, arg);
|
|
118
|
+
return seen;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
110
121
|
* Generates a Bash completion script for the program.
|
|
111
122
|
*/
|
|
112
123
|
function generateBashCompletion(program) {
|
|
113
124
|
const programName = program.name;
|
|
114
125
|
const commands = collectAllCommands(program);
|
|
115
126
|
const commandNames = commands.map((c) => c.name).join(" ");
|
|
127
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
116
128
|
const allArguments = /* @__PURE__ */ new Set();
|
|
117
129
|
allArguments.add("--help");
|
|
118
130
|
allArguments.add("--version");
|
|
119
|
-
for (const
|
|
131
|
+
for (const arg of uniqueArgs.values()) {
|
|
120
132
|
allArguments.add(`--${arg.name}`);
|
|
121
|
-
if (arg.alias) allArguments.add(
|
|
133
|
+
if (arg.alias) allArguments.add(`--${arg.alias}`);
|
|
122
134
|
}
|
|
123
135
|
const argsList = Array.from(allArguments).join(" ");
|
|
136
|
+
const enumCases = [];
|
|
137
|
+
for (const arg of uniqueArgs.values()) {
|
|
138
|
+
if (!arg.enum || arg.enum.length === 0) continue;
|
|
139
|
+
const values = arg.enum.join(" ");
|
|
140
|
+
const patterns = [`--${arg.name}`];
|
|
141
|
+
if (arg.alias) patterns.push(`--${arg.alias}`);
|
|
142
|
+
enumCases.push(` ${patterns.join("|")}) COMPREPLY=($(compgen -W "${values}" -- "$cur")); return 0 ;;`);
|
|
143
|
+
}
|
|
124
144
|
return `###-begin-${programName}-completion-###
|
|
125
145
|
#
|
|
126
146
|
# ${programName} command completion script
|
|
@@ -144,8 +164,13 @@ if type complete &>/dev/null; then
|
|
|
144
164
|
|
|
145
165
|
local commands="${commandNames}"
|
|
146
166
|
local args="${argsList}"
|
|
167
|
+
${enumCases.length > 0 ? `
|
|
168
|
+
# Complete option values
|
|
169
|
+
case "$prev" in
|
|
170
|
+
${enumCases.join("\n")}
|
|
171
|
+
esac
|
|
147
172
|
|
|
148
|
-
# Complete args when current word starts with -
|
|
173
|
+
` : "\n"} # Complete args when current word starts with -
|
|
149
174
|
if [[ "$cur" == -* ]]; then
|
|
150
175
|
COMPREPLY=($(compgen -W "$args" -- "$cur"))
|
|
151
176
|
return 0
|
|
@@ -197,13 +222,12 @@ function generateZshCompletion(program) {
|
|
|
197
222
|
const argumentCompletions = [];
|
|
198
223
|
argumentCompletions.push(" '--help[Show help information]'");
|
|
199
224
|
argumentCompletions.push(" '--version[Show version number]'");
|
|
200
|
-
const
|
|
201
|
-
for (const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
else argumentCompletions.push(` '--${arg.name}[${escapedDesc}]'`);
|
|
225
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
226
|
+
for (const arg of uniqueArgs.values()) {
|
|
227
|
+
const escapedDesc = (arg.description || "").replace(/'/g, "'\\''").replace(/\[/g, "\\[").replace(/\]/g, "\\]");
|
|
228
|
+
const valueAction = arg.enum?.length ? `: :(${arg.enum.join(" ")})` : "";
|
|
229
|
+
if (arg.alias) argumentCompletions.push(` {--${arg.alias},--${arg.name}}'[${escapedDesc}]${valueAction}'`);
|
|
230
|
+
else argumentCompletions.push(` '--${arg.name}[${escapedDesc}]${valueAction}'`);
|
|
207
231
|
}
|
|
208
232
|
return `#compdef ${programName}
|
|
209
233
|
###-begin-${programName}-completion-###
|
|
@@ -268,13 +292,12 @@ function generateFishCompletion(program) {
|
|
|
268
292
|
lines.push("# Global arguments");
|
|
269
293
|
lines.push(`complete -c ${programName} -l help -d 'Show help information'`);
|
|
270
294
|
lines.push(`complete -c ${programName} -l version -d 'Show version number'`);
|
|
271
|
-
const
|
|
272
|
-
for (const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
else lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'`);
|
|
295
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
296
|
+
for (const arg of uniqueArgs.values()) {
|
|
297
|
+
const escapedDesc = (arg.description || "").replace(/'/g, "\\'");
|
|
298
|
+
const valueFlag = arg.enum?.length ? ` -xa '${arg.enum.join(" ")}'` : "";
|
|
299
|
+
if (arg.alias) lines.push(`complete -c ${programName} -l ${arg.name} -s ${arg.alias} -d '${escapedDesc}'${valueFlag}`);
|
|
300
|
+
else lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'${valueFlag}`);
|
|
278
301
|
}
|
|
279
302
|
lines.push(`###-end-${programName}-completion-###`);
|
|
280
303
|
return lines.join("\n");
|
|
@@ -284,6 +307,32 @@ function generateFishCompletion(program) {
|
|
|
284
307
|
*/
|
|
285
308
|
function generatePowerShellCompletion(program) {
|
|
286
309
|
const programName = program.name;
|
|
310
|
+
const commands = collectAllCommands(program);
|
|
311
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
312
|
+
const commandNames = commands.map((c) => `'${c.name}'`).join(", ");
|
|
313
|
+
const argNames = ["'--help'", "'--version'"];
|
|
314
|
+
for (const arg of uniqueArgs.values()) {
|
|
315
|
+
argNames.push(`'--${arg.name}'`);
|
|
316
|
+
if (arg.alias) argNames.push(`'--${arg.alias}'`);
|
|
317
|
+
}
|
|
318
|
+
const enumCases = [];
|
|
319
|
+
for (const arg of uniqueArgs.values()) {
|
|
320
|
+
if (!arg.enum || arg.enum.length === 0) continue;
|
|
321
|
+
const values = arg.enum.map((v) => `'${v}'`).join(", ");
|
|
322
|
+
const patterns = [`'--${arg.name}'`];
|
|
323
|
+
if (arg.alias) patterns.push(`'--${arg.alias}'`);
|
|
324
|
+
enumCases.push(` ${patterns.join(", ")} { @(${values}) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
325
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
326
|
+
}; return }`);
|
|
327
|
+
}
|
|
328
|
+
const enumBlock = enumCases.length > 0 ? `
|
|
329
|
+
# Complete option values
|
|
330
|
+
$prevWord = $commandAst.CommandElements | Select-Object -Last 2 | Select-Object -First 1
|
|
331
|
+
switch ($prevWord) {
|
|
332
|
+
${enumCases.join("\n")}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
` : "\n";
|
|
287
336
|
return `###-begin-${programName}-completion-###
|
|
288
337
|
#
|
|
289
338
|
# ${programName} command completion script for PowerShell
|
|
@@ -294,10 +343,9 @@ function generatePowerShellCompletion(program) {
|
|
|
294
343
|
Register-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {
|
|
295
344
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
296
345
|
|
|
297
|
-
$commands = @(${
|
|
298
|
-
$args = @(
|
|
299
|
-
|
|
300
|
-
if ($wordToComplete -like '-*') {
|
|
346
|
+
$commands = @(${commandNames})
|
|
347
|
+
$args = @(${argNames.join(", ")})
|
|
348
|
+
${enumBlock} if ($wordToComplete -like '-*') {
|
|
301
349
|
$args | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
302
350
|
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
303
351
|
}
|
package/dist/completion.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion.mjs","names":[],"sources":["../src/shell-utils.ts","../src/completion.ts"],"sourcesContent":["export type ShellType = 'bash' | 'zsh' | 'fish' | 'powershell';\n\n/**\n * Detects the current shell from environment variables and process info.\n * @returns The detected shell type, or undefined if unknown\n */\nexport function detectShell(): ShellType | undefined {\n if (typeof process === 'undefined') return undefined;\n\n // Method 1: Check SHELL environment variable (most common)\n const shellEnv = process.env.SHELL || '';\n if (shellEnv.includes('zsh')) return 'zsh';\n if (shellEnv.includes('bash')) return 'bash';\n if (shellEnv.includes('fish')) return 'fish';\n\n // Method 2: Check Windows-specific shells\n if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {\n return 'powershell';\n }\n\n // Method 3: Check parent process on Unix-like systems\n try {\n const ppid = process.ppid;\n if (ppid) {\n const { execSync } = require('node:child_process') as typeof import('node:child_process');\n const processName = execSync(`ps -p ${ppid} -o comm=`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'ignore'],\n }).trim();\n\n if (processName.includes('zsh')) return 'zsh';\n if (processName.includes('bash')) return 'bash';\n if (processName.includes('fish')) return 'fish';\n }\n } catch {\n // Ignore errors (e.g., ps not available)\n }\n\n return undefined;\n}\n\nexport function getRcFile(shell: ShellType, home?: string): string | null {\n const { homedir } = require('node:os') as typeof import('node:os');\n const { join } = require('node:path') as typeof import('node:path');\n const h = home ?? homedir();\n switch (shell) {\n case 'bash':\n return join(h, '.bashrc');\n case 'zsh':\n return join(h, '.zshrc');\n case 'fish':\n return join(h, '.config', 'fish', 'config.fish');\n case 'powershell':\n return process.env.PROFILE || join(h, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');\n default:\n return null;\n }\n}\n\nexport function escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Writes a snippet to a shell config file using begin/end markers for idempotency.\n * If a block with the same begin marker exists, it is replaced. Otherwise the snippet is appended.\n */\nexport function writeToRcFile(rcFile: string, snippet: string, beginMarker: string, endMarker: string): { file: string; updated: boolean } {\n const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('node:fs') as typeof import('node:fs');\n const { dirname } = require('node:path') as typeof import('node:path');\n const existing = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';\n\n if (existing.includes(beginMarker)) {\n const pattern = new RegExp(`${escapeRegExp(beginMarker)}[\\\\s\\\\S]*?${escapeRegExp(endMarker)}`);\n writeFileSync(rcFile, existing.replace(pattern, snippet));\n return { file: rcFile, updated: true };\n }\n\n mkdirSync(dirname(rcFile), { recursive: true });\n const separator = existing.length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n writeFileSync(rcFile, `${existing}${separator}\\n${snippet}\\n`);\n return { file: rcFile, updated: false };\n}\n","import { extractSchemaMetadata } from './args.ts';\nimport { detectShell, getRcFile, type ShellType, writeToRcFile } from './shell-utils.ts';\nimport type { AnyPadroneCommand } from './types.ts';\n\nexport { detectShell, escapeRegExp, getRcFile, type ShellType, writeToRcFile } from './shell-utils.ts';\n\n/**\n * Collects all commands from a program recursively.\n */\nfunction collectAllCommands(cmd: AnyPadroneCommand): AnyPadroneCommand[] {\n const result: AnyPadroneCommand[] = [];\n\n if (cmd.commands) {\n for (const subcmd of cmd.commands) {\n if (!subcmd.hidden) {\n result.push(subcmd);\n result.push(...collectAllCommands(subcmd));\n }\n }\n }\n\n return result;\n}\n\n/**\n * Extracts all argument names from a command's schema.\n */\nfunction extractArguments(cmd: AnyPadroneCommand): { name: string; alias?: string; isBoolean: boolean }[] {\n const argList: { name: string; alias?: string; isBoolean: boolean }[] = [];\n\n if (!cmd.argsSchema) return argList;\n\n try {\n const argsMeta = cmd.meta?.fields;\n const { aliases } = extractSchemaMetadata(cmd.argsSchema, argsMeta, cmd.meta?.autoAlias);\n\n // Reverse aliases map (alias -> arg name)\n const aliasToArgument: Record<string, string> = {};\n for (const [arg, alias] of Object.entries(aliases)) {\n aliasToArgument[alias] = arg;\n }\n\n const jsonSchema = cmd.argsSchema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) as Record<string, any>;\n\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n for (const [key, prop] of Object.entries(jsonSchema.properties as Record<string, any>)) {\n const alias = Object.entries(aliases).find(([arg]) => arg === key)?.[1];\n argList.push({\n name: key,\n alias: alias,\n isBoolean: prop?.type === 'boolean',\n });\n }\n }\n } catch {\n // Ignore schema parsing errors\n }\n\n return argList;\n}\n\n/**\n * Generates a Bash completion script for the program.\n */\nexport function generateBashCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n const commandNames = commands.map((c) => c.name).join(' ');\n\n // Collect all args from all commands\n const allArguments = new Set<string>();\n allArguments.add('--help');\n allArguments.add('--version');\n\n for (const cmd of [program, ...commands]) {\n for (const arg of extractArguments(cmd)) {\n allArguments.add(`--${arg.name}`);\n if (arg.alias) allArguments.add(`-${arg.alias}`);\n }\n }\n\n const argsList = Array.from(allArguments).join(' ');\n\n return `###-begin-${programName}-completion-###\n#\n# ${programName} command completion script\n#\n# Installation: ${programName} completion >> ~/.bashrc (or ~/.zshrc)\n# Or, maybe: ${programName} completion > /usr/local/etc/bash_completion.d/${programName}\n#\n\nif type complete &>/dev/null; then\n _${programName}_completion() {\n local cur prev words cword\n if type _get_comp_words_by_ref &>/dev/null; then\n _get_comp_words_by_ref -n = -n @ -n : -w words -i cword\n else\n cword=\"$COMP_CWORD\"\n words=(\"\\${COMP_WORDS[@]}\")\n fi\n\n cur=\"\\${words[cword]}\"\n prev=\"\\${words[cword-1]}\"\n\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n # Complete args when current word starts with -\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$args\" -- \"$cur\"))\n return 0\n fi\n\n # Complete commands\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n }\n complete -o bashdefault -o default -o nospace -F _${programName}_completion ${programName}\nelif type compdef &>/dev/null; then\n _${programName}_completion() {\n local si=$IFS\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n if [[ \"\\${words[CURRENT]}\" == -* ]]; then\n compadd -- \\${=args}\n else\n compadd -- \\${=commands}\n fi\n IFS=$si\n }\n compdef _${programName}_completion ${programName}\nelif type compctl &>/dev/null; then\n _${programName}_completion() {\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n if [[ \"\\${words[CURRENT]}\" == -* ]]; then\n reply=(\\${=args})\n else\n reply=(\\${=commands})\n fi\n }\n compctl -K _${programName}_completion ${programName}\nfi\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a Zsh completion script for the program.\n */\nexport function generateZshCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n // Generate command completions with descriptions\n const commandCompletions = commands\n .map((cmd) => {\n const desc = cmd.description || cmd.title || '';\n const escapedDesc = desc.replace(/'/g, \"'\\\\''\").replace(/:/g, '\\\\:');\n return ` '${cmd.name}:${escapedDesc}'`;\n })\n .join('\\n');\n\n // Collect all args with descriptions\n const argumentCompletions: string[] = [];\n argumentCompletions.push(\" '--help[Show help information]'\");\n argumentCompletions.push(\" '--version[Show version number]'\");\n\n const seenArgs = new Set<string>(['help', 'version']);\n\n for (const cmd of [program, ...commands]) {\n for (const arg of extractArguments(cmd)) {\n if (seenArgs.has(arg.name)) continue;\n seenArgs.add(arg.name);\n\n const desc = cmd.meta?.fields?.[arg.name]?.description || '';\n const escapedDesc = desc.replace(/'/g, \"'\\\\''\").replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n\n if (arg.alias) {\n argumentCompletions.push(` {-${arg.alias},--${arg.name}}'[${escapedDesc}]'`);\n } else {\n argumentCompletions.push(` '--${arg.name}[${escapedDesc}]'`);\n }\n }\n }\n\n return `#compdef ${programName}\n###-begin-${programName}-completion-###\n#\n# ${programName} command completion script for Zsh\n#\n# Installation: ${programName} completion >> ~/.zshrc\n# Or: ${programName} completion > ~/.zsh/completions/_${programName}\n#\n\n_${programName}() {\n local -a commands\n local -a args\n\n commands=(\n${commandCompletions}\n )\n\n args=(\n${argumentCompletions.join('\\n')}\n )\n\n _arguments -s \\\\\n $args \\\\\n '1: :->command' \\\\\n '*::arg:->args'\n\n case \"$state\" in\n command)\n _describe 'command' commands\n ;;\n esac\n}\n\n_${programName}\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a Fish completion script for the program.\n */\nexport function generateFishCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n const lines: string[] = [\n `###-begin-${programName}-completion-###`,\n '#',\n `# ${programName} command completion script for Fish`,\n '#',\n `# Installation: ${programName} completion > ~/.config/fish/completions/${programName}.fish`,\n '#',\n '',\n `# Clear existing completions`,\n `complete -c ${programName} -e`,\n '',\n '# Commands',\n ];\n\n for (const cmd of commands) {\n const desc = cmd.description || cmd.title || '';\n const escapedDesc = desc.replace(/'/g, \"\\\\'\");\n lines.push(`complete -c ${programName} -n \"__fish_use_subcommand\" -a \"${cmd.name}\" -d '${escapedDesc}'`);\n }\n\n lines.push('');\n lines.push('# Global arguments');\n lines.push(`complete -c ${programName} -l help -d 'Show help information'`);\n lines.push(`complete -c ${programName} -l version -d 'Show version number'`);\n\n const seenArgs = new Set<string>(['help', 'version']);\n\n for (const cmd of [program, ...commands]) {\n for (const arg of extractArguments(cmd)) {\n if (seenArgs.has(arg.name)) continue;\n seenArgs.add(arg.name);\n\n const desc = cmd.meta?.fields?.[arg.name]?.description || '';\n const escapedDesc = desc.replace(/'/g, \"\\\\'\");\n\n if (arg.alias) {\n lines.push(`complete -c ${programName} -s ${arg.alias} -l ${arg.name} -d '${escapedDesc}'`);\n } else {\n lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'`);\n }\n }\n }\n\n lines.push(`###-end-${programName}-completion-###`);\n\n return lines.join('\\n');\n}\n\n/**\n * Generates a PowerShell completion script for the program.\n */\nexport function generatePowerShellCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n const commandNames = commands.map((c) => `'${c.name}'`).join(', ');\n\n return `###-begin-${programName}-completion-###\n#\n# ${programName} command completion script for PowerShell\n#\n# Installation: ${programName} completion >> $PROFILE\n#\n\nRegister-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {\n param($wordToComplete, $commandAst, $cursorPosition)\n\n $commands = @(${commandNames})\n $args = @('--help', '--version')\n\n if ($wordToComplete -like '-*') {\n $args | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }\n } else {\n $commands | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }\n }\n}\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a completion script for the specified shell.\n */\nexport function generateCompletion(program: AnyPadroneCommand, shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return generateBashCompletion(program);\n case 'zsh':\n return generateZshCompletion(program);\n case 'fish':\n return generateFishCompletion(program);\n case 'powershell':\n return generatePowerShellCompletion(program);\n default:\n throw new Error(`Unsupported shell: ${shell}`);\n }\n}\n\n/**\n * Gets the installation instructions for a shell completion script.\n */\nexport function getCompletionInstallInstructions(programName: string, shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return `# Add to ~/.bashrc:\n${programName} completion bash >> ~/.bashrc\n\n# Or install system-wide:\n${programName} completion bash > /usr/local/etc/bash_completion.d/${programName}`;\n\n case 'zsh':\n return `# Add to ~/.zshrc:\n${programName} completion zsh >> ~/.zshrc\n\n# Or add to completions directory:\n${programName} completion zsh > ~/.zsh/completions/_${programName}`;\n\n case 'fish':\n return `# Install to Fish completions:\n${programName} completion fish > ~/.config/fish/completions/${programName}.fish`;\n\n case 'powershell':\n return `# Add to PowerShell profile:\n${programName} completion powershell >> $PROFILE`;\n\n default:\n return `# Run: ${programName} completion <shell>\n# Supported shells: bash, zsh, fish, powershell`;\n }\n}\n\n/**\n * Generates the completion output with automatic shell detection.\n * If shell is not specified, detects the current shell and provides instructions.\n */\nexport function generateCompletionOutput(program: AnyPadroneCommand, shell?: ShellType): string {\n const programName = program.name;\n\n if (shell) {\n return generateCompletion(program, shell);\n }\n\n // Auto-detect shell and provide instructions\n const detectedShell = detectShell();\n\n if (detectedShell) {\n const instructions = getCompletionInstallInstructions(programName, detectedShell);\n const script = generateCompletion(program, detectedShell);\n\n return `# Detected shell: ${detectedShell}\n#\n${instructions}\n#\n# Or evaluate directly (temporary, for current session only):\n# eval \"$(${programName} completion ${detectedShell})\"\n\n${script}`;\n }\n\n // Could not detect shell - provide usage info\n return `# Shell auto-detection failed.\n#\n# Usage: ${programName} completion <shell>\n#\n# Supported shells:\n# bash - Bash completion script\n# zsh - Zsh completion script\n# fish - Fish completion script\n# powershell - PowerShell completion script\n#\n# Example:\n# ${programName} completion bash >> ~/.bashrc\n# ${programName} completion zsh >> ~/.zshrc\n# ${programName} completion fish > ~/.config/fish/completions/${programName}.fish\n# ${programName} completion powershell >> $PROFILE`;\n}\n\nexport interface SetupCompletionsResult {\n /** The file that was written to. */\n file: string;\n /** Whether an existing completion block was replaced (true) or a new one was appended (false). */\n updated: boolean;\n}\n\n/**\n * Sets up shell completions by writing an eval snippet to the appropriate shell config file.\n * Uses marker comments for idempotency — re-running replaces the existing block.\n */\nexport function setupCompletions(programName: string, shell: ShellType): SetupCompletionsResult {\n const { existsSync, mkdirSync, writeFileSync } = require('node:fs') as typeof import('node:fs');\n const { join } = require('node:path') as typeof import('node:path');\n const { homedir } = require('node:os') as typeof import('node:os');\n\n const beginMarker = `###-begin-${programName}-completion-###`;\n const endMarker = `###-end-${programName}-completion-###`;\n const snippet = buildSetupSnippet(programName, shell, beginMarker, endMarker);\n\n if (shell === 'fish') {\n const completionsDir = join(homedir(), '.config', 'fish', 'completions');\n const filePath = join(completionsDir, `${programName}.fish`);\n mkdirSync(completionsDir, { recursive: true });\n const existed = existsSync(filePath);\n writeFileSync(filePath, `${snippet}\\n`);\n return { file: filePath, updated: existed };\n }\n\n const rcFile = getRcFile(shell);\n if (!rcFile) {\n throw new Error(`Could not determine config file for ${shell}.`);\n }\n\n return writeToRcFile(rcFile, snippet, beginMarker, endMarker);\n}\n\nfunction buildSetupSnippet(programName: string, shell: ShellType, beginMarker: string, endMarker: string): string {\n const evalCmd = `${programName} completion ${shell}`;\n\n switch (shell) {\n case 'bash':\n case 'zsh':\n return `${beginMarker}\\neval \"$(${evalCmd})\"\\n${endMarker}`;\n case 'fish':\n return `${beginMarker}\\n${evalCmd} | source\\n${endMarker}`;\n case 'powershell':\n return `${beginMarker}\\n${evalCmd} | Invoke-Expression\\n${endMarker}`;\n }\n}\n"],"mappings":";;;;;;;AAMA,SAAgB,cAAqC;AACnD,KAAI,OAAO,YAAY,YAAa,QAAO,KAAA;CAG3C,MAAM,WAAW,QAAQ,IAAI,SAAS;AACtC,KAAI,SAAS,SAAS,MAAM,CAAE,QAAO;AACrC,KAAI,SAAS,SAAS,OAAO,CAAE,QAAO;AACtC,KAAI,SAAS,SAAS,OAAO,CAAE,QAAO;AAGtC,KAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,gCAC1C,QAAO;AAIT,KAAI;EACF,MAAM,OAAO,QAAQ;AACrB,MAAI,MAAM;GACR,MAAM,EAAE,aAAA,UAAqB,qBAAqB;GAClD,MAAM,cAAc,SAAS,SAAS,KAAK,YAAY;IACrD,UAAU;IACV,OAAO;KAAC;KAAQ;KAAQ;KAAS;IAClC,CAAC,CAAC,MAAM;AAET,OAAI,YAAY,SAAS,MAAM,CAAE,QAAO;AACxC,OAAI,YAAY,SAAS,OAAO,CAAE,QAAO;AACzC,OAAI,YAAY,SAAS,OAAO,CAAE,QAAO;;SAErC;;AAOV,SAAgB,UAAU,OAAkB,MAA8B;CACxE,MAAM,EAAE,YAAA,UAAoB,UAAU;CACtC,MAAM,EAAE,SAAA,UAAiB,YAAY;CACrC,MAAM,IAAI,QAAQ,SAAS;AAC3B,SAAQ,OAAR;EACE,KAAK,OACH,QAAO,KAAK,GAAG,UAAU;EAC3B,KAAK,MACH,QAAO,KAAK,GAAG,SAAS;EAC1B,KAAK,OACH,QAAO,KAAK,GAAG,WAAW,QAAQ,cAAc;EAClD,KAAK,aACH,QAAO,QAAQ,IAAI,WAAW,KAAK,GAAG,aAAa,cAAc,mCAAmC;EACtG,QACE,QAAO;;;AAIb,SAAgB,aAAa,KAAqB;AAChD,QAAO,IAAI,QAAQ,uBAAuB,OAAO;;;;;;AAOnD,SAAgB,cAAc,QAAgB,SAAiB,aAAqB,WAAuD;CACzI,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAA,UAA0B,UAAU;CACjF,MAAM,EAAE,YAAA,UAAoB,YAAY;CACxC,MAAM,WAAW,WAAW,OAAO,GAAG,aAAa,QAAQ,QAAQ,GAAG;AAEtE,KAAI,SAAS,SAAS,YAAY,EAAE;EAClC,MAAM,UAAU,IAAI,OAAO,GAAG,aAAa,YAAY,CAAC,YAAY,aAAa,UAAU,GAAG;AAC9F,gBAAc,QAAQ,SAAS,QAAQ,SAAS,QAAQ,CAAC;AACzD,SAAO;GAAE,MAAM;GAAQ,SAAS;GAAM;;AAGxC,WAAU,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AAE/C,eAAc,QAAQ,GAAG,WADP,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,KAAK,GAAG,OAAO,GAC7B,IAAI,QAAQ,IAAI;AAC9D,QAAO;EAAE,MAAM;EAAQ,SAAS;EAAO;;;;;;;ACxEzC,SAAS,mBAAmB,KAA6C;CACvE,MAAM,SAA8B,EAAE;AAEtC,KAAI,IAAI;OACD,MAAM,UAAU,IAAI,SACvB,KAAI,CAAC,OAAO,QAAQ;AAClB,UAAO,KAAK,OAAO;AACnB,UAAO,KAAK,GAAG,mBAAmB,OAAO,CAAC;;;AAKhD,QAAO;;;;;AAMT,SAAS,iBAAiB,KAAgF;CACxG,MAAM,UAAkE,EAAE;AAE1E,KAAI,CAAC,IAAI,WAAY,QAAO;AAE5B,KAAI;EACF,MAAM,WAAW,IAAI,MAAM;EAC3B,MAAM,EAAE,YAAY,sBAAsB,IAAI,YAAY,UAAU,IAAI,MAAM,UAAU;EAGxF,MAAM,kBAA0C,EAAE;AAClD,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAChD,iBAAgB,SAAS;EAG3B,MAAM,aAAa,IAAI,WAAW,aAAa,WAAW,MAAM,EAAE,QAAQ,iBAAiB,CAAC;AAE5F,MAAI,WAAW,SAAS,YAAY,WAAW,WAC7C,MAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,WAAW,WAAkC,EAAE;GACtF,MAAM,QAAQ,OAAO,QAAQ,QAAQ,CAAC,MAAM,CAAC,SAAS,QAAQ,IAAI,GAAG;AACrE,WAAQ,KAAK;IACX,MAAM;IACC;IACP,WAAW,MAAM,SAAS;IAC3B,CAAC;;SAGA;AAIR,QAAO;;;;;AAMT,SAAgB,uBAAuB,SAAoC;CACzE,MAAM,cAAc,QAAQ;CAC5B,MAAM,WAAW,mBAAmB,QAAQ;CAC5C,MAAM,eAAe,SAAS,KAAK,MAAM,EAAE,KAAK,CAAC,KAAK,IAAI;CAG1D,MAAM,+BAAe,IAAI,KAAa;AACtC,cAAa,IAAI,SAAS;AAC1B,cAAa,IAAI,YAAY;AAE7B,MAAK,MAAM,OAAO,CAAC,SAAS,GAAG,SAAS,CACtC,MAAK,MAAM,OAAO,iBAAiB,IAAI,EAAE;AACvC,eAAa,IAAI,KAAK,IAAI,OAAO;AACjC,MAAI,IAAI,MAAO,cAAa,IAAI,IAAI,IAAI,QAAQ;;CAIpD,MAAM,WAAW,MAAM,KAAK,aAAa,CAAC,KAAK,IAAI;AAEnD,QAAO,aAAa,YAAY;;IAE9B,YAAY;;kBAEE,YAAY;eACf,YAAY,iDAAiD,YAAY;;;;KAInF,YAAY;;;;;;;;;;;;sBAYK,aAAa;kBACjB,SAAS;;;;;;;;;;;sDAW2B,YAAY,cAAc,YAAY;;KAEvF,YAAY;;sBAEK,aAAa;kBACjB,SAAS;;;;;;;;;aASd,YAAY,cAAc,YAAY;;KAE9C,YAAY;sBACK,aAAa;kBACjB,SAAS;;;;;;;;gBAQX,YAAY,cAAc,YAAY;;UAE5C,YAAY;;;;;AAMtB,SAAgB,sBAAsB,SAAoC;CACxE,MAAM,cAAc,QAAQ;CAC5B,MAAM,WAAW,mBAAmB,QAAQ;CAG5C,MAAM,qBAAqB,SACxB,KAAK,QAAQ;EAEZ,MAAM,eADO,IAAI,eAAe,IAAI,SAAS,IACpB,QAAQ,MAAM,QAAQ,CAAC,QAAQ,MAAM,MAAM;AACpE,SAAO,UAAU,IAAI,KAAK,GAAG,YAAY;GACzC,CACD,KAAK,KAAK;CAGb,MAAM,sBAAgC,EAAE;AACxC,qBAAoB,KAAK,wCAAwC;AACjE,qBAAoB,KAAK,yCAAyC;CAElE,MAAM,WAAW,IAAI,IAAY,CAAC,QAAQ,UAAU,CAAC;AAErD,MAAK,MAAM,OAAO,CAAC,SAAS,GAAG,SAAS,CACtC,MAAK,MAAM,OAAO,iBAAiB,IAAI,EAAE;AACvC,MAAI,SAAS,IAAI,IAAI,KAAK,CAAE;AAC5B,WAAS,IAAI,IAAI,KAAK;EAGtB,MAAM,eADO,IAAI,MAAM,SAAS,IAAI,OAAO,eAAe,IACjC,QAAQ,MAAM,QAAQ,CAAC,QAAQ,OAAO,MAAM,CAAC,QAAQ,OAAO,MAAM;AAE3F,MAAI,IAAI,MACN,qBAAoB,KAAK,WAAW,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,YAAY,IAAI;MAEjF,qBAAoB,KAAK,YAAY,IAAI,KAAK,GAAG,YAAY,IAAI;;AAKvE,QAAO,YAAY,YAAY;YACrB,YAAY;;IAEpB,YAAY;;kBAEE,YAAY;QACtB,YAAY,oCAAoC,YAAY;;;GAGjE,YAAY;;;;;EAKb,mBAAmB;;;;EAInB,oBAAoB,KAAK,KAAK,CAAC;;;;;;;;;;;;;;;GAe9B,YAAY;UACL,YAAY;;;;;AAMtB,SAAgB,uBAAuB,SAAoC;CACzE,MAAM,cAAc,QAAQ;CAC5B,MAAM,WAAW,mBAAmB,QAAQ;CAE5C,MAAM,QAAkB;EACtB,aAAa,YAAY;EACzB;EACA,KAAK,YAAY;EACjB;EACA,mBAAmB,YAAY,2CAA2C,YAAY;EACtF;EACA;EACA;EACA,eAAe,YAAY;EAC3B;EACA;EACD;AAED,MAAK,MAAM,OAAO,UAAU;EAE1B,MAAM,eADO,IAAI,eAAe,IAAI,SAAS,IACpB,QAAQ,MAAM,MAAM;AAC7C,QAAM,KAAK,eAAe,YAAY,kCAAkC,IAAI,KAAK,QAAQ,YAAY,GAAG;;AAG1G,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,qBAAqB;AAChC,OAAM,KAAK,eAAe,YAAY,qCAAqC;AAC3E,OAAM,KAAK,eAAe,YAAY,sCAAsC;CAE5E,MAAM,WAAW,IAAI,IAAY,CAAC,QAAQ,UAAU,CAAC;AAErD,MAAK,MAAM,OAAO,CAAC,SAAS,GAAG,SAAS,CACtC,MAAK,MAAM,OAAO,iBAAiB,IAAI,EAAE;AACvC,MAAI,SAAS,IAAI,IAAI,KAAK,CAAE;AAC5B,WAAS,IAAI,IAAI,KAAK;EAGtB,MAAM,eADO,IAAI,MAAM,SAAS,IAAI,OAAO,eAAe,IACjC,QAAQ,MAAM,MAAM;AAE7C,MAAI,IAAI,MACN,OAAM,KAAK,eAAe,YAAY,MAAM,IAAI,MAAM,MAAM,IAAI,KAAK,OAAO,YAAY,GAAG;MAE3F,OAAM,KAAK,eAAe,YAAY,MAAM,IAAI,KAAK,OAAO,YAAY,GAAG;;AAKjF,OAAM,KAAK,WAAW,YAAY,iBAAiB;AAEnD,QAAO,MAAM,KAAK,KAAK;;;;;AAMzB,SAAgB,6BAA6B,SAAoC;CAC/E,MAAM,cAAc,QAAQ;AAK5B,QAAO,aAAa,YAAY;;IAE9B,YAAY;;kBAEE,YAAY;;;kDAGoB,YAAY;;;kBAX3C,mBAAmB,QAAQ,CAEd,KAAK,MAAM,IAAI,EAAE,KAAK,GAAG,CAAC,KAAK,KAAK,CAYrC;;;;;;;;;;;;;UAarB,YAAY;;;;;AAMtB,SAAgB,mBAAmB,SAA4B,OAA0B;AACvF,SAAQ,OAAR;EACE,KAAK,OACH,QAAO,uBAAuB,QAAQ;EACxC,KAAK,MACH,QAAO,sBAAsB,QAAQ;EACvC,KAAK,OACH,QAAO,uBAAuB,QAAQ;EACxC,KAAK,aACH,QAAO,6BAA6B,QAAQ;EAC9C,QACE,OAAM,IAAI,MAAM,sBAAsB,QAAQ;;;;;;AAOpD,SAAgB,iCAAiC,aAAqB,OAA0B;AAC9F,SAAQ,OAAR;EACE,KAAK,OACH,QAAO;EACX,YAAY;;;EAGZ,YAAY,sDAAsD;EAEhE,KAAK,MACH,QAAO;EACX,YAAY;;;EAGZ,YAAY,wCAAwC;EAElD,KAAK,OACH,QAAO;EACX,YAAY,gDAAgD,YAAY;EAEtE,KAAK,aACH,QAAO;EACX,YAAY;EAEV,QACE,QAAO,UAAU,YAAY;;;;;;;;AASnC,SAAgB,yBAAyB,SAA4B,OAA2B;CAC9F,MAAM,cAAc,QAAQ;AAE5B,KAAI,MACF,QAAO,mBAAmB,SAAS,MAAM;CAI3C,MAAM,gBAAgB,aAAa;AAEnC,KAAI,cAIF,QAAO,qBAAqB,cAAc;;EAHrB,iCAAiC,aAAa,cAAc,CAKtE;;;YAGH,YAAY,cAAc,cAAc;;EAPjC,mBAAmB,SAAS,cAAc;AAa3D,QAAO;;WAEE,YAAY;;;;;;;;;MASjB,YAAY;MACZ,YAAY;MACZ,YAAY,gDAAgD,YAAY;MACxE,YAAY;;;;;;AAclB,SAAgB,iBAAiB,aAAqB,OAA0C;CAC9F,MAAM,EAAE,YAAY,WAAW,kBAAA,UAA0B,UAAU;CACnE,MAAM,EAAE,SAAA,UAAiB,YAAY;CACrC,MAAM,EAAE,YAAA,UAAoB,UAAU;CAEtC,MAAM,cAAc,aAAa,YAAY;CAC7C,MAAM,YAAY,WAAW,YAAY;CACzC,MAAM,UAAU,kBAAkB,aAAa,OAAO,aAAa,UAAU;AAE7E,KAAI,UAAU,QAAQ;EACpB,MAAM,iBAAiB,KAAK,SAAS,EAAE,WAAW,QAAQ,cAAc;EACxE,MAAM,WAAW,KAAK,gBAAgB,GAAG,YAAY,OAAO;AAC5D,YAAU,gBAAgB,EAAE,WAAW,MAAM,CAAC;EAC9C,MAAM,UAAU,WAAW,SAAS;AACpC,gBAAc,UAAU,GAAG,QAAQ,IAAI;AACvC,SAAO;GAAE,MAAM;GAAU,SAAS;GAAS;;CAG7C,MAAM,SAAS,UAAU,MAAM;AAC/B,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,uCAAuC,MAAM,GAAG;AAGlE,QAAO,cAAc,QAAQ,SAAS,aAAa,UAAU;;AAG/D,SAAS,kBAAkB,aAAqB,OAAkB,aAAqB,WAA2B;CAChH,MAAM,UAAU,GAAG,YAAY,cAAc;AAE7C,SAAQ,OAAR;EACE,KAAK;EACL,KAAK,MACH,QAAO,GAAG,YAAY,YAAY,QAAQ,MAAM;EAClD,KAAK,OACH,QAAO,GAAG,YAAY,IAAI,QAAQ,aAAa;EACjD,KAAK,aACH,QAAO,GAAG,YAAY,IAAI,QAAQ,wBAAwB"}
|
|
1
|
+
{"version":3,"file":"completion.mjs","names":[],"sources":["../src/shell-utils.ts","../src/completion.ts"],"sourcesContent":["export type ShellType = 'bash' | 'zsh' | 'fish' | 'powershell';\n\n/**\n * Detects the current shell from environment variables and process info.\n * @returns The detected shell type, or undefined if unknown\n */\nexport function detectShell(): ShellType | undefined {\n if (typeof process === 'undefined') return undefined;\n\n // Method 1: Check SHELL environment variable (most common)\n const shellEnv = process.env.SHELL || '';\n if (shellEnv.includes('zsh')) return 'zsh';\n if (shellEnv.includes('bash')) return 'bash';\n if (shellEnv.includes('fish')) return 'fish';\n\n // Method 2: Check Windows-specific shells\n if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {\n return 'powershell';\n }\n\n // Method 3: Check parent process on Unix-like systems\n try {\n const ppid = process.ppid;\n if (ppid) {\n const { execSync } = require('node:child_process') as typeof import('node:child_process');\n const processName = execSync(`ps -p ${ppid} -o comm=`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'ignore'],\n }).trim();\n\n if (processName.includes('zsh')) return 'zsh';\n if (processName.includes('bash')) return 'bash';\n if (processName.includes('fish')) return 'fish';\n }\n } catch {\n // Ignore errors (e.g., ps not available)\n }\n\n return undefined;\n}\n\nexport function getRcFile(shell: ShellType, home?: string): string | null {\n const { homedir } = require('node:os') as typeof import('node:os');\n const { join } = require('node:path') as typeof import('node:path');\n const h = home ?? homedir();\n switch (shell) {\n case 'bash':\n return join(h, '.bashrc');\n case 'zsh':\n return join(h, '.zshrc');\n case 'fish':\n return join(h, '.config', 'fish', 'config.fish');\n case 'powershell':\n return process.env.PROFILE || join(h, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1');\n default:\n return null;\n }\n}\n\nexport function escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Writes a snippet to a shell config file using begin/end markers for idempotency.\n * If a block with the same begin marker exists, it is replaced. Otherwise the snippet is appended.\n */\nexport function writeToRcFile(rcFile: string, snippet: string, beginMarker: string, endMarker: string): { file: string; updated: boolean } {\n const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('node:fs') as typeof import('node:fs');\n const { dirname } = require('node:path') as typeof import('node:path');\n const existing = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';\n\n if (existing.includes(beginMarker)) {\n const pattern = new RegExp(`${escapeRegExp(beginMarker)}[\\\\s\\\\S]*?${escapeRegExp(endMarker)}`);\n writeFileSync(rcFile, existing.replace(pattern, snippet));\n return { file: rcFile, updated: true };\n }\n\n mkdirSync(dirname(rcFile), { recursive: true });\n const separator = existing.length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n writeFileSync(rcFile, `${existing}${separator}\\n${snippet}\\n`);\n return { file: rcFile, updated: false };\n}\n","import { extractSchemaMetadata, JSON_SCHEMA_OPTS } from './args.ts';\nimport { detectShell, getRcFile, type ShellType, writeToRcFile } from './shell-utils.ts';\nimport type { AnyPadroneCommand } from './types.ts';\n\nexport { detectShell, escapeRegExp, getRcFile, type ShellType, writeToRcFile } from './shell-utils.ts';\n\n/**\n * Collects all commands from a program recursively.\n */\nfunction collectAllCommands(cmd: AnyPadroneCommand): AnyPadroneCommand[] {\n const result: AnyPadroneCommand[] = [];\n\n if (cmd.commands) {\n for (const subcmd of cmd.commands) {\n if (!subcmd.hidden) {\n result.push(subcmd);\n result.push(...collectAllCommands(subcmd));\n }\n }\n }\n\n return result;\n}\n\ninterface ExtractedArg {\n name: string;\n alias?: string;\n isBoolean: boolean;\n enum?: string[];\n description?: string;\n}\n\n/**\n * Extracts all argument names from a command's schema.\n */\nfunction extractArguments(cmd: AnyPadroneCommand): ExtractedArg[] {\n const argList: ExtractedArg[] = [];\n\n if (!cmd.argsSchema) return argList;\n\n try {\n const argsMeta = cmd.meta?.fields;\n const { aliases } = extractSchemaMetadata(cmd.argsSchema, argsMeta, cmd.meta?.autoAlias);\n\n // Build reverse map: argName → aliasName\n const argToAlias: Record<string, string> = {};\n for (const [aliasName, argName] of Object.entries(aliases)) {\n if (!argToAlias[argName]) argToAlias[argName] = aliasName;\n }\n\n const jsonSchema = cmd.argsSchema['~standard'].jsonSchema.input(JSON_SCHEMA_OPTS) as Record<string, any>;\n\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n for (const [key, prop] of Object.entries(jsonSchema.properties as Record<string, any>)) {\n const enumValues = (prop.enum ?? prop.items?.enum) as string[] | undefined;\n const optMeta = argsMeta?.[key];\n argList.push({\n name: key,\n alias: argToAlias[key],\n isBoolean: prop?.type === 'boolean',\n enum: enumValues,\n description: optMeta?.description ?? prop.description,\n });\n }\n }\n } catch {\n // Ignore schema parsing errors\n }\n\n return argList;\n}\n\n/**\n * Collects unique args across all commands, preserving first-seen enum values.\n */\nfunction collectUniqueArgs(program: AnyPadroneCommand, commands: AnyPadroneCommand[]): Map<string, ExtractedArg> {\n const seen = new Map<string, ExtractedArg>();\n\n for (const cmd of [program, ...commands]) {\n for (const arg of extractArguments(cmd)) {\n if (!seen.has(arg.name)) {\n seen.set(arg.name, arg);\n }\n }\n }\n\n return seen;\n}\n\n/**\n * Generates a Bash completion script for the program.\n */\nexport function generateBashCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n const commandNames = commands.map((c) => c.name).join(' ');\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n // Collect all option names\n const allArguments = new Set<string>();\n allArguments.add('--help');\n allArguments.add('--version');\n\n for (const arg of uniqueArgs.values()) {\n allArguments.add(`--${arg.name}`);\n if (arg.alias) allArguments.add(`--${arg.alias}`);\n }\n\n const argsList = Array.from(allArguments).join(' ');\n\n // Build case branches for options with enum values\n const enumCases: string[] = [];\n for (const arg of uniqueArgs.values()) {\n if (!arg.enum || arg.enum.length === 0) continue;\n const values = arg.enum.join(' ');\n const patterns = [`--${arg.name}`];\n if (arg.alias) patterns.push(`--${arg.alias}`);\n enumCases.push(` ${patterns.join('|')}) COMPREPLY=($(compgen -W \"${values}\" -- \"$cur\")); return 0 ;;`);\n }\n\n const enumBlock =\n enumCases.length > 0\n ? `\n # Complete option values\n case \"$prev\" in\n${enumCases.join('\\n')}\n esac\n\n`\n : '\\n';\n\n return `###-begin-${programName}-completion-###\n#\n# ${programName} command completion script\n#\n# Installation: ${programName} completion >> ~/.bashrc (or ~/.zshrc)\n# Or, maybe: ${programName} completion > /usr/local/etc/bash_completion.d/${programName}\n#\n\nif type complete &>/dev/null; then\n _${programName}_completion() {\n local cur prev words cword\n if type _get_comp_words_by_ref &>/dev/null; then\n _get_comp_words_by_ref -n = -n @ -n : -w words -i cword\n else\n cword=\"$COMP_CWORD\"\n words=(\"\\${COMP_WORDS[@]}\")\n fi\n\n cur=\"\\${words[cword]}\"\n prev=\"\\${words[cword-1]}\"\n\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n${enumBlock} # Complete args when current word starts with -\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$args\" -- \"$cur\"))\n return 0\n fi\n\n # Complete commands\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n }\n complete -o bashdefault -o default -o nospace -F _${programName}_completion ${programName}\nelif type compdef &>/dev/null; then\n _${programName}_completion() {\n local si=$IFS\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n if [[ \"\\${words[CURRENT]}\" == -* ]]; then\n compadd -- \\${=args}\n else\n compadd -- \\${=commands}\n fi\n IFS=$si\n }\n compdef _${programName}_completion ${programName}\nelif type compctl &>/dev/null; then\n _${programName}_completion() {\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n if [[ \"\\${words[CURRENT]}\" == -* ]]; then\n reply=(\\${=args})\n else\n reply=(\\${=commands})\n fi\n }\n compctl -K _${programName}_completion ${programName}\nfi\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a Zsh completion script for the program.\n */\nexport function generateZshCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n // Generate command completions with descriptions\n const commandCompletions = commands\n .map((cmd) => {\n const desc = cmd.description || cmd.title || '';\n const escapedDesc = desc.replace(/'/g, \"'\\\\''\").replace(/:/g, '\\\\:');\n return ` '${cmd.name}:${escapedDesc}'`;\n })\n .join('\\n');\n\n // Collect all args with descriptions and enum values\n const argumentCompletions: string[] = [];\n argumentCompletions.push(\" '--help[Show help information]'\");\n argumentCompletions.push(\" '--version[Show version number]'\");\n\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n for (const arg of uniqueArgs.values()) {\n const desc = arg.description || '';\n const escapedDesc = desc.replace(/'/g, \"'\\\\''\").replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n\n // Zsh action spec for enum values: :label:(val1 val2 val3)\n const valueAction = arg.enum?.length ? `: :(${arg.enum.join(' ')})` : '';\n\n if (arg.alias) {\n argumentCompletions.push(` {--${arg.alias},--${arg.name}}'[${escapedDesc}]${valueAction}'`);\n } else {\n argumentCompletions.push(` '--${arg.name}[${escapedDesc}]${valueAction}'`);\n }\n }\n\n return `#compdef ${programName}\n###-begin-${programName}-completion-###\n#\n# ${programName} command completion script for Zsh\n#\n# Installation: ${programName} completion >> ~/.zshrc\n# Or: ${programName} completion > ~/.zsh/completions/_${programName}\n#\n\n_${programName}() {\n local -a commands\n local -a args\n\n commands=(\n${commandCompletions}\n )\n\n args=(\n${argumentCompletions.join('\\n')}\n )\n\n _arguments -s \\\\\n $args \\\\\n '1: :->command' \\\\\n '*::arg:->args'\n\n case \"$state\" in\n command)\n _describe 'command' commands\n ;;\n esac\n}\n\n_${programName}\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a Fish completion script for the program.\n */\nexport function generateFishCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n const lines: string[] = [\n `###-begin-${programName}-completion-###`,\n '#',\n `# ${programName} command completion script for Fish`,\n '#',\n `# Installation: ${programName} completion > ~/.config/fish/completions/${programName}.fish`,\n '#',\n '',\n `# Clear existing completions`,\n `complete -c ${programName} -e`,\n '',\n '# Commands',\n ];\n\n for (const cmd of commands) {\n const desc = cmd.description || cmd.title || '';\n const escapedDesc = desc.replace(/'/g, \"\\\\'\");\n lines.push(`complete -c ${programName} -n \"__fish_use_subcommand\" -a \"${cmd.name}\" -d '${escapedDesc}'`);\n }\n\n lines.push('');\n lines.push('# Global arguments');\n lines.push(`complete -c ${programName} -l help -d 'Show help information'`);\n lines.push(`complete -c ${programName} -l version -d 'Show version number'`);\n\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n for (const arg of uniqueArgs.values()) {\n const desc = arg.description || '';\n const escapedDesc = desc.replace(/'/g, \"\\\\'\");\n // Fish: -xa 'val1 val2' provides exclusive value completions\n const valueFlag = arg.enum?.length ? ` -xa '${arg.enum.join(' ')}'` : '';\n\n if (arg.alias) {\n lines.push(`complete -c ${programName} -l ${arg.name} -s ${arg.alias} -d '${escapedDesc}'${valueFlag}`);\n } else {\n lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'${valueFlag}`);\n }\n }\n\n lines.push(`###-end-${programName}-completion-###`);\n\n return lines.join('\\n');\n}\n\n/**\n * Generates a PowerShell completion script for the program.\n */\nexport function generatePowerShellCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n const commandNames = commands.map((c) => `'${c.name}'`).join(', ');\n\n // Collect all option names\n const argNames: string[] = [\"'--help'\", \"'--version'\"];\n for (const arg of uniqueArgs.values()) {\n argNames.push(`'--${arg.name}'`);\n if (arg.alias) argNames.push(`'--${arg.alias}'`);\n }\n\n // Build switch cases for option value completion\n const enumCases: string[] = [];\n for (const arg of uniqueArgs.values()) {\n if (!arg.enum || arg.enum.length === 0) continue;\n const values = arg.enum.map((v) => `'${v}'`).join(', ');\n const patterns = [`'--${arg.name}'`];\n if (arg.alias) patterns.push(`'--${arg.alias}'`);\n enumCases.push(` ${patterns.join(', ')} { @(${values}) | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }; return }`);\n }\n\n const enumBlock =\n enumCases.length > 0\n ? `\n # Complete option values\n $prevWord = $commandAst.CommandElements | Select-Object -Last 2 | Select-Object -First 1\n switch ($prevWord) {\n${enumCases.join('\\n')}\n }\n\n`\n : '\\n';\n\n return `###-begin-${programName}-completion-###\n#\n# ${programName} command completion script for PowerShell\n#\n# Installation: ${programName} completion >> $PROFILE\n#\n\nRegister-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {\n param($wordToComplete, $commandAst, $cursorPosition)\n\n $commands = @(${commandNames})\n $args = @(${argNames.join(', ')})\n${enumBlock} if ($wordToComplete -like '-*') {\n $args | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }\n } else {\n $commands | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }\n }\n}\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a completion script for the specified shell.\n */\nexport function generateCompletion(program: AnyPadroneCommand, shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return generateBashCompletion(program);\n case 'zsh':\n return generateZshCompletion(program);\n case 'fish':\n return generateFishCompletion(program);\n case 'powershell':\n return generatePowerShellCompletion(program);\n default:\n throw new Error(`Unsupported shell: ${shell}`);\n }\n}\n\n/**\n * Gets the installation instructions for a shell completion script.\n */\nexport function getCompletionInstallInstructions(programName: string, shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return `# Add to ~/.bashrc:\n${programName} completion bash >> ~/.bashrc\n\n# Or install system-wide:\n${programName} completion bash > /usr/local/etc/bash_completion.d/${programName}`;\n\n case 'zsh':\n return `# Add to ~/.zshrc:\n${programName} completion zsh >> ~/.zshrc\n\n# Or add to completions directory:\n${programName} completion zsh > ~/.zsh/completions/_${programName}`;\n\n case 'fish':\n return `# Install to Fish completions:\n${programName} completion fish > ~/.config/fish/completions/${programName}.fish`;\n\n case 'powershell':\n return `# Add to PowerShell profile:\n${programName} completion powershell >> $PROFILE`;\n\n default:\n return `# Run: ${programName} completion <shell>\n# Supported shells: bash, zsh, fish, powershell`;\n }\n}\n\n/**\n * Generates the completion output with automatic shell detection.\n * If shell is not specified, detects the current shell and provides instructions.\n */\nexport function generateCompletionOutput(program: AnyPadroneCommand, shell?: ShellType): string {\n const programName = program.name;\n\n if (shell) {\n return generateCompletion(program, shell);\n }\n\n // Auto-detect shell and provide instructions\n const detectedShell = detectShell();\n\n if (detectedShell) {\n const instructions = getCompletionInstallInstructions(programName, detectedShell);\n const script = generateCompletion(program, detectedShell);\n\n return `# Detected shell: ${detectedShell}\n#\n${instructions}\n#\n# Or evaluate directly (temporary, for current session only):\n# eval \"$(${programName} completion ${detectedShell})\"\n\n${script}`;\n }\n\n // Could not detect shell - provide usage info\n return `# Shell auto-detection failed.\n#\n# Usage: ${programName} completion <shell>\n#\n# Supported shells:\n# bash - Bash completion script\n# zsh - Zsh completion script\n# fish - Fish completion script\n# powershell - PowerShell completion script\n#\n# Example:\n# ${programName} completion bash >> ~/.bashrc\n# ${programName} completion zsh >> ~/.zshrc\n# ${programName} completion fish > ~/.config/fish/completions/${programName}.fish\n# ${programName} completion powershell >> $PROFILE`;\n}\n\nexport interface SetupCompletionsResult {\n /** The file that was written to. */\n file: string;\n /** Whether an existing completion block was replaced (true) or a new one was appended (false). */\n updated: boolean;\n}\n\n/**\n * Sets up shell completions by writing an eval snippet to the appropriate shell config file.\n * Uses marker comments for idempotency — re-running replaces the existing block.\n */\nexport function setupCompletions(programName: string, shell: ShellType): SetupCompletionsResult {\n const { existsSync, mkdirSync, writeFileSync } = require('node:fs') as typeof import('node:fs');\n const { join } = require('node:path') as typeof import('node:path');\n const { homedir } = require('node:os') as typeof import('node:os');\n\n const beginMarker = `###-begin-${programName}-completion-###`;\n const endMarker = `###-end-${programName}-completion-###`;\n const snippet = buildSetupSnippet(programName, shell, beginMarker, endMarker);\n\n if (shell === 'fish') {\n const completionsDir = join(homedir(), '.config', 'fish', 'completions');\n const filePath = join(completionsDir, `${programName}.fish`);\n mkdirSync(completionsDir, { recursive: true });\n const existed = existsSync(filePath);\n writeFileSync(filePath, `${snippet}\\n`);\n return { file: filePath, updated: existed };\n }\n\n const rcFile = getRcFile(shell);\n if (!rcFile) {\n throw new Error(`Could not determine config file for ${shell}.`);\n }\n\n return writeToRcFile(rcFile, snippet, beginMarker, endMarker);\n}\n\nfunction buildSetupSnippet(programName: string, shell: ShellType, beginMarker: string, endMarker: string): string {\n const evalCmd = `${programName} completion ${shell}`;\n\n switch (shell) {\n case 'bash':\n case 'zsh':\n return `${beginMarker}\\neval \"$(${evalCmd})\"\\n${endMarker}`;\n case 'fish':\n return `${beginMarker}\\n${evalCmd} | source\\n${endMarker}`;\n case 'powershell':\n return `${beginMarker}\\n${evalCmd} | Invoke-Expression\\n${endMarker}`;\n }\n}\n"],"mappings":"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"}
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as HelpInfo } from "../formatter-
|
|
1
|
+
import { r as HelpInfo } from "../formatter-DtHzbP22.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/docs/index.d.ts
|
|
4
4
|
type DocsFormat = 'markdown' | 'html' | 'man' | 'json';
|
|
@@ -29,6 +29,26 @@ type DocsResult = {
|
|
|
29
29
|
* Accepts either a PadroneProgram (from createPadrone()) or a raw AnyPadroneCommand.
|
|
30
30
|
*/
|
|
31
31
|
declare function generateDocs(program: object, options?: DocsOptions): DocsResult;
|
|
32
|
+
type SetupManPagesResult = {
|
|
33
|
+
/** Directory where man pages were written. */dir: string; /** Man page files that were written. */
|
|
34
|
+
written: string[]; /** Whether existing pages were overwritten (true) or newly created (false). */
|
|
35
|
+
updated: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Installs man pages for a Padrone CLI program into the local man directory.
|
|
39
|
+
* Generates man pages for all commands and writes them to `~/.local/share/man/man1/`.
|
|
40
|
+
*
|
|
41
|
+
* After installation, `man <program>` and `man <program>-<subcommand>` should work
|
|
42
|
+
* (assuming `~/.local/share/man` is in `MANPATH` or `manpath` picks it up).
|
|
43
|
+
*/
|
|
44
|
+
declare function setupManPages(program: object): SetupManPagesResult;
|
|
45
|
+
/**
|
|
46
|
+
* Removes installed man pages for a Padrone CLI program.
|
|
47
|
+
*/
|
|
48
|
+
declare function removeManPages(program: object): {
|
|
49
|
+
dir: string;
|
|
50
|
+
removed: string[];
|
|
51
|
+
};
|
|
32
52
|
//#endregion
|
|
33
|
-
export { DocsFormat, DocsOptions, DocsPage, DocsResult, generateDocs };
|
|
53
|
+
export { DocsFormat, DocsOptions, DocsPage, DocsResult, SetupManPagesResult, generateDocs, removeManPages, setupManPages };
|
|
34
54
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/docs/index.ts"],"mappings":";;;KAWY,UAAA;AAAA,KAEA,WAAA;EAFA,6CAIV,MAAA,GAAS,UAAA;EAET,MAAA,WANoB;EAQpB,aAAA,YANqB;EAQrB,WAAA,IAAe,IAAA,EAAM,QAAA,EAAU,KAAA,aAAkB,MAAA,mBANxC;EAQT,SAAA,YAFiD;EAIjD,MAAA;AAAA;AAAA,KAGU,QAAA;EAbD,8EAeT,IAAA,UAXA;EAaA,OAAA,UAXqB;EAarB,OAAA;AAAA;AAAA,KAGU,UAAA;EAdV,2BAgBA,KAAA,EAAO,QAAA,IAdD;EAgBN,OAAA,YAbU;EAeV,OAAA;EAEA,MAAA;IAAU,IAAA;IAAc,KAAA,EAAO,KAAA;EAAA;AAAA;;AARjC;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/docs/index.ts"],"mappings":";;;KAWY,UAAA;AAAA,KAEA,WAAA;EAFA,6CAIV,MAAA,GAAS,UAAA;EAET,MAAA,WANoB;EAQpB,aAAA,YANqB;EAQrB,WAAA,IAAe,IAAA,EAAM,QAAA,EAAU,KAAA,aAAkB,MAAA,mBANxC;EAQT,SAAA,YAFiD;EAIjD,MAAA;AAAA;AAAA,KAGU,QAAA;EAbD,8EAeT,IAAA,UAXA;EAaA,OAAA,UAXqB;EAarB,OAAA;AAAA;AAAA,KAGU,UAAA;EAdV,2BAgBA,KAAA,EAAO,QAAA,IAdD;EAgBN,OAAA,YAbU;EAeV,OAAA;EAEA,MAAA;IAAU,IAAA;IAAc,KAAA,EAAO,KAAA;EAAA;AAAA;;AARjC;;;iBAigBgB,YAAA,CAAa,OAAA,UAAiB,OAAA,GAAS,WAAA,GAAmB,UAAA;AAAA,KAoF9D,mBAAA;EAnlBH,8CAqlBP,GAAA,UAjlBA;EAmlBA,OAAA,YAjlBU;EAmlBV,OAAA;AAAA;;;AA1FF;;;;;iBAsHgB,aAAA,CAAc,OAAA,WAAkB,mBAAA;;;;iBA+BhC,cAAA,CAAe,OAAA;EAAoB,GAAA;EAAa,OAAA;AAAA"}
|