@outfitter/cli 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import { ActionCliOption } from "@outfitter/contracts";
1
2
  import { Command } from "commander";
2
3
  import { CancelledError, ErrorCategory, ValidationError } from "@outfitter/contracts";
3
4
  import { Result } from "better-result";
@@ -79,12 +80,164 @@ interface CommandBuilder {
79
80
  requiredOption(flags: string, description: string, defaultValue?: unknown): this;
80
81
  /** Add command aliases */
81
82
  alias(alias: string): this;
83
+ /** Apply a flag preset (adds its options to the command) */
84
+ preset(preset: FlagPreset<Record<string, unknown>>): this;
82
85
  /** Set the action handler */
83
86
  action<TFlags extends CommandFlags = CommandFlags>(handler: CommandAction<TFlags>): this;
84
87
  /** Build the underlying Commander command */
85
88
  build(): Command;
86
89
  }
87
90
  /**
91
+ * A family of related command verbs with a primary name and aliases.
92
+ */
93
+ interface VerbFamily {
94
+ /** Primary verb name */
95
+ readonly primary: string;
96
+ /** Alternative names for this verb */
97
+ readonly aliases: readonly string[];
98
+ /** Description of what this verb family does */
99
+ readonly description: string;
100
+ }
101
+ /**
102
+ * Configuration for resolving a verb family with project-level overrides.
103
+ */
104
+ interface VerbConfig {
105
+ /** Override the primary verb (e.g., "edit" instead of "modify") */
106
+ readonly primary?: string;
107
+ /** Whether to include aliases (default: true) */
108
+ readonly aliases?: boolean;
109
+ /** Additional aliases beyond defaults */
110
+ readonly extraAliases?: readonly string[];
111
+ /** Aliases to exclude */
112
+ readonly excludeAliases?: readonly string[];
113
+ }
114
+ /**
115
+ * A composable set of CLI flags with typed resolution.
116
+ *
117
+ * Presets bundle flag definitions with a resolver that coerces
118
+ * raw Commander output into typed values.
119
+ */
120
+ interface FlagPreset<TResolved extends Record<string, unknown>> {
121
+ /** Unique identifier for deduplication in composePresets */
122
+ readonly id: string;
123
+ /** Commander option definitions */
124
+ readonly options: readonly ActionCliOption[];
125
+ /** Resolve raw Commander flags into typed values */
126
+ readonly resolve: (flags: Record<string, unknown>) => TResolved;
127
+ }
128
+ /**
129
+ * Configuration for creating a flag preset.
130
+ */
131
+ interface FlagPresetConfig<TResolved extends Record<string, unknown>> {
132
+ /** Unique identifier for deduplication */
133
+ readonly id: string;
134
+ /** Commander option definitions */
135
+ readonly options: readonly ActionCliOption[];
136
+ /** Resolve raw Commander flags into typed values */
137
+ readonly resolve: (flags: Record<string, unknown>) => TResolved;
138
+ }
139
+ /**
140
+ * Result of composing multiple presets together.
141
+ * Options are deduplicated by preset id (first wins).
142
+ */
143
+ type ComposedPreset<TResolved extends Record<string, unknown>> = FlagPreset<TResolved>;
144
+ /**
145
+ * Configuration for the pagination flag preset.
146
+ */
147
+ interface PaginationPresetConfig {
148
+ /** Default limit when not specified (default: 20) */
149
+ readonly defaultLimit?: number;
150
+ /** Maximum allowed limit (default: 100) */
151
+ readonly maxLimit?: number;
152
+ }
153
+ /**
154
+ * Resolved interaction flags from CLI input.
155
+ */
156
+ type InteractionFlags = {
157
+ /** Whether interactive prompts are allowed */
158
+ readonly interactive: boolean;
159
+ /** Whether to auto-confirm prompts */
160
+ readonly yes: boolean;
161
+ };
162
+ /**
163
+ * Resolved strict mode flags from CLI input.
164
+ */
165
+ type StrictFlags = {
166
+ /** Whether strict mode is enabled */
167
+ readonly strict: boolean;
168
+ };
169
+ /**
170
+ * Resolved time-window flags from CLI input.
171
+ */
172
+ type TimeWindowFlags = {
173
+ /** Start of time window */
174
+ readonly since: Date | undefined;
175
+ /** End of time window */
176
+ readonly until: Date | undefined;
177
+ };
178
+ /**
179
+ * Configuration for the time-window flag preset.
180
+ */
181
+ interface TimeWindowPresetConfig {
182
+ /** Maximum range in milliseconds between since and until (optional guard) */
183
+ readonly maxRange?: number;
184
+ }
185
+ /**
186
+ * Resolved execution flags from CLI input.
187
+ */
188
+ type ExecutionFlags = {
189
+ /** Timeout in milliseconds (undefined = no timeout) */
190
+ readonly timeout: number | undefined;
191
+ /** Number of retries */
192
+ readonly retries: number;
193
+ /** Whether to operate in offline mode */
194
+ readonly offline: boolean;
195
+ };
196
+ /**
197
+ * Configuration for the execution flag preset.
198
+ */
199
+ interface ExecutionPresetConfig {
200
+ /** Default timeout in milliseconds (default: undefined) */
201
+ readonly defaultTimeout?: number;
202
+ /** Default number of retries (default: 0) */
203
+ readonly defaultRetries?: number;
204
+ /** Maximum number of retries (default: 10) */
205
+ readonly maxRetries?: number;
206
+ }
207
+ /**
208
+ * Resolved projection flags from CLI input.
209
+ */
210
+ type ProjectionFlags = {
211
+ /** Fields to include (undefined = all) */
212
+ readonly fields: string[] | undefined;
213
+ /** Fields to exclude (undefined = none) */
214
+ readonly excludeFields: string[] | undefined;
215
+ /** Whether to output only the count of results */
216
+ readonly count: boolean;
217
+ };
218
+ /**
219
+ * Color mode for CLI output.
220
+ */
221
+ type ColorMode = "auto" | "always" | "never";
222
+ /**
223
+ * Resolved color flags from CLI input.
224
+ */
225
+ type ColorFlags = {
226
+ /** Color output mode */
227
+ readonly color: ColorMode;
228
+ };
229
+ /**
230
+ * Resolved pagination flags from CLI input.
231
+ */
232
+ type PaginationFlags = {
233
+ /** Number of results to return */
234
+ readonly limit: number;
235
+ /** Continue from last position */
236
+ readonly next: boolean;
237
+ /** Clear saved cursor and start fresh */
238
+ readonly reset: boolean;
239
+ };
240
+ /**
88
241
  * Available output modes for CLI commands.
89
242
  */
90
243
  type OutputMode = "human" | "json" | "jsonl" | "tree" | "table";
@@ -239,4 +392,4 @@ interface CursorOptions {
239
392
  /** Total count of results (if known) */
240
393
  readonly total?: number;
241
394
  }
242
- export { CLIConfig, CLI, CommandConfig, CommandAction, CommandFlags, CommandBuilder, OutputMode, OutputOptions, CollectIdsOptions, ExpandFileOptions, ParseGlobOptions, NormalizeIdOptions, Range, NumericRange, DateRange, FilterExpression, SortCriteria, KeyValuePair, PaginationState, CursorOptions, CancelledError, ErrorCategory, ValidationError, Result };
395
+ export { CLIConfig, CLI, CommandConfig, CommandAction, CommandFlags, CommandBuilder, VerbFamily, VerbConfig, FlagPreset, FlagPresetConfig, ComposedPreset, PaginationPresetConfig, InteractionFlags, StrictFlags, TimeWindowFlags, TimeWindowPresetConfig, ExecutionFlags, ExecutionPresetConfig, ProjectionFlags, ColorMode, ColorFlags, PaginationFlags, OutputMode, OutputOptions, CollectIdsOptions, ExpandFileOptions, ParseGlobOptions, NormalizeIdOptions, Range, NumericRange, DateRange, FilterExpression, SortCriteria, KeyValuePair, PaginationState, CursorOptions, CancelledError, ErrorCategory, ValidationError, Result };
@@ -0,0 +1,33 @@
1
+ import { ActionManifest, ActionSource } from "@outfitter/schema";
2
+ import { Command } from "commander";
3
+ import { ActionManifest as ActionManifest2, ActionManifestEntry, ActionSource as ActionSource2, GenerateManifestOptions } from "@outfitter/schema";
4
+ import { generateManifest } from "@outfitter/schema";
5
+ interface SurfaceCommandOptions {
6
+ readonly cwd?: string;
7
+ readonly outputDir?: string;
8
+ }
9
+ interface SchemaCommandOptions {
10
+ readonly programName?: string;
11
+ readonly surface?: SurfaceCommandOptions;
12
+ }
13
+ /**
14
+ * Format a manifest for human-readable terminal output.
15
+ *
16
+ * @param manifest - The manifest to format
17
+ * @param programName - CLI program name (for header)
18
+ * @param actionId - If provided, show detail for this single action
19
+ * @returns Formatted string
20
+ */
21
+ declare function formatManifestHuman(manifest: ActionManifest, programName?: string, actionId?: string): string;
22
+ /**
23
+ * Create a `schema` command for CLI introspection.
24
+ *
25
+ * When `options.surface` is provided, adds `generate` and `diff` subcommands
26
+ * for surface map file I/O and drift detection.
27
+ *
28
+ * @param source - ActionRegistry or array of ActionSpec
29
+ * @param options - Command configuration
30
+ * @returns A Commander command instance
31
+ */
32
+ declare function createSchemaCommand(source: ActionSource, options?: SchemaCommandOptions): Command;
33
+ export { SurfaceCommandOptions, SchemaCommandOptions, formatManifestHuman, createSchemaCommand, ActionManifest2 as ActionManifest, ActionManifestEntry, ActionSource2 as ActionSource, GenerateManifestOptions, generateManifest };
package/dist/types.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { CLI, CLIConfig, CancelledError, CollectIdsOptions, CommandAction, CommandBuilder, CommandConfig, CommandFlags, CursorOptions, DateRange, ErrorCategory, ExpandFileOptions, FilterExpression, KeyValuePair, NormalizeIdOptions, NumericRange, OutputMode, OutputOptions, PaginationState, ParseGlobOptions, Range, Result, SortCriteria, ValidationError } from "./shared/@outfitter/cli-02kyvj7h";
2
- export { ValidationError, SortCriteria, Result, Range, ParseGlobOptions, PaginationState, OutputOptions, OutputMode, NumericRange, NormalizeIdOptions, KeyValuePair, FilterExpression, ExpandFileOptions, ErrorCategory, DateRange, CursorOptions, CommandFlags, CommandConfig, CommandBuilder, CommandAction, CollectIdsOptions, CancelledError, CLIConfig, CLI };
1
+ import { CLI, CLIConfig, CancelledError, CollectIdsOptions, ColorFlags, ColorMode, CommandAction, CommandBuilder, CommandConfig, CommandFlags, ComposedPreset, CursorOptions, DateRange, ErrorCategory, ExecutionFlags, ExecutionPresetConfig, ExpandFileOptions, FilterExpression, FlagPreset, FlagPresetConfig, InteractionFlags, KeyValuePair, NormalizeIdOptions, NumericRange, OutputMode, OutputOptions, PaginationFlags, PaginationPresetConfig, PaginationState, ParseGlobOptions, ProjectionFlags, Range, Result, SortCriteria, StrictFlags, TimeWindowFlags, TimeWindowPresetConfig, ValidationError, VerbConfig, VerbFamily } from "./shared/@outfitter/cli-md9347gn";
2
+ export { VerbFamily, VerbConfig, ValidationError, TimeWindowPresetConfig, TimeWindowFlags, StrictFlags, SortCriteria, Result, Range, ProjectionFlags, ParseGlobOptions, PaginationState, PaginationPresetConfig, PaginationFlags, OutputOptions, OutputMode, NumericRange, NormalizeIdOptions, KeyValuePair, InteractionFlags, FlagPresetConfig, FlagPreset, FilterExpression, ExpandFileOptions, ExecutionPresetConfig, ExecutionFlags, ErrorCategory, DateRange, CursorOptions, ComposedPreset, CommandFlags, CommandConfig, CommandBuilder, CommandAction, ColorMode, ColorFlags, CollectIdsOptions, CancelledError, CLIConfig, CLI };
@@ -0,0 +1,50 @@
1
+ import { CommandBuilder, VerbConfig, VerbFamily } from "./shared/@outfitter/cli-md9347gn";
2
+ /**
3
+ * Built-in verb families with standard primary verbs and aliases.
4
+ *
5
+ * These follow POSIX and modern CLI conventions:
6
+ * - `create` / `new` — Create a new resource
7
+ * - `modify` / `edit` / `update` — Modify an existing resource
8
+ * - `remove` / `delete` / `rm` — Remove a resource
9
+ * - `list` / `ls` — List resources
10
+ * - `show` / `get` / `view` — Show resource details
11
+ */
12
+ declare const VERB_FAMILIES: Readonly<Record<string, VerbFamily>>;
13
+ /**
14
+ * Resolve a verb family with optional project-level config overrides.
15
+ *
16
+ * @param family - Name of the verb family (e.g., "create", "modify")
17
+ * @param config - Optional overrides for primary verb, aliases, etc.
18
+ * @returns Resolved verb name and aliases
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * resolveVerb("modify"); // { name: "modify", aliases: ["edit", "update"] }
23
+ * resolveVerb("modify", { primary: "edit" }); // { name: "edit", aliases: ["update"] }
24
+ * resolveVerb("remove", { aliases: false }); // { name: "remove", aliases: [] }
25
+ * ```
26
+ */
27
+ declare function resolveVerb(family: string, config?: VerbConfig): {
28
+ name: string;
29
+ aliases: string[];
30
+ };
31
+ /**
32
+ * Apply verb conventions to a CommandBuilder.
33
+ *
34
+ * Adds aliases from the resolved verb family to the command builder.
35
+ *
36
+ * @param builder - CommandBuilder to apply aliases to
37
+ * @param family - Name of the verb family
38
+ * @param config - Optional overrides
39
+ * @returns The builder for chaining
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const cmd = command("remove <id>")
44
+ * .description("Remove a resource");
45
+ * applyVerb(cmd, "remove");
46
+ * // Adds aliases: "delete", "rm"
47
+ * ```
48
+ */
49
+ declare function applyVerb(builder: CommandBuilder, family: string, config?: VerbConfig): CommandBuilder;
50
+ export { resolveVerb, applyVerb, VERB_FAMILIES };
package/dist/verbs.js ADDED
@@ -0,0 +1,61 @@
1
+ // @bun
2
+ // packages/cli/src/verbs.ts
3
+ var VERB_FAMILIES = {
4
+ create: {
5
+ primary: "create",
6
+ aliases: ["new"],
7
+ description: "Create a new resource"
8
+ },
9
+ modify: {
10
+ primary: "modify",
11
+ aliases: ["edit", "update"],
12
+ description: "Modify a resource"
13
+ },
14
+ remove: {
15
+ primary: "remove",
16
+ aliases: ["delete", "rm"],
17
+ description: "Remove a resource"
18
+ },
19
+ list: {
20
+ primary: "list",
21
+ aliases: ["ls"],
22
+ description: "List resources"
23
+ },
24
+ show: {
25
+ primary: "show",
26
+ aliases: ["get", "view"],
27
+ description: "Show details"
28
+ }
29
+ };
30
+ function resolveVerb(family, config) {
31
+ const def = VERB_FAMILIES[family];
32
+ if (!Object.hasOwn(VERB_FAMILIES, family) || def === undefined) {
33
+ throw new Error(`Unknown verb family: "${family}"`);
34
+ }
35
+ const name = config?.primary ?? def.primary;
36
+ if (config?.aliases === false) {
37
+ return { name, aliases: [] };
38
+ }
39
+ let aliases = [...def.aliases].filter((a) => a !== name);
40
+ if (config?.extraAliases) {
41
+ aliases.push(...config.extraAliases);
42
+ }
43
+ if (config?.excludeAliases) {
44
+ const exclude = new Set(config.excludeAliases);
45
+ aliases = aliases.filter((a) => !exclude.has(a));
46
+ }
47
+ aliases = [...new Set(aliases)];
48
+ return { name, aliases };
49
+ }
50
+ function applyVerb(builder, family, config) {
51
+ const { aliases } = resolveVerb(family, config);
52
+ for (const alias of aliases) {
53
+ builder.alias(alias);
54
+ }
55
+ return builder;
56
+ }
57
+ export {
58
+ resolveVerb,
59
+ applyVerb,
60
+ VERB_FAMILIES
61
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@outfitter/cli",
3
3
  "description": "Typed CLI runtime with terminal detection, rendering, output contracts, and input parsing",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "dist"
@@ -33,6 +33,18 @@
33
33
  "default": "./dist/command.js"
34
34
  }
35
35
  },
36
+ "./completion": {
37
+ "import": {
38
+ "types": "./dist/completion.d.ts",
39
+ "default": "./dist/completion.js"
40
+ }
41
+ },
42
+ "./flags": {
43
+ "import": {
44
+ "types": "./dist/flags.d.ts",
45
+ "default": "./dist/flags.js"
46
+ }
47
+ },
36
48
  "./input": {
37
49
  "import": {
38
50
  "types": "./dist/input.d.ts",
@@ -52,6 +64,18 @@
52
64
  "default": "./dist/pagination.js"
53
65
  }
54
66
  },
67
+ "./query": {
68
+ "import": {
69
+ "types": "./dist/query.d.ts",
70
+ "default": "./dist/query.js"
71
+ }
72
+ },
73
+ "./schema": {
74
+ "import": {
75
+ "types": "./dist/schema.d.ts",
76
+ "default": "./dist/schema.js"
77
+ }
78
+ },
55
79
  "./terminal": {
56
80
  "import": {
57
81
  "types": "./dist/terminal/index.d.ts",
@@ -75,6 +99,12 @@
75
99
  "types": "./dist/types.d.ts",
76
100
  "default": "./dist/types.js"
77
101
  }
102
+ },
103
+ "./verbs": {
104
+ "import": {
105
+ "types": "./dist/verbs.d.ts",
106
+ "default": "./dist/verbs.js"
107
+ }
78
108
  }
79
109
  },
80
110
  "sideEffects": false,
@@ -95,12 +125,14 @@
95
125
  "peerDependencies": {
96
126
  "@outfitter/config": ">=0.3.0",
97
127
  "@outfitter/contracts": ">=0.2.0",
128
+ "@outfitter/schema": ">=0.1.0",
98
129
  "@outfitter/types": ">=0.2.0",
99
130
  "zod": "^4.3.5"
100
131
  },
101
132
  "devDependencies": {
102
- "@outfitter/config": "0.3.1",
103
- "@outfitter/contracts": "0.3.0",
133
+ "@outfitter/config": "0.3.2",
134
+ "@outfitter/contracts": "0.4.0",
135
+ "@outfitter/schema": "0.2.0",
104
136
  "@types/bun": "^1.3.7",
105
137
  "@types/node": "^25.0.10",
106
138
  "typescript": "^5.9.3"