argsbarg 5.0.1 → 5.0.2

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 (38) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/docs/distribution-homebrew.md +2 -0
  3. package/examples/full-example/scripts/formula-shared.ts +1 -0
  4. package/package.json +1 -1
  5. package/src/builtins/builtins.test.ts +23 -0
  6. package/src/builtins/config.test.ts +8 -0
  7. package/src/cli-tool/cli-smoke.test.ts +8 -0
  8. package/src/cli-tool/create.test.ts +13 -0
  9. package/src/cli-tool/full-example-capabilities.test.ts +8 -0
  10. package/src/cli-tool/main.ts +0 -0
  11. package/src/config/context.test.ts +8 -0
  12. package/src/config/file.test.ts +12 -0
  13. package/src/config/resolve.test.ts +18 -0
  14. package/src/config/validate.test.ts +11 -0
  15. package/src/config.integration.test.ts +5 -0
  16. package/src/configure/configure.test.ts +22 -0
  17. package/src/configure/index.ts +14 -0
  18. package/src/configure/prompt.ts +7 -0
  19. package/src/docs/api-guide.test.ts +10 -0
  20. package/src/docs/docs.test.ts +27 -0
  21. package/src/docs/mcp-resources.test.ts +10 -0
  22. package/src/formats.test.ts +9 -0
  23. package/src/headless.test.ts +10 -0
  24. package/src/hidden-mcpb.test.ts +22 -0
  25. package/src/install/binary-placement.test.ts +14 -0
  26. package/src/install/gh-release-update.test.ts +9 -0
  27. package/src/install/install-validate.test.ts +10 -0
  28. package/src/install/mcp-codex.test.ts +7 -0
  29. package/src/install/mcp-openclaw.test.ts +6 -0
  30. package/src/install/mcp-opencode.test.ts +10 -0
  31. package/src/install/status.test.ts +9 -0
  32. package/src/install/targets.test.ts +19 -0
  33. package/src/invoke.test.ts +14 -0
  34. package/src/mcp/claude.test.ts +10 -0
  35. package/src/mcp/env.test.ts +12 -0
  36. package/src/mcp/zip.test.ts +5 -0
  37. package/src/mcp.integration.test.ts +39 -0
  38. package/src/parse.test.ts +71 -0
package/src/parse.test.ts CHANGED
@@ -31,6 +31,7 @@ import {
31
31
  } from "./test-fixtures.ts";
32
32
  import { cliValidateProgram } from "./validate.ts";
33
33
 
34
+ /** Tests that bundled short presence flags. */
34
35
  test("bundled short presence flags", () => {
35
36
  const root = testProgram({
36
37
  key: "app",
@@ -64,6 +65,7 @@ test("bundled short presence flags", () => {
64
65
  expect(pr.opts.b).toBe("1");
65
66
  });
66
67
 
68
+ /** Tests that long option equals. */
67
69
  test("long option equals", () => {
68
70
  const root = testProgram({
69
71
  key: "app",
@@ -89,6 +91,7 @@ test("long option equals", () => {
89
91
  expect(pr.opts.name).toBe("pat");
90
92
  });
91
93
 
94
+ /** Tests that fallback missing or unknown root flags. */
92
95
  test("fallback missing or unknown root flags", () => {
93
96
  const root = testProgram({
94
97
  key: "app",
@@ -117,6 +120,7 @@ test("fallback missing or unknown root flags", () => {
117
120
  expect(pr.opts.name).toBe("bob");
118
121
  });
119
122
 
123
+ /** Tests that unknown command. */
120
124
  test("unknown command", () => {
121
125
  const root = testProgram({
122
126
  key: "app",
@@ -129,6 +133,7 @@ test("unknown command", () => {
129
133
  expect(pr.errorMsg).toContain("Unknown command");
130
134
  });
131
135
 
136
+ /** Tests that implicit help empty. */
132
137
  test("implicit help empty", () => {
133
138
  const root = testProgram({
134
139
  key: "app",
@@ -141,6 +146,7 @@ test("implicit help empty", () => {
141
146
  expect(pr.helpExplicit).toBe(false);
142
147
  });
143
148
 
149
+ /** Invalid number post validate. */
144
150
  test("invalid number post validate", () => {
145
151
  const root = testProgram({
146
152
  key: "app",
@@ -167,6 +173,7 @@ test("invalid number post validate", () => {
167
173
  expect(pr.errorMsg).toContain("Invalid number");
168
174
  });
169
175
 
176
+ /** Supports scientific notation in numbers. */
170
177
  test("supports scientific notation in numbers", () => {
171
178
  const root = testProgram({
172
179
  key: "app",
@@ -193,6 +200,7 @@ test("supports scientific notation in numbers", () => {
193
200
  expect(Number(pr.opts.n)).toBe(12300);
194
201
  });
195
202
 
203
+ /** Completion scripts contain app name. */
196
204
  test("completion scripts contain app name", () => {
197
205
  const root = testProgram({
198
206
  key: "myapp",
@@ -210,6 +218,7 @@ test("completion scripts contain app name", () => {
210
218
  expect(zsh).toContain("hello:Say hello.");
211
219
  });
212
220
 
221
+ /** Completion scripts do not emit invalid bash substitutions. */
213
222
  test("completion scripts do not emit invalid bash substitutions", () => {
214
223
  const root = testProgram({
215
224
  key: "app",
@@ -221,6 +230,7 @@ test("completion scripts do not emit invalid bash substitutions", () => {
221
230
  expect(bash).not.toContain("${${");
222
231
  });
223
232
 
233
+ /** Completion scripts escape shell-sensitive command text in zsh. */
224
234
  test("completion scripts escape shell-sensitive command text in zsh", () => {
225
235
  const root = testProgram({
226
236
  key: "app",
@@ -238,6 +248,7 @@ test("completion scripts escape shell-sensitive command text in zsh", () => {
238
248
  expect(zsh).toContain("quote'\\''cmd:Say '\\''hello'\\'' and keep going.");
239
249
  });
240
250
 
251
+ /** Completion scripts keep dotted app names in registration names. */
241
252
  test("completion scripts keep dotted app names in registration names", () => {
242
253
  const root = testProgram({
243
254
  key: "minimal.ts",
@@ -253,6 +264,7 @@ test("completion scripts keep dotted app names in registration names", () => {
253
264
  expect(zsh).toContain("compdef _minimal_ts minimal.ts");
254
265
  });
255
266
 
267
+ /** Tests that trailing options after bounded positionals. */
256
268
  test("trailing options after bounded positionals", () => {
257
269
  const root = testProgram({
258
270
  key: "app",
@@ -286,6 +298,7 @@ test("trailing options after bounded positionals", () => {
286
298
  expect(pr.opts.verbose).toBe("1");
287
299
  });
288
300
 
301
+ /** Tests that trailing options include parent-scoped flags. */
289
302
  test("trailing options include parent-scoped flags", () => {
290
303
  const root = testProgram({
291
304
  key: "app",
@@ -338,6 +351,7 @@ test("trailing options include parent-scoped flags", () => {
338
351
  expect(pr.opts.json).toBe("1");
339
352
  });
340
353
 
354
+ /** Varargs tail parses trailing options. */
341
355
  test("varargs tail parses trailing options", () => {
342
356
  const root = testProgram({
343
357
  key: "app",
@@ -373,6 +387,7 @@ test("varargs tail parses trailing options", () => {
373
387
  expect(pr.opts.json).toBe("1");
374
388
  });
375
389
 
390
+ /** Stops parsing options at --. */
376
391
  test("stops parsing options at --", () => {
377
392
  const root = testProgram({
378
393
  key: "app",
@@ -411,6 +426,7 @@ test("stops parsing options at --", () => {
411
426
  expect(pr.args).toEqual(["--name", "bob", "-x"]);
412
427
  });
413
428
 
429
+ /** Missing required option returns error. */
414
430
  test("missing required option returns error", () => {
415
431
  const root = testProgram({
416
432
  key: "app",
@@ -437,6 +453,7 @@ test("missing required option returns error", () => {
437
453
  expect(pr.errorMsg).toContain("Missing required option: --req");
438
454
  });
439
455
 
456
+ /** Provided required option parses ok. */
440
457
  test("provided required option parses ok", () => {
441
458
  const root = testProgram({
442
459
  key: "app",
@@ -463,6 +480,7 @@ test("provided required option parses ok", () => {
463
480
  expect(pr.opts.req).toBe("val");
464
481
  });
465
482
 
483
+ /** Tests that presence option cannot be required. */
466
484
  test("presence option cannot be required", () => {
467
485
  const root = testProgram({
468
486
  key: "app",
@@ -486,6 +504,7 @@ test("presence option cannot be required", () => {
486
504
  expect(() => cliValidateProgram(root)).toThrow(/Presence option cannot be required/);
487
505
  });
488
506
 
507
+ /** Leaf completion help prints correctly. */
489
508
  test("leaf completion help prints correctly", async () => {
490
509
  // Test the fix where `completion zsh -h` on a leaf root was incorrectly ignored.
491
510
  // We run this as a subprocess so we don't accidentally exit the test runner.
@@ -499,6 +518,7 @@ test("leaf completion help prints correctly", async () => {
499
518
  expect(stderr.toString()).toBe("");
500
519
  });
501
520
 
521
+ /** Docs schema exports JSON for nested CLIs. */
502
522
  test("docs schema exports JSON for nested CLIs", async () => {
503
523
  const { stdout, stderr, exitCode } = await $`bun run examples/nested.ts docs schema`
504
524
  .nothrow()
@@ -517,6 +537,7 @@ test("docs schema exports JSON for nested CLIs", async () => {
517
537
  expect(lookup.positionals[0].name).toBe("path");
518
538
  });
519
539
 
540
+ /** Docs schema exports JSON for leaf roots. */
520
541
  test("docs schema exports JSON for leaf roots", async () => {
521
542
  const { stdout, exitCode } = await $`bun run examples/minimal.ts docs schema`.nothrow().quiet();
522
543
  expect(exitCode).toBe(0);
@@ -532,12 +553,14 @@ test("docs schema exports JSON for leaf roots", async () => {
532
553
  ]);
533
554
  });
534
555
 
556
+ /** Tests that version builtin prints program version. */
535
557
  test("version builtin prints program version", async () => {
536
558
  const { stdout, exitCode } = await $`bun run examples/nested.ts version`.nothrow().quiet();
537
559
  expect(exitCode).toBe(0);
538
560
  expect(stdout.toString().trim()).toMatch(/^\d+\.\d+\.\d+/);
539
561
  });
540
562
 
563
+ /** Leaf root help omits hidden completion built-in. */
541
564
  test("leaf root help omits hidden completion built-in", async () => {
542
565
  const { stdout, exitCode } = await $`bun run examples/minimal.ts -h`.nothrow().quiet();
543
566
  expect(exitCode).toBe(0);
@@ -545,6 +568,7 @@ test("leaf root help omits hidden completion built-in", async () => {
545
568
  expect(stdout.toString()).toContain("configure");
546
569
  });
547
570
 
571
+ /** Root --schema is no longer a flag. */
548
572
  test("root --schema is no longer a flag", () => {
549
573
  const root = testProgram({
550
574
  key: "app",
@@ -567,6 +591,7 @@ test("root --schema is no longer a flag", () => {
567
591
  expect(pr.kind).not.toBe(ParseKind.Ok);
568
592
  });
569
593
 
594
+ /** CliSchemaJson omits handlers and completion built-ins. */
570
595
  test("cliSchemaJson omits handlers and completion built-ins", () => {
571
596
  const root = testProgram({
572
597
  key: "app",
@@ -597,6 +622,7 @@ test("cliSchemaJson omits handlers and completion built-ins", () => {
597
622
  expect(schema).not.toHaveProperty("handler");
598
623
  });
599
624
 
625
+ /** CliSchemaExport resolves program key in install notes. */
600
626
  test("cliSchemaExport resolves program key in install notes", () => {
601
627
  const root = testProgram({
602
628
  key: "myapp",
@@ -616,6 +642,7 @@ test("cliSchemaExport resolves program key in install notes", () => {
616
642
  expect(json).toContain("brew install");
617
643
  });
618
644
 
645
+ /** CliSchemaExport resolves {argsbarg:program} in consumer notes. */
619
646
  test("cliSchemaExport resolves {argsbarg:program} in consumer notes", () => {
620
647
  const root = testProgram({
621
648
  key: "myapp",
@@ -635,6 +662,7 @@ test("cliSchemaExport resolves {argsbarg:program} in consumer notes", () => {
635
662
  expect(schema.commands[0].notes).toBe("Run `myapp run` to start.");
636
663
  });
637
664
 
665
+ /** Docs help lists schema, api, and skill subcommands. */
638
666
  test("docs help lists schema, api, and skill subcommands", () => {
639
667
  const root = testProgram({
640
668
  key: "app",
@@ -661,6 +689,7 @@ test("docs help lists schema, api, and skill subcommands", () => {
661
689
  expect(help).toContain("reference agent SKILL");
662
690
  });
663
691
 
692
+ /** Root help omits legacy --schema flag. */
664
693
  test("root help omits legacy --schema flag", () => {
665
694
  const root = testProgram({
666
695
  key: "app",
@@ -678,6 +707,7 @@ test("root help omits legacy --schema flag", () => {
678
707
  expect(help).not.toContain("--schema");
679
708
  });
680
709
 
710
+ /** Root help shows agent docs hint when docs enabled. */
681
711
  test("root help shows agent docs hint when docs enabled", () => {
682
712
  const root = testProgram({
683
713
  key: "myapp",
@@ -694,6 +724,7 @@ test("root help shows agent docs hint when docs enabled", () => {
694
724
  expect(help).not.toContain("install --skill");
695
725
  });
696
726
 
727
+ /** Root help omits agent hint when docs disabled. */
697
728
  test("root help omits agent hint when docs disabled", () => {
698
729
  const root = testProgram({
699
730
  key: "myapp",
@@ -706,6 +737,7 @@ test("root help omits agent hint when docs disabled", () => {
706
737
  expect(help).not.toContain("docs skill");
707
738
  });
708
739
 
740
+ /** Root help includes program notes and agent hint. */
709
741
  test("root help includes program notes and agent hint", () => {
710
742
  const root = testProgram({
711
743
  key: "myapp",
@@ -723,6 +755,7 @@ test("root help includes program notes and agent hint", () => {
723
755
  expect(help).toContain("myapp docs skill");
724
756
  });
725
757
 
758
+ /** Enum option inputSchema includes enum array. */
726
759
  test("Enum option inputSchema includes enum array", () => {
727
760
  const tools = collectMcpTools(enumMcpFixture);
728
761
  const run = tools.find((t) => t.name === "run")!;
@@ -730,6 +763,7 @@ test("Enum option inputSchema includes enum array", () => {
730
763
  expect(schema.properties.mode.enum).toEqual(["dev", "prod"]);
731
764
  });
732
765
 
766
+ /** CliValidateProgram rejects Enum with no choices. */
733
767
  test("cliValidateProgram rejects Enum with no choices", () => {
734
768
  const root = testProgram({
735
769
  key: "app",
@@ -740,6 +774,7 @@ test("cliValidateProgram rejects Enum with no choices", () => {
740
774
  expect(() => cliValidateProgram(root)).toThrow(/requires non-empty choices/);
741
775
  });
742
776
 
777
+ /** CliValidateProgram rejects Enum with duplicate choices. */
743
778
  test("cliValidateProgram rejects Enum with duplicate choices", () => {
744
779
  const root = testProgram({
745
780
  key: "app",
@@ -750,6 +785,7 @@ test("cliValidateProgram rejects Enum with duplicate choices", () => {
750
785
  expect(() => cliValidateProgram(root)).toThrow(/choices must be distinct/);
751
786
  });
752
787
 
788
+ /** McpTool.description override wins without env suffix. */
753
789
  test("mcpTool.description override wins without env suffix", () => {
754
790
  const root = testProgram({
755
791
  key: "app",
@@ -768,6 +804,7 @@ test("mcpTool.description override wins without env suffix", () => {
768
804
  expect(tools[0]?.description).toBe("custom");
769
805
  });
770
806
 
807
+ /** CliValidateProgram requires program.appConfig description. */
771
808
  test("cliValidateProgram requires program.appConfig description", () => {
772
809
  const root = testProgram({
773
810
  key: "app",
@@ -778,6 +815,7 @@ test("cliValidateProgram requires program.appConfig description", () => {
778
815
  expect(() => cliValidateProgram(root)).toThrow(/description must be a non-empty string/);
779
816
  });
780
817
 
818
+ /** CliValidateProgram rejects duplicate mcpResources URIs. */
781
819
  test("cliValidateProgram rejects duplicate mcpResources URIs", () => {
782
820
  const root = testProgram({
783
821
  key: "app",
@@ -794,6 +832,7 @@ test("cliValidateProgram rejects duplicate mcpResources URIs", () => {
794
832
  expect(() => cliValidateProgram(root)).toThrow(/URIs must be unique/);
795
833
  });
796
834
 
835
+ /** CliValidateProgram rejects empty mcpServer. */
797
836
  test("cliValidateProgram rejects empty mcpServer", () => {
798
837
  const root = testProgram({
799
838
  key: "app",
@@ -804,6 +843,7 @@ test("cliValidateProgram rejects empty mcpServer", () => {
804
843
  expect(() => cliValidateProgram(root)).toThrow(/mcpServer requires enabled: true/);
805
844
  });
806
845
 
846
+ /** ResolveMcpSchemaUri uses sanitized root key. */
807
847
  test("resolveMcpSchemaUri uses sanitized root key", () => {
808
848
  const root = testProgram({
809
849
  key: "nested.ts",
@@ -814,6 +854,7 @@ test("resolveMcpSchemaUri uses sanitized root key", () => {
814
854
  expect(resolveMcpSchemaUri(root)).toBe("nested_ts://schema");
815
855
  });
816
856
 
857
+ /** ResolveMcpSchemaUri uses plain key when alphanumeric. */
817
858
  test("resolveMcpSchemaUri uses plain key when alphanumeric", () => {
818
859
  const root = testProgram({
819
860
  key: "qa",
@@ -824,6 +865,7 @@ test("resolveMcpSchemaUri uses plain key when alphanumeric", () => {
824
865
  expect(resolveMcpSchemaUri(root)).toBe("qa://schema");
825
866
  });
826
867
 
868
+ /** CliValidateProgram rejects resource URI matching default schema URI. */
827
869
  test("cliValidateProgram rejects resource URI matching default schema URI", () => {
828
870
  const root = testProgram({
829
871
  key: "app",
@@ -837,6 +879,7 @@ test("cliValidateProgram rejects resource URI matching default schema URI", () =
837
879
  expect(() => cliValidateProgram(root)).toThrow(/conflicts with built-in schema resource/);
838
880
  });
839
881
 
882
+ /** CliValidateProgram rejects resource URI matching schemaResourceUri. */
840
883
  test("cliValidateProgram rejects resource URI matching schemaResourceUri", () => {
841
884
  const root = testProgram({
842
885
  key: "app",
@@ -851,6 +894,7 @@ test("cliValidateProgram rejects resource URI matching schemaResourceUri", () =>
851
894
  expect(() => cliValidateProgram(root)).toThrow(/conflicts with built-in schema resource/);
852
895
  });
853
896
 
897
+ /** CliValidateProgram rejects resource URI matching auto docs topic. */
854
898
  test("cliValidateProgram rejects resource URI matching auto docs topic", () => {
855
899
  const root = testProgram({
856
900
  key: "app",
@@ -865,6 +909,7 @@ test("cliValidateProgram rejects resource URI matching auto docs topic", () => {
865
909
  expect(() => cliValidateProgram(root)).toThrow(/conflicts with auto docs topic resource/);
866
910
  });
867
911
 
912
+ /** AllMcpResources includes custom resources. */
868
913
  test("allMcpResources includes custom resources", () => {
869
914
  const root = testProgram({
870
915
  key: "app",
@@ -880,6 +925,7 @@ test("allMcpResources includes custom resources", () => {
880
925
  expect(resources.map((r) => r.uri)).toContain("test://x");
881
926
  });
882
927
 
928
+ /** AllMcpResources includes docs topic resources. */
883
929
  test("allMcpResources includes docs topic resources", () => {
884
930
  const root = testProgram({
885
931
  key: "app",
@@ -894,6 +940,7 @@ test("allMcpResources includes docs topic resources", () => {
894
940
  expect(readme?.load()).toBe("# hi\n");
895
941
  });
896
942
 
943
+ /** ApplyShellEnv merges PATH and preserves host vars. */
897
944
  test("applyShellEnv merges PATH and preserves host vars", () => {
898
945
  const origPath = process.env.PATH ?? "";
899
946
  const origHome = process.env.HOME;
@@ -913,6 +960,7 @@ test("applyShellEnv merges PATH and preserves host vars", () => {
913
960
  delete process.env.NEWVAR;
914
961
  });
915
962
 
963
+ /** Enum completions list choices in bash script. */
916
964
  test("Enum completions list choices in bash script", () => {
917
965
  const root = testProgram({
918
966
  key: "app",
@@ -934,6 +982,7 @@ test("Enum completions list choices in bash script", () => {
934
982
  expect(bash).toContain("prod");
935
983
  });
936
984
 
985
+ /** Nested fallback routes to default when argv exhausted at router. */
937
986
  test("nested fallback routes to default when argv exhausted at router", () => {
938
987
  const root = nestedDocsFallbackFixture();
939
988
  cliValidateProgram(root);
@@ -942,6 +991,7 @@ test("nested fallback routes to default when argv exhausted at router", () => {
942
991
  expect(pr.path).toEqual(["docs", "guide"]);
943
992
  });
944
993
 
994
+ /** Nested fallback MissingOrUnknown routes unknown token to default. */
945
995
  test("nested fallback MissingOrUnknown routes unknown token to default", () => {
946
996
  const root = testProgram({
947
997
  key: "app",
@@ -983,6 +1033,7 @@ test("nested fallback MissingOrUnknown routes unknown token to default", () => {
983
1033
  expect(pr.args).toEqual(["extra-topic"]);
984
1034
  });
985
1035
 
1036
+ /** Nested fallback MissingOnly errors on unknown subcommand. */
986
1037
  test("nested fallback MissingOnly errors on unknown subcommand", () => {
987
1038
  const root = nestedDocsFallbackFixture();
988
1039
  cliValidateProgram(root);
@@ -991,6 +1042,7 @@ test("nested fallback MissingOnly errors on unknown subcommand", () => {
991
1042
  expect(pr.errorMsg).toContain("Unknown subcommand");
992
1043
  });
993
1044
 
1045
+ /** CliValidateProgram rejects invalid nested fallbackCommand. */
994
1046
  test("cliValidateProgram rejects invalid nested fallbackCommand", () => {
995
1047
  const root = testProgram({
996
1048
  key: "app",
@@ -1015,11 +1067,13 @@ test("cliValidateProgram rejects invalid nested fallbackCommand", () => {
1015
1067
  );
1016
1068
  });
1017
1069
 
1070
+ /** CliValidateProgram accepts nested fallbackCommand when child exists. */
1018
1071
  test("cliValidateProgram accepts nested fallbackCommand when child exists", () => {
1019
1072
  const root = nestedDocsFallbackFixture();
1020
1073
  expect(() => cliValidateProgram(root)).not.toThrow();
1021
1074
  });
1022
1075
 
1076
+ /** Nested router scoped help does not route to fallback. */
1023
1077
  test("nested router scoped help does not route to fallback", () => {
1024
1078
  const root = nestedDocsFallbackFixture();
1025
1079
  cliValidateProgram(root);
@@ -1032,6 +1086,7 @@ test("nested router scoped help does not route to fallback", () => {
1032
1086
  expect(help).toContain("guide");
1033
1087
  });
1034
1088
 
1089
+ /** Varargs trailing option after positionals via Cli.invoke. */
1035
1090
  test("varargs trailing option after positionals via Cli.invoke", async () => {
1036
1091
  const root = varargsReadFixture();
1037
1092
  cliValidateProgram(root);
@@ -1041,6 +1096,7 @@ test("varargs trailing option after positionals via Cli.invoke", async () => {
1041
1096
  expect(pr.opts.json).toBe("1");
1042
1097
  });
1043
1098
 
1099
+ /** Varargs option before positionals. */
1044
1100
  test("varargs option before positionals", () => {
1045
1101
  const root = varargsReadFixture();
1046
1102
  cliValidateProgram(root);
@@ -1050,6 +1106,7 @@ test("varargs option before positionals", () => {
1050
1106
  expect(pr.opts.json).toBe("1");
1051
1107
  });
1052
1108
 
1109
+ /** Varargs multiple files then trailing option. */
1053
1110
  test("varargs multiple files then trailing option", () => {
1054
1111
  const root = varargsReadFixture();
1055
1112
  cliValidateProgram(root);
@@ -1059,6 +1116,7 @@ test("varargs multiple files then trailing option", () => {
1059
1116
  expect(pr.opts.json).toBe("1");
1060
1117
  });
1061
1118
 
1119
+ /** Varargs double dash forces positional. */
1062
1120
  test("varargs double dash forces positional", () => {
1063
1121
  const root = varargsReadFixture();
1064
1122
  cliValidateProgram(root);
@@ -1068,6 +1126,7 @@ test("varargs double dash forces positional", () => {
1068
1126
  expect(pr.opts.json).toBeUndefined();
1069
1127
  });
1070
1128
 
1129
+ /** Varargs unknown flag errors. */
1071
1130
  test("varargs unknown flag errors", async () => {
1072
1131
  const root = varargsReadFixture();
1073
1132
  cliValidateProgram(root);
@@ -1076,6 +1135,7 @@ test("varargs unknown flag errors", async () => {
1076
1135
  expect(result.stderr).toContain("--unknown");
1077
1136
  });
1078
1137
 
1138
+ /** McpToolCallToArgv rejects comma-separated string for varargs. */
1079
1139
  test("mcpToolCallToArgv rejects comma-separated string for varargs", () => {
1080
1140
  const tools = collectMcpTools(nestedMcpFixture);
1081
1141
  const read = tools.find((t) => t.name === "read")!;
@@ -1083,6 +1143,7 @@ test("mcpToolCallToArgv rejects comma-separated string for varargs", () => {
1083
1143
  expect(argv).toEqual({ error: expect.stringContaining("JSON array") });
1084
1144
  });
1085
1145
 
1146
+ /** McpToolCallToArgv rejects bare string for varargs. */
1086
1147
  test("mcpToolCallToArgv rejects bare string for varargs", () => {
1087
1148
  const tools = collectMcpTools(nestedMcpFixture);
1088
1149
  const read = tools.find((t) => t.name === "read")!;
@@ -1090,6 +1151,7 @@ test("mcpToolCallToArgv rejects bare string for varargs", () => {
1090
1151
  expect(argv).toEqual({ error: expect.stringContaining("JSON array") });
1091
1152
  });
1092
1153
 
1154
+ /** McpToolCallToArgv array varargs unchanged. */
1093
1155
  test("mcpToolCallToArgv array varargs unchanged", () => {
1094
1156
  const tools = collectMcpTools(nestedMcpFixture);
1095
1157
  const read = tools.find((t) => t.name === "read")!;
@@ -1097,6 +1159,7 @@ test("mcpToolCallToArgv array varargs unchanged", () => {
1097
1159
  expect(argv).toEqual(["read", "a", "b"]);
1098
1160
  });
1099
1161
 
1162
+ /** McpToolCallToArgv empty array varargs errors when required. */
1100
1163
  test("mcpToolCallToArgv empty array varargs errors when required", () => {
1101
1164
  const tools = collectMcpTools(nestedMcpFixture);
1102
1165
  const read = tools.find((t) => t.name === "read")!;
@@ -1106,6 +1169,7 @@ test("mcpToolCallToArgv empty array varargs errors when required", () => {
1106
1169
 
1107
1170
  // ── Skills ────────────────────────────────────────────────────────────────────
1108
1171
 
1172
+ /** Configure config on non-root node is rejected. */
1109
1173
  test("configure config on non-root node is rejected", () => {
1110
1174
  const root = {
1111
1175
  key: "app",
@@ -1123,6 +1187,7 @@ test("configure config on non-root node is rejected", () => {
1123
1187
  expect(() => cliValidateProgram(root)).toThrow(/configure is only supported on the program root/);
1124
1188
  });
1125
1189
 
1190
+ /** Configure.prefix is rejected. */
1126
1191
  test("configure.prefix is rejected", () => {
1127
1192
  const root = {
1128
1193
  key: "app",
@@ -1134,6 +1199,7 @@ test("configure.prefix is rejected", () => {
1134
1199
  expect(() => cliValidateProgram(root)).toThrow(/configure\.prefix removed/);
1135
1200
  });
1136
1201
 
1202
+ /** Tests that generateSkillBundle includes frontmatter and compact command index. */
1137
1203
  test("generateSkillBundle includes frontmatter and compact command index", () => {
1138
1204
  const bundle = generateSkillBundle(nestedMcpFixture, "cursor");
1139
1205
  expect(bundle.dirName).toBe("nested_ts");
@@ -1154,6 +1220,7 @@ test("generateSkillBundle includes frontmatter and compact command index", () =>
1154
1220
  expect(bundle.referenceMd).not.toContain("```json");
1155
1221
  });
1156
1222
 
1223
+ /** Tests that generatePluginSkillBundle is MCP routing stub without shell catalog. */
1157
1224
  test("generatePluginSkillBundle is MCP routing stub without shell catalog", () => {
1158
1225
  const bundle = generatePluginSkillBundle(nestedMcpFixture);
1159
1226
  expect(bundle.dirName).toBe("nested_ts");
@@ -1168,6 +1235,7 @@ test("generatePluginSkillBundle is MCP routing stub without shell catalog", () =
1168
1235
  expect(bundle.skillMd).not.toContain("## Commands");
1169
1236
  });
1170
1237
 
1238
+ /** CliSkillInstall writes project Cursor skill files. */
1171
1239
  test("cliSkillInstall writes project Cursor skill files", () => {
1172
1240
  const cwd = mkdtempSync(join(tmpdir(), "argsbarg-skill-"));
1173
1241
  const prev = process.cwd();
@@ -1192,6 +1260,7 @@ test("cliSkillInstall writes project Cursor skill files", () => {
1192
1260
  }
1193
1261
  });
1194
1262
 
1263
+ /** CliSkillInstall global uses HOME skills directory. */
1195
1264
  test("cliSkillInstall global uses HOME skills directory", () => {
1196
1265
  const home = mkdtempSync(join(tmpdir(), "argsbarg-home-"));
1197
1266
  const prevHome = process.env.HOME;
@@ -1210,6 +1279,7 @@ test("cliSkillInstall global uses HOME skills directory", () => {
1210
1279
  }
1211
1280
  });
1212
1281
 
1282
+ /** CliSkillInstall rimraf overwrites existing directory. */
1213
1283
  test("cliSkillInstall rimraf overwrites existing directory", () => {
1214
1284
  const cwd = mkdtempSync(join(tmpdir(), "argsbarg-skill-dup-"));
1215
1285
  const prev = process.cwd();
@@ -1228,6 +1298,7 @@ test("cliSkillInstall rimraf overwrites existing directory", () => {
1228
1298
  }
1229
1299
  });
1230
1300
 
1301
+ /** CliSkillInstall claude target uses .claude/skills. */
1231
1302
  test("cliSkillInstall claude target uses .claude/skills", () => {
1232
1303
  const cwd = mkdtempSync(join(tmpdir(), "argsbarg-skill-claude-"));
1233
1304
  const prev = process.cwd();