padrone 1.7.0 → 1.8.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 +22 -0
- package/README.md +2 -1
- package/dist/{args-Cnq0nwSM.mjs → args-DrCXxXeP.mjs} +20 -4
- package/dist/args-DrCXxXeP.mjs.map +1 -0
- package/dist/codegen/index.mjs +1 -1
- package/dist/{commands-B_gufyR9.mjs → commands-DLR0rFgq.mjs} +2 -2
- package/dist/{commands-B_gufyR9.mjs.map → commands-DLR0rFgq.mjs.map} +1 -1
- package/dist/{completion-BEuflbDO.mjs → completion-UnBKfGuk.mjs} +2 -2
- package/dist/{completion-BEuflbDO.mjs.map → completion-UnBKfGuk.mjs.map} +1 -1
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/{formatter-DrvhDMrq.d.mts → formatter-CY3KrOEd.d.mts} +3 -2
- package/dist/formatter-CY3KrOEd.d.mts.map +1 -0
- package/dist/{help-BtxLgrF_.mjs → help-B-ZMYyn-.mjs} +16 -6
- package/dist/help-B-ZMYyn-.mjs.map +1 -0
- package/dist/{index-D6-7dz0l.d.mts → index-C2n3k4e8.d.mts} +332 -116
- package/dist/index-C2n3k4e8.d.mts.map +1 -0
- package/dist/index.d.mts +17 -160
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +78 -65
- package/dist/index.mjs.map +1 -1
- package/dist/{mcp-6-Jw4Bpq.mjs → mcp-D6PdtjIs.mjs} +4 -4
- package/dist/{mcp-6-Jw4Bpq.mjs.map → mcp-D6PdtjIs.mjs.map} +1 -1
- package/dist/{serve-YVTPzBCl.mjs → serve-PaCLsNoD.mjs} +4 -4
- package/dist/{serve-YVTPzBCl.mjs.map → serve-PaCLsNoD.mjs.map} +1 -1
- package/dist/test.d.mts +1 -1
- package/dist/zod.d.mts +1 -1
- package/package.json +3 -3
- package/src/core/args.ts +24 -1
- package/src/core/create.ts +21 -14
- package/src/core/exec.ts +4 -3
- package/src/core/interceptors.ts +12 -6
- package/src/core/program-methods.ts +12 -2
- package/src/core/validate.ts +26 -7
- package/src/extension/auto-output.ts +1 -1
- package/src/extension/config.ts +2 -1
- package/src/extension/env.ts +5 -4
- package/src/extension/index.ts +1 -0
- package/src/extension/interactive.ts +2 -1
- package/src/extension/logger.ts +1 -1
- package/src/extension/progress.ts +2 -2
- package/src/extension/tracing.ts +1 -1
- package/src/index.ts +5 -1
- package/src/output/formatter.ts +6 -1
- package/src/output/help.ts +15 -3
- package/src/types/args-meta.ts +10 -0
- package/src/types/builder.ts +140 -38
- package/src/types/index.ts +2 -0
- package/src/types/interceptor.ts +12 -12
- package/src/util/type-utils.ts +22 -0
- package/dist/args-Cnq0nwSM.mjs.map +0 -1
- package/dist/formatter-DrvhDMrq.d.mts.map +0 -1
- package/dist/help-BtxLgrF_.mjs.map +0 -1
- package/dist/index-D6-7dz0l.d.mts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# padrone
|
|
2
2
|
|
|
3
|
+
## 1.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`7b58742`](https://github.com/KurtGokhan/padrone/commit/7b5874220f829fbbbc770a850093ce45430a8094) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Add `negative` meta option for boolean arguments. Custom keyword(s) set the option to `false` and disable the default `--no-` prefix. Supports string, array, and empty values to only disable the prefix.
|
|
8
|
+
|
|
9
|
+
- [`07b49ae`](https://github.com/KurtGokhan/padrone/commit/07b49aec2bdef4192c514b2ef3dc1a6ef65efce7) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Add `DefineCommandContext` interface and `defineCommand().requires()` for typed interceptor context in modular commands. Commands defined with `defineCommand()` now have optional `logger`, `tracing`, and `progress` context by default. Use `defineCommand().requires<T>().define(fn)` for additional context requirements with compile-time validation at `.command()` registration.
|
|
10
|
+
|
|
11
|
+
- [`e8bc2df`](https://github.com/KurtGokhan/padrone/commit/e8bc2dfd6f74f828f5cafb7dc2c0835974e24fc4) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Mark `padroneEnv` and `padroneConfig` as async at the type level. Extensions now return `WithAsync<T>` so `eval()` and `cli()` correctly return `Promise` when used.
|
|
12
|
+
|
|
13
|
+
- [`46cf13f`](https://github.com/KurtGokhan/padrone/commit/46cf13f96d2f376eb7ab7c6557c9ef45085535e5) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Auto-merge interceptor context in `next()`. Passing `next({ context: { user } })` now shallow-merges into existing context instead of replacing it. Default `TContext` changed from `unknown` to `object` so `ctx.context` is spreadable without type assertions.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- [`735ffb4`](https://github.com/KurtGokhan/padrone/commit/735ffb4a7d165c35feb050c4d6c6a5e136f1b173) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Detect ambiguous positional arguments provided both positionally and as named options. For example, `cmd val --pos1=val` with `positional: ['pos1', 'pos2']` now reports a validation error instead of silently overwriting.
|
|
18
|
+
|
|
19
|
+
## 1.7.1
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- [`e15d537`](https://github.com/KurtGokhan/padrone/commit/e15d537bf492eaac80ec9f26ff01cfc398e4fd3b) Thanks [@KurtGokhan](https://github.com/KurtGokhan)! - Fix `DefineCommand` with default context being incompatible with parent programs that have a specific context type.
|
|
24
|
+
|
|
3
25
|
## 1.7.0
|
|
4
26
|
|
|
5
27
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ program.help('greet', { format: 'json' }); // json, markdown, html, ansi
|
|
|
99
99
|
|
|
100
100
|
## Features at a Glance
|
|
101
101
|
|
|
102
|
-
**Arguments** — positional args, variadic args, short flags (`-v`), long aliases (`--dry-run`), auto kebab-case aliases, negatable booleans (`--no-verbose`).
|
|
102
|
+
**Arguments** — positional args, variadic args, short flags (`-v`), long aliases (`--dry-run`), auto kebab-case aliases, negatable booleans (`--no-verbose`), custom negation keywords (`--remote` → sets `local` to `false`).
|
|
103
103
|
|
|
104
104
|
**Env & Config** — load from environment variables with `.extend(padroneEnv(schema))` and config files with `.extend(padroneConfig({ files, schema }))`. Precedence: CLI > stdin > env > config > defaults.
|
|
105
105
|
|
|
@@ -161,6 +161,7 @@ program.help('greet', { format: 'json' }); // json, markdown, html, ansi
|
|
|
161
161
|
|-------|---------|---------|
|
|
162
162
|
| `flags` | `'v'` | Single-char short flag (`-v`) |
|
|
163
163
|
| `alias` | `'dry-run'` | Multi-char long alias (`--dry-run`) |
|
|
164
|
+
| `negative` | `'remote'` | Custom negation keyword for booleans (disables `--no-`) |
|
|
164
165
|
| `examples` | `['8080']` | Example values in help |
|
|
165
166
|
| `deprecated` | `'Use --debug'` | Deprecation warning |
|
|
166
167
|
| `hidden` | `true` | Hide from help |
|
|
@@ -130,10 +130,16 @@ function addEntries(target, key, items, filter) {
|
|
|
130
130
|
function extractSchemaMetadata(schema, meta, autoAlias) {
|
|
131
131
|
const flags = {};
|
|
132
132
|
const aliases = {};
|
|
133
|
+
const negatives = {};
|
|
134
|
+
const customNegation = /* @__PURE__ */ new Set();
|
|
133
135
|
if (meta) for (const [key, value] of Object.entries(meta)) {
|
|
134
136
|
if (!value) continue;
|
|
135
137
|
if (value.flags) addEntries(flags, key, value.flags, (item) => item.length === 1);
|
|
136
138
|
if (value.alias) addEntries(aliases, key, value.alias, (item) => item.length > 1);
|
|
139
|
+
if (value.negative !== void 0) {
|
|
140
|
+
customNegation.add(key);
|
|
141
|
+
addEntries(negatives, key, value.negative);
|
|
142
|
+
}
|
|
137
143
|
}
|
|
138
144
|
try {
|
|
139
145
|
const jsonSchema = getJsonSchema(schema);
|
|
@@ -146,6 +152,12 @@ function extractSchemaMetadata(schema, meta, autoAlias) {
|
|
|
146
152
|
const list = typeof propAlias === "string" ? [propAlias] : propAlias;
|
|
147
153
|
if (Array.isArray(list)) addEntries(aliases, propertyName, list, (item) => item.length > 1);
|
|
148
154
|
}
|
|
155
|
+
const propNegative = propertySchema.negative;
|
|
156
|
+
if (propNegative !== void 0 && !customNegation.has(propertyName)) {
|
|
157
|
+
customNegation.add(propertyName);
|
|
158
|
+
const list = typeof propNegative === "string" ? [propNegative] : propNegative;
|
|
159
|
+
if (Array.isArray(list)) addEntries(negatives, propertyName, list);
|
|
160
|
+
}
|
|
149
161
|
if (autoAlias !== false) {
|
|
150
162
|
const kebab = camelToKebab(propertyName);
|
|
151
163
|
if (kebab && !(kebab in aliases)) aliases[kebab] = propertyName;
|
|
@@ -154,7 +166,9 @@ function extractSchemaMetadata(schema, meta, autoAlias) {
|
|
|
154
166
|
} catch {}
|
|
155
167
|
return {
|
|
156
168
|
flags,
|
|
157
|
-
aliases
|
|
169
|
+
aliases,
|
|
170
|
+
negatives,
|
|
171
|
+
customNegation
|
|
158
172
|
};
|
|
159
173
|
}
|
|
160
174
|
function preprocessMappings(data, mappings) {
|
|
@@ -243,7 +257,7 @@ function coerceArgs(data, schema) {
|
|
|
243
257
|
* Returns an array of { key } for each unknown key.
|
|
244
258
|
* Framework-reserved keys (--config, -c) are always allowed.
|
|
245
259
|
*/
|
|
246
|
-
function detectUnknownArgs(data, schema, flags, aliases) {
|
|
260
|
+
function detectUnknownArgs(data, schema, flags, aliases, negatives) {
|
|
247
261
|
let properties;
|
|
248
262
|
let isLoose = false;
|
|
249
263
|
try {
|
|
@@ -260,7 +274,9 @@ function detectUnknownArgs(data, schema, flags, aliases) {
|
|
|
260
274
|
...Object.keys(flags),
|
|
261
275
|
...Object.values(flags),
|
|
262
276
|
...Object.keys(aliases),
|
|
263
|
-
...Object.values(aliases)
|
|
277
|
+
...Object.values(aliases),
|
|
278
|
+
...negatives ? Object.keys(negatives) : [],
|
|
279
|
+
...negatives ? Object.values(negatives) : []
|
|
264
280
|
]);
|
|
265
281
|
const unknowns = [];
|
|
266
282
|
for (const key of Object.keys(data)) if (!knownKeys.has(key)) unknowns.push({ key });
|
|
@@ -269,4 +285,4 @@ function detectUnknownArgs(data, schema, flags, aliases) {
|
|
|
269
285
|
//#endregion
|
|
270
286
|
export { getJsonSchema as a, parsePositionalConfig as c, detectShell as d, escapeRegExp as f, extractSchemaMetadata as i, preprocessArgs as l, writeToRcFile as m, coerceArgs as n, isArrayField as o, getRcFile as p, detectUnknownArgs as r, isAsyncStreamField as s, applyValues as t, camelToKebab as u };
|
|
271
287
|
|
|
272
|
-
//# sourceMappingURL=args-
|
|
288
|
+
//# sourceMappingURL=args-DrCXxXeP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args-DrCXxXeP.mjs","names":[],"sources":["../src/util/shell-utils.ts","../src/core/args.ts"],"sourcesContent":["/**\n * Convert a camelCase string to kebab-case.\n * Returns null if the string has no uppercase letters (no conversion needed).\n */\nexport function camelToKebab(str: string): string | null {\n if (!/[A-Z]/.test(str)) return null;\n return str.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);\n}\n\nexport 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 async function detectShell(): Promise<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 } = (await import('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 async function getRcFile(shell: ShellType, home?: string): Promise<string | null> {\n const { homedir } = await import('node:os');\n const { join } = await 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 (\n (typeof process !== 'undefined' ? process.env.PROFILE : undefined) ||\n join(h, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1')\n );\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 async function writeToRcFile(\n rcFile: string,\n snippet: string,\n beginMarker: string,\n endMarker: string,\n): Promise<{ file: string; updated: boolean }> {\n const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import('node:fs');\n const { dirname } = await 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 type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec';\nimport type { PadroneFieldMeta } from '../types/args-meta.ts';\nimport { camelToKebab } from '../util/shell-utils.ts';\nimport { asyncStreamRegistry } from '../util/stream.ts';\n\nexport type { PadroneArgsSchemaMeta, PadroneFieldMeta, SingleChar, StdinConfig } from '../types/args-meta.ts';\n\n/** Extract the JSON schema from a Standard Schema, returning it as a plain record. */\nexport function getJsonSchema(schema: StandardJSONSchemaV1): Record<string, any> {\n return schema['~standard'].jsonSchema.input({\n target: 'draft-2020-12',\n libraryOptions: { unrepresentable: 'any' },\n }) as Record<string, any>;\n}\n\nfunction getFieldJsonSchema(schema: StandardJSONSchemaV1 | undefined, field: string): Record<string, any> | undefined {\n if (!schema) return undefined;\n try {\n const jsonSchema = getJsonSchema(schema);\n if (jsonSchema.type === 'object' && jsonSchema.properties) return jsonSchema.properties[field];\n } catch {}\n return undefined;\n}\n\n/**\n * Checks if a field in the schema is an array type (e.g. `z.string().array()`).\n */\nexport function isArrayField(schema: StandardJSONSchemaV1 | undefined, field: string): boolean {\n return getFieldJsonSchema(schema, field)?.type === 'array';\n}\n\n/**\n * Checks if a field is an async stream (marked with `asyncStream()` metadata).\n * Returns the item schema if provided, or `true` if it's a plain string stream.\n */\nexport function isAsyncStreamField(schema: StandardJSONSchemaV1 | undefined, field: string): { itemSchema?: StandardSchemaV1 } | false {\n const prop = getFieldJsonSchema(schema, field);\n const asyncStreamId = prop?.asyncStream;\n if (asyncStreamId && asyncStreamRegistry.has(asyncStreamId)) {\n const meta = asyncStreamRegistry.get(asyncStreamId);\n return { itemSchema: meta?.itemSchema };\n }\n\n return false;\n}\n\n/**\n * Parse positional configuration to extract names and variadic info.\n */\nexport function parsePositionalConfig(positional: readonly string[]): { name: string; variadic: boolean }[] {\n return positional.map((p) => {\n const variadic = p.startsWith('...');\n const name = variadic ? p.slice(3) : p;\n return { name, variadic };\n });\n}\n\n/**\n * Result type for extractSchemaMetadata function.\n */\ninterface SchemaMetadataResult {\n /** Single-char flags: maps flag char → full arg name (e.g. `{ v: 'verbose' }`) */\n flags: Record<string, string>;\n /** Multi-char aliases: maps alias → full arg name (e.g. `{ 'dry-run': 'dryRun' }`) */\n aliases: Record<string, string>;\n /** Negative keywords: maps keyword → target arg name (e.g. `{ remote: 'local' }`) */\n negatives: Record<string, string>;\n /** Args that have custom negation set (even if empty), disabling the `--no-` prefix */\n customNegation: Set<string>;\n}\n\nfunction addEntries(target: Record<string, string>, key: string, items: string | readonly string[], filter?: (item: string) => boolean) {\n const list = typeof items === 'string' ? [items] : items;\n for (const item of list) {\n if (typeof item === 'string' && item && item !== key && !(item in target) && (!filter || filter(item))) {\n target[item] = key;\n }\n }\n}\n\n/**\n * Extract all arg metadata from schema and meta in a single pass.\n * Returns flags (single-char, stackable) and aliases (multi-char, long names) separately.\n * When `autoAlias` is true (default), camelCase property names automatically get kebab-case aliases.\n */\nexport function extractSchemaMetadata(\n schema: StandardJSONSchemaV1,\n meta?: Record<string, PadroneFieldMeta | undefined>,\n autoAlias?: boolean,\n): SchemaMetadataResult {\n const flags: Record<string, string> = {};\n const aliases: Record<string, string> = {};\n const negatives: Record<string, string> = {};\n const customNegation = new Set<string>();\n\n // Extract from meta object\n if (meta) {\n for (const [key, value] of Object.entries(meta)) {\n if (!value) continue;\n\n if (value.flags) {\n addEntries(flags, key, value.flags, (item) => item.length === 1);\n }\n if (value.alias) {\n addEntries(aliases, key, value.alias, (item) => item.length > 1);\n }\n if (value.negative !== undefined) {\n customNegation.add(key);\n addEntries(negatives, key, value.negative);\n }\n }\n }\n\n // Extract from JSON schema properties\n try {\n const jsonSchema = getJsonSchema(schema) as Record<string, any>;\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n for (const [propertyName, propertySchema] of Object.entries(jsonSchema.properties as Record<string, any>)) {\n if (!propertySchema) continue;\n\n // Extract flags from schema `.meta({ flags: ... })`\n const propFlags = propertySchema.flags;\n if (propFlags) {\n addEntries(flags, propertyName, propFlags, (item) => item.length === 1);\n }\n\n // Extract aliases from schema `.meta({ alias: ... })`\n const propAlias = propertySchema.alias;\n if (propAlias) {\n const list = typeof propAlias === 'string' ? [propAlias] : propAlias;\n if (Array.isArray(list)) {\n addEntries(aliases, propertyName, list, (item) => item.length > 1);\n }\n }\n\n // Extract negative keywords from schema `.meta({ negative: ... })`\n const propNegative = propertySchema.negative;\n if (propNegative !== undefined && !customNegation.has(propertyName)) {\n customNegation.add(propertyName);\n const list = typeof propNegative === 'string' ? [propNegative] : propNegative;\n if (Array.isArray(list)) {\n addEntries(negatives, propertyName, list);\n }\n }\n\n // Auto-generate kebab-case alias for camelCase property names\n if (autoAlias !== false) {\n const kebab = camelToKebab(propertyName);\n if (kebab && !(kebab in aliases)) {\n aliases[kebab] = propertyName;\n }\n }\n }\n }\n } catch {\n // Ignore errors from JSON schema generation\n }\n\n return { flags, aliases, negatives, customNegation };\n}\n\nfunction preprocessMappings(data: Record<string, unknown>, mappings: Record<string, string>): Record<string, unknown> {\n const result = { ...data };\n\n for (const [mappedKey, fullArgName] of Object.entries(mappings)) {\n if (mappedKey in data && mappedKey !== fullArgName) {\n const mappedValue = data[mappedKey];\n // Prefer full arg name if it exists\n if (!(fullArgName in result)) result[fullArgName] = mappedValue;\n delete result[mappedKey];\n }\n }\n\n return result;\n}\n\n/**\n * Apply values to arguments using \"set if not present\" semantics.\n * Existing values take precedence — only fills in undefined or missing keys.\n */\nexport function applyValues(data: Record<string, unknown>, values: Record<string, unknown>): Record<string, unknown> {\n const result = { ...data };\n\n for (const [key, value] of Object.entries(values)) {\n if (key in result && result[key] !== undefined) continue;\n if (value !== undefined) {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/** Applies flag and alias mappings to raw arguments. */\nexport function preprocessArgs(\n data: Record<string, unknown>,\n ctx: { flags?: Record<string, string>; aliases?: Record<string, string> },\n): Record<string, unknown> {\n let result = { ...data };\n\n if (ctx.flags && Object.keys(ctx.flags).length > 0) {\n result = preprocessMappings(result, ctx.flags);\n }\n if (ctx.aliases && Object.keys(ctx.aliases).length > 0) {\n result = preprocessMappings(result, ctx.aliases);\n }\n\n return result;\n}\n\n/**\n * Auto-coerce CLI string values to match the expected schema types.\n * Handles: string → number, string → boolean for primitive schema fields.\n * Arrays of primitives are also coerced element-wise.\n */\nexport function coerceArgs(data: Record<string, unknown>, schema: StandardJSONSchemaV1): Record<string, unknown> {\n let properties: Record<string, any>;\n try {\n const jsonSchema = getJsonSchema(schema) as Record<string, any>;\n if (jsonSchema.type !== 'object' || !jsonSchema.properties) return data;\n properties = jsonSchema.properties;\n } catch {\n return data;\n }\n\n const result = { ...data };\n\n for (const [key, value] of Object.entries(result)) {\n const prop = properties[key];\n if (!prop) continue;\n\n const targetType = prop.type as string | undefined;\n\n if (targetType === 'number' || targetType === 'integer') {\n if (typeof value === 'string') {\n const num = Number(value);\n if (!Number.isNaN(num)) result[key] = num;\n }\n } else if (targetType === 'boolean') {\n if (typeof value === 'string') {\n const lower = value.toLowerCase();\n if (lower === 'true' || lower === '1' || lower === 'yes' || lower === 'on') result[key] = true;\n else if (lower === 'false' || lower === '0' || lower === 'no' || lower === 'off') result[key] = false;\n }\n } else if (targetType === 'array') {\n // Coerce single items to array\n const arr = Array.isArray(value) ? value : [value];\n const itemType = prop.items?.type as string | undefined;\n if (itemType === 'number' || itemType === 'integer') {\n result[key] = arr.map((v) => {\n if (typeof v === 'string') {\n const num = Number(v);\n return Number.isNaN(num) ? v : num;\n }\n return v;\n });\n } else if (itemType === 'boolean') {\n result[key] = arr.map((v) => {\n if (typeof v === 'string') {\n const lower = v.toLowerCase();\n if (lower === 'true' || lower === '1' || lower === 'yes' || lower === 'on') return true;\n if (lower === 'false' || lower === '0' || lower === 'no' || lower === 'off') return false;\n }\n return v;\n });\n } else if (!Array.isArray(value)) {\n result[key] = arr;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Detect unknown keys in the args that don't match any schema property.\n * Returns an array of { key } for each unknown key.\n * Framework-reserved keys (--config, -c) are always allowed.\n */\nexport function detectUnknownArgs(\n data: Record<string, unknown>,\n schema: StandardJSONSchemaV1,\n flags: Record<string, string>,\n aliases: Record<string, string>,\n negatives?: Record<string, string>,\n): { key: string }[] {\n let properties: Record<string, any>;\n let isLoose = false;\n try {\n const jsonSchema = getJsonSchema(schema) as Record<string, any>;\n if (jsonSchema.type !== 'object' || !jsonSchema.properties) return [];\n properties = jsonSchema.properties;\n // If additionalProperties is set (true, {}, or a schema), the schema allows extra keys\n if (jsonSchema.additionalProperties !== undefined && jsonSchema.additionalProperties !== false) isLoose = true;\n } catch {\n return [];\n }\n\n if (isLoose) return [];\n\n const knownKeys = new Set<string>([\n ...Object.keys(properties),\n ...Object.keys(flags),\n ...Object.values(flags),\n ...Object.keys(aliases),\n ...Object.values(aliases),\n ...(negatives ? Object.keys(negatives) : []),\n ...(negatives ? Object.values(negatives) : []),\n ]);\n const unknowns: { key: string }[] = [];\n\n for (const key of Object.keys(data)) {\n if (!knownKeys.has(key)) {\n unknowns.push({ key });\n }\n }\n\n return unknowns;\n}\n"],"mappings":"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"}
|
package/dist/codegen/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getJsonSchema } from "../args-
|
|
1
|
+
import { a as getJsonSchema } from "../args-DrCXxXeP.mjs";
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getJsonSchema, i as extractSchemaMetadata } from "./args-
|
|
1
|
+
import { a as getJsonSchema, i as extractSchemaMetadata } from "./args-DrCXxXeP.mjs";
|
|
2
2
|
import { a as readStreamAsText } from "./stream-DC4H8YTx.mjs";
|
|
3
3
|
//#region \0rolldown/runtime.js
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -511,4 +511,4 @@ function serializeArgsToFlags(args) {
|
|
|
511
511
|
//#endregion
|
|
512
512
|
export { resolveStdin as _, commands_exports as a, getCommandRuntime as c, repathCommandTree as d, resolveAllCommands as f, createTerminalReplSession as g, suggestSimilar as h, commandSymbol as i, lazyResolver as l, serializeArgsToFlags as m, buildReplCompleter as n, findCommandByName as o, resolveCommand as p, collectEndpoints as r, getCommand as s, buildInputSchema as t, mergeCommands as u, resolveStdinAlways as v, REPL_SIGINT as y };
|
|
513
513
|
|
|
514
|
-
//# sourceMappingURL=commands-
|
|
514
|
+
//# sourceMappingURL=commands-DLR0rFgq.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands-B_gufyR9.mjs","names":[],"sources":["../src/core/runtime.ts","../src/core/default-runtime.ts","../src/core/commands.ts"],"sourcesContent":["import type { ColorConfig, ColorTheme } from '../output/colorizer.ts';\nimport type { HelpFormat } from '../output/formatter.ts';\n\n/** Process signals that Padrone can handle for graceful shutdown. */\nexport type PadroneSignal = 'SIGINT' | 'SIGTERM' | 'SIGHUP';\n\n/** Value accepted by `PadroneProgressIndicator.update()`. */\nexport type PadroneProgressUpdate = string | number | { message?: string; progress?: number; indeterminate?: boolean; time?: boolean };\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 /**\n * Update the indicator.\n * - `string` — update the displayed message.\n * - `number` — set progress ratio (0–1). Values outside this range are clamped.\n * - `{ message?, progress?, indeterminate? }` — update message, progress, or both.\n *\n * Set `indeterminate: true` to force the bar into indeterminate mode (shows animation, no percentage).\n * This makes the bar visible even in `show: 'auto'` mode without providing a number.\n * Omitting `progress` (or passing a string) leaves the bar in its current state.\n * Setting `progress` when bar mode is not enabled is a no-op for the bar portion.\n *\n * Set `time: true` to start the elapsed timer on demand (useful when `time` was not set in options).\n * Set `time: false` to hide the elapsed timer.\n */\n update: (value: PadroneProgressUpdate) => 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/** Controls when a progress element (spinner or bar) is visible. */\nexport type PadroneProgressShow = 'auto' | 'always' | 'never';\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 * - `true` — default spinner with `show: 'always'` (visible even alongside a bar).\n * - An object with custom `frames`, `interval`, and/or `show`.\n * - `false` to disable the spinner (`show: 'never'`).\n *\n * Default `show` is `'auto'`: visible when the bar is not shown.\n */\nexport type PadroneSpinnerConfig = PadroneSpinnerPreset | boolean | { frames?: string[]; interval?: number; show?: PadroneProgressShow };\n\n/**\n * Options passed to the runtime's `progress` factory.\n */\n/** Common fill/empty character pairs for progress bars. */\nexport type PadroneBarChar = '█' | '░' | '▓' | '▒' | '─' | '━' | '■' | '□' | '#' | '-' | '=' | '·' | '▰' | '▱' | (string & {});\n\n/**\n * Built-in indeterminate bar animation presets.\n * - `'bounce'` — a filled segment slides back and forth (default).\n * - `'slide'` — a filled segment slides left-to-right and wraps around.\n * - `'pulse'` — the entire bar fades in and out using gradient characters (`░▒▓█▓▒░`).\n */\nexport type PadroneBarAnimation = 'bounce' | 'slide' | 'pulse';\n\n/**\n * Progress bar configuration.\n */\nexport type PadroneBarConfig = {\n /** Total width of the bar in characters. Defaults to `20`. */\n width?: number;\n /** Character used for the filled portion of the bar. Defaults to `'█'`. */\n filled?: PadroneBarChar;\n /** Character used for the empty portion of the bar. Defaults to `'░'`. */\n empty?: PadroneBarChar;\n /** Indeterminate animation style. Defaults to `'bounce'`. */\n animation?: PadroneBarAnimation;\n /**\n * When the bar is visible. Defaults to `'always'` when bar is enabled, `'auto'` when bar is not explicitly configured.\n * - `'always'` — bar is always shown (indeterminate until a number is provided).\n * - `'auto'` — bar is shown only after `update()` is called with a number.\n * - `'never'` — bar is never shown.\n */\n show?: PadroneProgressShow;\n};\n\nexport type PadroneProgressOptions = {\n spinner?: PadroneSpinnerConfig;\n /** Enable a progress bar. `true` for defaults (`show: 'always'`), or a `PadroneBarConfig` object. `false` to disable entirely. When omitted, bar defaults to `show: 'auto'` (appears when a number is provided). */\n bar?: boolean | PadroneBarConfig;\n /** Show elapsed time since the indicator started. Defaults to `false`. */\n time?: boolean;\n /** Show estimated time remaining based on progress rate. Requires numeric `update()` calls. Defaults to `false`. */\n eta?: boolean;\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 /**\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 * 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 * Register a callback for process signals. Returns an unsubscribe function.\n * The default runtime wires this to `process.on('SIGINT' | 'SIGTERM' | 'SIGHUP')`.\n * Non-Node runtimes (web UIs, tests) can map their own cancellation semantics.\n *\n * When not provided, signal handling is disabled for this runtime.\n */\n onSignal?: (callback: (signal: PadroneSignal) => void) => () => void;\n\n /**\n * Terminal/output capabilities. Used for ANSI detection, text wrapping, and TTY checks.\n * The default runtime auto-detects from `process.stdout`. Non-terminal runtimes\n * (web UIs, tests) should provide explicit values.\n */\n terminal?: {\n /** Number of columns in the terminal. Used for text wrapping. */\n columns?: number;\n /** Whether stdout is a TTY. Affects ANSI color output and interactive features. */\n isTTY?: boolean;\n };\n\n /**\n * Force-exit the process. The default runtime wires this to `process.exit()`.\n * Non-Node runtimes can throw an error or no-op.\n */\n exit?: (code: number) => never;\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' | 'theme' | 'onSignal' | 'terminal' | 'exit'>\n> &\n Pick<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin' | 'theme' | 'onSignal' | 'terminal' | 'exit'>;\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\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","import { readStreamAsText } from '../util/stream.ts';\nimport type {\n InteractiveMode,\n InteractivePromptConfig,\n PadroneRuntime,\n PadroneSignal,\n ReplSessionConfig,\n ResolvedPadroneRuntime,\n} from './runtime.ts';\nimport { REPL_SIGINT } from './runtime.ts';\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\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 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 return readStreamAsText(process.stdin);\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\n/**\n * Default signal listener that wires to `process.on(signal)`.\n * Returns an unsubscribe function that removes all listeners.\n */\nfunction defaultOnSignal(callback: (signal: PadroneSignal) => void): () => void {\n if (typeof process === 'undefined') return () => {};\n const signals: PadroneSignal[] = ['SIGINT', 'SIGTERM', 'SIGHUP'];\n const handlers = new Map<PadroneSignal, () => void>();\n for (const sig of signals) {\n const handler = () => callback(sig);\n handlers.set(sig, handler);\n process.on(sig, handler);\n }\n return () => {\n for (const [sig, handler] of handlers) {\n process.removeListener(sig, handler);\n }\n };\n}\n\n/**\n * Creates the default Node.js/Bun runtime.\n */\nfunction defaultExit(code: number): never {\n if (typeof process !== 'undefined') process.exit(code);\n throw new Error(`Exit with code ${code}`);\n}\n\nfunction getTerminalInfo(): PadroneRuntime['terminal'] {\n if (typeof process === 'undefined') return undefined;\n return {\n get columns() {\n return process.stdout?.columns;\n },\n get isTTY() {\n return process.stdout?.isTTY === true;\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 prompt: defaultTerminalPrompt,\n interactive: detectInteractiveMode(),\n onSignal: defaultOnSignal,\n terminal: getTerminalInfo(),\n exit: defaultExit,\n };\n}\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\n/**\n * Merges a partial runtime with the default runtime.\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 interactive: partial.interactive ?? defaults.interactive,\n prompt: partial.prompt ?? defaults.prompt,\n readLine: partial.readLine ?? defaults.readLine,\n stdin: partial.stdin,\n theme: partial.theme,\n onSignal: partial.onSignal ?? defaults.onSignal,\n terminal: partial.terminal ?? defaults.terminal,\n exit: partial.exit ?? defaults.exit,\n };\n}\n","import type { AnyPadroneCommand } from '../types/index.ts';\nimport { extractSchemaMetadata, getJsonSchema } from './args.ts';\nimport { resolveRuntime } from './default-runtime.ts';\nimport type { ResolvedPadroneRuntime } from './runtime.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\nexport const commandSymbol = Symbol('padrone_command');\n\n/** Config keys that are merged when overriding a command. */\nexport const configKeys = ['title', 'description', 'version', 'deprecated', 'hidden', 'mutation', 'needsApproval'] 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.isAsync !== existing.isAsync) merged.isAsync = override.isAsync || existing.isAsync;\n if (override.runtime !== existing.runtime) merged.runtime = override.runtime;\n if (override.interceptors !== existing.interceptors) merged.interceptors = override.interceptors;\n if (override.aliases !== existing.aliases) merged.aliases = override.aliases;\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 * 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/**\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 = getJsonSchema(targetCommand.argsSchema) 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 close matches from a list of candidates using Levenshtein distance\n * and prefix/substring matching (for inputs longer than 3 characters).\n * Returns up to 3 matching candidate names (raw, unformatted).\n */\nexport function suggestSimilar(input: string, candidates: string[]): string[] {\n if (candidates.length === 0) return [];\n\n const lower = input.toLowerCase();\n const matches: { candidate: string; score: number }[] = [];\n\n for (const candidate of candidates) {\n const candidateLower = candidate.toLowerCase();\n if (candidateLower === lower) continue;\n\n const dist = levenshtein(lower, candidateLower);\n const maxLen = Math.max(input.length, candidate.length);\n const threshold = Math.min(3, Math.max(1, Math.ceil(maxLen * 0.4)));\n\n if (dist > 0 && dist <= threshold) {\n matches.push({ candidate, score: dist });\n } else if (lower.length >= 3) {\n // Prefix or substring match for longer inputs\n if (candidateLower.startsWith(lower) || candidateLower.includes(lower)) {\n matches.push({ candidate, score: threshold + 1 });\n }\n }\n }\n\n matches.sort((a, b) => a.score - b.score);\n return matches.slice(0, 3).map((m) => m.candidate);\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 getJsonSchema(cmd.argsSchema) 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":";;;;;;;;;;;;;;;;;;;AA6OA,MAAa,cAAc,OAAO,cAAc;;;;;;;AC9NhD,eAAe,sBAAsB,QAAmD;CACtF,MAAM,YAAY,MAAM,OAAO,aAAa;CAE5C,MAAM,WAAoC;EACxC,MAAM,OAAO;EACb,MAAM,OAAO;EACb,SAAS,OAAO;EACjB;AAED,KAAI,OAAO,YAAY,KAAA,EACrB,UAAS,UAAU,OAAO;AAG5B,KAAI,OAAO,QACT,UAAS,UAAU,OAAO,QAAQ,KAAK,OAAO;EAC5C,MAAM,OAAO,EAAE,MAAM;EACrB,SAAS,EAAE;EACZ,EAAE;AAIL,SADkB,MAAM,SAAS,OAAO,SAAgB,EACxC,OAAO;;AAGzB,SAAgB,0BAA0B,QAA2B;CAInE,IAAI,UAAoB,OAAO,UAAU,CAAC,GAAG,OAAO,QAAQ,GAAG,EAAE;CACjE,IAAI,mBAAmB,OAAO;AAE9B,QAAO;EAEL,IAAI,UAAU,IAAwD;AACpE,sBAAmB;;EAErB,MAAM,SAAS,QAA6D;GAC1E,MAAM,EAAE,oBAAoB,MAAM,OAAO;GACzC,MAAM,OAAgC;IACpC,OAAO,QAAQ;IACf,QAAQ,QAAQ;IAChB,UAAU;IACV,SAAS,CAAC,GAAG,QAAQ;IACrB,aAAa,KAAK,IAAI,QAAQ,QAAQ,IAAK;IAC5C;AACD,OAAI,iBACF,MAAK,YAAY;GAEnB,MAAM,KAAK,gBAAgB,KAAY;AAEvC,UAAO,IAAI,SAAS,YAAY;IAC9B,IAAI,WAAW;IACf,MAAM,UAAU,UAA8C;AAC5D,SAAI,SAAU;AACd,gBAAW;AACX,QAAG,OAAO;AACV,aAAQ,MAAM;;AAGhB,OAAG,SAAS,SAAS,WAAW;AAE9B,SAAI,MAAM,QAAS,GAAW,QAAQ,CAAE,WAAU,CAAC,GAAI,GAAW,QAAQ;AAC1E,YAAO,OAAO;MACd;AAEF,OAAG,KAAK,gBAAgB;AACtB,aAAQ,OAAO,MAAM,KAAK;AAC1B,YAAO,YAAY;MACnB;AAEF,OAAG,KAAK,eAAe;AAErB,aAAQ,OAAO,MAAM,KAAK;AAC1B,YAAO,KAAK;MACZ;KACF;;EAEJ,QAAQ;EAGT;;;;;;AAOH,SAAS,wBAAyC;AAChD,KAAI,OAAO,YAAY,YAAa,QAAO;AAC3C,KAAI,QAAQ,IAAI,MAAM,QAAQ,IAAI,uBAAwB,QAAO;AACjE,KAAI,CAAC,QAAQ,QAAQ,MAAO,QAAO;AACnC,QAAO;;;;;;AAOT,SAAS,qBAA2D;AAClE,QAAO;EACL,IAAI,QAAQ;AAGV,OAAI,OAAO,YAAY,YAAa,QAAO;AAC3C,UAAO,QAAQ,OAAO,UAAU;;EAElC,MAAM,OAAO;AACX,OAAI,OAAO,YAAY,YAAa,QAAO;AAC3C,UAAO,iBAAiB,QAAQ,MAAM;;EAExC,OAAO,QAAQ;AACb,OAAI,OAAO,YAAY,YAAa;GACpC,MAAM,EAAE,oBAAoB,MAAM,OAAO;GACzC,MAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,CAAC;AACpD,OAAI;AACF,eAAW,MAAM,QAAQ,GACvB,OAAM;aAEA;AACR,OAAG,OAAO;;;EAGf;;;;;;AAOH,SAAS,gBAAgB,UAAuD;AAC9E,KAAI,OAAO,YAAY,YAAa,cAAa;CACjD,MAAM,UAA2B;EAAC;EAAU;EAAW;EAAS;CAChE,MAAM,2BAAW,IAAI,KAAgC;AACrD,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,gBAAgB,SAAS,IAAI;AACnC,WAAS,IAAI,KAAK,QAAQ;AAC1B,UAAQ,GAAG,KAAK,QAAQ;;AAE1B,cAAa;AACX,OAAK,MAAM,CAAC,KAAK,YAAY,SAC3B,SAAQ,eAAe,KAAK,QAAQ;;;;;;AAQ1C,SAAS,YAAY,MAAqB;AACxC,KAAI,OAAO,YAAY,YAAa,SAAQ,KAAK,KAAK;AACtD,OAAM,IAAI,MAAM,kBAAkB,OAAO;;AAG3C,SAAS,kBAA8C;AACrD,KAAI,OAAO,YAAY,YAAa,QAAO,KAAA;AAC3C,QAAO;EACL,IAAI,UAAU;AACZ,UAAO,QAAQ,QAAQ;;EAEzB,IAAI,QAAQ;AACV,UAAO,QAAQ,QAAQ,UAAU;;EAEpC;;AAGH,SAAgB,uBAA+C;AAC7D,QAAO;EACL,SAAS,GAAG,SAAS,QAAQ,IAAI,GAAG,KAAK;EACzC,QAAQ,SAAS,QAAQ,MAAM,KAAK;EACpC,YAAa,OAAO,YAAY,cAAc,QAAQ,KAAK,MAAM,EAAE,GAAG,EAAE;EACxE,WAAY,OAAO,YAAY,cAAe,QAAQ,MAA6C,EAAE;EACrG,QAAQ;EACR,QAAQ;EACR,aAAa,uBAAuB;EACpC,UAAU;EACV,UAAU,iBAAiB;EAC3B,MAAM;EACP;;;;;;AAOH,SAAgB,aAAa,SAA4E;AACvG,KAAI,SAAS,MAAO,QAAO,QAAQ;CACnC,MAAM,eAAe,oBAAoB;AAGzC,KAAI,aAAa,MAAO,QAAO,KAAA;AAC/B,QAAO;;;;;;AAOT,SAAgB,mBAAmB,SAAgE;AACjG,KAAI,SAAS,MAAO,QAAO,QAAQ;AACnC,QAAO,oBAAoB;;;;;AAM7B,SAAgB,eAAe,SAAkD;CAC/E,MAAM,WAAW,sBAAsB;AACvC,KAAI,CAAC,QAAS,QAAO;AACrB,QAAO;EACL,QAAQ,QAAQ,UAAU,SAAS;EACnC,OAAO,QAAQ,SAAS,SAAS;EACjC,MAAM,QAAQ,QAAQ,SAAS;EAC/B,KAAK,QAAQ,OAAO,SAAS;EAC7B,QAAQ,QAAQ,UAAU,SAAS;EACnC,aAAa,QAAQ,eAAe,SAAS;EAC7C,QAAQ,QAAQ,UAAU,SAAS;EACnC,UAAU,QAAQ,YAAY,SAAS;EACvC,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,UAAU,QAAQ,YAAY,SAAS;EACvC,UAAU,QAAQ,YAAY,SAAS;EACvC,MAAM,QAAQ,QAAQ,SAAS;EAChC;;;;;;;;;;;;;;;;;;;;;ACpOH,MAAa,eAAe,OAAO,eAAe;;AAGlD,SAAgB,eAAe,KAA2C;CACxE,MAAM,WAAY,IAAY;AAC9B,KAAI,UAAU;AACZ,SAAQ,IAAY;AACpB,WAAS,IAAI;;AAEf,QAAO;;;AAIT,SAAgB,mBAAmB,KAA8B;AAC/D,gBAAe,IAAI;AACnB,KAAI,IAAI,SACN,MAAK,MAAM,OAAO,IAAI,SAAU,oBAAmB,IAAI;;;AAU3D,SAAgB,WAAW,SAAoC;CAC7D,MAAM,MAAM,iBAAiB,UAAY,QAAgB,iBAAwC;AACjG,oBAAmB,IAAI;AACvB,QAAO;;AAGT,MAAa,gBAAgB,OAAO,kBAAkB;;AAGtD,MAAa,aAAa;CAAC;CAAS;CAAe;CAAW;CAAc;CAAU;CAAY;CAAgB;;;;;;;AAQlH,SAAgB,cAAc,UAA6B,UAAgD;AACzG,gBAAe,SAAS;AACxB,gBAAe,SAAS;CACxB,MAAM,SAA4B,EAAE,GAAG,UAAU;AAGjD,MAAK,MAAM,OAAO,WAChB,KAAI,SAAS,SAAS,KAAA,EAAY,QAAe,OAAO,SAAS;AAInE,KAAI,SAAS,WAAW,SAAS,OAAQ,QAAO,SAAS,SAAS;AAClE,KAAI,SAAS,eAAe,SAAS,WAAY,QAAO,aAAa,SAAS;AAC9E,KAAI,SAAS,SAAS,SAAS,KAAM,QAAO,OAAO,SAAS;AAC5D,KAAI,SAAS,YAAY,SAAS,QAAS,QAAO,UAAU,SAAS,WAAW,SAAS;AACzF,KAAI,SAAS,YAAY,SAAS,QAAS,QAAO,UAAU,SAAS;AACrE,KAAI,SAAS,iBAAiB,SAAS,aAAc,QAAO,eAAe,SAAS;AACpF,KAAI,SAAS,YAAY,SAAS,QAAS,QAAO,UAAU,SAAS;AAErE,KAAI,SAAS,UAAU;EACrB,MAAM,eAAe,CAAC,GAAI,SAAS,YAAY,EAAE,CAAE;AACnD,OAAK,MAAM,iBAAiB,SAAS,UAAU;GAC7C,MAAM,gBAAgB,aAAa,WAAW,MAAM,EAAE,SAAS,cAAc,KAAK;AAClF,OAAI,iBAAiB,EACnB,cAAa,iBAAiB,cAAc,aAAa,gBAAiB,cAAc;OAExF,cAAa,KAAK,cAAc;;AAGpC,SAAO,WAAW;;AAGpB,QAAO;;;;;;AAOT,SAAgB,kBAAkB,KAAgD;CAChF,IAAI,UAAyC;AAC7C,QAAO,SAAS;AACd,MAAI,QAAQ,QAAS,QAAO,eAAe,QAAQ,QAAQ;AAC3D,YAAU,QAAQ;;AAEpB,QAAO,gBAAgB;;;;;AAMzB,SAAgB,kBACd,KACA,SACA,YACA,QACmB;AACnB,gBAAe,IAAI;CACnB,MAAM,UAAU,aAAa,GAAG,WAAW,GAAG,YAAY;CAC1D,MAAM,YAA+B;EACnC,GAAG;EACH,MAAM;EACN,MAAM;EACN;EACA,SAAS,KAAA;EACV;AAED,KAAI,IAAI,UAAU,OAChB,WAAU,WAAW,IAAI,SAAS,KAAK,UAAU,kBAAkB,OAAO,MAAM,MAAM,SAAS,UAAU,CAAC;AAG5G,QAAO;;;;;;;AAQT,SAAgB,mBACd,aACA,UAGsC;AACtC,oBAAmB,YAAY;AAC/B,SAAQ,SAAqC;EAE3C,MAAM,QADU,KAAK,WAAW,CACV,MAAM,MAAM;EAClC,MAAM,WAAW,MAAM,MAAM,SAAS,MAAM;AAG5C,MAAI,SAAS,WAAW,IAAI,EAAE;GAC5B,MAAM,UAAU;IAAC;IAAS;IAAU;IAAS;IAAW;AACxD,OAAI,YAAY,UAAU,MAAM,MAAM,EAAE,UAAU,OAAO,IAAI,SAAS,QAAS,SAAQ,KAAK,SAAS;GACrG,MAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;AAC1D,UAAO,CAAC,KAAK,SAAS,OAAO,SAAS,SAAS;;AAIjD,MAAI,SAAS,WAAW,IAAI,EAAE;GAE5B,MAAM,eAAe,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC;GACzE,IAAI,gBAAgB;AACpB,QAAK,MAAM,QAAQ,cAAc;AAC/B,mBAAe,cAAc;IAC7B,MAAM,MAAM,cAAc,UAAU,MAAM,MAAM,EAAE,SAAS,QAAQ,EAAE,SAAS,SAAS,KAAK,CAAC;AAC7F,QAAI,KAAK;AACP,oBAAe,IAAI;AACnB,qBAAgB;UACX;;GAIT,MAAM,UAAoB,EAAE;AAC5B,OAAI,cAAc,WAChB,KAAI;IACF,MAAM,WAAW,cAAc,MAAM;IACrC,MAAM,EAAE,OAAO,YAAY,sBAAsB,cAAc,YAAY,UAAU,cAAc,MAAM,UAAU;IACnH,MAAM,aAAa,cAAc,cAAc,WAAW;AAC1D,QAAI,WAAW,SAAS,YAAY,WAAW,YAAY;AACzD,UAAK,MAAM,OAAO,OAAO,KAAK,WAAW,WAAW,CAClD,SAAQ,KAAK,KAAK,MAAM;AAE1B,UAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,CACnC,SAAQ,KAAK,IAAI,OAAO;AAE1B,UAAK,MAAM,SAAS,OAAO,KAAK,QAAQ,CACtC,SAAQ,KAAK,KAAK,QAAQ;;WAGxB;AAKV,WAAQ,KAAK,UAAU,KAAK;GAE5B,MAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;AAC1D,UAAO,CAAC,KAAK,SAAS,OAAO,SAAS,SAAS;;EAIjD,MAAM,eAAe,MAAM,QAAQ,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC;EAE5D,IAAI,gBAAgB;AACpB,OAAK,IAAI,IAAI,GAAG,IAAI,aAAa,SAAS,GAAG,KAAK;AAChD,kBAAe,cAAc;GAC7B,MAAM,MAAM,cAAc,UAAU,MAAM,MAAM,EAAE,SAAS,aAAa,MAAM,EAAE,SAAS,SAAS,aAAa,GAAI,CAAC;AACpH,OAAI,KAAK;AACP,mBAAe,IAAI;AACnB,oBAAgB;SACX;;EAGT,MAAM,aAAuB,EAAE;AAG/B,MAAI,cAAc;QACX,MAAM,OAAO,cAAc,SAC9B,KAAI,CAAC,IAAI,QAAQ;AACf,eAAW,KAAK,IAAI,KAAK;AACzB,QAAI,IAAI,QAAS,YAAW,KAAK,GAAG,IAAI,QAAQ;;;AAMtD,MAAI,kBAAkB,aAAa;AACjC,cAAW,KAAK,SAAS,SAAS,UAAU,WAAW;AACvD,OAAI,YAAY,UAAU,MAAM,MAAM,EAAE,UAAU,OAAO,IAAI,SAAS,QAAS,YAAW,KAAK,SAAS;AACxG,OAAI,SAAS,QAAS,YAAW,KAAK,KAAK;;EAG7C,MAAM,OAAO,WAAW,QAAQ,MAAM,EAAE,WAAW,SAAS,CAAC;AAC7D,SAAO,CAAC,KAAK,SAAS,OAAO,YAAY,SAAS;;;;;;AAOtD,SAAS,YAAY,GAAW,GAAmB;CACjD,MAAM,IAAI,EAAE;CACZ,MAAM,IAAI,EAAE;CACZ,MAAM,KAAe,MAAM,KAAK,EAAE,QAAQ,IAAI,GAAG,GAAG,GAAG,MAAM,EAAE;AAE/D,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC3B,IAAI,OAAO,GAAG;AACd,KAAG,KAAK;AACR,OAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;GAC3B,MAAM,OAAO,GAAG;AAChB,MAAG,KAAK,EAAE,IAAI,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI,KAAK,IAAI,MAAM,GAAG,IAAK,GAAG,IAAI,GAAI;AAC7E,UAAO;;;AAIX,QAAO,GAAG;;;;;;;AAQZ,SAAgB,eAAe,OAAe,YAAgC;AAC5E,KAAI,WAAW,WAAW,EAAG,QAAO,EAAE;CAEtC,MAAM,QAAQ,MAAM,aAAa;CACjC,MAAM,UAAkD,EAAE;AAE1D,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,iBAAiB,UAAU,aAAa;AAC9C,MAAI,mBAAmB,MAAO;EAE9B,MAAM,OAAO,YAAY,OAAO,eAAe;EAC/C,MAAM,SAAS,KAAK,IAAI,MAAM,QAAQ,UAAU,OAAO;EACvD,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,KAAK,SAAS,GAAI,CAAC,CAAC;AAEnE,MAAI,OAAO,KAAK,QAAQ,UACtB,SAAQ,KAAK;GAAE;GAAW,OAAO;GAAM,CAAC;WAC/B,MAAM,UAAU;OAErB,eAAe,WAAW,MAAM,IAAI,eAAe,SAAS,MAAM,CACpE,SAAQ,KAAK;IAAE;IAAW,OAAO,YAAY;IAAG,CAAC;;;AAKvD,SAAQ,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AACzC,QAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM,EAAE,UAAU;;AAGpD,SAAgB,kBAAkB,MAAc,UAA+D;AAC7G,KAAI,CAAC,SAAU,QAAO,KAAA;CAEtB,MAAM,cAAc,SAAS,MAAM,QAAQ,IAAI,SAAS,KAAK;AAC7D,KAAI,YAAa,QAAO,eAAe,YAAY;CAGnD,MAAM,eAAe,SAAS,MAAM,QAAQ,IAAI,SAAS,SAAS,KAAK,CAAC;AACxE,KAAI,aAAc,QAAO,eAAe,aAAa;AAErD,MAAK,MAAM,OAAO,UAAU;AAC1B,MAAI,KAAK,WAAW,GAAG,IAAI,KAAK,GAAG,EAAE;AACnC,kBAAe,IAAI;AACnB,OAAI,IAAI,UAAU;IAEhB,MAAM,aAAa,kBADI,KAAK,MAAM,IAAI,KAAK,SAAS,EAAE,EACD,IAAI,SAAS;AAClE,QAAI,WAAY,QAAO;;;AAI3B,MAAI,IAAI;QACD,MAAM,SAAS,IAAI,QACtB,KAAI,KAAK,WAAW,GAAG,MAAM,GAAG,EAAE;AAChC,mBAAe,IAAI;AACnB,QAAI,IAAI,UAAU;KAEhB,MAAM,aAAa,kBADI,KAAK,MAAM,MAAM,SAAS,EAAE,EACE,IAAI,SAAS;AAClE,SAAI,WAAY,QAAO;;;;;;;AAgBnC,SAAgB,iBAAiB,UAA2C,QAAqC;AAC/G,KAAI,CAAC,SAAU,QAAO,EAAE;CACxB,MAAM,YAAiC,EAAE;AACzC,MAAK,MAAM,OAAO,UAAU;AAC1B,iBAAe,IAAI;AACnB,MAAI,IAAI,OAAQ;EAChB,MAAM,OAAO,IAAI,OAAQ,SAAS,GAAG,OAAO,GAAG,IAAI,SAAS,IAAI,OAAQ;AACxE,MAAI,IAAI,UAAU,IAAI,WACpB,WAAU,KAAK;GAAE,MAAM;GAAM,SAAS;GAAK,CAAC;AAE9C,MAAI,IAAI,UAAU,OAChB,WAAU,KAAK,GAAG,iBAAiB,IAAI,UAAU,KAAK,CAAC;;AAG3D,QAAO;;;AAIT,SAAgB,iBAAiB,KAAiD;AAChF,KAAI,CAAC,IAAI,WACP,QAAO;EAAE,MAAM;EAAU,sBAAsB;EAAO;AAExD,KAAI;AACF,SAAO,cAAc,IAAI,WAAW;SAC9B;AACN,SAAO;GAAE,MAAM;GAAU,sBAAsB;GAAO;;;;AAK1D,SAAgB,qBAAqB,MAAyC;CAC5E,MAAM,QAAkB,EAAE;AAC1B,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,EAAE;AAC/C,MAAI,UAAU,KAAA,EAAW;AACzB,MAAI,OAAO,UAAU,UACnB,OAAM,KAAK,QAAQ,KAAK,QAAQ,QAAQ,MAAM;WACrC,MAAM,QAAQ,MAAM,CAC7B,MAAK,MAAM,KAAK,MAAO,OAAM,KAAK,KAAK,IAAI,GAAG,OAAO,EAAE,GAAG;OACrD;GACL,MAAM,SAAS,OAAO,MAAM;AAC5B,SAAM,KAAK,OAAO,SAAS,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,IAAI,GAAG,SAAS;;;AAGpF,QAAO"}
|
|
1
|
+
{"version":3,"file":"commands-DLR0rFgq.mjs","names":[],"sources":["../src/core/runtime.ts","../src/core/default-runtime.ts","../src/core/commands.ts"],"sourcesContent":["import type { ColorConfig, ColorTheme } from '../output/colorizer.ts';\nimport type { HelpFormat } from '../output/formatter.ts';\n\n/** Process signals that Padrone can handle for graceful shutdown. */\nexport type PadroneSignal = 'SIGINT' | 'SIGTERM' | 'SIGHUP';\n\n/** Value accepted by `PadroneProgressIndicator.update()`. */\nexport type PadroneProgressUpdate = string | number | { message?: string; progress?: number; indeterminate?: boolean; time?: boolean };\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 /**\n * Update the indicator.\n * - `string` — update the displayed message.\n * - `number` — set progress ratio (0–1). Values outside this range are clamped.\n * - `{ message?, progress?, indeterminate? }` — update message, progress, or both.\n *\n * Set `indeterminate: true` to force the bar into indeterminate mode (shows animation, no percentage).\n * This makes the bar visible even in `show: 'auto'` mode without providing a number.\n * Omitting `progress` (or passing a string) leaves the bar in its current state.\n * Setting `progress` when bar mode is not enabled is a no-op for the bar portion.\n *\n * Set `time: true` to start the elapsed timer on demand (useful when `time` was not set in options).\n * Set `time: false` to hide the elapsed timer.\n */\n update: (value: PadroneProgressUpdate) => 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/** Controls when a progress element (spinner or bar) is visible. */\nexport type PadroneProgressShow = 'auto' | 'always' | 'never';\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 * - `true` — default spinner with `show: 'always'` (visible even alongside a bar).\n * - An object with custom `frames`, `interval`, and/or `show`.\n * - `false` to disable the spinner (`show: 'never'`).\n *\n * Default `show` is `'auto'`: visible when the bar is not shown.\n */\nexport type PadroneSpinnerConfig = PadroneSpinnerPreset | boolean | { frames?: string[]; interval?: number; show?: PadroneProgressShow };\n\n/**\n * Options passed to the runtime's `progress` factory.\n */\n/** Common fill/empty character pairs for progress bars. */\nexport type PadroneBarChar = '█' | '░' | '▓' | '▒' | '─' | '━' | '■' | '□' | '#' | '-' | '=' | '·' | '▰' | '▱' | (string & {});\n\n/**\n * Built-in indeterminate bar animation presets.\n * - `'bounce'` — a filled segment slides back and forth (default).\n * - `'slide'` — a filled segment slides left-to-right and wraps around.\n * - `'pulse'` — the entire bar fades in and out using gradient characters (`░▒▓█▓▒░`).\n */\nexport type PadroneBarAnimation = 'bounce' | 'slide' | 'pulse';\n\n/**\n * Progress bar configuration.\n */\nexport type PadroneBarConfig = {\n /** Total width of the bar in characters. Defaults to `20`. */\n width?: number;\n /** Character used for the filled portion of the bar. Defaults to `'█'`. */\n filled?: PadroneBarChar;\n /** Character used for the empty portion of the bar. Defaults to `'░'`. */\n empty?: PadroneBarChar;\n /** Indeterminate animation style. Defaults to `'bounce'`. */\n animation?: PadroneBarAnimation;\n /**\n * When the bar is visible. Defaults to `'always'` when bar is enabled, `'auto'` when bar is not explicitly configured.\n * - `'always'` — bar is always shown (indeterminate until a number is provided).\n * - `'auto'` — bar is shown only after `update()` is called with a number.\n * - `'never'` — bar is never shown.\n */\n show?: PadroneProgressShow;\n};\n\nexport type PadroneProgressOptions = {\n spinner?: PadroneSpinnerConfig;\n /** Enable a progress bar. `true` for defaults (`show: 'always'`), or a `PadroneBarConfig` object. `false` to disable entirely. When omitted, bar defaults to `show: 'auto'` (appears when a number is provided). */\n bar?: boolean | PadroneBarConfig;\n /** Show elapsed time since the indicator started. Defaults to `false`. */\n time?: boolean;\n /** Show estimated time remaining based on progress rate. Requires numeric `update()` calls. Defaults to `false`. */\n eta?: boolean;\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 /**\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 * 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 * Register a callback for process signals. Returns an unsubscribe function.\n * The default runtime wires this to `process.on('SIGINT' | 'SIGTERM' | 'SIGHUP')`.\n * Non-Node runtimes (web UIs, tests) can map their own cancellation semantics.\n *\n * When not provided, signal handling is disabled for this runtime.\n */\n onSignal?: (callback: (signal: PadroneSignal) => void) => () => void;\n\n /**\n * Terminal/output capabilities. Used for ANSI detection, text wrapping, and TTY checks.\n * The default runtime auto-detects from `process.stdout`. Non-terminal runtimes\n * (web UIs, tests) should provide explicit values.\n */\n terminal?: {\n /** Number of columns in the terminal. Used for text wrapping. */\n columns?: number;\n /** Whether stdout is a TTY. Affects ANSI color output and interactive features. */\n isTTY?: boolean;\n };\n\n /**\n * Force-exit the process. The default runtime wires this to `process.exit()`.\n * Non-Node runtimes can throw an error or no-op.\n */\n exit?: (code: number) => never;\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' | 'theme' | 'onSignal' | 'terminal' | 'exit'>\n> &\n Pick<PadroneRuntime, 'prompt' | 'interactive' | 'readLine' | 'stdin' | 'theme' | 'onSignal' | 'terminal' | 'exit'>;\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\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","import { readStreamAsText } from '../util/stream.ts';\nimport type {\n InteractiveMode,\n InteractivePromptConfig,\n PadroneRuntime,\n PadroneSignal,\n ReplSessionConfig,\n ResolvedPadroneRuntime,\n} from './runtime.ts';\nimport { REPL_SIGINT } from './runtime.ts';\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\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 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 return readStreamAsText(process.stdin);\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\n/**\n * Default signal listener that wires to `process.on(signal)`.\n * Returns an unsubscribe function that removes all listeners.\n */\nfunction defaultOnSignal(callback: (signal: PadroneSignal) => void): () => void {\n if (typeof process === 'undefined') return () => {};\n const signals: PadroneSignal[] = ['SIGINT', 'SIGTERM', 'SIGHUP'];\n const handlers = new Map<PadroneSignal, () => void>();\n for (const sig of signals) {\n const handler = () => callback(sig);\n handlers.set(sig, handler);\n process.on(sig, handler);\n }\n return () => {\n for (const [sig, handler] of handlers) {\n process.removeListener(sig, handler);\n }\n };\n}\n\n/**\n * Creates the default Node.js/Bun runtime.\n */\nfunction defaultExit(code: number): never {\n if (typeof process !== 'undefined') process.exit(code);\n throw new Error(`Exit with code ${code}`);\n}\n\nfunction getTerminalInfo(): PadroneRuntime['terminal'] {\n if (typeof process === 'undefined') return undefined;\n return {\n get columns() {\n return process.stdout?.columns;\n },\n get isTTY() {\n return process.stdout?.isTTY === true;\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 prompt: defaultTerminalPrompt,\n interactive: detectInteractiveMode(),\n onSignal: defaultOnSignal,\n terminal: getTerminalInfo(),\n exit: defaultExit,\n };\n}\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\n/**\n * Merges a partial runtime with the default runtime.\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 interactive: partial.interactive ?? defaults.interactive,\n prompt: partial.prompt ?? defaults.prompt,\n readLine: partial.readLine ?? defaults.readLine,\n stdin: partial.stdin,\n theme: partial.theme,\n onSignal: partial.onSignal ?? defaults.onSignal,\n terminal: partial.terminal ?? defaults.terminal,\n exit: partial.exit ?? defaults.exit,\n };\n}\n","import type { AnyPadroneCommand } from '../types/index.ts';\nimport { extractSchemaMetadata, getJsonSchema } from './args.ts';\nimport { resolveRuntime } from './default-runtime.ts';\nimport type { ResolvedPadroneRuntime } from './runtime.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\nexport const commandSymbol = Symbol('padrone_command');\n\n/** Config keys that are merged when overriding a command. */\nexport const configKeys = ['title', 'description', 'version', 'deprecated', 'hidden', 'mutation', 'needsApproval'] 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.isAsync !== existing.isAsync) merged.isAsync = override.isAsync || existing.isAsync;\n if (override.runtime !== existing.runtime) merged.runtime = override.runtime;\n if (override.interceptors !== existing.interceptors) merged.interceptors = override.interceptors;\n if (override.aliases !== existing.aliases) merged.aliases = override.aliases;\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 * 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/**\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 = getJsonSchema(targetCommand.argsSchema) 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 close matches from a list of candidates using Levenshtein distance\n * and prefix/substring matching (for inputs longer than 3 characters).\n * Returns up to 3 matching candidate names (raw, unformatted).\n */\nexport function suggestSimilar(input: string, candidates: string[]): string[] {\n if (candidates.length === 0) return [];\n\n const lower = input.toLowerCase();\n const matches: { candidate: string; score: number }[] = [];\n\n for (const candidate of candidates) {\n const candidateLower = candidate.toLowerCase();\n if (candidateLower === lower) continue;\n\n const dist = levenshtein(lower, candidateLower);\n const maxLen = Math.max(input.length, candidate.length);\n const threshold = Math.min(3, Math.max(1, Math.ceil(maxLen * 0.4)));\n\n if (dist > 0 && dist <= threshold) {\n matches.push({ candidate, score: dist });\n } else if (lower.length >= 3) {\n // Prefix or substring match for longer inputs\n if (candidateLower.startsWith(lower) || candidateLower.includes(lower)) {\n matches.push({ candidate, score: threshold + 1 });\n }\n }\n }\n\n matches.sort((a, b) => a.score - b.score);\n return matches.slice(0, 3).map((m) => m.candidate);\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 getJsonSchema(cmd.argsSchema) 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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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getJsonSchema, d as detectShell, i as extractSchemaMetadata, m as writeToRcFile, p as getRcFile } from "./args-
|
|
1
|
+
import { a as getJsonSchema, d as detectShell, i as extractSchemaMetadata, m as writeToRcFile, p as getRcFile } from "./args-DrCXxXeP.mjs";
|
|
2
2
|
//#region src/feature/completion.ts
|
|
3
3
|
/**
|
|
4
4
|
* Collects all commands from a program recursively.
|
|
@@ -392,4 +392,4 @@ function buildSetupSnippet(programName, shell, beginMarker, endMarker) {
|
|
|
392
392
|
//#endregion
|
|
393
393
|
export { detectShell, generateCompletionOutput, setupCompletions };
|
|
394
394
|
|
|
395
|
-
//# sourceMappingURL=completion-
|
|
395
|
+
//# sourceMappingURL=completion-UnBKfGuk.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completion-BEuflbDO.mjs","names":[],"sources":["../src/feature/completion.ts"],"sourcesContent":["import { extractSchemaMetadata, getJsonSchema } from '../core/args.ts';\nimport type { AnyPadroneCommand } from '../types/index.ts';\nimport { detectShell, getRcFile, type ShellType, writeToRcFile } from '../util/shell-utils.ts';\n\nexport { detectShell, escapeRegExp, getRcFile, type ShellType, writeToRcFile } from '../util/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 = getJsonSchema(cmd.argsSchema) 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 async function generateCompletionOutput(program: AnyPadroneCommand, shell?: ShellType): Promise<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 = await 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 async function setupCompletions(programName: string, shell: ShellType): Promise<SetupCompletionsResult> {\n const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { homedir } = await 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 = await 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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"}
|
|
1
|
+
{"version":3,"file":"completion-UnBKfGuk.mjs","names":[],"sources":["../src/feature/completion.ts"],"sourcesContent":["import { extractSchemaMetadata, getJsonSchema } from '../core/args.ts';\nimport type { AnyPadroneCommand } from '../types/index.ts';\nimport { detectShell, getRcFile, type ShellType, writeToRcFile } from '../util/shell-utils.ts';\n\nexport { detectShell, escapeRegExp, getRcFile, type ShellType, writeToRcFile } from '../util/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 = getJsonSchema(cmd.argsSchema) 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 async function generateCompletionOutput(program: AnyPadroneCommand, shell?: ShellType): Promise<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 = await 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 async function setupCompletions(programName: string, shell: ShellType): Promise<SetupCompletionsResult> {\n const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { homedir } = await 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 = await 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":";;;;;AASA,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;;;;;AAcT,SAAS,iBAAiB,KAAwC;CAChE,MAAM,UAA0B,EAAE;AAElC,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,aAAqC,EAAE;AAC7C,OAAK,MAAM,CAAC,WAAW,YAAY,OAAO,QAAQ,QAAQ,CACxD,KAAI,CAAC,WAAW,SAAU,YAAW,WAAW;EAGlD,MAAM,aAAa,cAAc,IAAI,WAAW;AAEhD,MAAI,WAAW,SAAS,YAAY,WAAW,WAC7C,MAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,WAAW,WAAkC,EAAE;GACtF,MAAM,aAAc,KAAK,QAAQ,KAAK,OAAO;GAC7C,MAAM,UAAU,WAAW;AAC3B,WAAQ,KAAK;IACX,MAAM;IACN,OAAO,WAAW;IAClB,WAAW,MAAM,SAAS;IAC1B,MAAM;IACN,aAAa,SAAS,eAAe,KAAK;IAC3C,CAAC;;SAGA;AAIR,QAAO;;;;;AAMT,SAAS,kBAAkB,SAA4B,UAA0D;CAC/G,MAAM,uBAAO,IAAI,KAA2B;AAE5C,MAAK,MAAM,OAAO,CAAC,SAAS,GAAG,SAAS,CACtC,MAAK,MAAM,OAAO,iBAAiB,IAAI,CACrC,KAAI,CAAC,KAAK,IAAI,IAAI,KAAK,CACrB,MAAK,IAAI,IAAI,MAAM,IAAI;AAK7B,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;CAC1D,MAAM,aAAa,kBAAkB,SAAS,SAAS;CAGvD,MAAM,+BAAe,IAAI,KAAa;AACtC,cAAa,IAAI,SAAS;AAC1B,cAAa,IAAI,YAAY;AAE7B,MAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,eAAa,IAAI,KAAK,IAAI,OAAO;AACjC,MAAI,IAAI,MAAO,cAAa,IAAI,KAAK,IAAI,QAAQ;;CAGnD,MAAM,WAAW,MAAM,KAAK,aAAa,CAAC,KAAK,IAAI;CAGnD,MAAM,YAAsB,EAAE;AAC9B,MAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,MAAI,CAAC,IAAI,QAAQ,IAAI,KAAK,WAAW,EAAG;EACxC,MAAM,SAAS,IAAI,KAAK,KAAK,IAAI;EACjC,MAAM,WAAW,CAAC,KAAK,IAAI,OAAO;AAClC,MAAI,IAAI,MAAO,UAAS,KAAK,KAAK,IAAI,QAAQ;AAC9C,YAAU,KAAK,SAAS,SAAS,KAAK,IAAI,CAAC,6BAA6B,OAAO,4BAA4B;;AAc7G,QAAO,aAAa,YAAY;;IAE9B,YAAY;;kBAEE,YAAY;eACf,YAAY,iDAAiD,YAAY;;;;KAInF,YAAY;;;;;;;;;;;;sBAYK,aAAa;kBACjB,SAAS;EAhCvB,UAAU,SAAS,IACf;;;EAGN,UAAU,KAAK,KAAK,CAAC;;;IAIf,KAyBI;;;;;;;;;sDAS0C,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,aAAa,kBAAkB,SAAS,SAAS;AAEvD,MAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;EAErC,MAAM,eADO,IAAI,eAAe,IACP,QAAQ,MAAM,QAAQ,CAAC,QAAQ,OAAO,MAAM,CAAC,QAAQ,OAAO,MAAM;EAG3F,MAAM,cAAc,IAAI,MAAM,SAAS,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;AAEtE,MAAI,IAAI,MACN,qBAAoB,KAAK,YAAY,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,YAAY,GAAG,YAAY,GAAG;MAEhG,qBAAoB,KAAK,YAAY,IAAI,KAAK,GAAG,YAAY,GAAG,YAAY,GAAG;;AAInF,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,aAAa,kBAAkB,SAAS,SAAS;AAEvD,MAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;EAErC,MAAM,eADO,IAAI,eAAe,IACP,QAAQ,MAAM,MAAM;EAE7C,MAAM,YAAY,IAAI,MAAM,SAAS,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK;AAEtE,MAAI,IAAI,MACN,OAAM,KAAK,eAAe,YAAY,MAAM,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,YAAY,GAAG,YAAY;MAEvG,OAAM,KAAK,eAAe,YAAY,MAAM,IAAI,KAAK,OAAO,YAAY,GAAG,YAAY;;AAI3F,OAAM,KAAK,WAAW,YAAY,iBAAiB;AAEnD,QAAO,MAAM,KAAK,KAAK;;;;;AAMzB,SAAgB,6BAA6B,SAAoC;CAC/E,MAAM,cAAc,QAAQ;CAC5B,MAAM,WAAW,mBAAmB,QAAQ;CAC5C,MAAM,aAAa,kBAAkB,SAAS,SAAS;CAEvD,MAAM,eAAe,SAAS,KAAK,MAAM,IAAI,EAAE,KAAK,GAAG,CAAC,KAAK,KAAK;CAGlE,MAAM,WAAqB,CAAC,YAAY,cAAc;AACtD,MAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,WAAS,KAAK,MAAM,IAAI,KAAK,GAAG;AAChC,MAAI,IAAI,MAAO,UAAS,KAAK,MAAM,IAAI,MAAM,GAAG;;CAIlD,MAAM,YAAsB,EAAE;AAC9B,MAAK,MAAM,OAAO,WAAW,QAAQ,EAAE;AACrC,MAAI,CAAC,IAAI,QAAQ,IAAI,KAAK,WAAW,EAAG;EACxC,MAAM,SAAS,IAAI,KAAK,KAAK,MAAM,IAAI,EAAE,GAAG,CAAC,KAAK,KAAK;EACvD,MAAM,WAAW,CAAC,MAAM,IAAI,KAAK,GAAG;AACpC,MAAI,IAAI,MAAO,UAAS,KAAK,MAAM,IAAI,MAAM,GAAG;AAChD,YAAU,KAAK,SAAS,SAAS,KAAK,KAAK,CAAC,OAAO,OAAO;;mBAE3C;;CAGjB,MAAM,YACJ,UAAU,SAAS,IACf;;;;EAIN,UAAU,KAAK,KAAK,CAAC;;;IAIf;AAEN,QAAO,aAAa,YAAY;;IAE9B,YAAY;;kBAEE,YAAY;;;kDAGoB,YAAY;;;kBAG5C,aAAa;cACjB,SAAS,KAAK,KAAK,CAAC;EAChC,UAAU;;;;;;;;;;UAUF,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,eAAsB,yBAAyB,SAA4B,OAAoC;CAC7G,MAAM,cAAc,QAAQ;AAE5B,KAAI,MACF,QAAO,mBAAmB,SAAS,MAAM;CAI3C,MAAM,gBAAgB,MAAM,aAAa;AAEzC,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,eAAsB,iBAAiB,aAAqB,OAAmD;CAC7G,MAAM,EAAE,YAAY,WAAW,kBAAkB,MAAM,OAAO;CAC9D,MAAM,EAAE,SAAS,MAAM,OAAO;CAC9B,MAAM,EAAE,YAAY,MAAM,OAAO;CAEjC,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,MAAM,UAAU,MAAM;AACrC,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"}
|
package/dist/docs/index.d.mts
CHANGED
package/dist/docs/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { s as getCommand } from "../commands-
|
|
2
|
-
import { n as getHelpInfo } from "../help-
|
|
1
|
+
import { s as getCommand } from "../commands-DLR0rFgq.mjs";
|
|
2
|
+
import { n as getHelpInfo } from "../help-B-ZMYyn-.mjs";
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
//#region src/docs/index.ts
|
|
@@ -55,7 +55,8 @@ type HelpArgumentInfo = {
|
|
|
55
55
|
examples?: unknown[]; /** Environment variable(s) this arg can be set from */
|
|
56
56
|
env?: string | string[]; /** Whether this arg is an array type (shown as <type...>) */
|
|
57
57
|
variadic?: boolean; /** Whether this arg is a boolean (shown as --[no-]arg) */
|
|
58
|
-
negatable?: boolean; /**
|
|
58
|
+
negatable?: boolean; /** Custom negative keyword(s) that set this arg to false (e.g. `['remote']` for `--remote`) */
|
|
59
|
+
negative?: string[]; /** Config file key that maps to this arg */
|
|
59
60
|
configKey?: string; /** Group name for organizing this option under a labeled section in help output */
|
|
60
61
|
group?: string;
|
|
61
62
|
};
|
|
@@ -110,4 +111,4 @@ type HelpInfo = {
|
|
|
110
111
|
};
|
|
111
112
|
//#endregion
|
|
112
113
|
export { ColorConfig as a, AnsiStyle as i, HelpFormat as n, ColorTheme as o, HelpInfo as r, colorThemes as s, HelpDetail as t };
|
|
113
|
-
//# sourceMappingURL=formatter-
|
|
114
|
+
//# sourceMappingURL=formatter-CY3KrOEd.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter-CY3KrOEd.d.mts","names":[],"sources":["../src/output/colorizer.ts","../src/output/formatter.ts"],"mappings":";;AAqBA;;KAAY,SAAA;;;AAoBZ;;KAAY,WAAA;EACV,OAAA,GAAU,SAAA;EACV,GAAA,GAAM,SAAA;EACN,IAAA,GAAO,SAAA;EACP,WAAA,GAAc,SAAA;EACd,KAAA,GAAQ,SAAA;EACR,IAAA,GAAO,SAAA;EACP,OAAA,GAAU,SAAA;EACV,YAAA,GAAe,SAAA;EACf,UAAA,GAAa,SAAA;AAAA;;;;KAsEH,UAAA;AAAA,cAEC,WAAA,EAAa,MAAA,CAAO,UAAA,EAAY,QAAA,CAAS,WAAA;;;KCxG1C,UAAA;AAAA,KACA,UAAA;;;;KASA,kBAAA;EACV,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA;AAAA;;;;KAMU,gBAAA;EACV,IAAA;EACA,WAAA;EACA,QAAA;EACA,OAAA;EACA,IAAA;EACA,IAAA,aDFA;ECIA,KAAA,aDHA;ECKA,OAAA;EACA,UAAA;EACA,MAAA;EACA,QAAA,cDNO;ECQP,GAAA,sBDPU;ECSV,QAAA,YDRe;ECUf,SAAA,YDTa;ECWb,QAAA,aDXsB;ECatB,SAAA,WDyDoB;ECvDpB,KAAA;AAAA;;ADyDF;;KCnDY,kBAAA;EACV,IAAA;EACA,KAAA;EACA,WAAA;EACA,OAAA;EACA,UAAA;EACA,MAAA;EACA,cAAA,YD4C+B;EC1C/B,KAAA;AAAA;;;;KAMU,eAAA;EACV,IAAA;EACA,WAAA;EACA,GAAA;IAAQ,IAAA;IAAc,WAAA;EAAA;AAAA;;;;;KAOZ,QAAA;EApEkB,4DAsE5B,IAAA,UAtE4B;EAwE5B,KAAA,WAtEA;EAwEA,WAAA,WAtEA;EAwEA,OAAA,aAtEA;EAwEA,UAAA,qBAxEI;EA0EJ,MAAA,YApE0B;EAsE1B,KAAA;IACE,OAAA;IACA,cAAA;IACA,cAAA;IACA,YAAA,WAtEF;IAwEE,UAAA;EAAA,GApEF;EAuEA,WAAA,GAAc,kBAAA,IApEd;EAsEA,WAAA,GAAc,kBAAA,IApEd;EAsEA,SAAA,GAAY,gBAAA,IAlEZ;EAoEA,QAAA,GAAW,eAAA,IAhEX;EAkEA,QAAA,aA9DA;EAgEA,cAAA,GAAiB,QAAA;AAAA"}
|