@gh-symphony/cli 0.4.6 → 0.4.9

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.
package/dist/index.js CHANGED
@@ -5,6 +5,13 @@ import {
5
5
  setNoColor,
6
6
  yellow
7
7
  } from "./chunk-MVRF7BES.js";
8
+ import {
9
+ writeCliError
10
+ } from "./chunk-MAJOIZ5Q.js";
11
+ import {
12
+ formatErrorForTerminal,
13
+ hasVerboseFlag
14
+ } from "./chunk-77H5ED5L.js";
8
15
  import {
9
16
  resolveConfigDir
10
17
  } from "./chunk-YZP5N5XP.js";
@@ -61,6 +68,7 @@ var COMMAND_OPTIONS = {
61
68
  setup: [
62
69
  "--non-interactive",
63
70
  "--output",
71
+ "--runtime",
64
72
  "--skip-skills",
65
73
  "--skip-context",
66
74
  ...GLOBAL_OPTIONS
@@ -351,7 +359,7 @@ var HELP_SECTIONS = [
351
359
  },
352
360
  {
353
361
  name: "--verbose, -v",
354
- description: "Verbose output"
362
+ description: "Verbose output, including top-level error stack traces"
355
363
  },
356
364
  {
357
365
  name: "--json",
@@ -417,21 +425,25 @@ function createRemovedCommandHandler(message) {
417
425
 
418
426
  // src/index.ts
419
427
  var COMMANDS = {
420
- workflow: () => import("./workflow-WG55ZIZ6.js"),
421
- setup: () => import("./setup-IJMKV5YA.js"),
422
- doctor: () => import("./doctor-YV5NV4HX.js"),
423
- upgrade: () => import("./upgrade-TS42ZOSU.js"),
424
- repo: () => import("./repo-LBNPFDDF.js"),
428
+ workflow: () => import("./workflow-J3APOEMI.js"),
429
+ setup: () => import("./setup-KBZ7PU2R.js"),
430
+ doctor: () => import("./doctor-U57B6LVZ.js"),
431
+ upgrade: () => import("./upgrade-FUZ2ZM72.js"),
432
+ repo: () => import("./repo-CKOHL2HD.js"),
425
433
  config: () => import("./config-cmd-OIVIUKG7.js"),
426
- version: () => import("./version-QXB4FBVW.js")
434
+ version: () => import("./version-64B3R6RT.js")
427
435
  };
428
436
  function addGlobalOptions(command) {
429
- return command.option("--config <dir>", "Config directory").addOption(new Option("--config-dir <dir>").hideHelp()).option("-v, --verbose", "Enable verbose output").option("--json", "Output in JSON format").option("--no-color", "Disable color output");
437
+ return command.option("--config <dir>", "Config directory").addOption(new Option("--config-dir <dir>").hideHelp()).option("-v, --verbose", "Enable verbose output with stack traces").option("--json", "Output in JSON format").option("--no-color", "Disable color output");
430
438
  }
431
439
  function resolveGlobalOptions(values) {
432
440
  const configInput = typeof values.config === "string" ? values.config : typeof values.configDir === "string" ? values.configDir : void 0;
441
+ const configDirSource = configInput !== void 0 ? "cli" : typeof process.env.GH_SYMPHONY_CONFIG_DIR === "string" ? "env" : "default";
442
+ const hasConfigOverride = configDirSource === "cli" || hasExplicitConfigEnvOverride();
433
443
  const options = {
434
444
  configDir: resolveConfigDir(configInput),
445
+ configDirOverride: hasConfigOverride,
446
+ configDirSource,
435
447
  verbose: Boolean(values.verbose),
436
448
  json: Boolean(values.json),
437
449
  noColor: Boolean(values.noColor)
@@ -442,6 +454,13 @@ function resolveGlobalOptions(values) {
442
454
  setNoColor(options.noColor);
443
455
  return options;
444
456
  }
457
+ function hasExplicitConfigEnvOverride() {
458
+ const envConfigDir = process.env.GH_SYMPHONY_CONFIG_DIR;
459
+ if (!envConfigDir) {
460
+ return false;
461
+ }
462
+ return envConfigDir !== "/var/lib/gh-symphony";
463
+ }
445
464
  function resolveProjectId(values) {
446
465
  return values.projectId ?? values.project;
447
466
  }
@@ -470,6 +489,62 @@ function shellArgument(value) {
470
489
  function hasVersionFlag(argv) {
471
490
  return argv.some((arg) => arg === "--version" || arg === "-V");
472
491
  }
492
+ function extractNamespaceCommand(argv) {
493
+ const positionals = [];
494
+ for (let i = 0; i < argv.length; i += 1) {
495
+ const arg = argv[i];
496
+ if (!arg) {
497
+ continue;
498
+ }
499
+ if (arg === "--config" || arg === "--config-dir") {
500
+ i += 1;
501
+ continue;
502
+ }
503
+ if (arg.startsWith("--config=") || arg.startsWith("--config-dir=")) {
504
+ continue;
505
+ }
506
+ if (arg === "--json" || arg === "--no-color" || arg === "--verbose" || arg === "-v") {
507
+ continue;
508
+ }
509
+ if (arg.startsWith("-")) {
510
+ continue;
511
+ }
512
+ positionals.push(arg);
513
+ if (positionals.length === 2) {
514
+ break;
515
+ }
516
+ }
517
+ return {
518
+ namespace: positionals[0],
519
+ subcommand: positionals[1]
520
+ };
521
+ }
522
+ function getChildCommandNames(command) {
523
+ return command.commands.map((child) => child.name());
524
+ }
525
+ function handleUnknownNamespaceCommand(argv, program) {
526
+ const { namespace, subcommand } = extractNamespaceCommand(argv);
527
+ if (!namespace || !subcommand) {
528
+ return false;
529
+ }
530
+ const namespaceCommand = program.commands.find(
531
+ (command) => command.name() === namespace
532
+ );
533
+ if (!namespaceCommand || !["repo", "workflow"].includes(namespace)) {
534
+ return false;
535
+ }
536
+ if (getChildCommandNames(namespaceCommand).includes(subcommand)) {
537
+ return false;
538
+ }
539
+ writeCliError({
540
+ code: "unknown_command",
541
+ message: `error: unknown command '${subcommand}' for '${namespace}'`,
542
+ usage: "(run with --help for usage)",
543
+ json: argv.includes("--json"),
544
+ exitCode: 1
545
+ });
546
+ return true;
547
+ }
473
548
  function resolveVersionOptions(argv) {
474
549
  const options = {
475
550
  configDir: resolveConfigDir(),
@@ -514,7 +589,7 @@ function createProgram() {
514
589
  markInvoked
515
590
  );
516
591
  const workflow = addGlobalOptions(
517
- program.command("workflow").description("Manage WORKFLOW.md authoring")
592
+ program.command("workflow").description("Manage WORKFLOW.md authoring").showHelpAfterError("(run with --help for usage)")
518
593
  );
519
594
  workflow.action(async function() {
520
595
  markInvoked();
@@ -567,13 +642,17 @@ function createProgram() {
567
642
  await invokeHandler("workflow", args, values);
568
643
  });
569
644
  addGlobalOptions(
570
- program.command("setup").description("Run the one-command first-run setup flow").option("--non-interactive", "Run without prompts").option("--output <path>", "Write WORKFLOW.md to a custom path").option("--skip-skills", "Skip runtime skill generation").option("--skip-context", "Deprecated no-op").allowExcessArguments(false)
645
+ program.command("setup").description("Run the one-command first-run setup flow").option("--non-interactive", "Run without prompts").option("--output <path>", "Write WORKFLOW.md to a custom path").option(
646
+ "--runtime <kind>",
647
+ "Runtime preset: codex-app-server or claude-print"
648
+ ).option("--skip-skills", "Skip runtime skill generation").option("--skip-context", "Deprecated no-op").allowExcessArguments(false)
571
649
  ).action(async function() {
572
650
  markInvoked();
573
651
  const values = this.optsWithGlobals();
574
652
  const args = [];
575
653
  pushOption(args, "--non-interactive", values.nonInteractive);
576
654
  pushOption(args, "--output", values.output);
655
+ pushOption(args, "--runtime", values.runtime);
577
656
  pushOption(args, "--skip-skills", values.skipSkills);
578
657
  pushOption(args, "--skip-context", values.skipContext);
579
658
  await invokeHandler("setup", args, values);
@@ -651,23 +730,23 @@ function createProgram() {
651
730
  )([], resolveGlobalOptions(this.optsWithGlobals()));
652
731
  });
653
732
  const repo = addGlobalOptions(
654
- program.command("repo").description("Manage the current repository runtime")
733
+ program.command("repo").description("Manage the current repository runtime").showHelpAfterError("(run with --help for usage)")
655
734
  );
656
735
  repo.action(async function() {
657
736
  markInvoked();
658
737
  await invokeHandler("repo", [], this.optsWithGlobals());
659
738
  });
660
- addGlobalOptions(repo.command("list").description("Removed")).action(
661
- async function() {
662
- markInvoked();
663
- await invokeRemovedCommand(
664
- "Removed. Repository identity is shown by 'repo status'.",
665
- this.optsWithGlobals()
666
- );
667
- }
668
- );
669
739
  addGlobalOptions(
670
- repo.command("add").description("Removed").argument("[owner/name]", "Repository spec").allowExcessArguments(false)
740
+ repo.command("list", { hidden: true }).description("Removed")
741
+ ).action(async function() {
742
+ markInvoked();
743
+ await invokeRemovedCommand(
744
+ "Removed. Repository identity is shown by 'repo status'.",
745
+ this.optsWithGlobals()
746
+ );
747
+ });
748
+ addGlobalOptions(
749
+ repo.command("add", { hidden: true }).description("Removed").argument("[owner/name]", "Repository spec").allowExcessArguments(false)
671
750
  ).action(async function() {
672
751
  markInvoked();
673
752
  await invokeRemovedCommand(
@@ -676,7 +755,7 @@ function createProgram() {
676
755
  );
677
756
  });
678
757
  addGlobalOptions(
679
- repo.command("remove").description("Removed").argument("[owner/name]", "Repository spec").allowExcessArguments(false)
758
+ repo.command("remove", { hidden: true }).description("Removed").argument("[owner/name]", "Repository spec").allowExcessArguments(false)
680
759
  ).action(async function() {
681
760
  markInvoked();
682
761
  await invokeRemovedCommand(
@@ -685,7 +764,7 @@ function createProgram() {
685
764
  );
686
765
  });
687
766
  addGlobalOptions(
688
- repo.command("sync").description("Removed").allowExcessArguments(false)
767
+ repo.command("sync", { hidden: true }).description("Removed").allowExcessArguments(false)
689
768
  ).action(async function() {
690
769
  markInvoked();
691
770
  await invokeRemovedCommand(
@@ -706,7 +785,7 @@ function createProgram() {
706
785
  addGlobalOptions(
707
786
  repo.command("start").description("Start the orchestrator for the current repository").option("-d, --daemon", "Start in daemon mode").option("--once", "Run a single orchestration tick and exit").option("--assigned-only", "Limit this run to assigned issues").option(
708
787
  "--http [port]",
709
- "Expose dashboard and refresh endpoints over HTTP"
788
+ "Expose the JSON status API and refresh endpoints over HTTP"
710
789
  ).option(
711
790
  "--web [port]",
712
791
  "Expose the control plane web dashboard and API over HTTP"
@@ -742,11 +821,18 @@ function createProgram() {
742
821
  await invokeHandler("repo", args, values);
743
822
  });
744
823
  addGlobalOptions(
745
- repo.command("run").description("Dispatch a single issue from the current repository").argument("[args...]", "Issue identifier and passthrough options").option("--log-level <level>", "Orchestrator lifecycle log level").option("-w, --watch", "Watch status after dispatch").allowUnknownOption(true).allowExcessArguments(true)
746
- ).action(async function(passthrough) {
824
+ repo.command("run").description("Dispatch a single issue from the current repository").usage("[options] <issue>").argument("[issue]", "Issue identifier (owner/repo#number)").option("--log-level <level>", "Orchestrator lifecycle log level").option("-w, --watch", "Watch status after dispatch").allowUnknownOption(true).allowExcessArguments(true).addHelpText(
825
+ "after",
826
+ "\nExamples:\n $ gh-symphony repo run owner/repo#123\n"
827
+ )
828
+ ).action(async function(issue) {
747
829
  markInvoked();
748
830
  const values = this.optsWithGlobals();
749
- const args = ["run", ...passthrough];
831
+ const args = ["run"];
832
+ if (issue) {
833
+ args.push(issue);
834
+ }
835
+ args.push(...this.args.slice(issue ? 1 : 0));
750
836
  pushOption(args, "--log-level", values.logLevel);
751
837
  pushOption(args, "--watch", values.watch);
752
838
  await invokeHandler("repo", args, values);
@@ -773,11 +859,18 @@ function createProgram() {
773
859
  await invokeHandler("repo", args, values);
774
860
  });
775
861
  addGlobalOptions(
776
- repo.command("explain").description("Explain why a repository issue is not dispatching").argument("[args...]", "Issue identifier and passthrough options").option("--workflow <path>", "Path to the WORKFLOW.md file to evaluate").allowUnknownOption(true).allowExcessArguments(true)
777
- ).action(async function(passthrough) {
862
+ repo.command("explain").description("Explain why a repository issue is not dispatching").usage("[options] <issue>").argument("[issue]", "Issue identifier (owner/repo#number)").option("--workflow <path>", "Path to the WORKFLOW.md file to evaluate").allowUnknownOption(true).allowExcessArguments(true).addHelpText(
863
+ "after",
864
+ "\nExamples:\n $ gh-symphony repo explain owner/repo#123\n"
865
+ )
866
+ ).action(async function(issue) {
778
867
  markInvoked();
779
868
  const values = this.optsWithGlobals();
780
- const args = ["explain", ...passthrough];
869
+ const args = ["explain"];
870
+ if (issue) {
871
+ args.push(issue);
872
+ }
873
+ args.push(...this.args.slice(issue ? 1 : 0));
781
874
  pushOption(args, "--workflow", values.workflow);
782
875
  await invokeHandler("repo", args, values);
783
876
  });
@@ -841,6 +934,9 @@ async function runCli(argv) {
841
934
  await versionModule.default([], resolveVersionOptions(argv));
842
935
  return;
843
936
  }
937
+ if (handleUnknownNamespaceCommand(argv, program)) {
938
+ return;
939
+ }
844
940
  try {
845
941
  await program.parseAsync(["node", "gh-symphony", ...argv], {
846
942
  from: "node"
@@ -865,12 +961,14 @@ async function main() {
865
961
  if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) {
866
962
  main().catch((error) => {
867
963
  process.stderr.write(
868
- `${error instanceof Error ? error.message : "Unknown error"}
869
- `
964
+ formatErrorForTerminal(error, {
965
+ verbose: hasVerboseFlag(process.argv.slice(2))
966
+ })
870
967
  );
871
968
  process.exitCode = 1;
872
969
  });
873
970
  }
874
971
  export {
972
+ resolveGlobalOptions,
875
973
  runCli
876
974
  };