goke 6.6.2 → 6.8.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.
@@ -568,6 +568,46 @@ describe('regression: oracle-found issues', () => {
568
568
  const { options } = cli.parse('node bin --count 42'.split(' '));
569
569
  expect(options.count).toBe(42);
570
570
  });
571
+ test('optional value option with schema default returns default when omitted', () => {
572
+ // `z.number().default(30)` has input `number | undefined` → output `number`,
573
+ // so goke marks this option as effectively required and must surface the
574
+ // default value at runtime when the flag is omitted.
575
+ const cli = goke();
576
+ cli.option('--limit [n]', z.number().default(30).describe('Max items'));
577
+ const { options } = cli.parse('node bin'.split(' '));
578
+ expect(options.limit).toBe(30);
579
+ });
580
+ test('optional value option with schema default returns default when passed bare', () => {
581
+ // Bare `--limit` is mri's "flag present, no value" sentinel. Without a
582
+ // default, goke replaces it with `undefined`. With a default, goke must
583
+ // preserve the preset default value instead of clobbering it, so the
584
+ // type-level `HasSchemaDefault` promise ("property is required at runtime")
585
+ // holds for all three input states: omitted, bare, and with-value.
586
+ const cli = goke();
587
+ cli.option('--limit [n]', z.number().default(30).describe('Max items'));
588
+ const { options } = cli.parse('node bin --limit'.split(' '));
589
+ expect(options.limit).toBe(30);
590
+ });
591
+ test('optional value option with schema default coerces explicit value', () => {
592
+ const cli = goke();
593
+ cli.option('--limit [n]', z.number().default(30).describe('Max items'));
594
+ const { options } = cli.parse('node bin --limit 5'.split(' '));
595
+ expect(options.limit).toBe(5);
596
+ });
597
+ test('multiple optional options with defaults all preserve their defaults', () => {
598
+ // Regression test for the runtime-overwrite bug: when several schema-backed
599
+ // optional flags have defaults, passing one bare should not clobber the
600
+ // others, and the bare one should keep its own default.
601
+ const cli = goke();
602
+ cli
603
+ .option('--limit [n]', z.number().default(30))
604
+ .option('--sort [mode]', z.enum(['asc', 'desc']).default('asc'))
605
+ .option('--host [host]', z.string().default('localhost'));
606
+ const { options } = cli.parse('node bin --sort'.split(' '));
607
+ expect(options.limit).toBe(30);
608
+ expect(options.sort).toBe('asc');
609
+ expect(options.host).toBe('localhost');
610
+ });
571
611
  test('alias + schema coercion works', () => {
572
612
  const cli = goke();
573
613
  cli.option('-p, --port <port>', z.number().describe('Port'));
@@ -606,9 +646,13 @@ describe('edge cases: schema + defaults interaction', () => {
606
646
  // Passed with value → coerced
607
647
  const { options: opts2 } = cli.parse('node bin --count 42'.split(' '));
608
648
  expect(opts2.count).toBe(42);
609
- // Passed without value → undefined (sentinel replaced)
649
+ // Passed without value → default preserved. Before goke 6.7.0 this test
650
+ // expected `undefined` because the bare-flag sentinel overwrote the
651
+ // preset default. With the HasSchemaDefault type inference, the runtime
652
+ // must keep the default so that the type-level promise ("options.count
653
+ // is always a number") holds for all three input states.
610
654
  const { options: opts3 } = cli.parse('node bin --count'.split(' '));
611
- expect(opts3.count).toBe(undefined);
655
+ expect(opts3.count).toBe(10);
612
656
  });
613
657
  });
614
658
  describe('edge cases: boolean flags + schema', () => {
@@ -4,6 +4,31 @@
4
4
  import { describe, expect, test } from 'vitest';
5
5
  import { z } from 'zod';
6
6
  import goke from '../index.js';
7
+ /**
8
+ * Build a minimal `GokeFs` stub where every method throws unless the
9
+ * caller overrides it. Used by `createExecutionContext` tests that
10
+ * only care about a single method (e.g. `readFile`) but still need
11
+ * an object that satisfies the full `GokeFs` interface.
12
+ */
13
+ function stubGokeFs(overrides) {
14
+ const notImplemented = () => { throw new Error('not implemented in stub'); };
15
+ return {
16
+ appendFile: notImplemented,
17
+ chmod: notImplemented,
18
+ copyFile: notImplemented,
19
+ link: notImplemented,
20
+ mkdir: notImplemented,
21
+ readFile: notImplemented,
22
+ readlink: notImplemented,
23
+ realpath: notImplemented,
24
+ rename: notImplemented,
25
+ rm: notImplemented,
26
+ symlink: notImplemented,
27
+ utimes: notImplemented,
28
+ writeFile: notImplemented,
29
+ ...overrides,
30
+ };
31
+ }
7
32
  const ANSI_RE = /\x1B\[[0-9;]*m/g;
8
33
  const stripAnsi = (text) => text.replace(ANSI_RE, '');
9
34
  function createTestOutputStream() {
@@ -62,6 +87,71 @@ describe('clone', () => {
62
87
  expect(cli.matchedCommandName).toBeUndefined();
63
88
  });
64
89
  });
90
+ describe('createExecutionContext', () => {
91
+ test('returns a context that mirrors the cli defaults when called with no override', () => {
92
+ const stdout = createTestOutputStream();
93
+ const stderr = createTestOutputStream();
94
+ const cli = gokeTestable('mycli', {
95
+ cwd: '/workspace',
96
+ env: { TOKEN: 'abc' },
97
+ stdin: 'stdin-text',
98
+ stdout,
99
+ stderr,
100
+ });
101
+ const ctx = cli.createExecutionContext();
102
+ expect(ctx.process.cwd).toBe('/workspace');
103
+ expect(ctx.process.env.TOKEN).toBe('abc');
104
+ expect(ctx.process.stdin).toBe('stdin-text');
105
+ expect(ctx.process.stdout).toBe(stdout);
106
+ expect(ctx.process.stderr).toBe(stderr);
107
+ ctx.console.log('hi');
108
+ expect(stdout.text).toBe('hi\n');
109
+ });
110
+ test('honors per-call overrides for stdout, cwd, env, stdin, fs, and exit', async () => {
111
+ const defaultStdout = createTestOutputStream();
112
+ const defaultFs = stubGokeFs({ readFile: async () => 'default' });
113
+ const cli = gokeTestable('mycli', {
114
+ cwd: '/default',
115
+ env: { DEFAULT: '1' },
116
+ stdin: 'default-stdin',
117
+ stdout: defaultStdout,
118
+ fs: defaultFs,
119
+ });
120
+ const overrideStdout = createTestOutputStream();
121
+ const overrideStderr = createTestOutputStream();
122
+ const overrideFs = stubGokeFs({ readFile: async () => 'override' });
123
+ let receivedExitCode;
124
+ const ctx = cli.createExecutionContext({
125
+ cwd: '/tenant',
126
+ env: { TOKEN: 'xyz' },
127
+ stdin: 'tenant-stdin',
128
+ stdout: overrideStdout,
129
+ stderr: overrideStderr,
130
+ fs: overrideFs,
131
+ exit: (code) => {
132
+ receivedExitCode = code;
133
+ },
134
+ });
135
+ expect(ctx.process.cwd).toBe('/tenant');
136
+ expect(ctx.process.env.TOKEN).toBe('xyz');
137
+ expect(ctx.process.env.DEFAULT).toBeUndefined();
138
+ expect(ctx.process.stdin).toBe('tenant-stdin');
139
+ expect(ctx.process.stdout).toBe(overrideStdout);
140
+ expect(ctx.process.stderr).toBe(overrideStderr);
141
+ expect(ctx.fs).toBe(overrideFs);
142
+ expect(await ctx.fs.readFile('unused')).toBe('override');
143
+ // The cli's own stdout must NOT receive writes made through the
144
+ // override. This is what makes per-request capturing safe.
145
+ ctx.console.log('per-tenant');
146
+ expect(defaultStdout.text).toBe('');
147
+ expect(overrideStdout.text).toBe('per-tenant\n');
148
+ // Custom exit callback runs, then the wrapper throws GokeProcessExit
149
+ // so the action's code path stops at the exit site.
150
+ const { GokeProcessExit } = await import('../goke.js');
151
+ expect(() => ctx.process.exit(7)).toThrow(GokeProcessExit);
152
+ expect(receivedExitCode).toBe(7);
153
+ });
154
+ });
65
155
  describe('createJustBashCommand', () => {
66
156
  test('runs multi-word goke subcommands through one just-bash command', async () => {
67
157
  const cli = gokeTestable('parent');
@@ -288,6 +288,65 @@ describe('type-level: command() .action() option inference', () => {
288
288
  expectTypeOf(options.verbose).toEqualTypeOf();
289
289
  });
290
290
  });
291
+ test('schema with .default() on [value] is typed as required', () => {
292
+ // `z.number().default(30)` has Standard Schema input `number | undefined`
293
+ // but output `number`, so goke recognizes it as "effectively required"
294
+ // even though the bracket syntax is `[...]`. The property should NOT
295
+ // be optional in the action options — the runtime always produces 30
296
+ // when the flag is omitted or passed bare.
297
+ goke('test')
298
+ .command('list', 'List stuff')
299
+ .option('--limit [n]', z.number().default(30).describe('Max items'))
300
+ .option('--sort [mode]', z.enum(['asc', 'desc']).default('asc'))
301
+ .action((options) => {
302
+ expectTypeOf(options.limit).toEqualTypeOf();
303
+ expectTypeOf(options.sort).toEqualTypeOf();
304
+ });
305
+ });
306
+ test('schema without .default() on [value] stays optional', () => {
307
+ // Without a default, `[value]` remains genuinely optional at the type
308
+ // level — bare flag or omitted flag both produce `undefined`.
309
+ goke('test')
310
+ .command('list', 'List stuff')
311
+ .option('--limit [n]', z.number().describe('Max items'))
312
+ .option('--filter [pattern]', z.string())
313
+ .action((options) => {
314
+ expectTypeOf(options.limit).toEqualTypeOf();
315
+ expectTypeOf(options.filter).toEqualTypeOf();
316
+ });
317
+ });
318
+ test('z.string().optional() on [value] stays optional (no default)', () => {
319
+ // `.optional()` makes both input and output allow undefined, so
320
+ // HasSchemaDefault is false and the bracket-based optionality wins.
321
+ goke('test')
322
+ .command('serve', 'Start server')
323
+ .option('--host [host]', z.string().optional().describe('Host'))
324
+ .action((options) => {
325
+ expectTypeOf(options.host).toEqualTypeOf();
326
+ });
327
+ });
328
+ test('.default() combined with .optional() stays optional', () => {
329
+ // `z.number().default(30).optional()` has Input `number | undefined` AND
330
+ // Output `number | undefined`, so HasSchemaDefault is false — the user
331
+ // explicitly opted out of the default-inferred-as-required behavior by
332
+ // re-adding `.optional()`.
333
+ goke('test')
334
+ .command('list', 'List stuff')
335
+ .option('--limit [n]', z.number().default(30).optional())
336
+ .action((options) => {
337
+ expectTypeOf(options.limit).toEqualTypeOf();
338
+ });
339
+ });
340
+ test('.default() on <required> is typed as required output', () => {
341
+ // With `<value>` syntax the property is already required; the schema
342
+ // default just narrows the output type. This is the "old" behavior.
343
+ goke('test')
344
+ .command('serve', 'Start server')
345
+ .option('--port <port>', z.number().default(3000))
346
+ .action((options) => {
347
+ expectTypeOf(options.port).toEqualTypeOf();
348
+ });
349
+ });
291
350
  test('accessing a non-existent option in action is a type error', () => {
292
351
  goke('test')
293
352
  .command('serve', 'Start server')
@@ -339,6 +398,11 @@ describe('type-level: README TypeScript examples', () => {
339
398
  });
340
399
  });
341
400
  test('README global options and middleware example stays typed end-to-end', () => {
401
+ // `z.boolean().default(false)` and `z.string().default(...)` are
402
+ // effectively required at runtime: the default applies when the flag is
403
+ // omitted or passed bare, so goke types the property as required (no
404
+ // `| undefined`). Raw untyped boolean flags like `--dry-run` stay
405
+ // `boolean | undefined`.
342
406
  goke('mycli')
343
407
  .option('--verbose', z.boolean().default(false).describe('Enable verbose logging'))
344
408
  .option('--api-url [url]', z.string().default('https://api.example.com').describe('API base URL'))
package/dist/goke.d.ts CHANGED
@@ -53,8 +53,24 @@ type ExtractOptionName<S extends string> = S extends `${string}--${infer Name} <
53
53
  * Determines if an option takes a required value (<...>) vs optional ([...]) vs boolean flag.
54
54
  */
55
55
  type IsOptionalOption<S extends string> = S extends `${string}<${string}>` ? false : true;
56
+ /**
57
+ * Infer the input type from a StandardTypedV1-compatible schema.
58
+ *
59
+ * For Zod, this is the type accepted by `.parse()` before any transforms or
60
+ * defaults are applied (e.g. `z.number().default(30)` has input `number | undefined`).
61
+ */
62
+ type InferSchemaInput<S> = S extends {
63
+ readonly "~standard": {
64
+ readonly types?: {
65
+ readonly input: infer I;
66
+ };
67
+ };
68
+ } ? I : unknown;
56
69
  /**
57
70
  * Infer the output type from a StandardTypedV1-compatible schema.
71
+ *
72
+ * For Zod, this is the type produced by `.parse()` after transforms/defaults
73
+ * run (e.g. `z.number().default(30)` has output `number`).
58
74
  */
59
75
  type InferSchemaOutput<S> = S extends {
60
76
  readonly "~standard": {
@@ -63,12 +79,33 @@ type InferSchemaOutput<S> = S extends {
63
79
  };
64
80
  };
65
81
  } ? O : unknown;
82
+ /**
83
+ * Detects whether a Standard Schema has a "default" behavior: its input allows
84
+ * `undefined` but its output does not. This matches `z.number().default(30)`
85
+ * and similar `.default(...)` wrappers in other libraries: the schema fills
86
+ * in a value whenever the caller omits it, so at runtime the property is
87
+ * always populated and goke can mark it as required in the options type even
88
+ * when the option is declared with `[value]` square brackets.
89
+ *
90
+ * The `unknown extends Input` guard excludes the `wrapJsonSchema` path, where
91
+ * input defaults to `unknown` because the hand-written schema has no way to
92
+ * express a separate input type. For those schemas we fall back to the raw
93
+ * bracket-based optionality, which keeps existing behavior for consumers
94
+ * that use `wrapJsonSchema<T>()` for truly optional options.
95
+ */
96
+ type HasSchemaDefault<S> = unknown extends InferSchemaInput<S> ? false : undefined extends InferSchemaInput<S> ? undefined extends InferSchemaOutput<S> ? false : true : false;
66
97
  /**
67
98
  * Build the option type entry for a single .option() call.
68
- * Required options (<...>) produce a required key.
69
- * Optional options ([...]) and boolean flags produce an optional key.
99
+ *
100
+ * Required options (`<...>`) produce a required key.
101
+ * Optional options (`[...]`) produce an optional key, EXCEPT when the schema
102
+ * has an effective default (see `HasSchemaDefault`) — in that case goke's
103
+ * runtime always surfaces the default value, so the property is typed as
104
+ * required with the post-coercion output type.
70
105
  */
71
- type OptionEntry<RawName extends string, Schema> = IsOptionalOption<RawName> extends true ? {
106
+ type OptionEntry<RawName extends string, Schema> = IsOptionalOption<RawName> extends true ? HasSchemaDefault<Schema> extends true ? {
107
+ [K in ExtractOptionName<RawName>]: InferSchemaOutput<Schema>;
108
+ } : {
72
109
  [K in ExtractOptionName<RawName>]?: InferSchemaOutput<Schema>;
73
110
  } : {
74
111
  [K in ExtractOptionName<RawName>]: InferSchemaOutput<Schema>;
@@ -293,6 +330,44 @@ interface GokeExecutionContext {
293
330
  fs: GokeFs;
294
331
  process: GokeProcess;
295
332
  }
333
+ /**
334
+ * Per-request overrides accepted by `Goke#createExecutionContext()`.
335
+ *
336
+ * Any field left `undefined` falls back to the `Goke` instance's
337
+ * defaults (set via `GokeOptions`), which themselves fall back to the
338
+ * real Node.js `process.*`. Use this to construct an execution context
339
+ * with tenant-specific values — e.g. a per-user `cwd`/`env`/`fs` pair
340
+ * for a remote MCP server, or capture streams for stdout/stderr.
341
+ *
342
+ * Passing a custom `exit` replaces the default behavior of calling
343
+ * `this.exit(code)`. The returned `process.exit` still throws
344
+ * `GokeProcessExit` after the user-provided `exit` returns, so callers
345
+ * can catch the exit without the outer code needing to know about it.
346
+ */
347
+ interface GokeExecutionContextOverride {
348
+ /** Override the argv array exposed as `process.argv`. Defaults to the cli's raw parsed argv. */
349
+ argv?: string[];
350
+ /** Override the working directory exposed as `process.cwd`. */
351
+ cwd?: string;
352
+ /** Override the environment exposed as `process.env`. */
353
+ env?: Record<string, string | undefined>;
354
+ /** Override the filesystem exposed as `ctx.fs`. */
355
+ fs?: GokeFs;
356
+ /** Override the stdin content exposed as `process.stdin`. */
357
+ stdin?: string;
358
+ /** Override the stdout stream used by `ctx.console.log` and exposed as `process.stdout`. */
359
+ stdout?: GokeOutputStream;
360
+ /** Override the stderr stream used by `ctx.console.error` and exposed as `process.stderr`. */
361
+ stderr?: GokeOutputStream;
362
+ /**
363
+ * Override the exit function called by `process.exit(code)`.
364
+ *
365
+ * The returned context still throws `GokeProcessExit` after this
366
+ * callback returns, so callers that want to capture the exit
367
+ * without killing the host process can pass `() => {}`.
368
+ */
369
+ exit?: (code: number) => void;
370
+ }
296
371
  declare class GokeProcessExit extends Error {
297
372
  code: number;
298
373
  constructor(code: number);
@@ -387,7 +462,43 @@ declare class Goke<Opts = {}> extends EventEmitter {
387
462
  */
388
463
  constructor(name?: string, options?: GokeOptions);
389
464
  clone(options?: GokeOptions): Goke<Opts>;
390
- private createExecutionContext;
465
+ /**
466
+ * Build a `GokeExecutionContext` using this cli's defaults, optionally
467
+ * overridden per-request.
468
+ *
469
+ * `runMatchedCommand()` calls this internally with no arguments to
470
+ * construct the context passed to command actions and middlewares.
471
+ *
472
+ * The method is also public so adapters (MCP, remote RPC, batch
473
+ * runners, etc.) can build a context for a single invocation with
474
+ * tenant-specific values — e.g. capture streams for stdout/stderr,
475
+ * a per-user `cwd`/`env`/`fs`, or an `exit` that throws instead of
476
+ * killing the host process. See {@link GokeExecutionContextOverride}.
477
+ *
478
+ * @example
479
+ * ```ts
480
+ * // Build an execution context that captures output into strings and
481
+ * // treats `ctx.process.exit(code)` as a `GokeProcessExit` throw
482
+ * // instead of terminating the host process.
483
+ * const stdout = createTextCaptureStream()
484
+ * const stderr = createTextCaptureStream()
485
+ * const ctx = cli.createExecutionContext({
486
+ * stdout,
487
+ * stderr,
488
+ * exit: () => {},
489
+ * })
490
+ * try {
491
+ * await action(...args, options, ctx)
492
+ * } catch (err) {
493
+ * if (err instanceof GokeProcessExit) {
494
+ * // handle exit code
495
+ * } else {
496
+ * throw err
497
+ * }
498
+ * }
499
+ * ```
500
+ */
501
+ createExecutionContext(override?: GokeExecutionContextOverride): GokeExecutionContext;
391
502
  createJustBashCommand(options?: {
392
503
  name?: string;
393
504
  }): Promise<import("./just-bash.js").JustBashCommand>;
@@ -500,7 +611,7 @@ declare class Goke<Opts = {}> extends EventEmitter {
500
611
  private mri;
501
612
  runMatchedCommand(): any;
502
613
  }
503
- export type { GokeOutputStream, GokeConsole, GokeOptions, GokeProcess, GokeExecutionContext, GokeFs };
614
+ export type { GokeOutputStream, GokeConsole, GokeOptions, GokeProcess, GokeExecutionContext, GokeExecutionContextOverride, GokeFs };
504
615
  export { createConsole, Command, GokeProcessExit, openInBrowser };
505
616
  export default Goke;
506
617
  //# sourceMappingURL=goke.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"goke.d.ts","sourceRoot":"","sources":["../src/goke.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"goke.d.ts","sourceRoot":"","sources":["../src/goke.ts"],"names":[],"mappings":"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"}
package/dist/goke.js CHANGED
@@ -729,19 +729,63 @@ class Goke extends EventEmitter {
729
729
  }
730
730
  return cloned;
731
731
  }
732
- createExecutionContext(argv = this.rawArgs) {
732
+ /**
733
+ * Build a `GokeExecutionContext` using this cli's defaults, optionally
734
+ * overridden per-request.
735
+ *
736
+ * `runMatchedCommand()` calls this internally with no arguments to
737
+ * construct the context passed to command actions and middlewares.
738
+ *
739
+ * The method is also public so adapters (MCP, remote RPC, batch
740
+ * runners, etc.) can build a context for a single invocation with
741
+ * tenant-specific values — e.g. capture streams for stdout/stderr,
742
+ * a per-user `cwd`/`env`/`fs`, or an `exit` that throws instead of
743
+ * killing the host process. See {@link GokeExecutionContextOverride}.
744
+ *
745
+ * @example
746
+ * ```ts
747
+ * // Build an execution context that captures output into strings and
748
+ * // treats `ctx.process.exit(code)` as a `GokeProcessExit` throw
749
+ * // instead of terminating the host process.
750
+ * const stdout = createTextCaptureStream()
751
+ * const stderr = createTextCaptureStream()
752
+ * const ctx = cli.createExecutionContext({
753
+ * stdout,
754
+ * stderr,
755
+ * exit: () => {},
756
+ * })
757
+ * try {
758
+ * await action(...args, options, ctx)
759
+ * } catch (err) {
760
+ * if (err instanceof GokeProcessExit) {
761
+ * // handle exit code
762
+ * } else {
763
+ * throw err
764
+ * }
765
+ * }
766
+ * ```
767
+ */
768
+ createExecutionContext(override) {
769
+ const stdout = override?.stdout ?? this.stdout;
770
+ const stderr = override?.stderr ?? this.stderr;
771
+ // Reuse the cached console when streams aren't overridden; otherwise
772
+ // build a new one so ctx.console.log writes to the overridden streams.
773
+ const contextConsole = (override?.stdout !== undefined || override?.stderr !== undefined)
774
+ ? createConsole(stdout, stderr)
775
+ : this.console;
776
+ const exitFn = override?.exit ?? this.exit;
733
777
  return {
734
- console: this.console,
735
- fs: this.fs,
778
+ console: contextConsole,
779
+ fs: override?.fs ?? this.fs,
736
780
  process: {
737
- argv,
738
- cwd: this.cwd ?? process.cwd(),
739
- env: this.env ?? process.env,
740
- stdin: this.stdin ?? '',
741
- stdout: this.stdout,
742
- stderr: this.stderr,
781
+ argv: override?.argv ?? this.rawArgs,
782
+ cwd: override?.cwd ?? this.cwd ?? process.cwd(),
783
+ env: override?.env ?? this.env ?? process.env,
784
+ stdin: override?.stdin ?? this.stdin ?? '',
785
+ stdout,
786
+ stderr,
743
787
  exit: (code) => {
744
- this.exit(code);
788
+ exitFn(code);
745
789
  throw new GokeProcessExit(code);
746
790
  },
747
791
  },
@@ -1105,8 +1149,13 @@ class Goke extends EventEmitter {
1105
1149
  // For optional options ([...]) we want a single, uniform shape: `string`
1106
1150
  // with `''` meaning "flag present but no value" — callers get clean
1107
1151
  // `string | undefined` types instead of `string | boolean | undefined`.
1152
+ // The `optionsWithDefault` set tracks options whose schema produced a
1153
+ // non-undefined default — when the user passes such an option bare, we
1154
+ // keep the preset default instead of overwriting it with `undefined`,
1155
+ // which matches what the new `HasSchemaDefault` type inference promises.
1108
1156
  const requiredValueOptions = new Set();
1109
1157
  const optionalValueOptions = new Set();
1158
+ const optionsWithDefault = new Set();
1110
1159
  for (const cliOption of cliOptions) {
1111
1160
  if (cliOption.required === true) {
1112
1161
  for (const name of cliOption.names) {
@@ -1118,6 +1167,11 @@ class Goke extends EventEmitter {
1118
1167
  optionalValueOptions.add(name);
1119
1168
  }
1120
1169
  }
1170
+ if (cliOption.default !== undefined) {
1171
+ for (const name of cliOption.names) {
1172
+ optionsWithDefault.add(name);
1173
+ }
1174
+ }
1121
1175
  }
1122
1176
  // Set option values (support dot-nested property name)
1123
1177
  // Apply schema-based coercion for options with schemas
@@ -1129,15 +1183,23 @@ class Goke extends EventEmitter {
1129
1183
  // When value is boolean `true` and the option takes a value, it's mri's sentinel
1130
1184
  // for "flag present, no value given":
1131
1185
  // - Required options (<...>): preserve `true` so checkOptionValue() throws
1132
- // - Optional options ([...]) with schema: replace with `undefined` so
1133
- // any `.default(...)` on the schema kicks in (e.g. z.number().default(30)
1134
- // should produce 30, not try to coerce the `''` empty-string sentinel).
1186
+ // - Optional options ([...]) with schema AND a default: skip this
1187
+ // key entirely so the preset default (written into `options` at
1188
+ // the top of this function) survives. This keeps the type-level
1189
+ // `HasSchemaDefault` promise honest at runtime.
1190
+ // - Optional options ([...]) with schema and NO default: replace
1191
+ // `true` with `undefined` so the caller sees "flag present, no value"
1192
+ // as `undefined`.
1135
1193
  const schemaInfo = schemaMap.get(key);
1136
1194
  if (schemaInfo && value !== undefined) {
1137
1195
  if (value === true && requiredValueOptions.has(key)) {
1138
1196
  // Keep sentinel for checkOptionValue() to detect
1139
1197
  }
1140
1198
  else if (value === true && optionalValueOptions.has(key)) {
1199
+ if (optionsWithDefault.has(key)) {
1200
+ // Preserve the preset default — don't overwrite with undefined.
1201
+ continue;
1202
+ }
1141
1203
  value = undefined;
1142
1204
  }
1143
1205
  else {
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ declare const goke: (name?: string, options?: GokeOptions) => Goke<{}>;
9
9
  export default goke;
10
10
  export { goke, Goke, Command };
11
11
  export { createConsole, GokeProcessExit, openInBrowser } from "./goke.js";
12
- export type { GokeOutputStream, GokeConsole, GokeExecutionContext, GokeFs, GokeOptions, GokeProcess } from "./goke.js";
12
+ export type { GokeOutputStream, GokeConsole, GokeExecutionContext, GokeExecutionContextOverride, GokeFs, GokeOptions, GokeProcess } from "./goke.js";
13
13
  export type { StandardTypedV1, StandardJSONSchemaV1, JsonSchema } from "./coerce.js";
14
14
  export { GokeError, coerceBySchema, extractJsonSchema, wrapJsonSchema, isStandardSchema, extractSchemaMetadata } from "./coerce.js";
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC;;;GAGG;AACH,QAAA,MAAM,IAAI,GAAI,aAAS,EAAE,UAAU,WAAW,aAA4B,CAAA;AAE1E,eAAe,IAAI,CAAA;AACnB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAC9B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACtH,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC;;;GAGG;AACH,QAAA,MAAM,IAAI,GAAI,aAAS,EAAE,UAAU,WAAW,aAA4B,CAAA;AAE1E,eAAe,IAAI,CAAA;AACnB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAC9B,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACpJ,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "goke",
3
- "version": "6.6.2",
3
+ "version": "6.8.0",
4
4
  "type": "module",
5
5
  "description": "Simple yet powerful framework for building command-line apps. Inspired by cac.",
6
6
  "repository": {
@@ -728,6 +728,54 @@ describe('regression: oracle-found issues', () => {
728
728
  expect(options.count).toBe(42)
729
729
  })
730
730
 
731
+ test('optional value option with schema default returns default when omitted', () => {
732
+ // `z.number().default(30)` has input `number | undefined` → output `number`,
733
+ // so goke marks this option as effectively required and must surface the
734
+ // default value at runtime when the flag is omitted.
735
+ const cli = goke()
736
+ cli.option('--limit [n]', z.number().default(30).describe('Max items'))
737
+
738
+ const { options } = cli.parse('node bin'.split(' '))
739
+ expect(options.limit).toBe(30)
740
+ })
741
+
742
+ test('optional value option with schema default returns default when passed bare', () => {
743
+ // Bare `--limit` is mri's "flag present, no value" sentinel. Without a
744
+ // default, goke replaces it with `undefined`. With a default, goke must
745
+ // preserve the preset default value instead of clobbering it, so the
746
+ // type-level `HasSchemaDefault` promise ("property is required at runtime")
747
+ // holds for all three input states: omitted, bare, and with-value.
748
+ const cli = goke()
749
+ cli.option('--limit [n]', z.number().default(30).describe('Max items'))
750
+
751
+ const { options } = cli.parse('node bin --limit'.split(' '))
752
+ expect(options.limit).toBe(30)
753
+ })
754
+
755
+ test('optional value option with schema default coerces explicit value', () => {
756
+ const cli = goke()
757
+ cli.option('--limit [n]', z.number().default(30).describe('Max items'))
758
+
759
+ const { options } = cli.parse('node bin --limit 5'.split(' '))
760
+ expect(options.limit).toBe(5)
761
+ })
762
+
763
+ test('multiple optional options with defaults all preserve their defaults', () => {
764
+ // Regression test for the runtime-overwrite bug: when several schema-backed
765
+ // optional flags have defaults, passing one bare should not clobber the
766
+ // others, and the bare one should keep its own default.
767
+ const cli = goke()
768
+ cli
769
+ .option('--limit [n]', z.number().default(30))
770
+ .option('--sort [mode]', z.enum(['asc', 'desc']).default('asc'))
771
+ .option('--host [host]', z.string().default('localhost'))
772
+
773
+ const { options } = cli.parse('node bin --sort'.split(' '))
774
+ expect(options.limit).toBe(30)
775
+ expect(options.sort).toBe('asc')
776
+ expect(options.host).toBe('localhost')
777
+ })
778
+
731
779
  test('alias + schema coercion works', () => {
732
780
  const cli = goke()
733
781
 
@@ -783,9 +831,13 @@ describe('edge cases: schema + defaults interaction', () => {
783
831
  const { options: opts2 } = cli.parse('node bin --count 42'.split(' '))
784
832
  expect(opts2.count).toBe(42)
785
833
 
786
- // Passed without value → undefined (sentinel replaced)
834
+ // Passed without value → default preserved. Before goke 6.7.0 this test
835
+ // expected `undefined` because the bare-flag sentinel overwrote the
836
+ // preset default. With the HasSchemaDefault type inference, the runtime
837
+ // must keep the default so that the type-level promise ("options.count
838
+ // is always a number") holds for all three input states.
787
839
  const { options: opts3 } = cli.parse('node bin --count'.split(' '))
788
- expect(opts3.count).toBe(undefined)
840
+ expect(opts3.count).toBe(10)
789
841
  })
790
842
  })
791
843
 
@@ -5,7 +5,33 @@
5
5
  import { describe, expect, test } from 'vitest'
6
6
  import { z } from 'zod'
7
7
  import goke from '../index.js'
8
- import type { GokeOutputStream, GokeOptions } from '../index.js'
8
+ import type { GokeOutputStream, GokeOptions, GokeFs } from '../index.js'
9
+
10
+ /**
11
+ * Build a minimal `GokeFs` stub where every method throws unless the
12
+ * caller overrides it. Used by `createExecutionContext` tests that
13
+ * only care about a single method (e.g. `readFile`) but still need
14
+ * an object that satisfies the full `GokeFs` interface.
15
+ */
16
+ function stubGokeFs(overrides: Partial<GokeFs>): GokeFs {
17
+ const notImplemented = () => { throw new Error('not implemented in stub') }
18
+ return {
19
+ appendFile: notImplemented,
20
+ chmod: notImplemented,
21
+ copyFile: notImplemented,
22
+ link: notImplemented,
23
+ mkdir: notImplemented,
24
+ readFile: notImplemented,
25
+ readlink: notImplemented,
26
+ realpath: notImplemented,
27
+ rename: notImplemented,
28
+ rm: notImplemented,
29
+ symlink: notImplemented,
30
+ utimes: notImplemented,
31
+ writeFile: notImplemented,
32
+ ...overrides,
33
+ }
34
+ }
9
35
 
10
36
  const ANSI_RE = /\x1B\[[0-9;]*m/g
11
37
 
@@ -82,6 +108,80 @@ describe('clone', () => {
82
108
  })
83
109
  })
84
110
 
111
+ describe('createExecutionContext', () => {
112
+ test('returns a context that mirrors the cli defaults when called with no override', () => {
113
+ const stdout = createTestOutputStream()
114
+ const stderr = createTestOutputStream()
115
+ const cli = gokeTestable('mycli', {
116
+ cwd: '/workspace',
117
+ env: { TOKEN: 'abc' },
118
+ stdin: 'stdin-text',
119
+ stdout,
120
+ stderr,
121
+ })
122
+
123
+ const ctx = cli.createExecutionContext()
124
+
125
+ expect(ctx.process.cwd).toBe('/workspace')
126
+ expect(ctx.process.env.TOKEN).toBe('abc')
127
+ expect(ctx.process.stdin).toBe('stdin-text')
128
+ expect(ctx.process.stdout).toBe(stdout)
129
+ expect(ctx.process.stderr).toBe(stderr)
130
+
131
+ ctx.console.log('hi')
132
+ expect(stdout.text).toBe('hi\n')
133
+ })
134
+
135
+ test('honors per-call overrides for stdout, cwd, env, stdin, fs, and exit', async () => {
136
+ const defaultStdout = createTestOutputStream()
137
+ const defaultFs = stubGokeFs({ readFile: async () => 'default' })
138
+ const cli = gokeTestable('mycli', {
139
+ cwd: '/default',
140
+ env: { DEFAULT: '1' },
141
+ stdin: 'default-stdin',
142
+ stdout: defaultStdout,
143
+ fs: defaultFs,
144
+ })
145
+
146
+ const overrideStdout = createTestOutputStream()
147
+ const overrideStderr = createTestOutputStream()
148
+ const overrideFs = stubGokeFs({ readFile: async () => 'override' })
149
+ let receivedExitCode: number | undefined
150
+ const ctx = cli.createExecutionContext({
151
+ cwd: '/tenant',
152
+ env: { TOKEN: 'xyz' },
153
+ stdin: 'tenant-stdin',
154
+ stdout: overrideStdout,
155
+ stderr: overrideStderr,
156
+ fs: overrideFs,
157
+ exit: (code) => {
158
+ receivedExitCode = code
159
+ },
160
+ })
161
+
162
+ expect(ctx.process.cwd).toBe('/tenant')
163
+ expect(ctx.process.env.TOKEN).toBe('xyz')
164
+ expect(ctx.process.env.DEFAULT).toBeUndefined()
165
+ expect(ctx.process.stdin).toBe('tenant-stdin')
166
+ expect(ctx.process.stdout).toBe(overrideStdout)
167
+ expect(ctx.process.stderr).toBe(overrideStderr)
168
+ expect(ctx.fs).toBe(overrideFs)
169
+ expect(await ctx.fs.readFile('unused')).toBe('override')
170
+
171
+ // The cli's own stdout must NOT receive writes made through the
172
+ // override. This is what makes per-request capturing safe.
173
+ ctx.console.log('per-tenant')
174
+ expect(defaultStdout.text).toBe('')
175
+ expect(overrideStdout.text).toBe('per-tenant\n')
176
+
177
+ // Custom exit callback runs, then the wrapper throws GokeProcessExit
178
+ // so the action's code path stops at the exit site.
179
+ const { GokeProcessExit } = await import('../goke.js')
180
+ expect(() => ctx.process.exit(7)).toThrow(GokeProcessExit)
181
+ expect(receivedExitCode).toBe(7)
182
+ })
183
+ })
184
+
85
185
  describe('createJustBashCommand', () => {
86
186
  test('runs multi-word goke subcommands through one just-bash command', async () => {
87
187
  const cli = gokeTestable('parent')
@@ -362,6 +362,70 @@ describe('type-level: command() .action() option inference', () => {
362
362
  })
363
363
  })
364
364
 
365
+ test('schema with .default() on [value] is typed as required', () => {
366
+ // `z.number().default(30)` has Standard Schema input `number | undefined`
367
+ // but output `number`, so goke recognizes it as "effectively required"
368
+ // even though the bracket syntax is `[...]`. The property should NOT
369
+ // be optional in the action options — the runtime always produces 30
370
+ // when the flag is omitted or passed bare.
371
+ goke('test')
372
+ .command('list', 'List stuff')
373
+ .option('--limit [n]', z.number().default(30).describe('Max items'))
374
+ .option('--sort [mode]', z.enum(['asc', 'desc']).default('asc'))
375
+ .action((options) => {
376
+ expectTypeOf(options.limit).toEqualTypeOf<number>()
377
+ expectTypeOf(options.sort).toEqualTypeOf<'asc' | 'desc'>()
378
+ })
379
+ })
380
+
381
+ test('schema without .default() on [value] stays optional', () => {
382
+ // Without a default, `[value]` remains genuinely optional at the type
383
+ // level — bare flag or omitted flag both produce `undefined`.
384
+ goke('test')
385
+ .command('list', 'List stuff')
386
+ .option('--limit [n]', z.number().describe('Max items'))
387
+ .option('--filter [pattern]', z.string())
388
+ .action((options) => {
389
+ expectTypeOf(options.limit).toEqualTypeOf<number | undefined>()
390
+ expectTypeOf(options.filter).toEqualTypeOf<string | undefined>()
391
+ })
392
+ })
393
+
394
+ test('z.string().optional() on [value] stays optional (no default)', () => {
395
+ // `.optional()` makes both input and output allow undefined, so
396
+ // HasSchemaDefault is false and the bracket-based optionality wins.
397
+ goke('test')
398
+ .command('serve', 'Start server')
399
+ .option('--host [host]', z.string().optional().describe('Host'))
400
+ .action((options) => {
401
+ expectTypeOf(options.host).toEqualTypeOf<string | undefined>()
402
+ })
403
+ })
404
+
405
+ test('.default() combined with .optional() stays optional', () => {
406
+ // `z.number().default(30).optional()` has Input `number | undefined` AND
407
+ // Output `number | undefined`, so HasSchemaDefault is false — the user
408
+ // explicitly opted out of the default-inferred-as-required behavior by
409
+ // re-adding `.optional()`.
410
+ goke('test')
411
+ .command('list', 'List stuff')
412
+ .option('--limit [n]', z.number().default(30).optional())
413
+ .action((options) => {
414
+ expectTypeOf(options.limit).toEqualTypeOf<number | undefined>()
415
+ })
416
+ })
417
+
418
+ test('.default() on <required> is typed as required output', () => {
419
+ // With `<value>` syntax the property is already required; the schema
420
+ // default just narrows the output type. This is the "old" behavior.
421
+ goke('test')
422
+ .command('serve', 'Start server')
423
+ .option('--port <port>', z.number().default(3000))
424
+ .action((options) => {
425
+ expectTypeOf(options.port).toEqualTypeOf<number>()
426
+ })
427
+ })
428
+
365
429
  test('accessing a non-existent option in action is a type error', () => {
366
430
  goke('test')
367
431
  .command('serve', 'Start server')
@@ -418,20 +482,25 @@ describe('type-level: README TypeScript examples', () => {
418
482
  })
419
483
 
420
484
  test('README global options and middleware example stays typed end-to-end', () => {
485
+ // `z.boolean().default(false)` and `z.string().default(...)` are
486
+ // effectively required at runtime: the default applies when the flag is
487
+ // omitted or passed bare, so goke types the property as required (no
488
+ // `| undefined`). Raw untyped boolean flags like `--dry-run` stay
489
+ // `boolean | undefined`.
421
490
  goke('mycli')
422
491
  .option('--verbose', z.boolean().default(false).describe('Enable verbose logging'))
423
492
  .option('--api-url [url]', z.string().default('https://api.example.com').describe('API base URL'))
424
493
  .use((options, { process }) => {
425
- expectTypeOf(options.verbose).toEqualTypeOf<boolean | undefined>()
426
- expectTypeOf(options.apiUrl).toEqualTypeOf<string | undefined>()
494
+ expectTypeOf(options.verbose).toEqualTypeOf<boolean>()
495
+ expectTypeOf(options.apiUrl).toEqualTypeOf<string>()
427
496
  expectTypeOf(process.stdin).toEqualTypeOf<string>()
428
497
  })
429
498
  .command('deploy <env>', 'Deploy to an environment')
430
499
  .option('--dry-run', 'Preview without deploying')
431
500
  .action((env, options, ctx) => {
432
501
  expectTypeOf(env).toEqualTypeOf<string>()
433
- expectTypeOf(options.verbose).toEqualTypeOf<boolean | undefined>()
434
- expectTypeOf(options.apiUrl).toEqualTypeOf<string | undefined>()
502
+ expectTypeOf(options.verbose).toEqualTypeOf<boolean>()
503
+ expectTypeOf(options.apiUrl).toEqualTypeOf<string>()
435
504
  expectTypeOf(options.dryRun).toEqualTypeOf<boolean | undefined>()
436
505
  expectTypeOf(ctx).toEqualTypeOf<GokeExecutionContext>()
437
506
  })
package/src/goke.ts CHANGED
@@ -332,20 +332,61 @@ type IsOptionalOption<S extends string> =
332
332
  S extends `${string}<${string}>` ? false :
333
333
  true
334
334
 
335
+ /**
336
+ * Infer the input type from a StandardTypedV1-compatible schema.
337
+ *
338
+ * For Zod, this is the type accepted by `.parse()` before any transforms or
339
+ * defaults are applied (e.g. `z.number().default(30)` has input `number | undefined`).
340
+ */
341
+ type InferSchemaInput<S> =
342
+ S extends { readonly "~standard": { readonly types?: { readonly input: infer I } } } ? I : unknown
343
+
335
344
  /**
336
345
  * Infer the output type from a StandardTypedV1-compatible schema.
346
+ *
347
+ * For Zod, this is the type produced by `.parse()` after transforms/defaults
348
+ * run (e.g. `z.number().default(30)` has output `number`).
337
349
  */
338
350
  type InferSchemaOutput<S> =
339
351
  S extends { readonly "~standard": { readonly types?: { readonly output: infer O } } } ? O : unknown
340
352
 
353
+ /**
354
+ * Detects whether a Standard Schema has a "default" behavior: its input allows
355
+ * `undefined` but its output does not. This matches `z.number().default(30)`
356
+ * and similar `.default(...)` wrappers in other libraries: the schema fills
357
+ * in a value whenever the caller omits it, so at runtime the property is
358
+ * always populated and goke can mark it as required in the options type even
359
+ * when the option is declared with `[value]` square brackets.
360
+ *
361
+ * The `unknown extends Input` guard excludes the `wrapJsonSchema` path, where
362
+ * input defaults to `unknown` because the hand-written schema has no way to
363
+ * express a separate input type. For those schemas we fall back to the raw
364
+ * bracket-based optionality, which keeps existing behavior for consumers
365
+ * that use `wrapJsonSchema<T>()` for truly optional options.
366
+ */
367
+ type HasSchemaDefault<S> =
368
+ unknown extends InferSchemaInput<S>
369
+ ? false
370
+ : undefined extends InferSchemaInput<S>
371
+ ? undefined extends InferSchemaOutput<S>
372
+ ? false
373
+ : true
374
+ : false
375
+
341
376
  /**
342
377
  * Build the option type entry for a single .option() call.
343
- * Required options (<...>) produce a required key.
344
- * Optional options ([...]) and boolean flags produce an optional key.
378
+ *
379
+ * Required options (`<...>`) produce a required key.
380
+ * Optional options (`[...]`) produce an optional key, EXCEPT when the schema
381
+ * has an effective default (see `HasSchemaDefault`) — in that case goke's
382
+ * runtime always surfaces the default value, so the property is typed as
383
+ * required with the post-coercion output type.
345
384
  */
346
385
  type OptionEntry<RawName extends string, Schema> =
347
386
  IsOptionalOption<RawName> extends true
348
- ? { [K in ExtractOptionName<RawName>]?: InferSchemaOutput<Schema> }
387
+ ? HasSchemaDefault<Schema> extends true
388
+ ? { [K in ExtractOptionName<RawName>]: InferSchemaOutput<Schema> }
389
+ : { [K in ExtractOptionName<RawName>]?: InferSchemaOutput<Schema> }
349
390
  : { [K in ExtractOptionName<RawName>]: InferSchemaOutput<Schema> }
350
391
 
351
392
  /**
@@ -959,6 +1000,45 @@ interface GokeExecutionContext {
959
1000
  process: GokeProcess
960
1001
  }
961
1002
 
1003
+ /**
1004
+ * Per-request overrides accepted by `Goke#createExecutionContext()`.
1005
+ *
1006
+ * Any field left `undefined` falls back to the `Goke` instance's
1007
+ * defaults (set via `GokeOptions`), which themselves fall back to the
1008
+ * real Node.js `process.*`. Use this to construct an execution context
1009
+ * with tenant-specific values — e.g. a per-user `cwd`/`env`/`fs` pair
1010
+ * for a remote MCP server, or capture streams for stdout/stderr.
1011
+ *
1012
+ * Passing a custom `exit` replaces the default behavior of calling
1013
+ * `this.exit(code)`. The returned `process.exit` still throws
1014
+ * `GokeProcessExit` after the user-provided `exit` returns, so callers
1015
+ * can catch the exit without the outer code needing to know about it.
1016
+ */
1017
+ interface GokeExecutionContextOverride {
1018
+ /** Override the argv array exposed as `process.argv`. Defaults to the cli's raw parsed argv. */
1019
+ argv?: string[]
1020
+ /** Override the working directory exposed as `process.cwd`. */
1021
+ cwd?: string
1022
+ /** Override the environment exposed as `process.env`. */
1023
+ env?: Record<string, string | undefined>
1024
+ /** Override the filesystem exposed as `ctx.fs`. */
1025
+ fs?: GokeFs
1026
+ /** Override the stdin content exposed as `process.stdin`. */
1027
+ stdin?: string
1028
+ /** Override the stdout stream used by `ctx.console.log` and exposed as `process.stdout`. */
1029
+ stdout?: GokeOutputStream
1030
+ /** Override the stderr stream used by `ctx.console.error` and exposed as `process.stderr`. */
1031
+ stderr?: GokeOutputStream
1032
+ /**
1033
+ * Override the exit function called by `process.exit(code)`.
1034
+ *
1035
+ * The returned context still throws `GokeProcessExit` after this
1036
+ * callback returns, so callers that want to capture the exit
1037
+ * without killing the host process can pass `() => {}`.
1038
+ */
1039
+ exit?: (code: number) => void
1040
+ }
1041
+
962
1042
  class GokeProcessExit extends Error {
963
1043
  code: number
964
1044
 
@@ -1152,19 +1232,63 @@ class Goke<Opts = {}> extends EventEmitter {
1152
1232
  return cloned
1153
1233
  }
1154
1234
 
1155
- private createExecutionContext(argv = this.rawArgs): GokeExecutionContext {
1235
+ /**
1236
+ * Build a `GokeExecutionContext` using this cli's defaults, optionally
1237
+ * overridden per-request.
1238
+ *
1239
+ * `runMatchedCommand()` calls this internally with no arguments to
1240
+ * construct the context passed to command actions and middlewares.
1241
+ *
1242
+ * The method is also public so adapters (MCP, remote RPC, batch
1243
+ * runners, etc.) can build a context for a single invocation with
1244
+ * tenant-specific values — e.g. capture streams for stdout/stderr,
1245
+ * a per-user `cwd`/`env`/`fs`, or an `exit` that throws instead of
1246
+ * killing the host process. See {@link GokeExecutionContextOverride}.
1247
+ *
1248
+ * @example
1249
+ * ```ts
1250
+ * // Build an execution context that captures output into strings and
1251
+ * // treats `ctx.process.exit(code)` as a `GokeProcessExit` throw
1252
+ * // instead of terminating the host process.
1253
+ * const stdout = createTextCaptureStream()
1254
+ * const stderr = createTextCaptureStream()
1255
+ * const ctx = cli.createExecutionContext({
1256
+ * stdout,
1257
+ * stderr,
1258
+ * exit: () => {},
1259
+ * })
1260
+ * try {
1261
+ * await action(...args, options, ctx)
1262
+ * } catch (err) {
1263
+ * if (err instanceof GokeProcessExit) {
1264
+ * // handle exit code
1265
+ * } else {
1266
+ * throw err
1267
+ * }
1268
+ * }
1269
+ * ```
1270
+ */
1271
+ createExecutionContext(override?: GokeExecutionContextOverride): GokeExecutionContext {
1272
+ const stdout = override?.stdout ?? this.stdout
1273
+ const stderr = override?.stderr ?? this.stderr
1274
+ // Reuse the cached console when streams aren't overridden; otherwise
1275
+ // build a new one so ctx.console.log writes to the overridden streams.
1276
+ const contextConsole = (override?.stdout !== undefined || override?.stderr !== undefined)
1277
+ ? createConsole(stdout, stderr)
1278
+ : this.console
1279
+ const exitFn = override?.exit ?? this.exit
1156
1280
  return {
1157
- console: this.console,
1158
- fs: this.fs,
1281
+ console: contextConsole,
1282
+ fs: override?.fs ?? this.fs,
1159
1283
  process: {
1160
- argv,
1161
- cwd: this.cwd ?? process.cwd(),
1162
- env: this.env ?? process.env,
1163
- stdin: this.stdin ?? '',
1164
- stdout: this.stdout,
1165
- stderr: this.stderr,
1166
- exit: (code: number) => {
1167
- this.exit(code)
1284
+ argv: override?.argv ?? this.rawArgs,
1285
+ cwd: override?.cwd ?? this.cwd ?? process.cwd(),
1286
+ env: override?.env ?? this.env ?? process.env,
1287
+ stdin: override?.stdin ?? this.stdin ?? '',
1288
+ stdout,
1289
+ stderr,
1290
+ exit: (code) => {
1291
+ exitFn(code)
1168
1292
  throw new GokeProcessExit(code)
1169
1293
  },
1170
1294
  },
@@ -1619,8 +1743,13 @@ class Goke<Opts = {}> extends EventEmitter {
1619
1743
  // For optional options ([...]) we want a single, uniform shape: `string`
1620
1744
  // with `''` meaning "flag present but no value" — callers get clean
1621
1745
  // `string | undefined` types instead of `string | boolean | undefined`.
1746
+ // The `optionsWithDefault` set tracks options whose schema produced a
1747
+ // non-undefined default — when the user passes such an option bare, we
1748
+ // keep the preset default instead of overwriting it with `undefined`,
1749
+ // which matches what the new `HasSchemaDefault` type inference promises.
1622
1750
  const requiredValueOptions = new Set<string>()
1623
1751
  const optionalValueOptions = new Set<string>()
1752
+ const optionsWithDefault = new Set<string>()
1624
1753
  for (const cliOption of cliOptions) {
1625
1754
  if (cliOption.required === true) {
1626
1755
  for (const name of cliOption.names) {
@@ -1631,6 +1760,11 @@ class Goke<Opts = {}> extends EventEmitter {
1631
1760
  optionalValueOptions.add(name)
1632
1761
  }
1633
1762
  }
1763
+ if (cliOption.default !== undefined) {
1764
+ for (const name of cliOption.names) {
1765
+ optionsWithDefault.add(name)
1766
+ }
1767
+ }
1634
1768
  }
1635
1769
 
1636
1770
  // Set option values (support dot-nested property name)
@@ -1644,14 +1778,22 @@ class Goke<Opts = {}> extends EventEmitter {
1644
1778
  // When value is boolean `true` and the option takes a value, it's mri's sentinel
1645
1779
  // for "flag present, no value given":
1646
1780
  // - Required options (<...>): preserve `true` so checkOptionValue() throws
1647
- // - Optional options ([...]) with schema: replace with `undefined` so
1648
- // any `.default(...)` on the schema kicks in (e.g. z.number().default(30)
1649
- // should produce 30, not try to coerce the `''` empty-string sentinel).
1781
+ // - Optional options ([...]) with schema AND a default: skip this
1782
+ // key entirely so the preset default (written into `options` at
1783
+ // the top of this function) survives. This keeps the type-level
1784
+ // `HasSchemaDefault` promise honest at runtime.
1785
+ // - Optional options ([...]) with schema and NO default: replace
1786
+ // `true` with `undefined` so the caller sees "flag present, no value"
1787
+ // as `undefined`.
1650
1788
  const schemaInfo = schemaMap.get(key)
1651
1789
  if (schemaInfo && value !== undefined) {
1652
1790
  if (value === true && requiredValueOptions.has(key)) {
1653
1791
  // Keep sentinel for checkOptionValue() to detect
1654
1792
  } else if (value === true && optionalValueOptions.has(key)) {
1793
+ if (optionsWithDefault.has(key)) {
1794
+ // Preserve the preset default — don't overwrite with undefined.
1795
+ continue
1796
+ }
1655
1797
  value = undefined
1656
1798
  } else {
1657
1799
  value = coerceBySchema(value, schemaInfo.jsonSchema, schemaInfo.optionName)
@@ -1769,6 +1911,6 @@ class Goke<Opts = {}> extends EventEmitter {
1769
1911
 
1770
1912
  // ─── Exports ───
1771
1913
 
1772
- export type { GokeOutputStream, GokeConsole, GokeOptions, GokeProcess, GokeExecutionContext, GokeFs }
1914
+ export type { GokeOutputStream, GokeConsole, GokeOptions, GokeProcess, GokeExecutionContext, GokeExecutionContextOverride, GokeFs }
1773
1915
  export { createConsole, Command, GokeProcessExit, openInBrowser }
1774
1916
  export default Goke
package/src/index.ts CHANGED
@@ -11,6 +11,6 @@ const goke = (name = '', options?: GokeOptions) => new Goke(name, options)
11
11
  export default goke
12
12
  export { goke, Goke, Command }
13
13
  export { createConsole, GokeProcessExit, openInBrowser } from "./goke.js"
14
- export type { GokeOutputStream, GokeConsole, GokeExecutionContext, GokeFs, GokeOptions, GokeProcess } from "./goke.js"
14
+ export type { GokeOutputStream, GokeConsole, GokeExecutionContext, GokeExecutionContextOverride, GokeFs, GokeOptions, GokeProcess } from "./goke.js"
15
15
  export type { StandardTypedV1, StandardJSONSchemaV1, JsonSchema } from "./coerce.js"
16
16
  export { GokeError, coerceBySchema, extractJsonSchema, wrapJsonSchema, isStandardSchema, extractSchemaMetadata } from "./coerce.js"