padrone 1.5.0 → 1.7.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.
Files changed (141) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +15 -11
  3. package/dist/{args-D5PNDyNu.mjs → args-Cnq0nwSM.mjs} +91 -41
  4. package/dist/args-Cnq0nwSM.mjs.map +1 -0
  5. package/dist/codegen/index.mjs +4 -4
  6. package/dist/codegen/index.mjs.map +1 -1
  7. package/dist/commands-B_gufyR9.mjs +514 -0
  8. package/dist/commands-B_gufyR9.mjs.map +1 -0
  9. package/dist/{completion.mjs → completion-BEuflbDO.mjs} +12 -82
  10. package/dist/completion-BEuflbDO.mjs.map +1 -0
  11. package/dist/docs/index.d.mts +4 -4
  12. package/dist/docs/index.d.mts.map +1 -1
  13. package/dist/docs/index.mjs +10 -12
  14. package/dist/docs/index.mjs.map +1 -1
  15. package/dist/{errors-BiVrBgi6.mjs → errors-DA4KzK1M.mjs} +26 -3
  16. package/dist/errors-DA4KzK1M.mjs.map +1 -0
  17. package/dist/{formatter-DtHzbP22.d.mts → formatter-DrvhDMrq.d.mts} +3 -3
  18. package/dist/formatter-DrvhDMrq.d.mts.map +1 -0
  19. package/dist/{help-bbmu9-qd.mjs → help-BtxLgrF_.mjs} +190 -43
  20. package/dist/help-BtxLgrF_.mjs.map +1 -0
  21. package/dist/{types-Ch8Mk6Qb.d.mts → index-D6-7dz0l.d.mts} +634 -745
  22. package/dist/index-D6-7dz0l.d.mts.map +1 -0
  23. package/dist/index.d.mts +869 -36
  24. package/dist/index.d.mts.map +1 -1
  25. package/dist/index.mjs +3884 -1699
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/{mcp-mLWIdUIu.mjs → mcp-6-Jw4Bpq.mjs} +13 -15
  28. package/dist/mcp-6-Jw4Bpq.mjs.map +1 -0
  29. package/dist/{serve-B0u43DK7.mjs → serve-YVTPzBCl.mjs} +12 -14
  30. package/dist/serve-YVTPzBCl.mjs.map +1 -0
  31. package/dist/{stream-BcC146Ud.mjs → stream-DC4H8YTx.mjs} +24 -3
  32. package/dist/stream-DC4H8YTx.mjs.map +1 -0
  33. package/dist/test.d.mts +5 -8
  34. package/dist/test.d.mts.map +1 -1
  35. package/dist/test.mjs +2 -13
  36. package/dist/test.mjs.map +1 -1
  37. package/dist/{update-check-CFX1FV3v.mjs → update-check-CZ2VqjnV.mjs} +16 -17
  38. package/dist/update-check-CZ2VqjnV.mjs.map +1 -0
  39. package/dist/zod.d.mts +2 -2
  40. package/dist/zod.d.mts.map +1 -1
  41. package/dist/zod.mjs +2 -2
  42. package/dist/zod.mjs.map +1 -1
  43. package/package.json +15 -12
  44. package/src/cli/completions.ts +14 -11
  45. package/src/cli/docs.ts +13 -10
  46. package/src/cli/doctor.ts +22 -18
  47. package/src/cli/index.ts +28 -82
  48. package/src/cli/init.ts +10 -7
  49. package/src/cli/link.ts +20 -16
  50. package/src/cli/wrap.ts +14 -11
  51. package/src/codegen/schema-to-code.ts +2 -2
  52. package/src/{args.ts → core/args.ts} +32 -225
  53. package/src/core/commands.ts +373 -0
  54. package/src/core/create.ts +301 -0
  55. package/src/core/default-runtime.ts +239 -0
  56. package/src/{errors.ts → core/errors.ts} +22 -0
  57. package/src/core/exec.ts +259 -0
  58. package/src/core/interceptors.ts +302 -0
  59. package/src/{parse.ts → core/parse.ts} +36 -89
  60. package/src/core/program-methods.ts +301 -0
  61. package/src/core/results.ts +229 -0
  62. package/src/core/runtime.ts +246 -0
  63. package/src/core/validate.ts +247 -0
  64. package/src/docs/index.ts +12 -13
  65. package/src/extension/auto-output.ts +146 -0
  66. package/src/extension/color.ts +38 -0
  67. package/src/extension/completion.ts +49 -0
  68. package/src/extension/config.ts +262 -0
  69. package/src/extension/env.ts +101 -0
  70. package/src/extension/help.ts +192 -0
  71. package/src/extension/index.ts +44 -0
  72. package/src/extension/ink.ts +93 -0
  73. package/src/extension/interactive.ts +106 -0
  74. package/src/extension/logger.ts +262 -0
  75. package/src/extension/man.ts +51 -0
  76. package/src/extension/mcp.ts +52 -0
  77. package/src/extension/progress-renderer.ts +338 -0
  78. package/src/extension/progress.ts +299 -0
  79. package/src/extension/repl.ts +94 -0
  80. package/src/extension/serve.ts +48 -0
  81. package/src/extension/signal.ts +87 -0
  82. package/src/extension/stdin.ts +62 -0
  83. package/src/extension/suggestions.ts +114 -0
  84. package/src/extension/timing.ts +81 -0
  85. package/src/extension/tracing.ts +175 -0
  86. package/src/extension/update-check.ts +77 -0
  87. package/src/extension/utils.ts +51 -0
  88. package/src/extension/version.ts +63 -0
  89. package/src/{completion.ts → feature/completion.ts} +12 -12
  90. package/src/{interactive.ts → feature/interactive.ts} +4 -4
  91. package/src/{mcp.ts → feature/mcp.ts} +12 -15
  92. package/src/{repl-loop.ts → feature/repl-loop.ts} +10 -13
  93. package/src/{serve.ts → feature/serve.ts} +11 -15
  94. package/src/feature/test.ts +262 -0
  95. package/src/{update-check.ts → feature/update-check.ts} +16 -16
  96. package/src/{wrap.ts → feature/wrap.ts} +10 -8
  97. package/src/index.ts +115 -30
  98. package/src/{formatter.ts → output/formatter.ts} +124 -176
  99. package/src/{help.ts → output/help.ts} +22 -8
  100. package/src/output/output-indicator.ts +87 -0
  101. package/src/output/primitives.ts +335 -0
  102. package/src/output/styling.ts +221 -0
  103. package/src/{zod.d.ts → schema/zod.d.ts} +1 -1
  104. package/src/schema/zod.ts +50 -0
  105. package/src/test.ts +2 -276
  106. package/src/types/args-meta.ts +151 -0
  107. package/src/types/builder.ts +718 -0
  108. package/src/types/command.ts +157 -0
  109. package/src/types/index.ts +60 -0
  110. package/src/types/interceptor.ts +296 -0
  111. package/src/types/preferences.ts +83 -0
  112. package/src/types/result.ts +71 -0
  113. package/src/types/schema.ts +19 -0
  114. package/src/util/dotenv.ts +244 -0
  115. package/src/{shell-utils.ts → util/shell-utils.ts} +26 -9
  116. package/src/{stream.ts → util/stream.ts} +27 -1
  117. package/src/{type-helpers.ts → util/type-helpers.ts} +23 -16
  118. package/src/{type-utils.ts → util/type-utils.ts} +71 -33
  119. package/src/util/utils.ts +51 -0
  120. package/src/zod.ts +1 -50
  121. package/dist/args-D5PNDyNu.mjs.map +0 -1
  122. package/dist/chunk-CjcI7cDX.mjs +0 -15
  123. package/dist/command-utils-B1D-HqCd.mjs +0 -1117
  124. package/dist/command-utils-B1D-HqCd.mjs.map +0 -1
  125. package/dist/completion.d.mts +0 -64
  126. package/dist/completion.d.mts.map +0 -1
  127. package/dist/completion.mjs.map +0 -1
  128. package/dist/errors-BiVrBgi6.mjs.map +0 -1
  129. package/dist/formatter-DtHzbP22.d.mts.map +0 -1
  130. package/dist/help-bbmu9-qd.mjs.map +0 -1
  131. package/dist/mcp-mLWIdUIu.mjs.map +0 -1
  132. package/dist/serve-B0u43DK7.mjs.map +0 -1
  133. package/dist/stream-BcC146Ud.mjs.map +0 -1
  134. package/dist/types-Ch8Mk6Qb.d.mts.map +0 -1
  135. package/dist/update-check-CFX1FV3v.mjs.map +0 -1
  136. package/src/command-utils.ts +0 -882
  137. package/src/create.ts +0 -1829
  138. package/src/runtime.ts +0 -497
  139. package/src/types.ts +0 -1291
  140. package/src/utils.ts +0 -140
  141. /package/src/{colorizer.ts → output/colorizer.ts} +0 -0
package/src/test.ts CHANGED
@@ -1,276 +1,2 @@
1
- import type { InteractivePromptConfig, PadroneRuntime } from './runtime.ts';
2
- import type { AnyPadroneCommand, PadroneCommandResult } from './types.ts';
3
-
4
- /**
5
- * Result from a single command execution in test mode.
6
- * Extends the standard PadroneCommandResult with captured I/O.
7
- */
8
- export type TestCliResult = {
9
- /** The matched command. */
10
- command: AnyPadroneCommand;
11
- /** Validated arguments (undefined if validation failed). */
12
- args: unknown;
13
- /** Action handler return value (undefined if validation failed or no action). */
14
- result: unknown;
15
- /** Validation issues, if any. */
16
- issues: { message: string; path?: PropertyKey[] }[] | undefined;
17
- /** All values passed to `runtime.output()`. */
18
- stdout: unknown[];
19
- /** All strings passed to `runtime.error()`. */
20
- stderr: string[];
21
- /** The thrown error, if the command threw (routing error, action error, etc.). */
22
- error?: unknown;
23
- };
24
-
25
- /**
26
- * Result from a REPL test session.
27
- */
28
- export type TestReplResult = {
29
- /** One entry per successfully executed command (validation errors are captured in stderr, not here). */
30
- results: Omit<TestCliResult, 'stdout' | 'stderr'>[];
31
- /** All output from the entire REPL session. */
32
- stdout: unknown[];
33
- /** All errors from the entire REPL session. */
34
- stderr: string[];
35
- };
36
-
37
- /**
38
- * Fluent builder for setting up CLI test scenarios.
39
- */
40
- export type TestCliBuilder = {
41
- /** Set the CLI input string (e.g. `'deploy --env production'`). */
42
- args(input: string): TestCliBuilder;
43
- /** Set environment variables visible to the command. */
44
- env(vars: Record<string, string | undefined>): TestCliBuilder;
45
- /** Provide mock answers for interactive prompts. Keys are field names. */
46
- prompt(answers: Record<string, unknown>): TestCliBuilder;
47
- /** Provide mock config files. Keys are file paths, values are parsed config objects. */
48
- config(files: Record<string, Record<string, unknown>>): TestCliBuilder;
49
- /** Provide mock stdin data (simulates piped input). */
50
- stdin(data: string): TestCliBuilder;
51
- /**
52
- * Execute a single command via `eval()` and return the result with captured I/O.
53
- * @param input - Optional CLI input string. Overrides `.args()` if provided.
54
- */
55
- run(input?: string): Promise<TestCliResult>;
56
- /**
57
- * Run a REPL session with the given sequence of inputs.
58
- * Each string in the array is fed as one line of input.
59
- * The session ends after all inputs are consumed (EOF).
60
- */
61
- repl(inputs: string[]): Promise<TestReplResult>;
62
- };
63
-
64
- /**
65
- * Creates a fluent test builder for a Padrone program.
66
- * Captures all I/O and provides a clean interface for assertions.
67
- *
68
- * Works with any test framework (bun:test, vitest, jest, node:test, etc.).
69
- *
70
- * @example
71
- * ```ts
72
- * import { testCli } from 'padrone/test'
73
- *
74
- * const result = await testCli(myProgram)
75
- * .args('deploy --env production')
76
- * .env({ API_KEY: 'xxx' })
77
- * .run()
78
- *
79
- * expect(result.result).toBe('Deployed')
80
- * expect(result.stdout).toContain('Deploying...')
81
- * ```
82
- *
83
- * @example
84
- * ```ts
85
- * // Shorthand: pass input directly to run()
86
- * const result = await testCli(myProgram).run('deploy --env production')
87
- * ```
88
- *
89
- * @example
90
- * ```ts
91
- * // Test interactive prompts
92
- * const result = await testCli(myProgram)
93
- * .args('init')
94
- * .prompt({ name: 'myapp', template: 'react' })
95
- * .run()
96
- *
97
- * expect(result.args).toEqual({ name: 'myapp', template: 'react' })
98
- * ```
99
- *
100
- * @example
101
- * ```ts
102
- * // Test REPL sessions
103
- * const { results } = await testCli(myProgram)
104
- * .repl(['greet World', 'add --a=2 --b=3'])
105
- *
106
- * expect(results[0].result).toBe('Hello, World!')
107
- * expect(results[1].result).toBe(5)
108
- * ```
109
- */
110
- /**
111
- * Any program-like object that has `eval`, `runtime`, and `repl` methods.
112
- * Avoids strict variance issues with `AnyPadroneProgram`.
113
- */
114
- type TestableProgram = {
115
- eval: (input: string, prefs?: { autoOutput?: boolean }) => any;
116
- runtime: (runtime: PadroneRuntime) => TestableProgram;
117
- repl: (options?: { greeting?: false; hint?: false }) => AsyncIterable<any>;
118
- };
119
-
120
- export function testCli(program: TestableProgram): TestCliBuilder {
121
- let input: string | undefined;
122
- let envVars: Record<string, string | undefined> | undefined;
123
- let promptAnswers: Record<string, unknown> | undefined;
124
- let configFiles: Record<string, Record<string, unknown>> | undefined;
125
- let stdinData: string | undefined;
126
-
127
- const builder: TestCliBuilder = {
128
- args(args: string) {
129
- input = args;
130
- return builder;
131
- },
132
- env(vars) {
133
- envVars = vars;
134
- return builder;
135
- },
136
- prompt(answers) {
137
- promptAnswers = answers;
138
- return builder;
139
- },
140
- config(files) {
141
- configFiles = files;
142
- return builder;
143
- },
144
- stdin(data: string) {
145
- stdinData = data;
146
- return builder;
147
- },
148
-
149
- async run(runInput?: string) {
150
- const stdout: unknown[] = [];
151
- const stderr: string[] = [];
152
-
153
- const runtime = buildRuntime(stdout, stderr, { envVars, promptAnswers, configFiles, stdinData });
154
- const testProgram = program.runtime(runtime);
155
-
156
- const evalResult = await testProgram.eval(runInput ?? input ?? '', { autoOutput: false });
157
- if (evalResult.error) {
158
- stderr.push(evalResult.error instanceof Error ? evalResult.error.message : String(evalResult.error));
159
- }
160
- return toTestResult(evalResult, stdout, stderr);
161
- },
162
-
163
- async repl(inputs: string[]) {
164
- const stdout: unknown[] = [];
165
- const stderr: string[] = [];
166
-
167
- const runtime = buildRuntime(stdout, stderr, {
168
- envVars,
169
- promptAnswers,
170
- configFiles,
171
- readLine: createMockReadLine(inputs),
172
- });
173
-
174
- const testProgram = program.runtime(runtime);
175
- const results: Omit<TestCliResult, 'stdout' | 'stderr'>[] = [];
176
-
177
- for await (const r of testProgram.repl({ greeting: false, hint: false })) {
178
- results.push({
179
- command: r.command!,
180
- args: r.args,
181
- result: r.result,
182
- issues: r.argsResult?.issues as TestCliResult['issues'],
183
- });
184
- }
185
-
186
- return { results, stdout, stderr };
187
- },
188
- };
189
-
190
- return builder;
191
- }
192
-
193
- function toTestResult(evalResult: PadroneCommandResult, stdout: unknown[], stderr: string[]): TestCliResult {
194
- return {
195
- command: evalResult.command!,
196
- args: evalResult.args,
197
- result: evalResult.result,
198
- error: evalResult.error,
199
- issues: evalResult.argsResult?.issues as TestCliResult['issues'],
200
- stdout,
201
- stderr,
202
- };
203
- }
204
-
205
- function buildRuntime(
206
- stdout: unknown[],
207
- stderr: string[],
208
- opts: {
209
- envVars?: Record<string, string | undefined>;
210
- promptAnswers?: Record<string, unknown>;
211
- configFiles?: Record<string, Record<string, unknown>>;
212
- readLine?: (prompt: string) => Promise<string | null>;
213
- stdinData?: string;
214
- },
215
- ): PadroneRuntime {
216
- const runtime: PadroneRuntime = {
217
- output: (...args: unknown[]) => stdout.push(...args),
218
- error: (text: string) => stderr.push(text),
219
- };
220
-
221
- if (opts.envVars) {
222
- runtime.env = () => opts.envVars!;
223
- }
224
-
225
- if (opts.promptAnswers) {
226
- runtime.interactive = 'supported';
227
- runtime.prompt = async (config: InteractivePromptConfig) => opts.promptAnswers![config.name];
228
- }
229
-
230
- if (opts.configFiles) {
231
- runtime.loadConfigFile = (path: string) => opts.configFiles![path];
232
- runtime.findFile = (names: string[]) => names.find((n) => n in opts.configFiles!);
233
- }
234
-
235
- if (opts.readLine) {
236
- runtime.readLine = opts.readLine;
237
- }
238
-
239
- if (opts.stdinData !== undefined) {
240
- runtime.stdin = {
241
- isTTY: false,
242
- async text() {
243
- return opts.stdinData!;
244
- },
245
- async *lines() {
246
- const lines = opts.stdinData!.split('\n');
247
- // Remove trailing empty line from final newline (matches readline behavior)
248
- if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();
249
- for (const line of lines) {
250
- yield line;
251
- }
252
- },
253
- };
254
- } else {
255
- // No stdin data: simulate a TTY (no piped input) to avoid reading from process.stdin
256
- runtime.stdin = {
257
- isTTY: true,
258
- async text() {
259
- return '';
260
- },
261
- async *lines() {
262
- // no lines
263
- },
264
- };
265
- }
266
-
267
- return runtime;
268
- }
269
-
270
- function createMockReadLine(inputs: string[]): (prompt: string) => Promise<string | null> {
271
- let index = 0;
272
- return async (_prompt: string): Promise<string | null> => {
273
- if (index >= inputs.length) return null;
274
- return inputs[index++] ?? null;
275
- };
276
- }
1
+ export type { TestCliBuilder, TestCliResult, TestReplResult } from './feature/test.ts';
2
+ export { testCli } from './feature/test.ts';
@@ -0,0 +1,151 @@
1
+ type Letter =
2
+ | 'a'
3
+ | 'b'
4
+ | 'c'
5
+ | 'd'
6
+ | 'e'
7
+ | 'f'
8
+ | 'g'
9
+ | 'h'
10
+ | 'i'
11
+ | 'j'
12
+ | 'k'
13
+ | 'l'
14
+ | 'm'
15
+ | 'n'
16
+ | 'o'
17
+ | 'p'
18
+ | 'q'
19
+ | 'r'
20
+ | 's'
21
+ | 't'
22
+ | 'u'
23
+ | 'v'
24
+ | 'w'
25
+ | 'x'
26
+ | 'y'
27
+ | 'z';
28
+
29
+ /** A single letter character, valid as a short CLI flag (e.g. `'v'`, `'n'`, `'V'`). */
30
+ export type SingleChar = Letter | Uppercase<Letter>;
31
+
32
+ export interface PadroneFieldMeta {
33
+ description?: string;
34
+ /** Single-character short flags (stackable: `-abc` = `-a -b -c`). Used with single dash. */
35
+ flags?: readonly SingleChar[] | SingleChar;
36
+ /** Multi-character alternative long names. Used with double dash (e.g. `--dry-run` for `--dryRun`). */
37
+ alias?: readonly string[] | string;
38
+ deprecated?: boolean | string;
39
+ hidden?: boolean;
40
+ examples?: readonly unknown[];
41
+ /** Group name for organizing this option under a labeled section in help output. */
42
+ group?: string;
43
+ }
44
+
45
+ type PositionalArgs<TObj> =
46
+ TObj extends Record<string, any>
47
+ ? {
48
+ [K in keyof TObj]: NonNullable<TObj[K]> extends Array<any> ? `...${K & string}` | (K & string) : K & string;
49
+ }[keyof TObj]
50
+ : string;
51
+
52
+ /**
53
+ * Meta configuration for arguments, including positional arguments.
54
+ * The `positional` array defines which arguments are positional and their order.
55
+ * Use '...name' prefix to indicate variadic (rest) arguments, matching JS/TS rest syntax.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * .arguments(schema, {
60
+ * positional: ['source', '...files', 'dest'], // '...files' is variadic
61
+ * })
62
+ * ```
63
+ */
64
+ /**
65
+ * Configuration for reading from stdin and mapping it to an argument field.
66
+ * Simply specify the field name — the read mode is inferred from the schema:
67
+ * - `string` field → reads all stdin as text
68
+ * - `string[]` field → reads stdin line-by-line
69
+ */
70
+ export type StdinConfig<TObj = Record<string, any>> = keyof TObj & string;
71
+
72
+ export interface PadroneArgsSchemaMeta<TObj = Record<string, any>> {
73
+ /**
74
+ * Array of argument names that should be treated as positional arguments.
75
+ * Order in array determines position. Use '...name' prefix for variadic args.
76
+ * @example ['source', '...files', 'dest'] - 'files' captures multiple values
77
+ */
78
+ positional?: readonly PositionalArgs<TObj>[];
79
+ /**
80
+ * Per-argument metadata.
81
+ */
82
+ fields?: { [K in keyof TObj]?: PadroneFieldMeta };
83
+ /**
84
+ * Automatically generate kebab-case aliases for camelCase option names.
85
+ * For example, `dryRun` automatically gets `--dry-run` as an alias.
86
+ * Defaults to `true`. Set to `false` to disable.
87
+ *
88
+ * @default true
89
+ * @example
90
+ * ```ts
91
+ * // Auto-aliases enabled (default): --dry-run → dryRun
92
+ * .arguments(z.object({ dryRun: z.boolean() }))
93
+ *
94
+ * // Disable auto-aliases
95
+ * .arguments(z.object({ dryRun: z.boolean() }), { autoAlias: false })
96
+ * ```
97
+ */
98
+ autoAlias?: boolean;
99
+ /**
100
+ * Read from stdin and inject the data into the specified argument field.
101
+ * Only reads when stdin is piped (not a TTY) and the field wasn't already provided via CLI flags.
102
+ *
103
+ * The read mode is inferred from the schema type of the target field:
104
+ * - `string` field → reads all stdin as a single string
105
+ * - `string[]` field → reads stdin line-by-line into an array
106
+ *
107
+ * Precedence: CLI flags > stdin > env vars > config file > schema defaults.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * // Read all stdin as text into 'data' field
112
+ * .arguments(z.object({ data: z.string() }), { stdin: 'data' })
113
+ *
114
+ * // Read stdin lines into 'lines' field (inferred from array schema)
115
+ * .arguments(z.object({ lines: z.string().array() }), { stdin: 'lines' })
116
+ * ```
117
+ */
118
+ stdin?: StdinConfig<TObj>;
119
+ /**
120
+ * Fields to interactively prompt for when their values are missing after CLI/env/config resolution.
121
+ * - `true`: prompt for all required fields that are missing.
122
+ * - `string[]`: prompt for these specific fields if missing.
123
+ *
124
+ * Interactive prompting only occurs in `cli()` when the runtime has `interactive: true`.
125
+ * Setting this makes `parse()` and `cli()` return Promises.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * .arguments(schema, {
130
+ * interactive: true, // prompt all missing required fields
131
+ * interactive: ['name', 'template'], // prompt only these fields
132
+ * })
133
+ * ```
134
+ */
135
+ interactive?: true | readonly (keyof TObj & string)[];
136
+ /**
137
+ * Optional fields offered after required interactive prompts.
138
+ * Users are shown a multi-select to choose which of these fields to configure.
139
+ * - `true`: offer all optional fields that are missing.
140
+ * - `string[]`: offer these specific fields.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * .arguments(schema, {
145
+ * interactive: ['name'],
146
+ * optionalInteractive: ['typescript', 'eslint', 'prettier'],
147
+ * })
148
+ * ```
149
+ */
150
+ optionalInteractive?: true | readonly (keyof TObj & string)[];
151
+ }