Build complex CLIs with type safety and no dependencies
Type-safe positional argument definitions. Supports tuple (fixed named args) and array (variadic args) forms.
// Tuple (fixed arguments)
positional: {
kind: "tuple",
parameters: [
{ brief: "Source", parse: String },
{ brief: "Dest", parse: String, optional: true }
]
}
// Array (variadic arguments)
positional: {
kind: "array",
parameter: { brief: "Files", parse: String },
minimum: 1, // optional
maximum: 10 // optional
}Fixed number of named arguments in order.
positional: {
kind: "tuple",
parameters: [
{
brief: "Source file path",
parse: String,
placeholder: "source" // optional, defaults to arg1, arg2, ...
},
{
brief: "Destination file path",
parse: String,
placeholder: "dest",
optional: true // optional argument
}
]
}Example:
const copyCmd = buildCommand({
func: async function(flags, source, dest) {
this.process.stdout.write(`Copying ${source} to ${dest || "current directory"}\n`);
},
parameters: {
positional: {
kind: "tuple",
parameters: [
{ brief: "Source path", parse: String },
{ brief: "Destination path", parse: String, optional: true }
]
}
},
docs: { brief: "Copy file" }
});
// Usage: myapp source.txt dest.txt
// Usage: myapp source.txtVariable number of similar arguments.
positional: {
kind: "array",
parameter: {
brief: "Files to process",
parse: String,
placeholder: "files",
proposeCompletions: async () => await readdir(".") // optional
},
minimum: 1, // optional: minimum required args
maximum: 10 // optional: maximum allowed args
}Example:
const processCmd = buildCommand({
func: async function(flags, ...files) {
this.process.stdout.write(`Processing ${files.length} files\n`);
for (const file of files) {
this.process.stdout.write(` - ${file}\n`);
}
},
parameters: {
positional: {
kind: "array",
parameter: { brief: "Files to process", parse: String },
minimum: 1
}
},
docs: { brief: "Process files" }
});
// Usage: myapp file1.txt file2.txt file3.txtCommon:
brief: string (description)parse: InputParser<T, CONTEXT>optional: boolean (tuple only - makes parameter optional)placeholder: string (custom placeholder in usage line)default: string (default input value if not provided)proposeCompletions: (partial: string) => string[] | Promise<string[]>const command = buildCommand({
func: async function(flags, source, dest) {
if (flags.recursive) {
this.process.stdout.write("Recursive copy enabled\n");
}
this.process.stdout.write(`Copying ${source} to ${dest}\n`);
},
parameters: {
flags: {
recursive: { kind: "boolean", brief: "Recursive copy", default: false },
verbose: { kind: "boolean", brief: "Verbose output", optional: true }
},
positional: {
kind: "tuple",
parameters: [
{ brief: "Source path", parse: String },
{ brief: "Destination path", parse: String }
]
},
aliases: { r: "recursive", v: "verbose" }
},
docs: { brief: "Copy files" }
});
// Usage: myapp --recursive source/ dest/
// Usage: myapp -r source/ dest/
// Usage: myapp source.txt dest.txt --verboseInstall with Tessl CLI
npx tessl i tessl/npm-stricli--core