@outfitter/cli 0.4.1 → 0.5.1
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/README.md +1 -1
- package/dist/actions.d.ts +19 -2
- package/dist/actions.js +29 -1
- package/dist/cli.d.ts +1 -1
- package/dist/command.d.ts +1 -1
- package/dist/flags.d.ts +24 -2
- package/dist/flags.js +10 -2
- package/dist/index.d.ts +2 -2
- package/dist/input.d.ts +1 -1
- package/dist/output.d.ts +2 -2
- package/dist/pagination.d.ts +1 -1
- package/dist/query.d.ts +1 -1
- package/dist/query.js +1 -1
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +11 -0
- package/dist/shared/@outfitter/{cli-md9347gn.d.ts → cli-7n5zmndx.d.ts} +94 -1
- package/dist/shared/@outfitter/cli-g0sn0r0b.js +319 -0
- package/dist/shared/@outfitter/cli-n1k0d23k.d.ts +33 -0
- package/dist/shared/@outfitter/{cli-b2zk8fb3.js → cli-pdb7znbq.js} +144 -1
- package/dist/shared/@outfitter/{cli-k0yvzn6d.d.ts → cli-z7mgapx5.d.ts} +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/verbs.d.ts +1 -1
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -486,7 +486,7 @@ import type { PaginationState, CursorOptions } from "@outfitter/cli/pagination";
|
|
|
486
486
|
|
|
487
487
|
## Upgrading
|
|
488
488
|
|
|
489
|
-
Run `outfitter
|
|
489
|
+
Run `outfitter upgrade --guide` for version-specific migration instructions, or check the [migration docs](https://github.com/outfitter-dev/outfitter/tree/main/plugins/outfitter/shared/migrations) for detailed upgrade steps.
|
|
490
490
|
|
|
491
491
|
## License
|
|
492
492
|
|
package/dist/actions.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SchemaCommandOptions } from "./shared/@outfitter/cli-n1k0d23k";
|
|
2
|
+
import { FlagPreset } from "./shared/@outfitter/cli-7n5zmndx";
|
|
3
|
+
import { ActionCliInputContext, ActionCliOption, ActionRegistry, ActionSurface, AnyActionSpec, HandlerContext } from "@outfitter/contracts";
|
|
2
4
|
import { Command } from "commander";
|
|
3
5
|
interface BuildCliCommandsOptions {
|
|
4
6
|
readonly createContext?: (input: {
|
|
@@ -7,7 +9,22 @@ interface BuildCliCommandsOptions {
|
|
|
7
9
|
flags: Record<string, unknown>;
|
|
8
10
|
}) => HandlerContext;
|
|
9
11
|
readonly includeSurfaces?: readonly ActionSurface[];
|
|
12
|
+
readonly schema?: boolean | SchemaCommandOptions;
|
|
10
13
|
}
|
|
11
14
|
type ActionSource = ActionRegistry | readonly AnyActionSpec[];
|
|
15
|
+
type ResolvedType<T> = T extends FlagPreset<infer R> ? R : never;
|
|
16
|
+
type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
17
|
+
type MergedPresetResult<TPresets extends readonly FlagPreset<Record<string, unknown>>[]> = UnionToIntersection<ResolvedType<TPresets[number]>> extends Record<string, unknown> ? UnionToIntersection<ResolvedType<TPresets[number]>> : Record<string, unknown>;
|
|
18
|
+
interface ActionCliPresetAdapter<TResolved extends Record<string, unknown>> {
|
|
19
|
+
readonly options: readonly ActionCliOption[];
|
|
20
|
+
readonly resolve: (input: ActionCliInputContext | Record<string, unknown>) => TResolved;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Compose flag presets for action-spec CLI definitions.
|
|
24
|
+
*
|
|
25
|
+
* Returns an options array for `action.cli.options` and a typed `resolve()`
|
|
26
|
+
* that accepts either raw flags or full `ActionCliInputContext`.
|
|
27
|
+
*/
|
|
28
|
+
declare function actionCliPresets<TPresets extends readonly FlagPreset<Record<string, unknown>>[]>(...presets: TPresets): ActionCliPresetAdapter<MergedPresetResult<TPresets>>;
|
|
12
29
|
declare function buildCliCommands(source: ActionSource, options?: BuildCliCommandsOptions): Command[];
|
|
13
|
-
export { buildCliCommands, BuildCliCommandsOptions };
|
|
30
|
+
export { buildCliCommands, actionCliPresets, BuildCliCommandsOptions, ActionCliPresetAdapter };
|
package/dist/actions.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
import {
|
|
3
|
+
createSchemaCommand
|
|
4
|
+
} from "./shared/@outfitter/cli-g0sn0r0b.js";
|
|
5
|
+
import {
|
|
6
|
+
composePresets
|
|
7
|
+
} from "./shared/@outfitter/cli-pdb7znbq.js";
|
|
8
|
+
|
|
2
9
|
// packages/cli/src/actions.ts
|
|
3
10
|
import {
|
|
4
11
|
createContext as createHandlerContext,
|
|
@@ -7,6 +14,19 @@ import {
|
|
|
7
14
|
} from "@outfitter/contracts";
|
|
8
15
|
import { Command } from "commander";
|
|
9
16
|
var ARGUMENT_PREFIXES = ["<", "["];
|
|
17
|
+
function isInputContext(input) {
|
|
18
|
+
return "flags" in input && typeof input.flags === "object" && "args" in input && Array.isArray(input.args);
|
|
19
|
+
}
|
|
20
|
+
function actionCliPresets(...presets) {
|
|
21
|
+
const composed = composePresets(...presets);
|
|
22
|
+
return {
|
|
23
|
+
options: composed.options,
|
|
24
|
+
resolve: (input) => {
|
|
25
|
+
const flags = isInputContext(input) ? input.flags : input;
|
|
26
|
+
return composed.resolve(flags);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
10
30
|
function isArgumentToken(token) {
|
|
11
31
|
if (!token) {
|
|
12
32
|
return false;
|
|
@@ -163,11 +183,19 @@ function buildCliCommands(source, options = {}) {
|
|
|
163
183
|
}
|
|
164
184
|
commands.push(groupCommand);
|
|
165
185
|
}
|
|
186
|
+
if (options.schema !== false) {
|
|
187
|
+
const hasSchemaCommand = commands.some((cmd) => cmd.name() === "schema");
|
|
188
|
+
if (!hasSchemaCommand) {
|
|
189
|
+
const schemaOptions = typeof options.schema === "object" ? options.schema : undefined;
|
|
190
|
+
commands.push(createSchemaCommand(source, schemaOptions));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
166
193
|
return commands;
|
|
167
194
|
}
|
|
168
195
|
function isActionRegistry(source) {
|
|
169
196
|
return "list" in source;
|
|
170
197
|
}
|
|
171
198
|
export {
|
|
172
|
-
buildCliCommands
|
|
199
|
+
buildCliCommands,
|
|
200
|
+
actionCliPresets
|
|
173
201
|
};
|
package/dist/cli.d.ts
CHANGED
package/dist/command.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CLI, CLIConfig, CommandAction, CommandBuilder, CommandConfig, CommandFlags, FlagPreset } from "./shared/@outfitter/cli-
|
|
1
|
+
import { CLI, CLIConfig, CommandAction, CommandBuilder, CommandConfig, CommandFlags, FlagPreset } from "./shared/@outfitter/cli-7n5zmndx";
|
|
2
2
|
/**
|
|
3
3
|
* Create a CLI instance with a portable return type from this module.
|
|
4
4
|
*/
|
package/dist/flags.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColorFlags, ColorMode, ComposedPreset, ExecutionFlags, ExecutionPresetConfig, FlagPreset, FlagPresetConfig, InteractionFlags, PaginationFlags, PaginationPresetConfig, ProjectionFlags, StrictFlags, TimeWindowFlags, TimeWindowPresetConfig } from "./shared/@outfitter/cli-
|
|
1
|
+
import { BooleanFlagPresetConfig, ColorFlags, ColorMode, ComposedPreset, EnumFlagPresetConfig, ExecutionFlags, ExecutionPresetConfig, FlagPreset, FlagPresetConfig, InteractionFlags, NumberFlagPresetConfig, PaginationFlags, PaginationPresetConfig, ProjectionFlags, StrictFlags, StringListFlagPresetConfig, TimeWindowFlags, TimeWindowPresetConfig } from "./shared/@outfitter/cli-7n5zmndx";
|
|
2
2
|
/**
|
|
3
3
|
* Create a typed flag preset.
|
|
4
4
|
*
|
|
@@ -44,6 +44,28 @@ type MergedPresetResult<TPresets extends readonly FlagPreset<Record<string, unkn
|
|
|
44
44
|
*/
|
|
45
45
|
declare function composePresets<TPresets extends readonly FlagPreset<Record<string, unknown>>[]>(...presets: TPresets): ComposedPreset<MergedPresetResult<TPresets>>;
|
|
46
46
|
/**
|
|
47
|
+
* Generic boolean custom-flag builder.
|
|
48
|
+
*
|
|
49
|
+
* Supports normal sources and negated sources so `--no-foo` patterns can
|
|
50
|
+
* resolve consistently across Commander flag-shape differences.
|
|
51
|
+
*/
|
|
52
|
+
declare function booleanFlagPreset<TKey extends string>(config: BooleanFlagPresetConfig<TKey>): FlagPreset<{ [K in TKey] : boolean }>;
|
|
53
|
+
/**
|
|
54
|
+
* Generic enum custom-flag builder.
|
|
55
|
+
*/
|
|
56
|
+
declare function enumFlagPreset<
|
|
57
|
+
TKey extends string,
|
|
58
|
+
TValue extends string
|
|
59
|
+
>(config: EnumFlagPresetConfig<TKey, TValue>): FlagPreset<{ [K in TKey] : TValue }>;
|
|
60
|
+
/**
|
|
61
|
+
* Generic number custom-flag builder.
|
|
62
|
+
*/
|
|
63
|
+
declare function numberFlagPreset<TKey extends string>(config: NumberFlagPresetConfig<TKey>): FlagPreset<{ [K in TKey] : number }>;
|
|
64
|
+
/**
|
|
65
|
+
* Generic string-list custom-flag builder.
|
|
66
|
+
*/
|
|
67
|
+
declare function stringListFlagPreset<TKey extends string>(config: StringListFlagPresetConfig<TKey>): FlagPreset<{ [K in TKey] : string[] | undefined }>;
|
|
68
|
+
/**
|
|
47
69
|
* Verbose output flag preset.
|
|
48
70
|
*
|
|
49
71
|
* Adds: `-v, --verbose`
|
|
@@ -164,4 +186,4 @@ declare function executionPreset(config?: ExecutionPresetConfig): FlagPreset<Exe
|
|
|
164
186
|
* `@outfitter/cli/pagination`.
|
|
165
187
|
*/
|
|
166
188
|
declare function paginationPreset(config?: PaginationPresetConfig): FlagPreset<PaginationFlags>;
|
|
167
|
-
export { verbosePreset, timeWindowPreset, strictPreset, projectionPreset, paginationPreset, interactionPreset, forcePreset, executionPreset, dryRunPreset, cwdPreset, createPreset, composePresets, colorPreset, TimeWindowPresetConfig, TimeWindowFlags, StrictFlags, ProjectionFlags, PaginationPresetConfig, PaginationFlags, InteractionFlags, FlagPresetConfig, FlagPreset, ExecutionPresetConfig, ExecutionFlags, ComposedPreset, ColorMode, ColorFlags };
|
|
189
|
+
export { verbosePreset, timeWindowPreset, stringListFlagPreset, strictPreset, projectionPreset, paginationPreset, numberFlagPreset, interactionPreset, forcePreset, executionPreset, enumFlagPreset, dryRunPreset, cwdPreset, createPreset, composePresets, colorPreset, booleanFlagPreset, TimeWindowPresetConfig, TimeWindowFlags, StringListFlagPresetConfig, StrictFlags, ProjectionFlags, PaginationPresetConfig, PaginationFlags, NumberFlagPresetConfig, InteractionFlags, FlagPresetConfig, FlagPreset, ExecutionPresetConfig, ExecutionFlags, EnumFlagPresetConfig, ComposedPreset, ColorMode, ColorFlags, BooleanFlagPresetConfig };
|
package/dist/flags.js
CHANGED
|
@@ -1,31 +1,39 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
+
booleanFlagPreset,
|
|
3
4
|
colorPreset,
|
|
4
5
|
composePresets,
|
|
5
6
|
createPreset,
|
|
6
7
|
cwdPreset,
|
|
7
8
|
dryRunPreset,
|
|
9
|
+
enumFlagPreset,
|
|
8
10
|
executionPreset,
|
|
9
11
|
forcePreset,
|
|
10
12
|
interactionPreset,
|
|
13
|
+
numberFlagPreset,
|
|
11
14
|
paginationPreset,
|
|
12
15
|
projectionPreset,
|
|
13
16
|
strictPreset,
|
|
17
|
+
stringListFlagPreset,
|
|
14
18
|
timeWindowPreset,
|
|
15
19
|
verbosePreset
|
|
16
|
-
} from "./shared/@outfitter/cli-
|
|
20
|
+
} from "./shared/@outfitter/cli-pdb7znbq.js";
|
|
17
21
|
export {
|
|
18
22
|
verbosePreset,
|
|
19
23
|
timeWindowPreset,
|
|
24
|
+
stringListFlagPreset,
|
|
20
25
|
strictPreset,
|
|
21
26
|
projectionPreset,
|
|
22
27
|
paginationPreset,
|
|
28
|
+
numberFlagPreset,
|
|
23
29
|
interactionPreset,
|
|
24
30
|
forcePreset,
|
|
25
31
|
executionPreset,
|
|
32
|
+
enumFlagPreset,
|
|
26
33
|
dryRunPreset,
|
|
27
34
|
cwdPreset,
|
|
28
35
|
createPreset,
|
|
29
36
|
composePresets,
|
|
30
|
-
colorPreset
|
|
37
|
+
colorPreset,
|
|
38
|
+
booleanFlagPreset
|
|
31
39
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./shared/@outfitter/cli-qz47jk6d";
|
|
2
2
|
import { ANSI, Theme, Tokens, createTheme } from "./shared/@outfitter/cli-xppg982q";
|
|
3
|
-
import { exitWithError, output } from "./shared/@outfitter/cli-
|
|
4
|
-
import { OutputMode } from "./shared/@outfitter/cli-
|
|
3
|
+
import { exitWithError, output } from "./shared/@outfitter/cli-z7mgapx5";
|
|
4
|
+
import { OutputMode } from "./shared/@outfitter/cli-7n5zmndx";
|
|
5
5
|
export { output, exitWithError, createTheme, Tokens, Theme, OutputMode, ANSI };
|
package/dist/input.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CollectIdsOptions, ExpandFileOptions, FilterExpression, KeyValuePair, NormalizeIdOptions, ParseGlobOptions, Range, SortCriteria } from "./shared/@outfitter/cli-
|
|
1
|
+
import { CollectIdsOptions, ExpandFileOptions, FilterExpression, KeyValuePair, NormalizeIdOptions, ParseGlobOptions, Range, SortCriteria } from "./shared/@outfitter/cli-7n5zmndx";
|
|
2
2
|
import { ValidationError } from "@outfitter/contracts";
|
|
3
3
|
import { Result } from "better-result";
|
|
4
4
|
/**
|
package/dist/output.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { exitWithError, output, resolveVerbose } from "./shared/@outfitter/cli-
|
|
2
|
-
import "./shared/@outfitter/cli-
|
|
1
|
+
import { exitWithError, output, resolveVerbose } from "./shared/@outfitter/cli-z7mgapx5";
|
|
2
|
+
import "./shared/@outfitter/cli-7n5zmndx";
|
|
3
3
|
export { resolveVerbose, output, exitWithError };
|
package/dist/pagination.d.ts
CHANGED
package/dist/query.d.ts
CHANGED
package/dist/query.js
CHANGED
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { ActionManifest, ActionManifestEntry, ActionSource, GenerateManifestOptions, SchemaCommandOptions, SurfaceCommandOptions, createSchemaCommand, formatManifestHuman, generateManifest } from "./shared/@outfitter/cli-n1k0d23k";
|
|
2
|
+
export { generateManifest, formatManifestHuman, createSchemaCommand, SurfaceCommandOptions, SchemaCommandOptions, GenerateManifestOptions, ActionSource, ActionManifestEntry, ActionManifest };
|
package/dist/schema.js
ADDED
|
@@ -137,6 +137,99 @@ interface FlagPresetConfig<TResolved extends Record<string, unknown>> {
|
|
|
137
137
|
readonly resolve: (flags: Record<string, unknown>) => TResolved;
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
|
+
* Configuration for creating a custom boolean flag preset.
|
|
141
|
+
*/
|
|
142
|
+
interface BooleanFlagPresetConfig<TKey extends string> {
|
|
143
|
+
/** Unique identifier for deduplication */
|
|
144
|
+
readonly id: string;
|
|
145
|
+
/** Resolved output property name */
|
|
146
|
+
readonly key: TKey;
|
|
147
|
+
/** Commander option definition (e.g., "--force" or "--no-codemods") */
|
|
148
|
+
readonly flags: string;
|
|
149
|
+
/** Help description for the option */
|
|
150
|
+
readonly description: string;
|
|
151
|
+
/** Default resolved value (defaults to false) */
|
|
152
|
+
readonly defaultValue?: boolean;
|
|
153
|
+
/** Candidate raw flag keys to read (defaults to [key]) */
|
|
154
|
+
readonly sources?: readonly string[];
|
|
155
|
+
/** Positive keys that should be negated (e.g., "codemods" for --no-codemods) */
|
|
156
|
+
readonly negatedSources?: readonly string[];
|
|
157
|
+
/** Whether the option is required */
|
|
158
|
+
readonly required?: boolean;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Configuration for creating a custom enum flag preset.
|
|
162
|
+
*/
|
|
163
|
+
interface EnumFlagPresetConfig<
|
|
164
|
+
TKey extends string,
|
|
165
|
+
TValue extends string
|
|
166
|
+
> {
|
|
167
|
+
/** Unique identifier for deduplication */
|
|
168
|
+
readonly id: string;
|
|
169
|
+
/** Resolved output property name */
|
|
170
|
+
readonly key: TKey;
|
|
171
|
+
/** Commander option definition */
|
|
172
|
+
readonly flags: string;
|
|
173
|
+
/** Help description for the option */
|
|
174
|
+
readonly description: string;
|
|
175
|
+
/** Allowed enum values */
|
|
176
|
+
readonly values: readonly TValue[];
|
|
177
|
+
/** Fallback value when input is missing or invalid */
|
|
178
|
+
readonly defaultValue: TValue;
|
|
179
|
+
/** Candidate raw flag keys to read (defaults to [key]) */
|
|
180
|
+
readonly sources?: readonly string[];
|
|
181
|
+
/** Whether the option is required */
|
|
182
|
+
readonly required?: boolean;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Configuration for creating a custom numeric flag preset.
|
|
186
|
+
*/
|
|
187
|
+
interface NumberFlagPresetConfig<TKey extends string> {
|
|
188
|
+
/** Unique identifier for deduplication */
|
|
189
|
+
readonly id: string;
|
|
190
|
+
/** Resolved output property name */
|
|
191
|
+
readonly key: TKey;
|
|
192
|
+
/** Commander option definition */
|
|
193
|
+
readonly flags: string;
|
|
194
|
+
/** Help description for the option */
|
|
195
|
+
readonly description: string;
|
|
196
|
+
/** Fallback value when input is missing or invalid */
|
|
197
|
+
readonly defaultValue: number;
|
|
198
|
+
/** Candidate raw flag keys to read (defaults to [key]) */
|
|
199
|
+
readonly sources?: readonly string[];
|
|
200
|
+
/** Lower bound (inclusive) */
|
|
201
|
+
readonly min?: number;
|
|
202
|
+
/** Upper bound (inclusive) */
|
|
203
|
+
readonly max?: number;
|
|
204
|
+
/** Floor parsed values (defaults to true) */
|
|
205
|
+
readonly integer?: boolean;
|
|
206
|
+
/** Whether the option is required */
|
|
207
|
+
readonly required?: boolean;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Configuration for creating a custom string-list flag preset.
|
|
211
|
+
*/
|
|
212
|
+
interface StringListFlagPresetConfig<TKey extends string> {
|
|
213
|
+
/** Unique identifier for deduplication */
|
|
214
|
+
readonly id: string;
|
|
215
|
+
/** Resolved output property name */
|
|
216
|
+
readonly key: TKey;
|
|
217
|
+
/** Commander option definition */
|
|
218
|
+
readonly flags: string;
|
|
219
|
+
/** Help description for the option */
|
|
220
|
+
readonly description: string;
|
|
221
|
+
/** Candidate raw flag keys to read (defaults to [key]) */
|
|
222
|
+
readonly sources?: readonly string[];
|
|
223
|
+
/** Fallback list when input is missing or invalid */
|
|
224
|
+
readonly defaultValue?: readonly string[];
|
|
225
|
+
/** Split string values by this separator (defaults to ",") */
|
|
226
|
+
readonly separator?: string;
|
|
227
|
+
/** Remove duplicate values while preserving order */
|
|
228
|
+
readonly dedupe?: boolean;
|
|
229
|
+
/** Whether the option is required */
|
|
230
|
+
readonly required?: boolean;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
140
233
|
* Result of composing multiple presets together.
|
|
141
234
|
* Options are deduplicated by preset id (first wins).
|
|
142
235
|
*/
|
|
@@ -392,4 +485,4 @@ interface CursorOptions {
|
|
|
392
485
|
/** Total count of results (if known) */
|
|
393
486
|
readonly total?: number;
|
|
394
487
|
}
|
|
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 };
|
|
488
|
+
export { CLIConfig, CLI, CommandConfig, CommandAction, CommandFlags, CommandBuilder, VerbFamily, VerbConfig, FlagPreset, FlagPresetConfig, BooleanFlagPresetConfig, EnumFlagPresetConfig, NumberFlagPresetConfig, StringListFlagPresetConfig, 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,319 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// packages/cli/src/schema.ts
|
|
3
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
|
+
import {
|
|
6
|
+
diffSurfaceMaps,
|
|
7
|
+
formatManifestMarkdown,
|
|
8
|
+
generateManifest,
|
|
9
|
+
generateSurfaceMap,
|
|
10
|
+
readSurfaceMap,
|
|
11
|
+
resolveSnapshotPath,
|
|
12
|
+
writeSurfaceMap
|
|
13
|
+
} from "@outfitter/schema";
|
|
14
|
+
import { Command } from "commander";
|
|
15
|
+
import { generateManifest as generateManifest2 } from "@outfitter/schema";
|
|
16
|
+
function formatManifestHuman(manifest, programName, actionId) {
|
|
17
|
+
if (actionId) {
|
|
18
|
+
return formatActionDetail(manifest, actionId);
|
|
19
|
+
}
|
|
20
|
+
return formatSummary(manifest, programName);
|
|
21
|
+
}
|
|
22
|
+
function formatSummary(manifest, programName) {
|
|
23
|
+
const lines = [];
|
|
24
|
+
const name = programName ?? "cli";
|
|
25
|
+
const actionCount = manifest.actions.length;
|
|
26
|
+
const surfaceCount = manifest.surfaces.length;
|
|
27
|
+
const surfaceLabel = surfaceCount === 1 ? `${surfaceCount} surface` : `${surfaceCount} surfaces`;
|
|
28
|
+
lines.push(`${name} \u2014 ${actionCount} actions across ${surfaceLabel}`);
|
|
29
|
+
lines.push("");
|
|
30
|
+
const grouped = new Map;
|
|
31
|
+
const ungrouped = [];
|
|
32
|
+
for (const action of manifest.actions) {
|
|
33
|
+
const group = action.cli?.group;
|
|
34
|
+
if (group) {
|
|
35
|
+
const existing = grouped.get(group) ?? [];
|
|
36
|
+
existing.push(action);
|
|
37
|
+
grouped.set(group, existing);
|
|
38
|
+
} else {
|
|
39
|
+
ungrouped.push(action);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const [groupName, groupActions] of grouped.entries()) {
|
|
43
|
+
lines.push(groupName);
|
|
44
|
+
for (const action of groupActions) {
|
|
45
|
+
const commandPart = action.cli?.command ?? action.id;
|
|
46
|
+
const isBase = !commandPart || commandPart.startsWith("[") || commandPart.startsWith("<");
|
|
47
|
+
const displayCommand = isBase ? ` ${groupName} ${commandPart ?? ""}`.trimEnd() : ` ${groupName} ${commandPart}`;
|
|
48
|
+
const desc = action.cli?.description ?? action.description ?? "";
|
|
49
|
+
lines.push(padCommand(displayCommand, desc));
|
|
50
|
+
}
|
|
51
|
+
lines.push("");
|
|
52
|
+
}
|
|
53
|
+
for (const action of ungrouped) {
|
|
54
|
+
const commandPart = action.cli?.command ?? action.id;
|
|
55
|
+
const desc = action.cli?.description ?? action.description ?? "";
|
|
56
|
+
lines.push(padCommand(`${commandPart}`, desc));
|
|
57
|
+
}
|
|
58
|
+
lines.push("");
|
|
59
|
+
lines.push("Use --output json for machine-readable format.");
|
|
60
|
+
lines.push("Use --surface <name> to filter (cli, mcp, api, server).");
|
|
61
|
+
return lines.join(`
|
|
62
|
+
`);
|
|
63
|
+
}
|
|
64
|
+
function padCommand(command, description) {
|
|
65
|
+
const padding = Math.max(1, 32 - command.length);
|
|
66
|
+
return `${command}${" ".repeat(padding)}${description}`;
|
|
67
|
+
}
|
|
68
|
+
function formatActionDetail(manifest, actionId) {
|
|
69
|
+
const entry = manifest.actions.find((a) => a.id === actionId);
|
|
70
|
+
if (!entry) {
|
|
71
|
+
return `Unknown action: ${actionId}`;
|
|
72
|
+
}
|
|
73
|
+
const lines = [];
|
|
74
|
+
const desc = entry.cli?.description ?? entry.description ?? "";
|
|
75
|
+
lines.push(`${entry.id} \u2014 ${desc}`);
|
|
76
|
+
lines.push("");
|
|
77
|
+
if (entry.cli) {
|
|
78
|
+
const group = entry.cli.group;
|
|
79
|
+
const commandPart = entry.cli.command ?? entry.id;
|
|
80
|
+
const fullCommand = group ? `${group} ${commandPart}` : commandPart;
|
|
81
|
+
lines.push(` Command: ${fullCommand}`);
|
|
82
|
+
}
|
|
83
|
+
lines.push(` Surfaces: ${entry.surfaces.join(", ")}`);
|
|
84
|
+
if (entry.cli?.group) {
|
|
85
|
+
lines.push(` Group: ${entry.cli.group}`);
|
|
86
|
+
}
|
|
87
|
+
if (entry.cli?.aliases && entry.cli.aliases.length > 0) {
|
|
88
|
+
lines.push(` Aliases: ${entry.cli.aliases.join(", ")}`);
|
|
89
|
+
}
|
|
90
|
+
if (entry.cli?.options && entry.cli.options.length > 0) {
|
|
91
|
+
lines.push("");
|
|
92
|
+
lines.push(" Options:");
|
|
93
|
+
for (const opt of entry.cli.options) {
|
|
94
|
+
const defaultStr = opt.defaultValue !== undefined ? ` [${String(opt.defaultValue)}]` : "";
|
|
95
|
+
lines.push(padCommand(` ${opt.flags}`, `${opt.description}${defaultStr}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (entry.mcp) {
|
|
99
|
+
lines.push("");
|
|
100
|
+
lines.push(" MCP:");
|
|
101
|
+
if (entry.mcp.tool) {
|
|
102
|
+
lines.push(` Tool: ${entry.mcp.tool}`);
|
|
103
|
+
}
|
|
104
|
+
if (entry.mcp.description) {
|
|
105
|
+
lines.push(` Description: ${entry.mcp.description}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return lines.join(`
|
|
109
|
+
`);
|
|
110
|
+
}
|
|
111
|
+
function handleShow(source, programName, parentCmd, actionArg, cmdOptions) {
|
|
112
|
+
const manifestOptions = {};
|
|
113
|
+
if (cmdOptions.surface) {
|
|
114
|
+
manifestOptions.surface = cmdOptions.surface;
|
|
115
|
+
}
|
|
116
|
+
const manifest = generateManifest(source, manifestOptions);
|
|
117
|
+
if (cmdOptions.output === "json") {
|
|
118
|
+
const indent = cmdOptions.pretty ? 2 : undefined;
|
|
119
|
+
if (actionArg) {
|
|
120
|
+
const entry = manifest.actions.find((a) => a.id === actionArg);
|
|
121
|
+
if (!entry) {
|
|
122
|
+
process.stderr.write(`Unknown action: ${actionArg}
|
|
123
|
+
`);
|
|
124
|
+
process.exitCode = 1;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
process.stdout.write(`${JSON.stringify(entry, null, indent)}
|
|
128
|
+
`);
|
|
129
|
+
} else {
|
|
130
|
+
process.stdout.write(`${JSON.stringify(manifest, null, indent)}
|
|
131
|
+
`);
|
|
132
|
+
}
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const resolvedName = programName ?? parentCmd.parent?.name() ?? undefined;
|
|
136
|
+
const output = formatManifestHuman(manifest, resolvedName, actionArg);
|
|
137
|
+
process.stdout.write(`${output}
|
|
138
|
+
`);
|
|
139
|
+
}
|
|
140
|
+
function createSchemaCommand(source, options) {
|
|
141
|
+
const cmd = new Command("schema").description("Show CLI schema for machine or human consumption").argument("[action]", "Show detail for a specific action").option("--output <mode>", "Output mode (human, json)", "human").option("--surface <name>", "Filter by surface (cli, mcp, api, server)").option("--pretty", "Pretty-print JSON output").action((actionArg, cmdOptions) => {
|
|
142
|
+
handleShow(source, options?.programName, cmd, actionArg, cmdOptions);
|
|
143
|
+
});
|
|
144
|
+
const showCmd = new Command("show").description("Show schema for all actions or a specific action").argument("[action]", "Show detail for a specific action").option("--output <mode>", "Output mode (human, json)", "human").option("--surface <name>", "Filter by surface (cli, mcp, api, server)").option("--pretty", "Pretty-print JSON output").action((actionArg, cmdOptions) => {
|
|
145
|
+
handleShow(source, options?.programName, cmd, actionArg, cmdOptions);
|
|
146
|
+
});
|
|
147
|
+
cmd.addCommand(showCmd);
|
|
148
|
+
if (options?.surface) {
|
|
149
|
+
const surfaceOpts = options.surface;
|
|
150
|
+
const cwd = surfaceOpts.cwd ?? process.cwd();
|
|
151
|
+
const outputDir = surfaceOpts.outputDir ?? ".outfitter";
|
|
152
|
+
const generateCmd = new Command("generate").description("Generate surface map and write to disk").option("--dry-run", "Print surface map without writing to disk").option("--snapshot <version>", "Write snapshot to .outfitter/snapshots/<version>.json").action(async (genOptions) => {
|
|
153
|
+
const surfaceMap = generateSurfaceMap(source, {
|
|
154
|
+
generator: "build"
|
|
155
|
+
});
|
|
156
|
+
if (genOptions.dryRun) {
|
|
157
|
+
process.stdout.write(`${JSON.stringify(surfaceMap, null, 2)}
|
|
158
|
+
`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (genOptions.snapshot) {
|
|
162
|
+
const snapshotPath = resolveSnapshotPath(cwd, outputDir, genOptions.snapshot);
|
|
163
|
+
await writeSurfaceMap(surfaceMap, snapshotPath);
|
|
164
|
+
process.stdout.write(`Snapshot written to ${snapshotPath}
|
|
165
|
+
`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const outputPath = join(cwd, outputDir, "surface.json");
|
|
169
|
+
await writeSurfaceMap(surfaceMap, outputPath);
|
|
170
|
+
process.stdout.write(`Surface map written to ${outputPath}
|
|
171
|
+
`);
|
|
172
|
+
});
|
|
173
|
+
cmd.addCommand(generateCmd);
|
|
174
|
+
const diffCmd = new Command("diff").description("Compare runtime schema against committed surface map").option("--output <mode>", "Output mode (human, json)", "human").option("--against <version>", "Compare runtime against a named snapshot").option("--from <version>", "Base snapshot for snapshot-to-snapshot diff").option("--to <version>", "Target snapshot for snapshot-to-snapshot diff").action(async (diffOptions) => {
|
|
175
|
+
let left;
|
|
176
|
+
let right;
|
|
177
|
+
if (diffOptions.from && !diffOptions.to || !diffOptions.from && diffOptions.to) {
|
|
178
|
+
process.stderr.write(`Both --from and --to are required for snapshot-to-snapshot diff.
|
|
179
|
+
`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (diffOptions.from && diffOptions.to) {
|
|
184
|
+
const fromPath = resolveSnapshotPath(cwd, outputDir, diffOptions.from);
|
|
185
|
+
const toPath = resolveSnapshotPath(cwd, outputDir, diffOptions.to);
|
|
186
|
+
try {
|
|
187
|
+
left = await readSurfaceMap(fromPath);
|
|
188
|
+
} catch (err) {
|
|
189
|
+
if (err.code === "ENOENT") {
|
|
190
|
+
process.stderr.write(`No snapshot at ${fromPath}
|
|
191
|
+
`);
|
|
192
|
+
} else {
|
|
193
|
+
process.stderr.write(`Failed to read snapshot at ${fromPath}: ${err instanceof Error ? err.message : String(err)}
|
|
194
|
+
`);
|
|
195
|
+
}
|
|
196
|
+
process.exitCode = 1;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
right = await readSurfaceMap(toPath);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
if (err.code === "ENOENT") {
|
|
203
|
+
process.stderr.write(`No snapshot at ${toPath}
|
|
204
|
+
`);
|
|
205
|
+
} else {
|
|
206
|
+
process.stderr.write(`Failed to read snapshot at ${toPath}: ${err instanceof Error ? err.message : String(err)}
|
|
207
|
+
`);
|
|
208
|
+
}
|
|
209
|
+
process.exitCode = 1;
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
} else if (diffOptions.against) {
|
|
213
|
+
const snapshotPath = resolveSnapshotPath(cwd, outputDir, diffOptions.against);
|
|
214
|
+
try {
|
|
215
|
+
left = await readSurfaceMap(snapshotPath);
|
|
216
|
+
} catch (err) {
|
|
217
|
+
if (err.code === "ENOENT") {
|
|
218
|
+
process.stderr.write(`No snapshot at ${snapshotPath}
|
|
219
|
+
`);
|
|
220
|
+
} else {
|
|
221
|
+
process.stderr.write(`Failed to read snapshot at ${snapshotPath}: ${err instanceof Error ? err.message : String(err)}
|
|
222
|
+
`);
|
|
223
|
+
}
|
|
224
|
+
process.exitCode = 1;
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
right = generateSurfaceMap(source, { generator: "runtime" });
|
|
228
|
+
} else {
|
|
229
|
+
const surfacePath = join(cwd, outputDir, "surface.json");
|
|
230
|
+
try {
|
|
231
|
+
left = await readSurfaceMap(surfacePath);
|
|
232
|
+
} catch (err) {
|
|
233
|
+
if (err.code === "ENOENT") {
|
|
234
|
+
process.stderr.write(`No committed surface map at ${surfacePath}
|
|
235
|
+
`);
|
|
236
|
+
process.stderr.write(`Run 'schema generate' first.
|
|
237
|
+
`);
|
|
238
|
+
} else {
|
|
239
|
+
process.stderr.write(`Failed to read surface map at ${surfacePath}: ${err instanceof Error ? err.message : String(err)}
|
|
240
|
+
`);
|
|
241
|
+
}
|
|
242
|
+
process.exitCode = 1;
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
right = generateSurfaceMap(source, { generator: "runtime" });
|
|
246
|
+
}
|
|
247
|
+
const result = diffSurfaceMaps(left, right);
|
|
248
|
+
if (diffOptions.output === "json") {
|
|
249
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
250
|
+
`);
|
|
251
|
+
} else {
|
|
252
|
+
if (!result.hasChanges) {
|
|
253
|
+
process.stdout.write(`No schema drift detected.
|
|
254
|
+
`);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const lines = [];
|
|
258
|
+
lines.push(`Schema drift detected:
|
|
259
|
+
`);
|
|
260
|
+
if (result.added.length > 0) {
|
|
261
|
+
lines.push(" Added:");
|
|
262
|
+
for (const entry of result.added) {
|
|
263
|
+
lines.push(` + ${entry.id}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (result.removed.length > 0) {
|
|
267
|
+
lines.push(" Removed:");
|
|
268
|
+
for (const entry of result.removed) {
|
|
269
|
+
lines.push(` - ${entry.id}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (result.modified.length > 0) {
|
|
273
|
+
lines.push(" Modified:");
|
|
274
|
+
for (const entry of result.modified) {
|
|
275
|
+
lines.push(` ~ ${entry.id} (${entry.changes.join(", ")})`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (result.metadataChanges.length > 0) {
|
|
279
|
+
lines.push(" Metadata:");
|
|
280
|
+
for (const field of result.metadataChanges) {
|
|
281
|
+
lines.push(` ~ ${field}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
process.stdout.write(`${lines.join(`
|
|
285
|
+
`)}
|
|
286
|
+
`);
|
|
287
|
+
}
|
|
288
|
+
if (result.hasChanges) {
|
|
289
|
+
process.exitCode = 1;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
cmd.addCommand(diffCmd);
|
|
293
|
+
const docsCmd = new Command("docs").description("Generate markdown reference documentation").option("--surface <name>", "Which surface to document (cli, mcp)", "mcp").option("--output-dir <dir>", "Directory to write the reference doc", "docs/reference").option("--dry-run", "Print to stdout instead of writing to disk").action(async (docsOptions) => {
|
|
294
|
+
const surface = docsOptions.surface ?? "mcp";
|
|
295
|
+
if (surface !== "mcp" && surface !== "cli") {
|
|
296
|
+
process.stderr.write(`Unsupported surface for docs: "${surface}". Use "mcp" or "cli".
|
|
297
|
+
`);
|
|
298
|
+
process.exitCode = 1;
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const manifest = generateManifest(source, { surface });
|
|
302
|
+
const markdown = formatManifestMarkdown(manifest, { surface });
|
|
303
|
+
if (docsOptions.dryRun) {
|
|
304
|
+
process.stdout.write(markdown);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const outDir = docsOptions.outputDir ?? "docs/reference";
|
|
308
|
+
const outputPath = join(cwd, outDir, `${surface.toUpperCase()}_REFERENCE.md`);
|
|
309
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
310
|
+
await writeFile(outputPath, markdown, "utf-8");
|
|
311
|
+
process.stdout.write(`Reference written to ${outputPath}
|
|
312
|
+
`);
|
|
313
|
+
});
|
|
314
|
+
cmd.addCommand(docsCmd);
|
|
315
|
+
}
|
|
316
|
+
return cmd;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export { formatManifestHuman, createSchemaCommand, generateManifest2 as generateManifest };
|
|
@@ -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 };
|
|
@@ -46,6 +46,149 @@ function composePresets(...presets) {
|
|
|
46
46
|
composed[PRESET_IDS] = mergedIds;
|
|
47
47
|
return composed;
|
|
48
48
|
}
|
|
49
|
+
function resolveSourceKeys(key, sources) {
|
|
50
|
+
return sources && sources.length > 0 ? sources : [key];
|
|
51
|
+
}
|
|
52
|
+
function booleanFlagPreset(config) {
|
|
53
|
+
const sources = resolveSourceKeys(config.key, config.sources);
|
|
54
|
+
const defaultValue = config.defaultValue ?? false;
|
|
55
|
+
const isNegatedFlag = config.flags.includes("--no-");
|
|
56
|
+
const optionDefault = isNegatedFlag && config.defaultValue === undefined ? {} : { defaultValue };
|
|
57
|
+
return createPreset({
|
|
58
|
+
id: config.id,
|
|
59
|
+
options: [
|
|
60
|
+
{
|
|
61
|
+
flags: config.flags,
|
|
62
|
+
description: config.description,
|
|
63
|
+
...optionDefault,
|
|
64
|
+
...config.required === true ? { required: true } : {}
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
resolve: (flags) => {
|
|
68
|
+
for (const source of sources) {
|
|
69
|
+
const value = flags[source];
|
|
70
|
+
if (typeof value === "boolean") {
|
|
71
|
+
return { [config.key]: value };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (config.negatedSources) {
|
|
75
|
+
for (const source of config.negatedSources) {
|
|
76
|
+
const value = flags[source];
|
|
77
|
+
if (typeof value === "boolean") {
|
|
78
|
+
return { [config.key]: !value };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { [config.key]: defaultValue };
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function enumFlagPreset(config) {
|
|
87
|
+
const sources = resolveSourceKeys(config.key, config.sources);
|
|
88
|
+
const allowed = new Set(config.values);
|
|
89
|
+
return createPreset({
|
|
90
|
+
id: config.id,
|
|
91
|
+
options: [
|
|
92
|
+
{
|
|
93
|
+
flags: config.flags,
|
|
94
|
+
description: config.description,
|
|
95
|
+
...config.required === true ? { required: true } : {}
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
resolve: (flags) => {
|
|
99
|
+
for (const source of sources) {
|
|
100
|
+
const value = flags[source];
|
|
101
|
+
if (typeof value === "string" && allowed.has(value)) {
|
|
102
|
+
return { [config.key]: value };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
[config.key]: config.defaultValue
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function numberFlagPreset(config) {
|
|
112
|
+
const sources = resolveSourceKeys(config.key, config.sources);
|
|
113
|
+
return createPreset({
|
|
114
|
+
id: config.id,
|
|
115
|
+
options: [
|
|
116
|
+
{
|
|
117
|
+
flags: config.flags,
|
|
118
|
+
description: config.description,
|
|
119
|
+
...config.required === true ? { required: true } : {}
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
resolve: (flags) => {
|
|
123
|
+
let parsed;
|
|
124
|
+
for (const source of sources) {
|
|
125
|
+
const value = flags[source];
|
|
126
|
+
if (value === "" || value == null || typeof value === "boolean") {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const numeric = Number(value);
|
|
130
|
+
if (Number.isFinite(numeric)) {
|
|
131
|
+
parsed = config.integer === false ? numeric : Math.floor(numeric);
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (parsed === undefined) {
|
|
136
|
+
parsed = config.defaultValue;
|
|
137
|
+
}
|
|
138
|
+
if (typeof config.min === "number" && Number.isFinite(config.min)) {
|
|
139
|
+
parsed = Math.max(parsed, config.min);
|
|
140
|
+
}
|
|
141
|
+
if (typeof config.max === "number" && Number.isFinite(config.max)) {
|
|
142
|
+
parsed = Math.min(parsed, config.max);
|
|
143
|
+
}
|
|
144
|
+
return { [config.key]: parsed };
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function normalizeStringListInput(value, separator) {
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
const items2 = value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
151
|
+
return items2.length > 0 ? items2 : undefined;
|
|
152
|
+
}
|
|
153
|
+
if (typeof value !== "string")
|
|
154
|
+
return;
|
|
155
|
+
const items = value.split(separator).map((item) => item.trim()).filter(Boolean);
|
|
156
|
+
return items.length > 0 ? items : undefined;
|
|
157
|
+
}
|
|
158
|
+
function stringListFlagPreset(config) {
|
|
159
|
+
const sources = resolveSourceKeys(config.key, config.sources);
|
|
160
|
+
const separator = config.separator ?? ",";
|
|
161
|
+
const fallback = config.defaultValue === undefined ? undefined : [...config.defaultValue];
|
|
162
|
+
return createPreset({
|
|
163
|
+
id: config.id,
|
|
164
|
+
options: [
|
|
165
|
+
{
|
|
166
|
+
flags: config.flags,
|
|
167
|
+
description: config.description,
|
|
168
|
+
...config.required === true ? { required: true } : {}
|
|
169
|
+
}
|
|
170
|
+
],
|
|
171
|
+
resolve: (flags) => {
|
|
172
|
+
let resolved;
|
|
173
|
+
for (const source of sources) {
|
|
174
|
+
const parsed = normalizeStringListInput(flags[source], separator);
|
|
175
|
+
if (parsed !== undefined) {
|
|
176
|
+
resolved = parsed;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (resolved === undefined) {
|
|
181
|
+
resolved = fallback === undefined ? undefined : [...fallback];
|
|
182
|
+
}
|
|
183
|
+
if (resolved && config.dedupe) {
|
|
184
|
+
resolved = [...new Set(resolved)];
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
[config.key]: resolved
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
49
192
|
function verbosePreset() {
|
|
50
193
|
return createPreset({
|
|
51
194
|
id: "verbose",
|
|
@@ -354,4 +497,4 @@ function paginationPreset(config) {
|
|
|
354
497
|
});
|
|
355
498
|
}
|
|
356
499
|
|
|
357
|
-
export { createPreset, composePresets, verbosePreset, cwdPreset, dryRunPreset, forcePreset, interactionPreset, strictPreset, colorPreset, projectionPreset, timeWindowPreset, executionPreset, paginationPreset };
|
|
500
|
+
export { createPreset, composePresets, booleanFlagPreset, enumFlagPreset, numberFlagPreset, stringListFlagPreset, verbosePreset, cwdPreset, dryRunPreset, forcePreset, interactionPreset, strictPreset, colorPreset, projectionPreset, timeWindowPreset, executionPreset, paginationPreset };
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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 };
|
|
1
|
+
import { BooleanFlagPresetConfig, CLI, CLIConfig, CancelledError, CollectIdsOptions, ColorFlags, ColorMode, CommandAction, CommandBuilder, CommandConfig, CommandFlags, ComposedPreset, CursorOptions, DateRange, EnumFlagPresetConfig, ErrorCategory, ExecutionFlags, ExecutionPresetConfig, ExpandFileOptions, FilterExpression, FlagPreset, FlagPresetConfig, InteractionFlags, KeyValuePair, NormalizeIdOptions, NumberFlagPresetConfig, NumericRange, OutputMode, OutputOptions, PaginationFlags, PaginationPresetConfig, PaginationState, ParseGlobOptions, ProjectionFlags, Range, Result, SortCriteria, StrictFlags, StringListFlagPresetConfig, TimeWindowFlags, TimeWindowPresetConfig, ValidationError, VerbConfig, VerbFamily } from "./shared/@outfitter/cli-7n5zmndx";
|
|
2
|
+
export { VerbFamily, VerbConfig, ValidationError, TimeWindowPresetConfig, TimeWindowFlags, StringListFlagPresetConfig, StrictFlags, SortCriteria, Result, Range, ProjectionFlags, ParseGlobOptions, PaginationState, PaginationPresetConfig, PaginationFlags, OutputOptions, OutputMode, NumericRange, NumberFlagPresetConfig, NormalizeIdOptions, KeyValuePair, InteractionFlags, FlagPresetConfig, FlagPreset, FilterExpression, ExpandFileOptions, ExecutionPresetConfig, ExecutionFlags, ErrorCategory, EnumFlagPresetConfig, DateRange, CursorOptions, ComposedPreset, CommandFlags, CommandConfig, CommandBuilder, CommandAction, ColorMode, ColorFlags, CollectIdsOptions, CancelledError, CLIConfig, CLI, BooleanFlagPresetConfig };
|
package/dist/verbs.d.ts
CHANGED
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
|
+
"version": "0.5.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
@@ -70,6 +70,12 @@
|
|
|
70
70
|
"default": "./dist/query.js"
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
|
+
"./schema": {
|
|
74
|
+
"import": {
|
|
75
|
+
"types": "./dist/schema.d.ts",
|
|
76
|
+
"default": "./dist/schema.js"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
73
79
|
"./terminal": {
|
|
74
80
|
"import": {
|
|
75
81
|
"types": "./dist/terminal/index.d.ts",
|
|
@@ -109,7 +115,8 @@
|
|
|
109
115
|
"lint": "biome lint ./src",
|
|
110
116
|
"lint:fix": "biome lint --write ./src",
|
|
111
117
|
"typecheck": "tsc --noEmit",
|
|
112
|
-
"clean": "rm -rf dist"
|
|
118
|
+
"clean": "rm -rf dist",
|
|
119
|
+
"prepublishOnly": "bun ../../scripts/check-publish-manifest.ts"
|
|
113
120
|
},
|
|
114
121
|
"dependencies": {
|
|
115
122
|
"@clack/prompts": "^0.11.0",
|
|
@@ -119,12 +126,14 @@
|
|
|
119
126
|
"peerDependencies": {
|
|
120
127
|
"@outfitter/config": ">=0.3.0",
|
|
121
128
|
"@outfitter/contracts": ">=0.2.0",
|
|
129
|
+
"@outfitter/schema": ">=0.1.0",
|
|
122
130
|
"@outfitter/types": ">=0.2.0",
|
|
123
131
|
"zod": "^4.3.5"
|
|
124
132
|
},
|
|
125
133
|
"devDependencies": {
|
|
126
|
-
"@outfitter/config": "0.3.
|
|
127
|
-
"@outfitter/contracts": "0.
|
|
134
|
+
"@outfitter/config": "0.3.2",
|
|
135
|
+
"@outfitter/contracts": "0.4.0",
|
|
136
|
+
"@outfitter/schema": "0.2.1",
|
|
128
137
|
"@types/bun": "^1.3.7",
|
|
129
138
|
"@types/node": "^25.0.10",
|
|
130
139
|
"typescript": "^5.9.3"
|