goke 6.1.2 → 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.
@@ -16,6 +16,119 @@ function createTestOutputStream() {
16
16
  write(data) { lines.push(data); },
17
17
  };
18
18
  }
19
+ /**
20
+ * Helper: creates a goke instance with exit overridden to a no-op.
21
+ * This prevents process.exit(1) from killing the test runner while
22
+ * still allowing the original error to propagate (the framework
23
+ * re-throws after calling exit when exit doesn't halt execution).
24
+ *
25
+ * Tests can still use .toThrow() to assert CLI errors normally.
26
+ */
27
+ function gokeTestable(name = '', options) {
28
+ return goke(name, {
29
+ ...options,
30
+ exit: () => { },
31
+ });
32
+ }
33
+ /**
34
+ * Strip stack trace lines for stable snapshots.
35
+ * Keeps the error message and help hint, removes all " at ..." lines
36
+ * and the blank line before them, since those contain machine-specific paths.
37
+ */
38
+ function stripStackTrace(text) {
39
+ return text
40
+ .split('\n')
41
+ .filter(line => !line.match(/^\s+at /))
42
+ .join('\n')
43
+ .replace(/\n{2,}/g, '\n')
44
+ .trim();
45
+ }
46
+ describe('error formatting', () => {
47
+ test('unknown option prints formatted error to stderr', () => {
48
+ const stderr = createTestOutputStream();
49
+ const cli = goke('mycli', { stderr, exit: () => { } });
50
+ cli
51
+ .command('build', 'Build your app')
52
+ .option('--port <port>', 'Port')
53
+ .action(() => { });
54
+ try {
55
+ cli.parse('node bin build --unknown'.split(' '));
56
+ }
57
+ catch { }
58
+ expect(stripStackTrace(stderr.text)).toMatchInlineSnapshot(`"error: Unknown option \`--unknown\`"`);
59
+ });
60
+ test('missing required option value prints formatted error to stderr', () => {
61
+ const stderr = createTestOutputStream();
62
+ const cli = goke('mycli', { stderr, exit: () => { } });
63
+ cli
64
+ .command('serve', 'Start server')
65
+ .option('--port <port>', 'Port')
66
+ .action(() => { });
67
+ try {
68
+ cli.parse('node bin serve --port'.split(' '));
69
+ }
70
+ catch { }
71
+ expect(stripStackTrace(stderr.text)).toMatchInlineSnapshot(`"error: option \`--port <port>\` value is missing"`);
72
+ });
73
+ test('schema coercion error prints formatted error to stderr', () => {
74
+ const stderr = createTestOutputStream();
75
+ const cli = goke('mycli', { stderr, exit: () => { } });
76
+ cli.option('--port <port>', z.number().describe('Port'));
77
+ try {
78
+ cli.parse('node bin --port abc'.split(' '));
79
+ }
80
+ catch { }
81
+ expect(stripStackTrace(stderr.text)).toMatchInlineSnapshot(`"error: Invalid value for --port: expected number, got "abc""`);
82
+ });
83
+ test('error includes help hint when help is enabled', () => {
84
+ const stderr = createTestOutputStream();
85
+ const cli = goke('mycli', { stderr, exit: () => { } });
86
+ cli.help();
87
+ cli
88
+ .command('serve', 'Start server')
89
+ .option('--port <port>', 'Port')
90
+ .action(() => { });
91
+ try {
92
+ cli.parse('node bin serve --port'.split(' '));
93
+ }
94
+ catch { }
95
+ expect(stripStackTrace(stderr.text)).toMatchInlineSnapshot(`
96
+ "error: option \`--port <port>\` value is missing
97
+ Run "mycli serve --help" for usage information."
98
+ `);
99
+ });
100
+ test('async action error prints formatted error to stderr', async () => {
101
+ const stderr = createTestOutputStream();
102
+ let exitCode;
103
+ const cli = goke('mycli', { stderr, exit: (code) => { exitCode = code; } });
104
+ cli
105
+ .command('deploy', 'Deploy app')
106
+ .action(async () => {
107
+ throw new Error('connection refused');
108
+ });
109
+ cli.parse('node bin deploy'.split(' '));
110
+ // Wait for the async rejection to be handled
111
+ await new Promise(resolve => setTimeout(resolve, 10));
112
+ expect(exitCode).toBe(1);
113
+ expect(stripStackTrace(stderr.text)).toMatchInlineSnapshot(`"error: connection refused"`);
114
+ });
115
+ test('error output includes stack trace', () => {
116
+ const stderr = createTestOutputStream();
117
+ const cli = goke('mycli', { stderr, exit: () => { } });
118
+ cli
119
+ .command('build', 'Build app')
120
+ .action(() => { });
121
+ try {
122
+ cli.parse('node bin build --unknown'.split(' '));
123
+ }
124
+ catch { }
125
+ // Verify that stderr contains "error:" prefix and a stack trace with "at" lines
126
+ const text = stderr.text;
127
+ expect(text).toContain('error:');
128
+ expect(text).toContain('Unknown option `--unknown`');
129
+ expect(text).toMatch(/at /);
130
+ });
131
+ });
19
132
  test('double dashes', () => {
20
133
  const cli = goke();
21
134
  const { args, options } = cli.parse([
@@ -73,7 +186,7 @@ describe('schema-based options', () => {
73
186
  expect(options.items).toEqual([1, 2, 3]);
74
187
  });
75
188
  test('schema throws on invalid number', () => {
76
- const cli = goke();
189
+ const cli = gokeTestable();
77
190
  cli.option('--port <port>', z.number().describe('Port number'));
78
191
  expect(() => cli.parse('node bin --port abc'.split(' ')))
79
192
  .toThrow('expected number, got "abc"');
@@ -253,7 +366,7 @@ describe('typical CLI usage examples', () => {
253
366
  });
254
367
  describe('regression: oracle-found issues', () => {
255
368
  test('required option with schema still throws when value missing', () => {
256
- const cli = goke();
369
+ const cli = gokeTestable();
257
370
  let actionCalled = false;
258
371
  cli
259
372
  .command('serve', 'Start server')
@@ -266,13 +379,13 @@ describe('regression: oracle-found issues', () => {
266
379
  expect(actionCalled).toBe(false);
267
380
  });
268
381
  test('repeated flags with non-array schema throws', () => {
269
- const cli = goke();
382
+ const cli = gokeTestable();
270
383
  cli.option('--tag <tag>', z.string().describe('Tags'));
271
384
  expect(() => cli.parse('node bin --tag foo --tag bar'.split(' ')))
272
385
  .toThrow('does not accept multiple values');
273
386
  });
274
387
  test('repeated flags with number schema throws', () => {
275
- const cli = goke();
388
+ const cli = gokeTestable();
276
389
  cli.option('--id <id>', z.number().describe('ID'));
277
390
  expect(() => cli.parse('node bin --id 1 --id 2'.split(' ')))
278
391
  .toThrow('does not accept multiple values');
@@ -398,7 +511,7 @@ describe('edge cases: boolean flags + schema', () => {
398
511
  expect(opts2.flag).toBe(false);
399
512
  });
400
513
  test('invalid boolean string with boolean schema throws', () => {
401
- const cli = goke();
514
+ const cli = gokeTestable();
402
515
  cli.option('--flag <flag>', z.boolean().describe('A flag'));
403
516
  expect(() => cli.parse('node bin --flag yes'.split(' ')))
404
517
  .toThrow('expected true or false');
@@ -435,7 +548,7 @@ describe('edge cases: empty string values', () => {
435
548
  expect(options.name).toBe('');
436
549
  });
437
550
  test('empty string with number schema throws', () => {
438
- const cli = goke();
551
+ const cli = gokeTestable();
439
552
  cli.option('--port <port>', z.number().describe('Port'));
440
553
  expect(() => cli.parse(['node', 'bin', '--port', '']))
441
554
  .toThrow('expected number, got empty string');
@@ -482,14 +595,14 @@ describe('edge cases: short alias + schema', () => {
482
595
  expect(options.p).toBe(8080);
483
596
  });
484
597
  test('short alias repeated with non-array schema throws', () => {
485
- const cli = goke();
598
+ const cli = gokeTestable();
486
599
  cli.option('-p, --port <port>', z.number().describe('Port'));
487
600
  expect(() => cli.parse('node bin -p 3000 -p 4000'.split(' ')))
488
601
  .toThrow('does not accept multiple values');
489
602
  });
490
603
  });
491
604
  test('throw on unknown options', () => {
492
- const cli = goke();
605
+ const cli = gokeTestable();
493
606
  cli
494
607
  .command('build [entry]', 'Build your app')
495
608
  .option('--foo-bar', 'foo bar')
@@ -623,23 +736,32 @@ describe('space-separated subcommands', () => {
623
736
  expect(stripAnsi(output)).toMatchInlineSnapshot(`
624
737
  "mycli
625
738
 
739
+
626
740
  Usage:
627
741
  $ mycli <command> [options]
628
742
 
743
+
629
744
  Commands:
630
745
  mcp login <url> Login to MCP server
631
746
 
747
+
632
748
  mcp logout Logout from MCP server
633
749
 
750
+
634
751
  mcp status Show connection status
635
752
 
753
+
636
754
  git remote add <name> <url> Add a git remote
637
755
 
756
+
638
757
  git remote remove <name> Remove a git remote
639
758
 
759
+
640
760
  build Build the project
761
+
641
762
  --watch Watch mode
642
763
 
764
+
643
765
  Options:
644
766
  -h, --help Display this message
645
767
  "
@@ -679,6 +801,34 @@ describe('space-separated subcommands', () => {
679
801
  // Should not show filtered help since "foo" is not a prefix of any command
680
802
  expect(stripAnsi(output)).not.toContain('Available "foo" commands');
681
803
  });
804
+ test('unknown command without prefix outputs root help', () => {
805
+ let output = '';
806
+ const cli = goke('mycli', {
807
+ stdout: { write(data) { output += data; } },
808
+ });
809
+ cli.command('mcp login', 'Login to MCP');
810
+ cli.command('build', 'Build project');
811
+ cli.help();
812
+ // User types an unknown command that does not match any prefix group
813
+ cli.parse(['node', 'bin', 'something'], { run: true });
814
+ expect(cli.matchedCommand).toBeUndefined();
815
+ expect(stripAnsi(output)).toContain('Usage:');
816
+ expect(stripAnsi(output)).toContain('$ mycli <command> [options]');
817
+ expect(stripAnsi(output)).toContain('mcp login');
818
+ expect(stripAnsi(output)).toContain('build');
819
+ });
820
+ test('no args without default command outputs root help', () => {
821
+ const stdout = createTestOutputStream();
822
+ const cli = goke('mycli', { stdout });
823
+ cli.command('mcp login', 'Login to MCP');
824
+ cli.command('build', 'Build project');
825
+ cli.help();
826
+ cli.parse(['node', 'bin'], { run: true });
827
+ expect(stdout.text).toContain('Usage:');
828
+ expect(stdout.text).toContain('$ mycli <command> [options]');
829
+ expect(stdout.text).toContain('mcp login');
830
+ expect(stdout.text).toContain('build');
831
+ });
682
832
  test('prefix --help shows filtered help for matching command group', () => {
683
833
  let output = '';
684
834
  const cli = goke('mycli', {
@@ -809,6 +959,136 @@ describe('many commands with root command (empty string)', () => {
809
959
  expect(stdout.text).toContain('Initialize a new project');
810
960
  expect(stdout.text).toContain('Stream logs for a deployment');
811
961
  });
962
+ test('root help with many commands renders examples section after options', () => {
963
+ const stdout = createTestOutputStream();
964
+ const cli = goke('deploy', { stdout });
965
+ cli
966
+ .command('', 'Deploy the current project')
967
+ .option('--env <env>', 'Target environment')
968
+ .option('--dry-run', 'Preview without deploying')
969
+ .example('# Deploy to staging first')
970
+ .example('deploy --env staging --dry-run');
971
+ cli.command('init', 'Initialize a new project');
972
+ cli.command('login', 'Authenticate with the server');
973
+ cli.command('logout', 'Clear saved credentials');
974
+ cli.command('status', 'Show deployment status');
975
+ cli.command('logs <deploymentId>', 'Stream logs for a deployment');
976
+ cli.help();
977
+ cli.parse(['node', 'bin', '--help'], { run: false });
978
+ expect(stdout.text).toMatchInlineSnapshot(`
979
+ "deploy
980
+
981
+
982
+ Usage:
983
+ $ deploy [options]
984
+
985
+
986
+ Commands:
987
+ deploy Deploy the current project
988
+
989
+
990
+ init Initialize a new project
991
+
992
+
993
+ login Authenticate with the server
994
+
995
+
996
+ logout Clear saved credentials
997
+
998
+
999
+ status Show deployment status
1000
+
1001
+
1002
+ logs <deploymentId> Stream logs for a deployment
1003
+
1004
+
1005
+ Options:
1006
+ --env <env> Target environment
1007
+ --dry-run Preview without deploying
1008
+ -h, --help Display this message
1009
+
1010
+
1011
+ Examples:
1012
+ # Deploy to staging first
1013
+ deploy --env staging --dry-run
1014
+ "
1015
+ `);
1016
+ });
1017
+ test('subcommand help renders command examples at the end', () => {
1018
+ const stdout = createTestOutputStream();
1019
+ const cli = goke('deploy', { stdout, columns: 80 });
1020
+ cli.command('', 'Deploy the current project');
1021
+ cli.command('init', 'Initialize a new project');
1022
+ cli.command('login', 'Authenticate with the server');
1023
+ cli
1024
+ .command('logs <deploymentId>', 'Stream logs for a deployment')
1025
+ .option('--follow', 'Follow log output')
1026
+ .option('--lines <n>', z.number().default(100).describe('Number of lines'))
1027
+ .example('# Stream last 200 lines for a deployment')
1028
+ .example('deploy logs dep_123 --lines 200')
1029
+ .example('# Keep following new log lines')
1030
+ .example('deploy logs dep_123 --follow');
1031
+ cli.help();
1032
+ cli.parse(['node', 'bin', 'logs', '--help'], { run: false });
1033
+ expect(stdout.text).toMatchInlineSnapshot(`
1034
+ "deploy
1035
+
1036
+
1037
+ Usage:
1038
+ $ deploy logs <deploymentId>
1039
+
1040
+
1041
+ Options:
1042
+ --follow Follow log output
1043
+ --lines <n> Number of lines (default: 100)
1044
+ -h, --help Display this message
1045
+
1046
+
1047
+ Description:
1048
+ Stream logs for a deployment
1049
+
1050
+
1051
+ Examples:
1052
+ # Stream last 200 lines for a deployment
1053
+ deploy logs dep_123 --lines 200
1054
+ # Keep following new log lines
1055
+ deploy logs dep_123 --follow
1056
+ "
1057
+ `);
1058
+ });
1059
+ test('root help labels default command with cli name and does not duplicate global options', () => {
1060
+ const stdout = createTestOutputStream();
1061
+ const cli = goke('deploy', { stdout });
1062
+ cli.option('--env <env>', 'Target environment');
1063
+ cli
1064
+ .command('', 'Deploy the current project')
1065
+ .option('--env <env>', 'Target environment')
1066
+ .option('--dry-run', 'Preview without deploying');
1067
+ cli.command('status', 'Show deployment status');
1068
+ cli.help();
1069
+ cli.parse(['node', 'bin', '--help'], { run: false });
1070
+ expect(stdout.text).toMatchInlineSnapshot(`
1071
+ "deploy
1072
+
1073
+
1074
+ Usage:
1075
+ $ deploy [options]
1076
+
1077
+
1078
+ Commands:
1079
+ deploy Deploy the current project
1080
+
1081
+
1082
+ status Show deployment status
1083
+
1084
+
1085
+ Options:
1086
+ --env <env> Target environment
1087
+ --dry-run Preview without deploying
1088
+ -h, --help Display this message
1089
+ "
1090
+ `);
1091
+ });
812
1092
  test('root help wraps long command descriptions snapshot', () => {
813
1093
  const stdout = createTestOutputStream();
814
1094
  const cli = goke('mycli', { stdout, columns: 56 });
@@ -821,26 +1101,32 @@ describe('many commands with root command (empty string)', () => {
821
1101
  expect(stdout.text).toMatchInlineSnapshot(`
822
1102
  "mycli
823
1103
 
1104
+
824
1105
  Usage:
825
1106
  $ mycli <command> [options]
826
1107
 
1108
+
827
1109
  Commands:
828
1110
  notion-search Perform a semantic search over
829
1111
  Notion workspace content and
830
1112
  connected integrations with
831
1113
  advanced filtering options, date
832
1114
  filters, and creator filters.
1115
+
833
1116
  --query <query> Natural language query text to
834
1117
  search for
835
1118
  --limit [limit] Maximum number of results to return
836
1119
  (default: 10)
837
1120
 
1121
+
838
1122
  notion-fetch Retrieve a Notion page or database
839
1123
  by URL or ID and render the result
840
1124
  in enhanced markdown format for
841
1125
  terminal output.
1126
+
842
1127
  --id <id> Notion URL or UUID to fetch
843
1128
 
1129
+
844
1130
  Options:
845
1131
  -h, --help Display this message
846
1132
  "
@@ -858,20 +1144,28 @@ describe('many commands with root command (empty string)', () => {
858
1144
  expect(stdout.text).toMatchInlineSnapshot(`
859
1145
  "gtui
860
1146
 
1147
+
861
1148
  Usage:
862
1149
  $ gtui <command> [options]
863
1150
 
1151
+
864
1152
  Commands:
865
1153
  auth login Authenticate with Google (opens browser)
866
1154
 
1155
+
867
1156
  auth logout Remove stored credentials
1157
+
868
1158
  --force Skip confirmation
869
1159
 
1160
+
870
1161
  mail list List email threads
1162
+
871
1163
  --folder [folder] Folder to list
872
1164
 
1165
+
873
1166
  attachment get <messageId> <attachmentId> Download an attachment
874
1167
 
1168
+
875
1169
  Options:
876
1170
  -h, --help Display this message
877
1171
  "
@@ -903,14 +1197,18 @@ describe('many commands with root command (empty string)', () => {
903
1197
  expect(stdout.text).toMatchInlineSnapshot(`
904
1198
  "mycli
905
1199
 
1200
+
906
1201
  Usage:
907
1202
  $ mycli <command> [options]
908
1203
 
1204
+
909
1205
  Commands:
910
1206
  notion-search Perform a semantic search over Notion workspace content and connected integrations with advanced filtering options, date filters, and creator filters.
1207
+
911
1208
  --query <query> Natural language query text to search for
912
1209
  --limit [limit] Maximum number of results to return (default: 10)
913
1210
 
1211
+
914
1212
  Options:
915
1213
  -h, --help Display this message
916
1214
  "
@@ -1070,4 +1368,102 @@ describe('schema description and default extraction', () => {
1070
1368
  cli.parse(['node', 'bin', 'serve', '--help'], { run: false });
1071
1369
  expect(stdout.text).toContain('(default: 3000)');
1072
1370
  });
1371
+ test('deprecated options are hidden from help output', () => {
1372
+ const stdout = createTestOutputStream();
1373
+ const cli = goke('mycli', { stdout });
1374
+ cli
1375
+ .command('serve', 'Start server')
1376
+ .option('--old <value>', z.string().meta({ deprecated: true, description: 'Old option' }))
1377
+ .option('--new <value>', z.string().describe('Normal option'));
1378
+ cli.help();
1379
+ cli.parse(['node', 'bin', 'serve', '--help'], { run: false });
1380
+ // Normal option should be visible
1381
+ expect(stdout.text).toContain('--new');
1382
+ expect(stdout.text).toContain('Normal option');
1383
+ // Deprecated option should be hidden
1384
+ expect(stdout.text).not.toContain('--old');
1385
+ expect(stdout.text).not.toContain('Old option');
1386
+ });
1387
+ test('deprecated option still works for parsing (just hidden from help)', () => {
1388
+ const cli = gokeTestable('mycli');
1389
+ let result = {};
1390
+ cli
1391
+ .command('serve', 'Start server')
1392
+ .option('--old <value>', z.string().meta({ deprecated: true, description: 'Old option' }))
1393
+ .action((options) => { result = options; });
1394
+ cli.parse(['node', 'bin', 'serve', '--old', 'legacy-value']);
1395
+ // Deprecated option should still be parsed and usable
1396
+ expect(result.old).toBe('legacy-value');
1397
+ });
1398
+ test('deprecated options hidden from global help', () => {
1399
+ const stdout = createTestOutputStream();
1400
+ const cli = goke('mycli', { stdout });
1401
+ cli.option('--legacy [value]', z.string().meta({ deprecated: true, description: 'Deprecated global' }));
1402
+ cli.option('--current [value]', z.string().describe('Current option'));
1403
+ cli.help();
1404
+ cli.parse(['node', 'bin', '--help'], { run: false });
1405
+ expect(stdout.text).toContain('--current');
1406
+ expect(stdout.text).toContain('Current option');
1407
+ expect(stdout.text).not.toContain('--legacy');
1408
+ expect(stdout.text).not.toContain('Deprecated global');
1409
+ });
1410
+ });
1411
+ describe('helpText()', () => {
1412
+ test('returns help string without printing', () => {
1413
+ const stdout = createTestOutputStream();
1414
+ const cli = goke('mycli', { stdout });
1415
+ cli.command('serve', 'Start server');
1416
+ cli.option('--port <port>', 'Port number');
1417
+ cli.help();
1418
+ // parse a known command so help is not auto-triggered
1419
+ cli.parse(['node', 'bin', 'serve'], { run: false });
1420
+ // reset stdout after parse
1421
+ stdout.lines.length = 0;
1422
+ const text = stripAnsi(cli.helpText());
1423
+ expect(text).toContain('mycli');
1424
+ expect(text).toContain('serve');
1425
+ expect(text).toContain('Start server');
1426
+ expect(text).toContain('--port');
1427
+ // helpText() does not print to stdout
1428
+ expect(stdout.text).toBe('');
1429
+ });
1430
+ test('returns same content as outputHelp', () => {
1431
+ const stdout = createTestOutputStream();
1432
+ const cli = goke('mycli', { stdout });
1433
+ cli.command('build', 'Build project');
1434
+ cli.option('--watch [watch]', 'Watch mode');
1435
+ cli.help();
1436
+ // parse a known command so help is not auto-triggered
1437
+ cli.parse(['node', 'bin', 'build'], { run: false });
1438
+ // reset stdout after parse
1439
+ stdout.lines.length = 0;
1440
+ const helpTextResult = stripAnsi(cli.helpText());
1441
+ cli.outputHelp();
1442
+ // outputHelp adds a trailing newline via console.log
1443
+ const outputHelpResult = stdout.text.replace(/\n$/, '');
1444
+ expect(helpTextResult).toBe(outputHelpResult);
1445
+ });
1446
+ test('returns subcommand help when command is matched', () => {
1447
+ const cli = goke('mycli');
1448
+ cli.command('deploy <env>', 'Deploy to environment')
1449
+ .option('--force', 'Force deploy');
1450
+ cli.help();
1451
+ cli.parse(['node', 'bin', 'deploy', '--help'], { run: false });
1452
+ const text = stripAnsi(cli.helpText());
1453
+ expect(text).toContain('deploy');
1454
+ expect(text).toContain('--force');
1455
+ expect(text).toContain('Force deploy');
1456
+ });
1457
+ test('works without calling parse', () => {
1458
+ const cli = goke('mycli');
1459
+ cli.command('test', 'Run tests');
1460
+ cli.option('--coverage', 'Enable coverage');
1461
+ cli.help();
1462
+ // helpText() works even without parse
1463
+ const text = stripAnsi(cli.helpText());
1464
+ expect(text).toContain('mycli');
1465
+ expect(text).toContain('test');
1466
+ expect(text).toContain('Run tests');
1467
+ expect(text).toContain('--coverage');
1468
+ });
1073
1469
  });
package/dist/coerce.d.ts CHANGED
@@ -28,6 +28,14 @@
28
28
  * Union types (e.g. ["number", "string"]):
29
29
  * Tries each type in order, returns first successful coercion.
30
30
  */
31
+ /**
32
+ * Custom error class for CLI usage errors (unknown options, missing values,
33
+ * invalid types, etc.). Used by both the coercion layer and the framework
34
+ * to distinguish user-facing errors from unexpected failures.
35
+ */
36
+ export declare class GokeError extends Error {
37
+ constructor(message: string);
38
+ }
31
39
  /** The Standard Typed interface. Base type extended by other specs. */
32
40
  export interface StandardTypedV1<Input = unknown, Output = Input> {
33
41
  readonly "~standard": StandardTypedV1.Props<Input, Output>;
@@ -70,23 +78,8 @@ export declare namespace StandardJSONSchemaV1 {
70
78
  /**
71
79
  * Wraps a plain JSON Schema object into a StandardJSONSchemaV1-compatible object.
72
80
  *
73
- * This is useful for dynamic use cases where you have a raw JSON Schema
74
- * (e.g. from an MCP tool's inputSchema) and need to pass it to Goke's
75
- * schema option which expects StandardJSONSchemaV1.
76
- *
77
- * @example
78
- * ```ts
79
- * import { wrapJsonSchema } from 'goke'
80
- *
81
- * // Wrap a plain JSON Schema for use with Goke options
82
- * const schema = wrapJsonSchema({ type: "number" })
83
- * cmd.option('--port <port>', 'Port', { schema })
84
- *
85
- * // Wrap MCP tool property schemas
86
- * for (const [name, propSchema] of Object.entries(tool.inputSchema.properties)) {
87
- * cmd.option(`--${name} <${name}>`, desc, { schema: wrapJsonSchema(propSchema) })
88
- * }
89
- * ```
81
+ * @internal This is an internal helper used by @goke/mcp to wrap MCP tool schemas.
82
+ * Users should pass Zod or other StandardSchema-compatible schemas to `.option()`.
90
83
  *
91
84
  * @param jsonSchema - A plain JSON Schema object (e.g. `{ type: "number" }`)
92
85
  * @returns A StandardJSONSchemaV1-compatible object that Goke can use for coercion
@@ -106,6 +99,8 @@ export interface JsonSchema {
106
99
  additionalProperties?: boolean | JsonSchema;
107
100
  default?: unknown;
108
101
  description?: string;
102
+ /** JSON Schema deprecated annotation (draft 2019-09+) */
103
+ deprecated?: boolean;
109
104
  }
110
105
  /**
111
106
  * Coerce a raw CLI value to the type declared in a JSON Schema.
@@ -128,11 +123,12 @@ export declare function extractJsonSchema(schema: unknown): Record<string, unkno
128
123
  */
129
124
  export declare function isStandardSchema(value: unknown): value is StandardJSONSchemaV1;
130
125
  /**
131
- * Extract description and default value from a StandardJSONSchemaV1-compatible schema.
132
- * Calls extractJsonSchema() internally and pulls `description` and `default` fields.
126
+ * Extract description, default value, and deprecated flag from a StandardJSONSchemaV1-compatible schema.
127
+ * Calls extractJsonSchema() internally and pulls `description`, `default`, and `deprecated` fields.
133
128
  */
134
129
  export declare function extractSchemaMetadata(schema: StandardJSONSchemaV1): {
135
130
  description?: string;
136
131
  default?: unknown;
132
+ deprecated?: boolean;
137
133
  };
138
134
  //# sourceMappingURL=coerce.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coerce.d.ts","sourceRoot":"","sources":["../src/coerce.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coerce.d.ts","sourceRoot":"","sources":["../src/coerce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM;CAS5B;AASD,uEAAuE;AACvE,MAAM,WAAW,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;IAC9D,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;CAC5D;AAED,MAAM,CAAC,OAAO,WAAW,eAAe,CAAC;IACvC,UAAiB,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;QACpD,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;KACnD;IAED,UAAiB,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;QACpD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB;IAED,KAAY,UAAU,CAAC,MAAM,SAAS,eAAe,IAAI,WAAW,CAClE,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAC7B,CAAC,OAAO,CAAC,CAAC;IAEX,KAAY,WAAW,CAAC,MAAM,SAAS,eAAe,IAAI,WAAW,CACnE,MAAM,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAC7B,CAAC,QAAQ,CAAC,CAAC;CACb;AAED,0CAA0C;AAC1C,MAAM,WAAW,oBAAoB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;IACnE,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;CACjE;AAED,MAAM,CAAC,OAAO,WAAW,oBAAoB,CAAC;IAC5C,UAAiB,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK,CACpD,SAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC;QAC5C,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC,SAAS,CAAC;KACrD;IAED,UAAiB,SAAS;QACxB,QAAQ,CAAC,KAAK,EAAE,CACd,OAAO,EAAE,oBAAoB,CAAC,OAAO,KAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7B,QAAQ,CAAC,MAAM,EAAE,CACf,OAAO,EAAE,oBAAoB,CAAC,OAAO,KAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC9B;IAED,KAAY,MAAM,GACd,eAAe,GACf,UAAU,GACV,aAAa,GACb,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IAElB,UAAiB,OAAO;QACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;KAC/D;IAED,UAAiB,KAAK,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK,CACpD,SAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC;KAAG;IAEjD,KAAY,UAAU,CAAC,MAAM,SAAS,eAAe,IACnD,eAAe,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAErC,KAAY,WAAW,CAAC,MAAM,SAAS,eAAe,IACpD,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;CACvC;AAID;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,CAWxF;AAID,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACvC,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,UAAU,CAAA;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,yDAAyD;IACzD,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,EAAE,EAClC,SAAS,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/C,UAAU,EAAE,MAAM,GACjB,OAAO,CA4JT;AAkID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAgBtF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,oBAAoB,CAI9E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CAcrI"}