@karmaniverous/get-dotenv 6.1.0 → 6.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.
Files changed (51) hide show
  1. package/README.md +20 -14
  2. package/dist/cli.d.ts +58 -2
  3. package/dist/cli.mjs +800 -364
  4. package/dist/cliHost.d.ts +216 -17
  5. package/dist/cliHost.mjs +178 -14
  6. package/dist/config.d.ts +12 -0
  7. package/dist/config.mjs +79 -2
  8. package/dist/env-overlay.d.ts +8 -0
  9. package/dist/getdotenv.cli.mjs +800 -364
  10. package/dist/index.d.ts +220 -35
  11. package/dist/index.mjs +851 -365
  12. package/dist/plugins-aws.d.ts +94 -6
  13. package/dist/plugins-aws.mjs +462 -184
  14. package/dist/plugins-batch.d.ts +85 -3
  15. package/dist/plugins-batch.mjs +203 -54
  16. package/dist/plugins-cmd.d.ts +85 -3
  17. package/dist/plugins-cmd.mjs +150 -28
  18. package/dist/plugins-init.d.ts +85 -3
  19. package/dist/plugins-init.mjs +270 -131
  20. package/dist/plugins.d.ts +85 -4
  21. package/dist/plugins.mjs +800 -364
  22. package/dist/templates/cli/plugins/hello/defaultAction.ts +27 -0
  23. package/dist/templates/cli/plugins/hello/index.ts +26 -0
  24. package/dist/templates/cli/plugins/hello/options.ts +31 -0
  25. package/dist/templates/cli/plugins/hello/strangerAction.ts +20 -0
  26. package/dist/templates/cli/plugins/hello/types.ts +13 -0
  27. package/dist/templates/defaultAction.ts +27 -0
  28. package/dist/templates/hello/defaultAction.ts +27 -0
  29. package/dist/templates/hello/index.ts +26 -0
  30. package/dist/templates/hello/options.ts +31 -0
  31. package/dist/templates/hello/strangerAction.ts +20 -0
  32. package/dist/templates/hello/types.ts +13 -0
  33. package/dist/templates/index.ts +23 -22
  34. package/dist/templates/options.ts +31 -0
  35. package/dist/templates/plugins/hello/defaultAction.ts +27 -0
  36. package/dist/templates/plugins/hello/index.ts +26 -0
  37. package/dist/templates/plugins/hello/options.ts +31 -0
  38. package/dist/templates/plugins/hello/strangerAction.ts +20 -0
  39. package/dist/templates/plugins/hello/types.ts +13 -0
  40. package/dist/templates/strangerAction.ts +20 -0
  41. package/dist/templates/types.ts +13 -0
  42. package/package.json +3 -4
  43. package/templates/cli/plugins/hello/defaultAction.ts +27 -0
  44. package/templates/cli/plugins/hello/index.ts +26 -0
  45. package/templates/cli/plugins/hello/options.ts +31 -0
  46. package/templates/cli/plugins/hello/strangerAction.ts +20 -0
  47. package/templates/cli/plugins/hello/types.ts +13 -0
  48. package/dist/templates/cli/plugins/hello.ts +0 -42
  49. package/dist/templates/hello.ts +0 -42
  50. package/dist/templates/plugins/hello.ts +0 -42
  51. package/templates/cli/plugins/hello.ts +0 -42
@@ -20,9 +20,21 @@ type ScriptsTable<TShell extends string | boolean = string | boolean> = Record<s
20
20
  * @public
21
21
  */
22
22
  interface GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions> {
23
+ /**
24
+ * Fully resolved option bag used to compute this context.
25
+ */
23
26
  optionsResolved: TOptions;
27
+ /**
28
+ * Final composed dotenv environment for this invocation.
29
+ */
24
30
  dotenv: ProcessEnv;
31
+ /**
32
+ * Optional runtime plugin state bag. Plugins may publish non-sensitive metadata here.
33
+ */
25
34
  plugins?: Record<string, unknown>;
35
+ /**
36
+ * Per-plugin validated configuration slices keyed by realized mount path.
37
+ */
26
38
  pluginConfigs?: Record<string, unknown>;
27
39
  }
28
40
 
@@ -31,6 +43,14 @@ interface GetDotenvCliCtx<TOptions extends GetDotenvOptions = GetDotenvOptions>
31
43
  * For the current step this mirrors the RAW schema; later stages may further
32
44
  * narrow types post-resolution in the host pipeline.
33
45
  */
46
+ /**
47
+ * CLI options schema (resolved).
48
+ *
49
+ * Today this mirrors {@link getDotenvCliOptionsSchemaRaw}, but is kept as a distinct export
50
+ * so future resolution steps can narrow or materialize defaults without breaking the API.
51
+ *
52
+ * @public
53
+ */
34
54
  declare const getDotenvCliOptionsSchemaResolved: z.ZodObject<{
35
55
  defaultEnv: z.ZodOptional<z.ZodString>;
36
56
  dotenvToken: z.ZodOptional<z.ZodString>;
@@ -74,6 +94,14 @@ declare const getDotenvCliOptionsSchemaResolved: z.ZodObject<{
74
94
  * For now, this mirrors the RAW schema; future stages may materialize defaults
75
95
  * and narrow shapes as resolution is wired into the host.
76
96
  */
97
+ /**
98
+ * Programmatic options schema (resolved).
99
+ *
100
+ * Today this mirrors {@link getDotenvOptionsSchemaRaw}, but is kept as a distinct export
101
+ * so future resolution steps can narrow or materialize defaults without breaking the API.
102
+ *
103
+ * @public
104
+ */
77
105
  declare const getDotenvOptionsSchemaResolved: z.ZodObject<{
78
106
  defaultEnv: z.ZodOptional<z.ZodString>;
79
107
  dotenvToken: z.ZodOptional<z.ZodString>;
@@ -128,7 +156,7 @@ type Logger = Record<string, (...args: unknown[]) => void> | typeof console;
128
156
  * Canonical programmatic options type (schema-derived).
129
157
  * This type is the single source of truth for programmatic options.
130
158
  */
131
- type GetDotenvOptions = z.output<typeof getDotenvOptionsSchemaResolved> & {
159
+ type GetDotenvOptions = Omit<z.output<typeof getDotenvOptionsSchemaResolved>, 'logger' | 'dynamic'> & {
132
160
  /**
133
161
  * Compile-time overlay: narrowed logger for DX (schema stores unknown).
134
162
  */
@@ -149,11 +177,15 @@ type Scripts = ScriptsTable;
149
177
  * stringly paths/vars, and inherited programmatic fields (minus normalized
150
178
  * shapes that are handled by resolution).
151
179
  */
152
- type GetDotenvCliOptions = z.output<typeof getDotenvCliOptionsSchemaResolved> & {
180
+ type GetDotenvCliOptions = Omit<z.output<typeof getDotenvCliOptionsSchemaResolved>, 'logger' | 'dynamic' | 'scripts'> & {
153
181
  /**
154
182
  * Compile-only overlay for DX: logger narrowed from unknown.
155
183
  */
156
184
  logger: Logger;
185
+ /**
186
+ * Compile-only overlay for DX: dynamic map narrowed from unknown.
187
+ */
188
+ dynamic?: GetDotenvDynamic;
157
189
  /**
158
190
  * Compile-only overlay for DX: scripts narrowed from Record\<string, unknown\>.
159
191
  */
@@ -216,13 +248,37 @@ interface GetDotenvCliPublic<TOptions extends GetDotenvOptions = GetDotenvOption
216
248
  getCtx(): GetDotenvCliCtx<TOptions>;
217
249
  /** Check whether a context has been resolved (non-throwing). */
218
250
  hasCtx(): boolean;
251
+ /**
252
+ * Resolve options and compute the dotenv context for this invocation.
253
+ *
254
+ * @param customOptions - Partial options to overlay for this invocation.
255
+ * @param opts - Optional resolver behavior switches (for example, whether to run `afterResolve`).
256
+ * @returns A promise resolving to the computed invocation context.
257
+ */
219
258
  resolveAndLoad(customOptions?: Partial<TOptions>, opts?: ResolveAndLoadOptions): Promise<GetDotenvCliCtx<TOptions>>;
259
+ /**
260
+ * Tag an option with a help group identifier for grouped root help rendering.
261
+ *
262
+ * @param opt - The Commander option to tag.
263
+ * @param group - Group identifier (for example, `base`, `app`, or `plugin:<name>`).
264
+ * @returns Nothing.
265
+ */
220
266
  setOptionGroup(opt: Option, group: string): void;
221
267
  /**
222
268
  * Create a dynamic option whose description is computed at help time
223
269
  * from the resolved configuration.
224
270
  */
271
+ /**
272
+ * Create a dynamic option whose description is computed at help time from the resolved configuration.
273
+ *
274
+ * @param flags - Commander option flags usage string.
275
+ * @param desc - Description builder called during help rendering with the resolved help config.
276
+ * @param parser - Optional argument parser.
277
+ * @param defaultValue - Optional default value.
278
+ * @returns A Commander `Option` instance with a dynamic description.
279
+ */
225
280
  createDynamicOption<Usage extends string>(flags: Usage, desc: (cfg: ResolvedHelpConfig) => string, parser?: (value: string, previous?: unknown) => unknown, defaultValue?: unknown): Option<Usage>;
281
+ /** {@inheritDoc} */
226
282
  createDynamicOption<Usage extends string, TValue = unknown>(flags: Usage, desc: (cfg: ResolvedHelpConfig) => string, parser: (value: string, previous?: TValue) => TValue, defaultValue?: TValue): Option<Usage>;
227
283
  }
228
284
  /**
@@ -285,7 +341,27 @@ interface GetDotenvCliPlugin<TOptions extends GetDotenvOptions = GetDotenvOption
285
341
  * return types from definePlugin provide stronger DX for shipped/typed plugins.
286
342
  */
287
343
  interface PluginWithInstanceHelpers<TOptions extends GetDotenvOptions = GetDotenvOptions, TConfig = unknown, TArgs extends unknown[] = [], TOpts extends OptionValues = {}, TGlobal extends OptionValues = {}> extends GetDotenvCliPlugin<TOptions, TArgs, TOpts, TGlobal> {
344
+ /**
345
+ * Read the validated (and interpolated) configuration slice for this plugin instance.
346
+ *
347
+ * @param cli - The plugin mount (or any command under this mount) used to resolve the invocation context.
348
+ * @returns The plugin configuration slice, typed as `TCfg`.
349
+ * @throws Error when called before the host has resolved the invocation context.
350
+ */
288
351
  readConfig<TCfg = TConfig>(cli: GetDotenvCliPublic<TOptions, unknown[], OptionValues, OptionValues>): Readonly<TCfg>;
352
+ /**
353
+ * Create a Commander option whose help-time description receives the resolved root help config
354
+ * and this plugin instance’s validated configuration slice.
355
+ *
356
+ * @typeParam TCfg - The plugin configuration slice type.
357
+ * @typeParam Usage - The Commander usage string for the option flags.
358
+ * @param cli - The plugin mount used to associate the option with a realized mount path.
359
+ * @param flags - Commander option flags usage string.
360
+ * @param desc - Description builder receiving the resolved help config and the plugin config slice.
361
+ * @param parser - Optional argument parser.
362
+ * @param defaultValue - Optional default value.
363
+ * @returns A Commander `Option` instance with a dynamic description.
364
+ */
289
365
  createPluginDynamicOption<TCfg = TConfig, Usage extends string = string>(cli: GetDotenvCliPublic<TOptions, unknown[], OptionValues, OptionValues>, flags: Usage, desc: (cfg: ResolvedHelpConfig, pluginCfg: Readonly<TCfg>) => string, parser?: (value: string, previous?: unknown) => unknown, defaultValue?: unknown): Option<Usage>;
290
366
  }
291
367
 
@@ -426,6 +502,12 @@ declare const batchPlugin: (opts?: BatchPluginOptions) => PluginWithInstanceHelp
426
502
  globs?: string | undefined;
427
503
  pkgCwd?: boolean | undefined;
428
504
  }, [], {}, {}>;
505
+ /**
506
+ * Batch plugin instance type returned by {@link batchPlugin}.
507
+ *
508
+ * @public
509
+ */
510
+ type BatchPlugin = ReturnType<typeof batchPlugin>;
429
511
 
430
512
  export { batchPlugin };
431
- export type { BatchCmdSubcommandOptions, BatchGlobPathsOptions, BatchParentInvokerFlags, ExecShellCommandBatchOptions };
513
+ export type { BatchCmdSubcommandOptions, BatchGlobPathsOptions, BatchParentInvokerFlags, BatchPlugin, ExecShellCommandBatchOptions };
@@ -1,4 +1,3 @@
1
- import { Option, Command } from '@commander-js/extra-typings';
2
1
  import { z } from 'zod';
3
2
  import path, { join, extname } from 'path';
4
3
  import fs from 'fs-extra';
@@ -9,6 +8,7 @@ import { createHash } from 'crypto';
9
8
  import { nanoid } from 'nanoid';
10
9
  import { parse } from 'dotenv';
11
10
  import { execa, execaCommand } from 'execa';
11
+ import { Option, Command } from '@commander-js/extra-typings';
12
12
  import { globby } from 'globby';
13
13
 
14
14
  /**
@@ -21,26 +21,58 @@ import { globby } from 'globby';
21
21
  * Minimal process env representation used by options and helpers.
22
22
  * Values may be `undefined` to indicate "unset".
23
23
  */
24
+ /**
25
+ * Schema for an env-like record.
26
+ *
27
+ * Keys are environment variable names and values are either strings or `undefined`
28
+ * (to represent “unset”).
29
+ *
30
+ * @public
31
+ */
24
32
  const processEnvSchema = z.record(z.string(), z.string().optional());
25
33
  // RAW: all fields optional — undefined means "inherit" from lower layers.
34
+ /**
35
+ * Programmatic options schema (raw).
36
+ *
37
+ * This schema is the canonical runtime source of truth for the `getDotenv()` programmatic API.
38
+ * All fields are optional; `undefined` generally means “inherit default/lower layer”.
39
+ *
40
+ * @public
41
+ */
26
42
  const getDotenvOptionsSchemaRaw = z.object({
43
+ /** Default environment name when `env` is not provided. */
27
44
  defaultEnv: z.string().optional(),
45
+ /** Base dotenv filename token (default `.env`). */
28
46
  dotenvToken: z.string().optional(),
47
+ /** Path to a dynamic variables module (JS/TS) to load and apply. */
29
48
  dynamicPath: z.string().optional(),
30
- // Dynamic map is intentionally wide for now; refine once sources are normalized.
49
+ /** Dynamic map is intentionally wide for now; refine once sources are normalized. */
31
50
  dynamic: z.record(z.string(), z.unknown()).optional(),
51
+ /** Selected environment name for this invocation (for env-scoped files and overlays). */
32
52
  env: z.string().optional(),
53
+ /** When true, skip applying dynamic variables. */
33
54
  excludeDynamic: z.boolean().optional(),
55
+ /** When true, skip environment-scoped dotenv files. */
34
56
  excludeEnv: z.boolean().optional(),
57
+ /** When true, skip global dotenv files. */
35
58
  excludeGlobal: z.boolean().optional(),
59
+ /** When true, skip private dotenv files. */
36
60
  excludePrivate: z.boolean().optional(),
61
+ /** When true, skip public dotenv files. */
37
62
  excludePublic: z.boolean().optional(),
63
+ /** When true, merge the final composed environment into `process.env`. */
38
64
  loadProcess: z.boolean().optional(),
65
+ /** When true, log the final environment map via `logger`. */
39
66
  log: z.boolean().optional(),
67
+ /** Logger used when `log` is enabled (console-compatible). */
40
68
  logger: z.unknown().default(console),
69
+ /** Optional output dotenv file path to write after composition. */
41
70
  outputPath: z.string().optional(),
71
+ /** Dotenv search paths (ordered). */
42
72
  paths: z.array(z.string()).optional(),
73
+ /** Private token suffix for private dotenv files (default `local`). */
43
74
  privateToken: z.string().optional(),
75
+ /** Explicit variables to overlay onto the composed dotenv map. */
44
76
  vars: processEnvSchema.optional(),
45
77
  });
46
78
  /**
@@ -48,6 +80,14 @@ const getDotenvOptionsSchemaRaw = z.object({
48
80
  * For now, this mirrors the RAW schema; future stages may materialize defaults
49
81
  * and narrow shapes as resolution is wired into the host.
50
82
  */
83
+ /**
84
+ * Programmatic options schema (resolved).
85
+ *
86
+ * Today this mirrors {@link getDotenvOptionsSchemaRaw}, but is kept as a distinct export
87
+ * so future resolution steps can narrow or materialize defaults without breaking the API.
88
+ *
89
+ * @public
90
+ */
51
91
  const getDotenvOptionsSchemaResolved = getDotenvOptionsSchemaRaw;
52
92
 
53
93
  /**
@@ -57,27 +97,55 @@ const getDotenvOptionsSchemaResolved = getDotenvOptionsSchemaRaw;
57
97
  * reflect normalized types (paths: string[], vars: ProcessEnv), applied in the
58
98
  * CLI resolution pipeline.
59
99
  */
100
+ /**
101
+ * CLI options schema (raw).
102
+ *
103
+ * Extends the programmatic options schema with CLI-only flags and stringly inputs
104
+ * which are normalized later by the host resolution pipeline.
105
+ *
106
+ * @public
107
+ */
60
108
  const getDotenvCliOptionsSchemaRaw = getDotenvOptionsSchemaRaw.extend({
61
109
  // CLI-specific fields (stringly inputs before preprocessing)
110
+ /** Enable verbose debug output (host-specific). */
62
111
  debug: z.boolean().optional(),
112
+ /** Fail on validation errors (schema/requiredKeys). */
63
113
  strict: z.boolean().optional(),
114
+ /** Capture child process stdio (useful for CI/tests). */
64
115
  capture: z.boolean().optional(),
116
+ /** Emit child env diagnostics (boolean or selected keys). */
65
117
  trace: z.union([z.boolean(), z.array(z.string())]).optional(),
118
+ /** Enable presentation-time redaction in trace/log output. */
66
119
  redact: z.boolean().optional(),
120
+ /** Enable entropy warnings in trace/log output. */
67
121
  warnEntropy: z.boolean().optional(),
122
+ /** Entropy threshold (bits/char) for warnings. */
68
123
  entropyThreshold: z.number().optional(),
124
+ /** Minimum value length to consider for entropy warnings. */
69
125
  entropyMinLength: z.number().optional(),
126
+ /** Regex patterns (strings) to suppress entropy warnings by key. */
70
127
  entropyWhitelist: z.array(z.string()).optional(),
128
+ /** Additional key-match patterns (strings) for redaction. */
71
129
  redactPatterns: z.array(z.string()).optional(),
130
+ /** Dotenv search paths provided as a single delimited string. */
72
131
  paths: z.string().optional(),
132
+ /** Delimiter string used to split `paths`. */
73
133
  pathsDelimiter: z.string().optional(),
134
+ /** Regex pattern used to split `paths` (takes precedence over delimiter). */
74
135
  pathsDelimiterPattern: z.string().optional(),
136
+ /** Scripts table in a permissive shape at parse time (validated elsewhere). */
75
137
  scripts: z.record(z.string(), z.unknown()).optional(),
138
+ /** Shell selection (`false` for shell-off, string for explicit shell). */
76
139
  shell: z.union([z.boolean(), z.string()]).optional(),
140
+ /** Extra variables expressed as a single delimited string of assignments. */
77
141
  vars: z.string().optional(),
142
+ /** Assignment operator used when parsing `vars`. */
78
143
  varsAssignor: z.string().optional(),
144
+ /** Regex pattern used as the assignment operator for `vars` parsing. */
79
145
  varsAssignorPattern: z.string().optional(),
146
+ /** Delimiter string used to split `vars`. */
80
147
  varsDelimiter: z.string().optional(),
148
+ /** Regex pattern used to split `vars` (takes precedence over delimiter). */
81
149
  varsDelimiterPattern: z.string().optional(),
82
150
  });
83
151
 
@@ -101,17 +169,34 @@ const envStringMap = z.record(z.string(), stringMap);
101
169
  * Raw configuration schema for get‑dotenv config files (JSON/YAML/JS/TS).
102
170
  * Validates allowed top‑level keys without performing path normalization.
103
171
  */
172
+ /**
173
+ * Config schema for discovered get-dotenv configuration documents (raw).
174
+ *
175
+ * This schema validates the allowed top-level keys for configuration files.
176
+ * It does not normalize paths or coerce types beyond Zod’s parsing.
177
+ *
178
+ * @public
179
+ */
104
180
  const getDotenvConfigSchemaRaw = z.object({
181
+ /** Root option defaults applied by the host (CLI-like, collapsed families). */
105
182
  rootOptionDefaults: getDotenvCliOptionsSchemaRaw.optional(),
183
+ /** Help-time visibility map for root flags (false hides). */
106
184
  rootOptionVisibility: visibilityMap.optional(),
107
- scripts: z.record(z.string(), z.unknown()).optional(), // Scripts validation left wide; generator validates elsewhere
185
+ /** Scripts table used by cmd/batch resolution (validation intentionally permissive here). */
186
+ scripts: z.record(z.string(), z.unknown()).optional(),
187
+ /** Keys required to be present in the final composed environment. */
108
188
  requiredKeys: z.array(z.string()).optional(),
189
+ /** Validation schema (JS/TS only; JSON/YAML loader rejects). */
109
190
  schema: z.unknown().optional(), // JS/TS-only; loader rejects in JSON/YAML
191
+ /** Public global variables (string-only). */
110
192
  vars: stringMap.optional(), // public, global
193
+ /** Public per-environment variables (string-only). */
111
194
  envVars: envStringMap.optional(), // public, per-env
112
195
  // Dynamic in config (JS/TS only). JSON/YAML loader will reject if set.
196
+ /** Dynamic variable definitions (JS/TS only). */
113
197
  dynamic: z.unknown().optional(),
114
198
  // Per-plugin config bag; validated by plugins/host when used.
199
+ /** Per-plugin config slices keyed by realized mount path (for example, `aws/whoami`). */
115
200
  plugins: z.record(z.string(), z.unknown()).optional(),
116
201
  });
117
202
  /**
@@ -863,13 +948,21 @@ const redactObject = (obj, opts) => {
863
948
  * Base root CLI defaults (shared; kept untyped here to avoid cross-layer deps).
864
949
  * Used as the bottom layer for CLI option resolution.
865
950
  */
951
+ const baseScripts = {
952
+ 'git-status': {
953
+ cmd: 'git branch --show-current && git status -s -u',
954
+ shell: true,
955
+ },
956
+ };
866
957
  /**
867
- * Default values for root CLI options used by the host and helpers as the
868
- * baseline layer during option resolution.
958
+ * Default values for root CLI options used by the host and helpers as the baseline layer during option resolution.
959
+ *
960
+ * These defaults correspond to the “stringly” root surface (see `RootOptionsShape`) and are merged by precedence with:
961
+ * - create-time overrides
962
+ * - any discovered configuration `rootOptionDefaults`
963
+ * - and finally CLI flags at runtime
869
964
  *
870
- * These defaults correspond to the "stringly" root surface (see `RootOptionsShape`)
871
- * and are merged by precedence with create-time overrides and any discovered
872
- * configuration `rootOptionDefaults` before CLI flags are applied.
965
+ * @public
873
966
  */
874
967
  const baseRootOptionDefaults = {
875
968
  dotenvToken: '.env',
@@ -883,12 +976,7 @@ const baseRootOptionDefaults = {
883
976
  paths: './',
884
977
  pathsDelimiter: ' ',
885
978
  privateToken: 'local',
886
- scripts: {
887
- 'git-status': {
888
- cmd: 'git branch --show-current && git status -s -u',
889
- shell: true,
890
- },
891
- },
979
+ scripts: baseScripts,
892
980
  shell: true,
893
981
  vars: '',
894
982
  varsAssignor: '=',
@@ -1430,6 +1518,14 @@ async function _execNormalized(command, shell, opts = {}) {
1430
1518
  return out;
1431
1519
  }
1432
1520
  }
1521
+ /**
1522
+ * Execute a command and return its exit code.
1523
+ *
1524
+ * @param command - Command string (shell) or argv array (shell-off supported).
1525
+ * @param shell - Shell setting (false for plain execution).
1526
+ * @param opts - Execution options (cwd/env/stdio).
1527
+ * @returns A promise resolving to the process exit code.
1528
+ */
1433
1529
  async function runCommand(command, shell, opts) {
1434
1530
  // Build opts without injecting undefined (exactOptionalPropertyTypes-safe)
1435
1531
  const callOpts = {};
@@ -1889,6 +1985,16 @@ function evaluateDynamicOptions(root, resolved) {
1889
1985
  visit(root);
1890
1986
  }
1891
1987
 
1988
+ /**
1989
+ * Initialize a {@link GetDotenvCli} instance with help configuration and safe defaults.
1990
+ *
1991
+ * @remarks
1992
+ * This is a low-level initializer used by the host constructor to keep `GetDotenvCli.ts`
1993
+ * small and to centralize help/output behavior.
1994
+ *
1995
+ * @param cli - The CLI instance to initialize.
1996
+ * @param headerGetter - Callback returning an optional help header string.
1997
+ */
1892
1998
  function initializeInstance(cli, headerGetter) {
1893
1999
  // Configure grouped help: show only base options in default "Options";
1894
2000
  // subcommands show all of their own options.
@@ -2571,7 +2677,7 @@ const execShellCommandBatch = async ({ command, getDotenvCliOptions, dotenvEnv,
2571
2677
  /**
2572
2678
  * Attach the default "cmd" subcommand action with contextual typing.
2573
2679
  */
2574
- const attachDefaultCmdAction = (plugin, cli, batchCmd, pluginOpts, cmd) => {
2680
+ const attachBatchCmdAction = (plugin, cli, batchCmd, pluginOpts, cmd) => {
2575
2681
  cmd.action(async (commandParts, _subOpts, thisCommand) => {
2576
2682
  const mergedBag = readMergedOptions(batchCmd);
2577
2683
  const logger = mergedBag.logger;
@@ -2680,11 +2786,37 @@ const attachDefaultCmdAction = (plugin, cli, batchCmd, pluginOpts, cmd) => {
2680
2786
  });
2681
2787
  };
2682
2788
 
2789
+ /**
2790
+ * Attach the default `cmd` subcommand under the `batch` command.
2791
+ *
2792
+ * This encapsulates:
2793
+ * - Subcommand construction (`new Command().name('cmd')…`)
2794
+ * - Action wiring
2795
+ * - Mounting as the default subcommand for `batch`
2796
+ *
2797
+ * @param plugin - The batch plugin instance.
2798
+ * @param cli - The batch command mount.
2799
+ * @param batchCmd - The `batch` command (same as `cli` mount).
2800
+ * @param pluginOpts - Batch plugin factory options.
2801
+ *
2802
+ * @internal
2803
+ */
2804
+ const attachBatchCmdSubcommand = (plugin, cli, batchCmd, pluginOpts) => {
2805
+ const cmdSub = new Command()
2806
+ .name('cmd')
2807
+ .description('execute command, conflicts with --command option (default subcommand)')
2808
+ .enablePositionalOptions()
2809
+ .passThroughOptions()
2810
+ .argument('[command...]');
2811
+ attachBatchCmdAction(plugin, cli, batchCmd, pluginOpts, cmdSub);
2812
+ batchCmd.addCommand(cmdSub, { isDefault: true });
2813
+ };
2814
+
2683
2815
  /**
2684
2816
  * Attach the parent-level action for the batch plugin.
2685
2817
  * Handles parent flags (e.g. `getdotenv batch -l`) and delegates to the batch executor.
2686
2818
  */
2687
- const attachParentInvoker = (plugin, cli, pluginOpts, parent) => {
2819
+ const attachBatchDefaultAction = (plugin, cli, pluginOpts, parent) => {
2688
2820
  parent.action(async function (...args) {
2689
2821
  // Commander Unknown generics: [...unknown[], OptionValues, thisCommand]
2690
2822
  const thisCommand = args[args.length - 1];
@@ -2785,24 +2917,71 @@ const attachParentInvoker = (plugin, cli, pluginOpts, parent) => {
2785
2917
  });
2786
2918
  };
2787
2919
 
2920
+ /**
2921
+ * Attach options/arguments for the batch plugin mount.
2922
+ *
2923
+ * Note: the plugin description is owned by `src/plugins/batch/index.ts` and
2924
+ * must not be set here.
2925
+ *
2926
+ * @param plugin - Batch plugin instance (for dynamic option descriptions).
2927
+ * @param cli - The `batch` command mount.
2928
+ * @returns The same `cli` instance for chaining.
2929
+ *
2930
+ * @internal
2931
+ */
2932
+ /** @hidden */
2933
+ function attachBatchOptions(plugin, cli) {
2934
+ const GROUP = `plugin:${cli.name()}`;
2935
+ return (cli
2936
+ .enablePositionalOptions()
2937
+ .passThroughOptions()
2938
+ // Dynamic help: show effective defaults from the merged/interpolated plugin config slice.
2939
+ .addOption((() => {
2940
+ const opt = plugin.createPluginDynamicOption(cli, '-p, --pkg-cwd', (_bag, cfg) => `use nearest package directory as current working directory${cfg.pkgCwd ? ' (default)' : ''}`);
2941
+ cli.setOptionGroup(opt, GROUP);
2942
+ return opt;
2943
+ })())
2944
+ .addOption((() => {
2945
+ const opt = plugin.createPluginDynamicOption(cli, '-r, --root-path <string>', (_bag, cfg) => `path to batch root directory from current working directory (default: ${JSON.stringify(cfg.rootPath || './')})`);
2946
+ cli.setOptionGroup(opt, GROUP);
2947
+ return opt;
2948
+ })())
2949
+ .addOption((() => {
2950
+ const opt = plugin.createPluginDynamicOption(cli, '-g, --globs <string>', (_bag, cfg) => `space-delimited globs from root path (default: ${JSON.stringify(cfg.globs || '*')})`);
2951
+ cli.setOptionGroup(opt, GROUP);
2952
+ return opt;
2953
+ })())
2954
+ .option('-c, --command <string>', 'command executed according to the base shell resolution')
2955
+ .option('-l, --list', 'list working directories without executing command')
2956
+ .option('-e, --ignore-errors', 'ignore errors and continue with next path')
2957
+ .argument('[command...]'));
2958
+ }
2959
+
2788
2960
  /**
2789
2961
  * Zod schema for a single script entry (string or object).
2790
2962
  */
2791
2963
  const ScriptSchema = z.union([
2792
2964
  z.string(),
2793
2965
  z.object({
2966
+ /** Command string to execute. */
2794
2967
  cmd: z.string(),
2968
+ /** Optional shell override for this script entry. */
2795
2969
  shell: z.union([z.string(), z.boolean()]).optional(),
2796
2970
  }),
2797
2971
  ]);
2798
2972
  /**
2799
2973
  * Zod schema for batch plugin configuration.
2800
2974
  */
2801
- const BatchConfigSchema = z.object({
2975
+ const batchPluginConfigSchema = z.object({
2976
+ /** Optional scripts table scoped to the batch plugin. */
2802
2977
  scripts: z.record(z.string(), ScriptSchema).optional(),
2978
+ /** Optional default shell for batch execution (overridden by per-script shell when present). */
2803
2979
  shell: z.union([z.string(), z.boolean()]).optional(),
2980
+ /** Root path for discovery, relative to CWD (or package root when pkgCwd is true). */
2804
2981
  rootPath: z.string().optional(),
2982
+ /** Space-delimited glob patterns used to discover directories. */
2805
2983
  globs: z.string().optional(),
2984
+ /** When true, resolve the batch root from the nearest package directory. */
2806
2985
  pkgCwd: z.boolean().optional(),
2807
2986
  });
2808
2987
 
@@ -2824,45 +3003,15 @@ const batchPlugin = (opts = {}) => {
2824
3003
  ns: 'batch',
2825
3004
  // Host validates this when config-loader is enabled; plugins may also
2826
3005
  // re-validate at action time as a safety belt.
2827
- configSchema: BatchConfigSchema,
3006
+ configSchema: batchPluginConfigSchema,
2828
3007
  setup(cli) {
2829
3008
  const batchCmd = cli; // mount provided by host
2830
- const GROUP = `plugin:${cli.name()}`;
2831
- batchCmd
2832
- .description('Batch command execution across multiple working directories.')
2833
- .enablePositionalOptions()
2834
- .passThroughOptions()
2835
- // Dynamic help: show effective defaults from the merged/interpolated plugin config slice.
2836
- .addOption((() => {
2837
- const opt = plugin.createPluginDynamicOption(cli, '-p, --pkg-cwd', (_bag, cfg) => `use nearest package directory as current working directory${cfg.pkgCwd ? ' (default)' : ''}`);
2838
- cli.setOptionGroup(opt, GROUP);
2839
- return opt;
2840
- })())
2841
- .addOption((() => {
2842
- const opt = plugin.createPluginDynamicOption(cli, '-r, --root-path <string>', (_bag, cfg) => `path to batch root directory from current working directory (default: ${JSON.stringify(cfg.rootPath || './')})`);
2843
- cli.setOptionGroup(opt, GROUP);
2844
- return opt;
2845
- })())
2846
- .addOption((() => {
2847
- const opt = plugin.createPluginDynamicOption(cli, '-g, --globs <string>', (_bag, cfg) => `space-delimited globs from root path (default: ${JSON.stringify(cfg.globs || '*')})`);
2848
- cli.setOptionGroup(opt, GROUP);
2849
- return opt;
2850
- })())
2851
- .option('-c, --command <string>', 'command executed according to the base shell resolution')
2852
- .option('-l, --list', 'list working directories without executing command')
2853
- .option('-e, --ignore-errors', 'ignore errors and continue with next path')
2854
- .argument('[command...]');
2855
- // Default subcommand "cmd" with contextual typing for args/opts
2856
- const cmdSub = new Command()
2857
- .name('cmd')
2858
- .description('execute command, conflicts with --command option (default subcommand)')
2859
- .enablePositionalOptions()
2860
- .passThroughOptions()
2861
- .argument('[command...]');
2862
- attachDefaultCmdAction(plugin, cli, batchCmd, opts, cmdSub);
2863
- batchCmd.addCommand(cmdSub, { isDefault: true });
2864
- // Parent invoker (unified naming)
2865
- attachParentInvoker(plugin, cli, opts, batchCmd);
3009
+ batchCmd.description('Batch command execution across multiple working directories.');
3010
+ attachBatchOptions(plugin, batchCmd);
3011
+ // Default subcommand `cmd` (mounted as batch default subcommand)
3012
+ attachBatchCmdSubcommand(plugin, cli, batchCmd, opts);
3013
+ // Default action for the batch command mount (parent flags and positional form)
3014
+ attachBatchDefaultAction(plugin, cli, opts, batchCmd);
2866
3015
  return undefined;
2867
3016
  },
2868
3017
  });