padrone 1.1.0 → 1.2.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 +38 -1
- package/LICENSE +1 -1
- package/README.md +60 -30
- package/dist/args-CKNh7Dm9.mjs +175 -0
- package/dist/args-CKNh7Dm9.mjs.map +1 -0
- package/dist/chunk-y_GBKt04.mjs +5 -0
- package/dist/codegen/index.d.mts +305 -0
- package/dist/codegen/index.d.mts.map +1 -0
- package/dist/codegen/index.mjs +1348 -0
- package/dist/codegen/index.mjs.map +1 -0
- package/dist/completion.d.mts +64 -0
- package/dist/completion.d.mts.map +1 -0
- package/dist/completion.mjs +417 -0
- package/dist/completion.mjs.map +1 -0
- package/dist/docs/index.d.mts +34 -0
- package/dist/docs/index.d.mts.map +1 -0
- package/dist/docs/index.mjs +404 -0
- package/dist/docs/index.mjs.map +1 -0
- package/dist/formatter-Dvx7jFXr.d.mts +82 -0
- package/dist/formatter-Dvx7jFXr.d.mts.map +1 -0
- package/dist/help-mUIX0T0V.mjs +1195 -0
- package/dist/help-mUIX0T0V.mjs.map +1 -0
- package/dist/index.d.mts +120 -546
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1180 -1197
- package/dist/index.mjs.map +1 -1
- package/dist/test.d.mts +112 -0
- package/dist/test.d.mts.map +1 -0
- package/dist/test.mjs +138 -0
- package/dist/test.mjs.map +1 -0
- package/dist/types-qrtt0135.d.mts +1037 -0
- package/dist/types-qrtt0135.d.mts.map +1 -0
- package/dist/update-check-EbNDkzyV.mjs +146 -0
- package/dist/update-check-EbNDkzyV.mjs.map +1 -0
- package/package.json +61 -21
- package/src/args.ts +365 -0
- package/src/cli/completions.ts +29 -0
- package/src/cli/docs.ts +86 -0
- package/src/cli/doctor.ts +312 -0
- package/src/cli/index.ts +159 -0
- package/src/cli/init.ts +135 -0
- package/src/cli/link.ts +320 -0
- package/src/cli/wrap.ts +152 -0
- package/src/codegen/README.md +118 -0
- package/src/codegen/code-builder.ts +226 -0
- package/src/codegen/discovery.ts +232 -0
- package/src/codegen/file-emitter.ts +73 -0
- package/src/codegen/generators/barrel-file.ts +16 -0
- package/src/codegen/generators/command-file.ts +184 -0
- package/src/codegen/generators/command-tree.ts +124 -0
- package/src/codegen/index.ts +33 -0
- package/src/codegen/parsers/fish.ts +163 -0
- package/src/codegen/parsers/help.ts +378 -0
- package/src/codegen/parsers/merge.ts +158 -0
- package/src/codegen/parsers/zsh.ts +221 -0
- package/src/codegen/schema-to-code.ts +199 -0
- package/src/codegen/template.ts +69 -0
- package/src/codegen/types.ts +143 -0
- package/src/colorizer.ts +2 -2
- package/src/command-utils.ts +501 -0
- package/src/completion.ts +110 -97
- package/src/create.ts +1036 -305
- package/src/docs/index.ts +607 -0
- package/src/errors.ts +131 -0
- package/src/formatter.ts +149 -63
- package/src/help.ts +151 -55
- package/src/index.ts +12 -15
- package/src/interactive.ts +169 -0
- package/src/parse.ts +31 -16
- package/src/repl-loop.ts +317 -0
- package/src/runtime.ts +304 -0
- package/src/shell-utils.ts +83 -0
- package/src/test.ts +285 -0
- package/src/type-helpers.ts +10 -10
- package/src/type-utils.ts +124 -14
- package/src/types.ts +752 -154
- package/src/update-check.ts +244 -0
- package/src/wrap.ts +44 -40
- package/src/zod.d.ts +2 -2
- package/src/options.ts +0 -180
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,49 @@
|
|
|
1
1
|
# padrone
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 66336e5: auto-output is now enabled by default: command return values are automatically written to output in eval, cli, and repl modes. The runtime `output` function now accepts `unknown` values instead of only strings, letting runtimes handle formatting natively. Use `autoOutput: false` in preferences or `configure({ autoOutput: false })` on individual commands to opt out.
|
|
8
|
+
- 02a171c: Add runtime adapter for I/O abstraction, enabling CLI framework usage outside of terminals (web UIs, chat interfaces, testing). New `.runtime()` builder method configures output, error, argv, env, format, config file loading, and file discovery. All fields are optional with Node.js/Bun defaults. Successive `.runtime()` calls merge with previous configuration.
|
|
9
|
+
- 93155ef: Add `padrone/codegen` entry point with a generic code generation toolkit including CodeBuilder (fluent TypeScript source builder), template engine, schemaToCode (Standard Schema to Zod source), FileEmitter (multi-file output), built-in generators (command files, command trees, barrel files), and parsers (help text, fish completions, zsh completions, multi-source merge). Also add `padrone init` CLI command that scaffolds a new Padrone project using the codegen utilities, and reorganize CLI files into `src/cli/` subfolder.
|
|
10
|
+
- 68508a7: Add command override/extension support. Re-registering a command with the same name now merges instead of duplicating: configuration is shallow-merged, the previous handler is passed as a `base` parameter to `.action()`, arguments can be overridden, and subcommands are recursively merged by name. Aliases are preserved from the original when the override doesn't specify new ones. All fully strongly typed.
|
|
11
|
+
|
|
12
|
+
Also fixes: REPL `.` command now works at any scope (including root) to execute the current command, `.help` always shows `.` and `.scope` entries, `cli()` and `repl()` return types now include all possible command results, and nested commands with default `''` subcommands route correctly.
|
|
13
|
+
|
|
14
|
+
- 7e83ebb: Improve command routing, help display, and `--` separator support.
|
|
15
|
+
- 583394b: Add `padrone/completion` subpath export and `padrone completions` CLI command. Shell completion generation is now lazy-loaded via dynamic import, and `setupCompletions()` writes eval snippets to shell config files with idempotent marker-based replacement. User programs get `--setup` on the built-in `completion` command (e.g. `myapp completion bash --setup`). The `.completion()` method is now async.
|
|
16
|
+
- 457f1f7: Add `padrone/docs` entry point with a `generateDocs()` utility that walks the command tree and generates structured documentation in four formats: markdown (with index page, frontmatter support for VitePress/Starlight), HTML (semantic with CSS classes), man pages (groff-formatted), and JSON. Each page includes command name, description, usage syntax, options with types/defaults/choices/aliases/env vars/config keys/examples, positional arguments, and subcommands table. Also add `padrone docs` CLI command that imports a Padrone program from any entry file and generates documentation to an output directory.
|
|
17
|
+
- 038d0aa: Add `padrone doctor <entry>` CLI command that lints and validates a Padrone program definition. Catches duplicate aliases, shadowed option/command names (help, version), commands without actions, schemas without descriptions, conflicting positional configs, and unused plugins.
|
|
18
|
+
- 262e2e6: Add `eval()` method and separate from `cli()`. `program.eval(input)` parses, validates, and executes a command string with soft error handling (returns result with issues instead of throwing). `program.cli()` is now exclusively the process entry point that reads from `process.argv` and throws on validation errors. The REPL and AI SDK tool integration now use `eval()` internally.
|
|
19
|
+
- fb86d5b: Add fuzzy matching for "Did you mean?" suggestions on unknown commands and options.
|
|
20
|
+
- 020cc21: Add interactive field prompting. Commands can now declare `interactive` and `optionalInteractive` in the arguments meta to prompt users for missing field values during `cli()`. Interactive prompts are auto-detected from the schema (boolean → confirm, enum → select, array enum → multiselect). The runtime controls whether interactivity is enabled via `runtime({ interactive: true })`, with a built-in Enquirer-powered terminal prompt as the default. Custom prompt implementations can be provided for non-terminal runtimes.
|
|
21
|
+
- cba6615: Add lifecycle hooks to the plugin system: `start`, `error`, and `shutdown` phases. `start` wraps the entire pipeline (before parse), `error` handles pipeline failures with the ability to suppress or transform errors, and `shutdown` always runs after completion for cleanup. All three use the same onion/middleware pattern as existing phases. Available in `eval()` and `cli()` only. Sync preservation is maintained.
|
|
22
|
+
- 727c6af: Add `padrone link` and `padrone unlink` CLI commands for linking programs during development. Creates shell shims in `~/.padrone/bin/` that invoke the entry file with the detected runtime. Auto-detects entry from `package.json` bin field and runtime from lockfiles. Use `--setup` to automatically add `~/.padrone/bin` to PATH in shell config. Shell utilities (`detectShell`, `getRcFile`, `writeToRcFile`) extracted to `shell-utils.ts` for reuse.
|
|
23
|
+
- fdca76f: Add `.mount(name, program)` method for composing Padrone programs together. Mounts an existing program as a subcommand, recursively re-pathing all nested commands and preserving arguments, handlers, plugins, and schemas. Supports aliases via array syntax. Mounted program's root-level `version` is dropped. Type-level paths are recursively updated for correct inference with `eval()`, `find()`, `run()`, etc.
|
|
24
|
+
- 4706462: Add plugin system with middleware pattern for intercepting command execution phases. Plugins use an onion model with `next()` to wrap parse, validate, and execute phases. Registered via `.use()` on both programs and subcommand builders. Program-level plugins apply as outermost wrappers; subcommand plugins compose as inner layers. Parse phase runs root plugins only. Supports explicit ordering via `order` parameter, shared mutable `state` across phases, sync preservation, and short-circuiting.
|
|
25
|
+
- 1a44f9d: Add REPL command history, tab completion, and output styling. The built-in terminal REPL now supports up/down arrow history navigation and tab completion for command names, subcommands, options, and aliases. New `repl()` preferences: `history` (initial entries), `completion` (toggle tab completion), `spacing` (separators before/after command output — supports blank lines, repeated characters, multi-line arrays, and independent before/after config), and `outputPrefix` (prefix each output line, e.g. `'│ '`). The default prompt is bold in ANSI-capable terminals.
|
|
26
|
+
- a73bf6a: Add REPL mode. `program.repl()` starts an interactive Read-Eval-Print Loop that returns an `AsyncIterable<PadroneCommandResult>`, yielding a result for each successfully executed command. Errors are caught and printed without crashing the session. Built-in REPL commands (`exit`, `quit`, `clear`) are provided but yield to user-defined commands of the same name. The runtime gains a new `readLine` field for abstracting line input, with a default Node.js/Bun `readline` implementation.
|
|
27
|
+
- 5437416: Add scoped/contextual REPLs, `--repl` CLI flag, and dot-prefixed built-in commands. All REPL built-ins now use dot-prefix notation (`.exit`, `.quit`, `.clear`, `.scope`, `.help`, `.history`) to avoid collisions with user commands. `.scope <subcommand>` scopes the REPL session to a command subtree, `.scope ..`/`..` goes back up, `.` executes the current scoped command. `.help` shows REPL-specific commands and keybindings. `.history` shows session command history. Default greeting displays program name and version; configurable `hint` text shown below. Double Ctrl+C to exit (first press shows hint). The prompt updates to reflect scope (e.g. `myapp/db ❯`). `options.scope` allows starting pre-scoped and is strongly typed to valid command paths. The `--repl` flag in `cli()` starts a REPL (optionally scoped to a command).
|
|
28
|
+
- b021824: Removed parse options. Custom runtimes can be used for the same behavior.
|
|
29
|
+
- 3ad9c6f: Add stdin piping support. Commands can declare a `stdin` field in their arguments meta to read piped input and inject it into a schema field. Supports `text` mode (read all as string) and `lines` mode (read as string array). Precedence: CLI flags > stdin > env vars > config file > schema defaults. Stdin is only read when piped (not a TTY) and the target field wasn't already provided via CLI. Runtime abstraction (`PadroneRuntime.stdin`) enables custom stdin sources for testing and non-terminal environments. Test harness gains `.stdin(data)` builder method. Help output shows `[stdin > field]` in usage line.
|
|
30
|
+
- a64f576: Add `padrone/test` entry point with testing utilities. The `testCli(program)` function provides a fluent builder for setting up CLI test scenarios with mock I/O capture. Supports mocking environment variables (`.env()`), interactive prompt answers (`.prompt()`), config files (`.config()`), and REPL sessions (`.repl()`). Works with any test framework.
|
|
31
|
+
- 6269637: add async validation support
|
|
32
|
+
- 6d15076: Add built-in opt-in update checking via `.updateCheck()`. When enabled, the program checks the npm registry (or a custom URL) for newer versions in the background and displays a notification after command output. Checks are cached to avoid hitting the registry on every invocation. Respects CI environments, non-TTY contexts, `--no-update-check` flag, and a configurable env var to disable.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- 54de1b9: show built-in commands and flags (help, version, completion, --repl) in root help output
|
|
37
|
+
- 6fa2ac9: improve help output formatting: show actual positional argument names in usage line, use `[options]` instead of `[arguments]` for flags, and rename flags section from "Arguments" to "Options"
|
|
38
|
+
- bf6fe49: Add AI coding agent skill with API reference, examples, and installation instructions for Claude Code and other Agent Skills-compatible tools.
|
|
39
|
+
|
|
3
40
|
## 1.0.0
|
|
4
41
|
|
|
5
42
|
Initial stable release of Padrone - a TypeScript CLI framework with Zod schema support.
|
|
6
43
|
|
|
7
44
|
### Features
|
|
8
45
|
|
|
9
|
-
- Type-safe argument
|
|
46
|
+
- Type-safe argument parsing with Zod schemas
|
|
10
47
|
- Interactive prompts with validation
|
|
11
48
|
- AI integration support via Vercel AI SDK
|
|
12
49
|
- Standard Schema compatibility
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
## ✨ Features
|
|
20
20
|
|
|
21
21
|
- 🔒 **Type-safe** - Full TypeScript support with Zod schema validation
|
|
22
|
-
- 🎯 **Fluent API** - Chain commands
|
|
22
|
+
- 🎯 **Fluent API** - Chain commands and arguments with a clean builder pattern
|
|
23
23
|
- 🤖 **AI-Ready** - First-class support for Vercel AI SDK tool integration
|
|
24
24
|
- 📚 **Auto Help** - Automatic help generation from your schema definitions
|
|
25
25
|
- 🧩 **Nested Commands** - Support for deeply nested subcommands
|
|
@@ -62,9 +62,9 @@ const program = createPadrone('myapp')
|
|
|
62
62
|
}),
|
|
63
63
|
{ positional: ['...names'] },
|
|
64
64
|
)
|
|
65
|
-
.action((
|
|
66
|
-
const prefix =
|
|
67
|
-
|
|
65
|
+
.action((args) => {
|
|
66
|
+
const prefix = args?.prefix ? `${args.prefix} ` : '';
|
|
67
|
+
args.names.forEach((name) => {
|
|
68
68
|
console.log(`Hello, ${prefix}${name}!`);
|
|
69
69
|
});
|
|
70
70
|
}),
|
|
@@ -95,12 +95,12 @@ Hello, Mr. Jane!
|
|
|
95
95
|
### Programmatic Execution
|
|
96
96
|
|
|
97
97
|
```typescript
|
|
98
|
-
// Run a command directly with typed
|
|
98
|
+
// Run a command directly with typed arguments
|
|
99
99
|
program.run('greet', { names: ['John', 'Jane'], prefix: 'Dr.' });
|
|
100
100
|
|
|
101
101
|
// Parse CLI input without executing
|
|
102
102
|
const parsed = program.parse('greet John --prefix Mr.');
|
|
103
|
-
console.log(parsed.
|
|
103
|
+
console.log(parsed.args); // { names: ['John'], prefix: 'Mr.' }
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
### API Mode
|
|
@@ -127,8 +127,8 @@ const program = createPadrone('weather')
|
|
|
127
127
|
}),
|
|
128
128
|
{ positional: ['city'] },
|
|
129
129
|
)
|
|
130
|
-
.action((
|
|
131
|
-
console.log(`Forecast for ${
|
|
130
|
+
.action((args) => {
|
|
131
|
+
console.log(`Forecast for ${args.city}: ${args.days} days`);
|
|
132
132
|
})
|
|
133
133
|
.command('extended', (c) =>
|
|
134
134
|
c
|
|
@@ -138,14 +138,14 @@ const program = createPadrone('weather')
|
|
|
138
138
|
}),
|
|
139
139
|
{ positional: ['city'] },
|
|
140
140
|
)
|
|
141
|
-
.action((
|
|
142
|
-
console.log(`Extended forecast for ${
|
|
141
|
+
.action((args) => {
|
|
142
|
+
console.log(`Extended forecast for ${args.city}`);
|
|
143
143
|
}),
|
|
144
144
|
),
|
|
145
145
|
);
|
|
146
146
|
|
|
147
147
|
// Run nested command
|
|
148
|
-
program.
|
|
148
|
+
program.eval('forecast extended London');
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
### Option Aliases and Metadata
|
|
@@ -173,15 +173,15 @@ const program = createPadrone('app')
|
|
|
173
173
|
.meta({ alias: 'v', deprecated: 'Use --debug instead' }),
|
|
174
174
|
}),
|
|
175
175
|
)
|
|
176
|
-
.action((
|
|
177
|
-
console.log(`Server running at ${
|
|
176
|
+
.action((args) => {
|
|
177
|
+
console.log(`Server running at ${args.host}:${args.port}`);
|
|
178
178
|
}),
|
|
179
179
|
);
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
### Environment Variables and Config Files
|
|
183
183
|
|
|
184
|
-
Padrone supports loading
|
|
184
|
+
Padrone supports loading arguments from environment variables and config files using dedicated schema methods:
|
|
185
185
|
|
|
186
186
|
```typescript
|
|
187
187
|
const program = createPadrone('app')
|
|
@@ -193,7 +193,7 @@ const program = createPadrone('app')
|
|
|
193
193
|
apiKey: z.string().describe('API key for authentication'),
|
|
194
194
|
}),
|
|
195
195
|
)
|
|
196
|
-
// Map environment variables to
|
|
196
|
+
// Map environment variables to arguments
|
|
197
197
|
.env(
|
|
198
198
|
z
|
|
199
199
|
.object({
|
|
@@ -213,14 +213,35 @@ const program = createPadrone('app')
|
|
|
213
213
|
apiKey: z.string().optional(),
|
|
214
214
|
}),
|
|
215
215
|
)
|
|
216
|
-
.action((
|
|
217
|
-
console.log(`Server running on port ${
|
|
216
|
+
.action((args) => {
|
|
217
|
+
console.log(`Server running on port ${args.port}`);
|
|
218
218
|
}),
|
|
219
219
|
);
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
**Precedence order** (highest to lowest): CLI args > environment variables > config file
|
|
223
223
|
|
|
224
|
+
### Async Validation
|
|
225
|
+
|
|
226
|
+
If your schema uses async refinements (e.g. `z.check(async ...)`), mark the command as async so that `parse()` and `cli()` return Promises:
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { asyncSchema, createPadrone } from 'padrone';
|
|
230
|
+
|
|
231
|
+
const program = createPadrone('app')
|
|
232
|
+
.command('create', (c) =>
|
|
233
|
+
c
|
|
234
|
+
// Option 1: brand the schema with asyncSchema()
|
|
235
|
+
.arguments(asyncSchema(z.object({ name: z.string() }).check(async (ctx) => { /* ... */ })))
|
|
236
|
+
// Option 2: call .async() on the builder
|
|
237
|
+
.async()
|
|
238
|
+
.action((args) => args.name),
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// parse() and cli() now return Promises
|
|
242
|
+
const result = await program.parse('create --name test');
|
|
243
|
+
```
|
|
244
|
+
|
|
224
245
|
## 🤖 AI SDK Integration
|
|
225
246
|
|
|
226
247
|
Padrone provides first-class support for the [Vercel AI SDK](https://ai-sdk.dev/), making it easy to expose your CLI as an AI tool:
|
|
@@ -239,8 +260,8 @@ const weatherCli = createPadrone('weather')
|
|
|
239
260
|
}),
|
|
240
261
|
{ positional: ['city'] },
|
|
241
262
|
)
|
|
242
|
-
.action((
|
|
243
|
-
return { city:
|
|
263
|
+
.action((args) => {
|
|
264
|
+
return { city: args.city, temperature: 72, condition: 'Sunny' };
|
|
244
265
|
}),
|
|
245
266
|
);
|
|
246
267
|
|
|
@@ -264,12 +285,12 @@ console.log(program.help());
|
|
|
264
285
|
|
|
265
286
|
Example output:
|
|
266
287
|
```
|
|
267
|
-
Usage: myapp greet [names...] [
|
|
288
|
+
Usage: myapp greet [names...] [arguments]
|
|
268
289
|
|
|
269
|
-
|
|
290
|
+
Positionals:
|
|
270
291
|
names... Names to greet
|
|
271
292
|
|
|
272
|
-
|
|
293
|
+
Arguments:
|
|
273
294
|
-p, --prefix <string> Prefix to use in greeting
|
|
274
295
|
-h, --help Show help
|
|
275
296
|
```
|
|
@@ -286,34 +307,35 @@ Creates a new CLI program with the given name.
|
|
|
286
307
|
|--------|-------------|
|
|
287
308
|
| `.configure(config)` | Configure program properties (title, description, version) |
|
|
288
309
|
| `.command(name, builder)` | Add a command to the program |
|
|
289
|
-
| `.arguments(schema, meta?)` | Define
|
|
290
|
-
| `.
|
|
310
|
+
| `.arguments(schema, meta?)` | Define arguments schema with optional positional args |
|
|
311
|
+
| `.async()` | Mark command as async (for schemas with async validation) |
|
|
312
|
+
| `.env(schema)` | Define schema for parsing environment variables into arguments |
|
|
291
313
|
| `.configFile(file, schema?)` | Configure config file path(s) and schema |
|
|
292
314
|
| `.action(handler)` | Set the command handler function |
|
|
293
315
|
| `.cli(input?)` | Run as CLI (parses `process.argv` or input string) |
|
|
294
|
-
| `.run(command,
|
|
316
|
+
| `.run(command, args?)` | Run a command programmatically |
|
|
295
317
|
| `.parse(input?)` | Parse input without executing |
|
|
296
|
-
| `.stringify(command?,
|
|
318
|
+
| `.stringify(command?, args?)` | Convert command and arguments back to CLI string |
|
|
297
319
|
| `.api()` | Generate a typed API object |
|
|
298
320
|
| `.help(command?)` | Generate help text |
|
|
299
321
|
| `.tool()` | Generate a Vercel AI SDK tool |
|
|
300
322
|
| `.find(command)` | Find a command by name |
|
|
301
323
|
|
|
302
|
-
###
|
|
324
|
+
### Arguments Meta
|
|
303
325
|
|
|
304
|
-
Use the second argument of `.arguments()` to configure positional arguments and per-
|
|
326
|
+
Use the second argument of `.arguments()` to configure positional arguments and per-argument metadata:
|
|
305
327
|
|
|
306
328
|
```typescript
|
|
307
329
|
.arguments(schema, {
|
|
308
330
|
positional: ['source', '...files', 'dest'], // '...files' is variadic
|
|
309
|
-
|
|
331
|
+
fields: {
|
|
310
332
|
verbose: { alias: 'v' },
|
|
311
333
|
format: { deprecated: 'Use --output instead' },
|
|
312
334
|
},
|
|
313
335
|
})
|
|
314
336
|
```
|
|
315
337
|
|
|
316
|
-
### Zod
|
|
338
|
+
### Zod Metadata
|
|
317
339
|
|
|
318
340
|
Use `.meta()` on Zod schemas to provide additional CLI metadata:
|
|
319
341
|
|
|
@@ -326,6 +348,14 @@ z.string().meta({
|
|
|
326
348
|
})
|
|
327
349
|
```
|
|
328
350
|
|
|
351
|
+
## 🤖 AI Coding Agent Skill
|
|
352
|
+
|
|
353
|
+
Install the [Padrone skill](https://agentskills.io) to give your AI coding agent (Claude Code, etc.) knowledge of the Padrone API:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
npx skills add KurtGokhan/padrone
|
|
357
|
+
```
|
|
358
|
+
|
|
329
359
|
## 🛠️ Requirements
|
|
330
360
|
|
|
331
361
|
- Node.js 18+ or Bun
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
//#region src/args.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes stdin config into its explicit form.
|
|
4
|
+
*/
|
|
5
|
+
function parseStdinConfig(stdin) {
|
|
6
|
+
if (typeof stdin === "string") return {
|
|
7
|
+
field: stdin,
|
|
8
|
+
as: "text"
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
field: stdin.field,
|
|
12
|
+
as: stdin.as ?? "text"
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse positional configuration to extract names and variadic info.
|
|
17
|
+
*/
|
|
18
|
+
function parsePositionalConfig(positional) {
|
|
19
|
+
return positional.map((p) => {
|
|
20
|
+
const isVariadic = p.startsWith("...");
|
|
21
|
+
return {
|
|
22
|
+
name: isVariadic ? p.slice(3) : p,
|
|
23
|
+
variadic: isVariadic
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Extract all arg metadata from schema and meta in a single pass.
|
|
29
|
+
* This consolidates aliases, env bindings, and config keys extraction.
|
|
30
|
+
*/
|
|
31
|
+
function extractSchemaMetadata(schema, meta) {
|
|
32
|
+
const aliases = {};
|
|
33
|
+
if (meta) for (const [key, value] of Object.entries(meta)) {
|
|
34
|
+
if (!value) continue;
|
|
35
|
+
if (value.alias) {
|
|
36
|
+
const list = typeof value.alias === "string" ? [value.alias] : value.alias;
|
|
37
|
+
for (const aliasKey of list) if (typeof aliasKey === "string" && aliasKey && aliasKey !== key) aliases[aliasKey] = key;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const jsonSchema = schema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
|
|
42
|
+
if (jsonSchema.type === "object" && jsonSchema.properties) for (const [propertyName, propertySchema] of Object.entries(jsonSchema.properties)) {
|
|
43
|
+
if (!propertySchema) continue;
|
|
44
|
+
const propAlias = propertySchema.alias;
|
|
45
|
+
if (propAlias) {
|
|
46
|
+
const list = typeof propAlias === "string" ? [propAlias] : propAlias;
|
|
47
|
+
if (Array.isArray(list)) {
|
|
48
|
+
for (const aliasKey of list) if (typeof aliasKey === "string" && aliasKey && aliasKey !== propertyName && !(aliasKey in aliases)) aliases[aliasKey] = propertyName;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
} catch {}
|
|
53
|
+
return { aliases };
|
|
54
|
+
}
|
|
55
|
+
function preprocessAliases(data, aliases) {
|
|
56
|
+
const result = { ...data };
|
|
57
|
+
for (const [aliasKey, fullArgName] of Object.entries(aliases)) if (aliasKey in data && aliasKey !== fullArgName) {
|
|
58
|
+
const aliasValue = data[aliasKey];
|
|
59
|
+
if (!(fullArgName in result)) result[fullArgName] = aliasValue;
|
|
60
|
+
delete result[aliasKey];
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Apply values directly to arguments.
|
|
66
|
+
* CLI values take precedence over the provided values.
|
|
67
|
+
*/
|
|
68
|
+
function applyValues(data, values) {
|
|
69
|
+
const result = { ...data };
|
|
70
|
+
for (const [key, value] of Object.entries(values)) {
|
|
71
|
+
if (key in result && result[key] !== void 0) continue;
|
|
72
|
+
if (value !== void 0) result[key] = value;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Combined preprocessing of arguments with all features.
|
|
78
|
+
* Precedence order (highest to lowest): CLI args > stdin > env vars > config file
|
|
79
|
+
*/
|
|
80
|
+
function preprocessArgs(data, ctx) {
|
|
81
|
+
let result = { ...data };
|
|
82
|
+
if (ctx.aliases && Object.keys(ctx.aliases).length > 0) result = preprocessAliases(result, ctx.aliases);
|
|
83
|
+
if (ctx.stdinData) result = applyValues(result, ctx.stdinData);
|
|
84
|
+
if (ctx.envData) result = applyValues(result, ctx.envData);
|
|
85
|
+
if (ctx.configData) result = applyValues(result, ctx.configData);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Auto-coerce CLI string values to match the expected schema types.
|
|
90
|
+
* Handles: string → number, string → boolean for primitive schema fields.
|
|
91
|
+
* Arrays of primitives are also coerced element-wise.
|
|
92
|
+
*/
|
|
93
|
+
function coerceArgs(data, schema) {
|
|
94
|
+
let properties;
|
|
95
|
+
try {
|
|
96
|
+
const jsonSchema = schema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
|
|
97
|
+
if (jsonSchema.type !== "object" || !jsonSchema.properties) return data;
|
|
98
|
+
properties = jsonSchema.properties;
|
|
99
|
+
} catch {
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
102
|
+
const result = { ...data };
|
|
103
|
+
for (const [key, value] of Object.entries(result)) {
|
|
104
|
+
const prop = properties[key];
|
|
105
|
+
if (!prop) continue;
|
|
106
|
+
const targetType = prop.type;
|
|
107
|
+
if (targetType === "number" || targetType === "integer") {
|
|
108
|
+
if (typeof value === "string") {
|
|
109
|
+
const num = Number(value);
|
|
110
|
+
if (!Number.isNaN(num)) result[key] = num;
|
|
111
|
+
}
|
|
112
|
+
} else if (targetType === "boolean") {
|
|
113
|
+
if (typeof value === "string") {
|
|
114
|
+
if (value === "true" || value === "1") result[key] = true;
|
|
115
|
+
else if (value === "false" || value === "0") result[key] = false;
|
|
116
|
+
}
|
|
117
|
+
} else if (targetType === "array" && Array.isArray(value)) {
|
|
118
|
+
const itemType = prop.items?.type;
|
|
119
|
+
if (itemType === "number" || itemType === "integer") result[key] = value.map((v) => {
|
|
120
|
+
if (typeof v === "string") {
|
|
121
|
+
const num = Number(v);
|
|
122
|
+
return Number.isNaN(num) ? v : num;
|
|
123
|
+
}
|
|
124
|
+
return v;
|
|
125
|
+
});
|
|
126
|
+
else if (itemType === "boolean") result[key] = value.map((v) => {
|
|
127
|
+
if (typeof v === "string") {
|
|
128
|
+
if (v === "true" || v === "1") return true;
|
|
129
|
+
if (v === "false" || v === "0") return false;
|
|
130
|
+
}
|
|
131
|
+
return v;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
/** Keys consumed by the CLI framework that are not user-defined args. */
|
|
138
|
+
const frameworkReservedKeys = new Set(["config", "c"]);
|
|
139
|
+
/**
|
|
140
|
+
* Detect unknown keys in the args that don't match any schema property.
|
|
141
|
+
* Returns an array of { key, suggestion? } for each unknown key.
|
|
142
|
+
* Framework-reserved keys (--config, -c) are always allowed.
|
|
143
|
+
*/
|
|
144
|
+
function detectUnknownArgs(data, schema, aliases, suggestFn) {
|
|
145
|
+
let properties;
|
|
146
|
+
let isLoose = false;
|
|
147
|
+
try {
|
|
148
|
+
const jsonSchema = schema["~standard"].jsonSchema.input({ target: "draft-2020-12" });
|
|
149
|
+
if (jsonSchema.type !== "object" || !jsonSchema.properties) return [];
|
|
150
|
+
properties = jsonSchema.properties;
|
|
151
|
+
if (jsonSchema.additionalProperties !== void 0 && jsonSchema.additionalProperties !== false) isLoose = true;
|
|
152
|
+
} catch {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
if (isLoose) return [];
|
|
156
|
+
const knownKeys = new Set([
|
|
157
|
+
...Object.keys(properties),
|
|
158
|
+
...Object.keys(aliases),
|
|
159
|
+
...Object.values(aliases)
|
|
160
|
+
]);
|
|
161
|
+
const propertyNames = Object.keys(properties);
|
|
162
|
+
const unknowns = [];
|
|
163
|
+
for (const key of Object.keys(data)) if (!knownKeys.has(key) && !frameworkReservedKeys.has(key)) {
|
|
164
|
+
const suggestion = suggestFn(key, propertyNames);
|
|
165
|
+
unknowns.push({
|
|
166
|
+
key,
|
|
167
|
+
suggestion
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return unknowns;
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
export { parseStdinConfig as a, parsePositionalConfig as i, detectUnknownArgs as n, preprocessArgs as o, extractSchemaMetadata as r, coerceArgs as t };
|
|
174
|
+
|
|
175
|
+
//# sourceMappingURL=args-CKNh7Dm9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args-CKNh7Dm9.mjs","names":[],"sources":["../src/args.ts"],"sourcesContent":["import type { StandardJSONSchemaV1 } from '@standard-schema/spec';\n\nexport interface PadroneFieldMeta {\n description?: string;\n alias?: string[] | string;\n deprecated?: boolean | string;\n hidden?: boolean;\n examples?: unknown[];\n}\n\ntype PositionalArgs<TObj> =\n TObj extends Record<string, any>\n ? {\n [K in keyof TObj]: TObj[K] extends Array<any> ? `...${K & string}` : K & string;\n }[keyof TObj]\n : string;\n\n/**\n * Meta configuration for arguments, including positional arguments.\n * The `positional` array defines which arguments are positional and their order.\n * Use '...name' prefix to indicate variadic (rest) arguments, matching JS/TS rest syntax.\n *\n * @example\n * ```ts\n * .arguments(schema, {\n * positional: ['source', '...files', 'dest'], // '...files' is variadic\n * })\n * ```\n */\n/**\n * Configuration for reading from stdin and mapping it to an argument field.\n */\nexport type StdinConfig<TObj = Record<string, any>> =\n | (keyof TObj & string)\n | {\n /** The argument field to populate with stdin data. */\n field: keyof TObj & string;\n /**\n * How to consume stdin:\n * - `'text'` (default): read all stdin as a single string.\n * - `'lines'`: read stdin as an array of lines (string[]).\n */\n as?: 'text' | 'lines';\n };\n\nexport interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {\n /**\n * Array of argument names that should be treated as positional arguments.\n * Order in array determines position. Use '...name' prefix for variadic args.\n * @example ['source', '...files', 'dest'] - 'files' captures multiple values\n */\n positional?: PositionalArgs<TObj>[];\n /**\n * Per-argument metadata.\n */\n fields?: { [K in keyof TObj]?: PadroneFieldMeta };\n /**\n * Read from stdin and inject the data into the specified argument field.\n * Only reads when stdin is piped (not a TTY) and the field wasn't already provided via CLI flags.\n *\n * - `string`: shorthand for `{ field: name, as: 'text' }` — read all stdin as a string.\n * - `{ field, as }`: explicit form. `as: 'text'` reads all stdin as a string,\n * `as: 'lines'` reads stdin as an array of line strings.\n *\n * Precedence: CLI flags > stdin > env vars > config file > schema defaults.\n *\n * @example\n * ```ts\n * // Shorthand: read all stdin as text into 'data' field\n * .arguments(z.object({ data: z.string() }), { stdin: 'data' })\n *\n * // Explicit: read stdin lines into 'lines' field\n * .arguments(z.object({ lines: z.string().array() }), {\n * stdin: { field: 'lines', as: 'lines' },\n * })\n * ```\n */\n stdin?: StdinConfig<TObj>;\n /**\n * Fields to interactively prompt for when their values are missing after CLI/env/config resolution.\n * - `true`: prompt for all required fields that are missing.\n * - `string[]`: prompt for these specific fields if missing.\n *\n * Interactive prompting only occurs in `cli()` when the runtime has `interactive: true`.\n * Setting this makes `parse()` and `cli()` return Promises.\n *\n * @example\n * ```ts\n * .arguments(schema, {\n * interactive: true, // prompt all missing required fields\n * interactive: ['name', 'template'], // prompt only these fields\n * })\n * ```\n */\n interactive?: true | (keyof TObj & string)[];\n /**\n * Optional fields offered after required interactive prompts.\n * Users are shown a multi-select to choose which of these fields to configure.\n * - `true`: offer all optional fields that are missing.\n * - `string[]`: offer these specific fields.\n *\n * @example\n * ```ts\n * .arguments(schema, {\n * interactive: ['name'],\n * optionalInteractive: ['typescript', 'eslint', 'prettier'],\n * })\n * ```\n */\n optionalInteractive?: true | (keyof TObj & string)[];\n}\n\n/**\n * Normalizes stdin config into its explicit form.\n */\nexport function parseStdinConfig(stdin: StdinConfig): { field: string; as: 'text' | 'lines' } {\n if (typeof stdin === 'string') return { field: stdin, as: 'text' };\n return { field: stdin.field as string, as: stdin.as ?? 'text' };\n}\n\n/**\n * Parse positional configuration to extract names and variadic info.\n */\nexport function parsePositionalConfig(positional: string[]): { name: string; variadic: boolean }[] {\n return positional.map((p) => {\n const isVariadic = p.startsWith('...');\n const name = isVariadic ? p.slice(3) : p;\n return { name, variadic: isVariadic };\n });\n}\n\n/**\n * Result type for extractSchemaMetadata function.\n */\ninterface SchemaMetadataResult {\n aliases: Record<string, string>;\n}\n\n/**\n * Extract all arg metadata from schema and meta in a single pass.\n * This consolidates aliases, env bindings, and config keys extraction.\n */\nexport function extractSchemaMetadata(\n schema: StandardJSONSchemaV1,\n meta?: Record<string, PadroneFieldMeta | undefined>,\n): SchemaMetadataResult {\n const aliases: Record<string, 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 // Extract aliases\n if (value.alias) {\n const list = typeof value.alias === 'string' ? [value.alias] : value.alias;\n for (const aliasKey of list) {\n if (typeof aliasKey === 'string' && aliasKey && aliasKey !== key) {\n aliases[aliasKey] = key;\n }\n }\n }\n }\n }\n\n // Extract from JSON schema properties\n try {\n const jsonSchema = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) 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 aliases from schema\n const propAlias = propertySchema.alias;\n if (propAlias) {\n const list = typeof propAlias === 'string' ? [propAlias] : propAlias;\n if (Array.isArray(list)) {\n for (const aliasKey of list) {\n if (typeof aliasKey === 'string' && aliasKey && aliasKey !== propertyName && !(aliasKey in aliases)) {\n aliases[aliasKey] = propertyName;\n }\n }\n }\n }\n }\n }\n } catch {\n // Ignore errors from JSON schema generation\n }\n\n return { aliases };\n}\n\nfunction preprocessAliases(data: Record<string, unknown>, aliases: Record<string, string>): Record<string, unknown> {\n const result = { ...data };\n\n for (const [aliasKey, fullArgName] of Object.entries(aliases)) {\n if (aliasKey in data && aliasKey !== fullArgName) {\n const aliasValue = data[aliasKey];\n // Prefer full arg name if it exists\n if (!(fullArgName in result)) result[fullArgName] = aliasValue;\n delete result[aliasKey];\n }\n }\n\n return result;\n}\n\ninterface ParseArgsContext {\n aliases?: Record<string, string>;\n stdinData?: Record<string, unknown>;\n envData?: Record<string, unknown>;\n configData?: Record<string, unknown>;\n}\n\n/**\n * Apply values directly to arguments.\n * CLI values take precedence over the provided values.\n */\nfunction 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 // Only apply value if arg wasn't already set\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/**\n * Combined preprocessing of arguments with all features.\n * Precedence order (highest to lowest): CLI args > stdin > env vars > config file\n */\nexport function preprocessArgs(data: Record<string, unknown>, ctx: ParseArgsContext): Record<string, unknown> {\n let result = { ...data };\n\n // 1. Apply aliases first\n if (ctx.aliases && Object.keys(ctx.aliases).length > 0) {\n result = preprocessAliases(result, ctx.aliases);\n }\n\n // 2. Apply stdin data (higher precedence than env)\n // Only applies if CLI didn't set the arg\n if (ctx.stdinData) {\n result = applyValues(result, ctx.stdinData);\n }\n\n // 3. Apply environment variables (higher precedence than config)\n // These only apply if CLI/stdin didn't set the arg\n if (ctx.envData) {\n result = applyValues(result, ctx.envData);\n }\n\n // 4. Apply config file values (lowest precedence)\n // These only apply if neither CLI, stdin, nor env set the arg\n if (ctx.configData) {\n result = applyValues(result, ctx.configData);\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 = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) 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 if (value === 'true' || value === '1') result[key] = true;\n else if (value === 'false' || value === '0') result[key] = false;\n }\n } else if (targetType === 'array' && Array.isArray(value)) {\n const itemType = prop.items?.type as string | undefined;\n if (itemType === 'number' || itemType === 'integer') {\n result[key] = value.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] = value.map((v) => {\n if (typeof v === 'string') {\n if (v === 'true' || v === '1') return true;\n if (v === 'false' || v === '0') return false;\n }\n return v;\n });\n }\n }\n }\n\n return result;\n}\n\n/** Keys consumed by the CLI framework that are not user-defined args. */\nconst frameworkReservedKeys = new Set(['config', 'c']);\n\n/**\n * Detect unknown keys in the args that don't match any schema property.\n * Returns an array of { key, suggestion? } 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 aliases: Record<string, string>,\n suggestFn: (input: string, candidates: string[]) => string,\n): { key: string; suggestion: string }[] {\n let properties: Record<string, any>;\n let isLoose = false;\n try {\n const jsonSchema = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' }) 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>([...Object.keys(properties), ...Object.keys(aliases), ...Object.values(aliases)]);\n const propertyNames = Object.keys(properties);\n const unknowns: { key: string; suggestion: string }[] = [];\n\n for (const key of Object.keys(data)) {\n if (!knownKeys.has(key) && !frameworkReservedKeys.has(key)) {\n const suggestion = suggestFn(key, propertyNames);\n unknowns.push({ key, suggestion });\n }\n }\n\n return unknowns;\n}\n"],"mappings":"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"}
|