@gh-symphony/cli 0.4.7 → 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.
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  workflow_init_default
4
- } from "./chunk-775A5LB5.js";
4
+ } from "./chunk-77INSSMM.js";
5
5
  import {
6
6
  fetchGithubProjectIssueByRepositoryAndNumber,
7
7
  inspectManagedProjectSelection,
8
8
  resolveTrackerAdapter
9
- } from "./chunk-C4QCVQVY.js";
9
+ } from "./chunk-D7HICFZ5.js";
10
10
  import {
11
11
  GitHubApiError,
12
12
  createClient,
@@ -19,7 +19,7 @@ import {
19
19
  buildPromptVariables,
20
20
  parseWorkflowMarkdown,
21
21
  renderPrompt
22
- } from "./chunk-RGCSM2KZ.js";
22
+ } from "./chunk-77H5ED5L.js";
23
23
  import {
24
24
  loadActiveProjectConfig
25
25
  } from "./chunk-YZP5N5XP.js";
@@ -5,14 +5,18 @@ import {
5
5
  parseIssueReference,
6
6
  readGitHubProjectBinding,
7
7
  renderIssueWorkflowPreview
8
- } from "./chunk-3ACU7O47.js";
9
- import "./chunk-775A5LB5.js";
8
+ } from "./chunk-RMXW2QQF.js";
9
+ import {
10
+ commandExistsOnPath
11
+ } from "./chunk-JNEP7OYK.js";
12
+ import "./chunk-77INSSMM.js";
10
13
  import {
11
14
  fetchGithubProjectIssueByRepositoryAndNumber,
12
15
  fetchGithubProjectIssues,
13
16
  inspectManagedProjectSelection
14
- } from "./chunk-C4QCVQVY.js";
15
- import "./chunk-XLDJTMW5.js";
17
+ } from "./chunk-D7HICFZ5.js";
18
+ import "./chunk-MAJOIZ5Q.js";
19
+ import "./chunk-LSH5HRQT.js";
16
20
  import {
17
21
  resolveRuntimeRoot
18
22
  } from "./chunk-3IRPSPAF.js";
@@ -35,13 +39,15 @@ import {
35
39
  } from "./chunk-FFY5VKNV.js";
36
40
  import {
37
41
  isClaudeRuntimeCommand,
38
- parseWorkflowMarkdown,
39
- redactObservabilityDiagnosticsWithStats,
40
- redactObservabilityTextWithStats,
41
42
  resolveClaudeCommandBinary,
42
43
  resolveRuntimeCommandBinary,
43
44
  runClaudePreflight
44
- } from "./chunk-RGCSM2KZ.js";
45
+ } from "./chunk-PKUD2SVX.js";
46
+ import {
47
+ parseWorkflowMarkdown,
48
+ redactObservabilityDiagnosticsWithStats,
49
+ redactObservabilityTextWithStats
50
+ } from "./chunk-77H5ED5L.js";
45
51
  import {
46
52
  configFilePath,
47
53
  orchestratorLogPath,
@@ -52,7 +58,7 @@ import {
52
58
  import { constants as constants2 } from "fs";
53
59
  import { execFileSync, spawnSync } from "child_process";
54
60
  import { access as access2, mkdir as mkdir2, readFile as readFile2, stat as stat2 } from "fs/promises";
55
- import { delimiter, isAbsolute, join as join2, resolve as resolve2 } from "path";
61
+ import { isAbsolute, join as join2, resolve as resolve2 } from "path";
56
62
 
57
63
  // src/support/bundle.ts
58
64
  import { constants } from "fs";
@@ -688,49 +694,6 @@ function formatGhSymphonyCommand(args, deps, options) {
688
694
  );
689
695
  return `gh-symphony ${commandArgs.join(" ")}`;
690
696
  }
691
- function getCommandCandidates(binary, deps) {
692
- if (deps.platform !== "win32") {
693
- return [binary];
694
- }
695
- const pathExts = (deps.pathExtEnv ?? ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim()).filter(Boolean);
696
- const normalizedBinary = binary.toLowerCase();
697
- if (pathExts.some((ext) => normalizedBinary.endsWith(ext.toLowerCase()))) {
698
- return [binary];
699
- }
700
- return [binary, ...pathExts.map((ext) => `${binary}${ext}`)];
701
- }
702
- async function commandExistsOnPath(binary, deps) {
703
- if (!binary) {
704
- return false;
705
- }
706
- const candidates = getCommandCandidates(binary, deps);
707
- if (isAbsolute(binary) || binary.includes("/") || binary.includes("\\")) {
708
- for (const candidate of candidates) {
709
- try {
710
- await deps.access(resolve2(candidate), constants2.X_OK);
711
- return true;
712
- } catch {
713
- continue;
714
- }
715
- }
716
- return false;
717
- }
718
- for (const segment of (deps.pathEnv ?? "").split(delimiter)) {
719
- if (!segment) {
720
- continue;
721
- }
722
- for (const command of candidates) {
723
- const candidate = join2(segment, command);
724
- try {
725
- await deps.access(candidate, constants2.X_OK);
726
- return true;
727
- } catch {
728
- continue;
729
- }
730
- }
731
- }
732
- return false;
733
- }
734
697
  function toDoctorClaudeCheck(check) {
735
698
  const id = check.id;
736
699
  if (check.status === "pass") {
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,16 +425,16 @@ function createRemovedCommandHandler(message) {
417
425
 
418
426
  // src/index.ts
419
427
  var COMMANDS = {
420
- workflow: () => import("./workflow-JQNOLYAM.js"),
421
- setup: () => import("./setup-KCBVNMUJ.js"),
422
- doctor: () => import("./doctor-TFKCAGZF.js"),
423
- upgrade: () => import("./upgrade-YOYZAIIY.js"),
424
- repo: () => import("./repo-7UOBO3QG.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-ZTY3SPRG.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;
@@ -481,6 +489,62 @@ function shellArgument(value) {
481
489
  function hasVersionFlag(argv) {
482
490
  return argv.some((arg) => arg === "--version" || arg === "-V");
483
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
+ }
484
548
  function resolveVersionOptions(argv) {
485
549
  const options = {
486
550
  configDir: resolveConfigDir(),
@@ -525,7 +589,7 @@ function createProgram() {
525
589
  markInvoked
526
590
  );
527
591
  const workflow = addGlobalOptions(
528
- program.command("workflow").description("Manage WORKFLOW.md authoring")
592
+ program.command("workflow").description("Manage WORKFLOW.md authoring").showHelpAfterError("(run with --help for usage)")
529
593
  );
530
594
  workflow.action(async function() {
531
595
  markInvoked();
@@ -578,13 +642,17 @@ function createProgram() {
578
642
  await invokeHandler("workflow", args, values);
579
643
  });
580
644
  addGlobalOptions(
581
- 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)
582
649
  ).action(async function() {
583
650
  markInvoked();
584
651
  const values = this.optsWithGlobals();
585
652
  const args = [];
586
653
  pushOption(args, "--non-interactive", values.nonInteractive);
587
654
  pushOption(args, "--output", values.output);
655
+ pushOption(args, "--runtime", values.runtime);
588
656
  pushOption(args, "--skip-skills", values.skipSkills);
589
657
  pushOption(args, "--skip-context", values.skipContext);
590
658
  await invokeHandler("setup", args, values);
@@ -662,23 +730,23 @@ function createProgram() {
662
730
  )([], resolveGlobalOptions(this.optsWithGlobals()));
663
731
  });
664
732
  const repo = addGlobalOptions(
665
- 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)")
666
734
  );
667
735
  repo.action(async function() {
668
736
  markInvoked();
669
737
  await invokeHandler("repo", [], this.optsWithGlobals());
670
738
  });
671
- addGlobalOptions(repo.command("list").description("Removed")).action(
672
- async function() {
673
- markInvoked();
674
- await invokeRemovedCommand(
675
- "Removed. Repository identity is shown by 'repo status'.",
676
- this.optsWithGlobals()
677
- );
678
- }
679
- );
680
739
  addGlobalOptions(
681
- 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)
682
750
  ).action(async function() {
683
751
  markInvoked();
684
752
  await invokeRemovedCommand(
@@ -687,7 +755,7 @@ function createProgram() {
687
755
  );
688
756
  });
689
757
  addGlobalOptions(
690
- 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)
691
759
  ).action(async function() {
692
760
  markInvoked();
693
761
  await invokeRemovedCommand(
@@ -696,7 +764,7 @@ function createProgram() {
696
764
  );
697
765
  });
698
766
  addGlobalOptions(
699
- repo.command("sync").description("Removed").allowExcessArguments(false)
767
+ repo.command("sync", { hidden: true }).description("Removed").allowExcessArguments(false)
700
768
  ).action(async function() {
701
769
  markInvoked();
702
770
  await invokeRemovedCommand(
@@ -753,11 +821,18 @@ function createProgram() {
753
821
  await invokeHandler("repo", args, values);
754
822
  });
755
823
  addGlobalOptions(
756
- 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)
757
- ).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) {
758
829
  markInvoked();
759
830
  const values = this.optsWithGlobals();
760
- 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));
761
836
  pushOption(args, "--log-level", values.logLevel);
762
837
  pushOption(args, "--watch", values.watch);
763
838
  await invokeHandler("repo", args, values);
@@ -784,11 +859,18 @@ function createProgram() {
784
859
  await invokeHandler("repo", args, values);
785
860
  });
786
861
  addGlobalOptions(
787
- 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)
788
- ).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) {
789
867
  markInvoked();
790
868
  const values = this.optsWithGlobals();
791
- 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));
792
874
  pushOption(args, "--workflow", values.workflow);
793
875
  await invokeHandler("repo", args, values);
794
876
  });
@@ -852,6 +934,9 @@ async function runCli(argv) {
852
934
  await versionModule.default([], resolveVersionOptions(argv));
853
935
  return;
854
936
  }
937
+ if (handleUnknownNamespaceCommand(argv, program)) {
938
+ return;
939
+ }
855
940
  try {
856
941
  await program.parseAsync(["node", "gh-symphony", ...argv], {
857
942
  from: "node"
@@ -876,8 +961,9 @@ async function main() {
876
961
  if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) {
877
962
  main().catch((error) => {
878
963
  process.stderr.write(
879
- `${error instanceof Error ? error.message : "Unknown error"}
880
- `
964
+ formatErrorForTerminal(error, {
965
+ verbose: hasVerboseFlag(process.argv.slice(2))
966
+ })
881
967
  );
882
968
  process.exitCode = 1;
883
969
  });
@@ -15,9 +15,10 @@ import {
15
15
  yellow
16
16
  } from "./chunk-MVRF7BES.js";
17
17
  import {
18
+ MissingWorkflowFileError,
18
19
  initRepoRuntime,
19
20
  parseRepoRuntimeFlags
20
- } from "./chunk-EILO332E.js";
21
+ } from "./chunk-7XHWAJJA.js";
21
22
  import {
22
23
  OrchestratorService,
23
24
  acquireProjectLock,
@@ -33,8 +34,11 @@ import {
33
34
  resolveOrchestratorLogLevel,
34
35
  resolveTrackerAdapter,
35
36
  runCli
36
- } from "./chunk-C4QCVQVY.js";
37
- import "./chunk-XLDJTMW5.js";
37
+ } from "./chunk-D7HICFZ5.js";
38
+ import {
39
+ writeCliError
40
+ } from "./chunk-MAJOIZ5Q.js";
41
+ import "./chunk-LSH5HRQT.js";
38
42
  import {
39
43
  resolveRepoRuntimeRoot,
40
44
  resolveRuntimeRoot
@@ -49,6 +53,7 @@ import {
49
53
  runGhAuthLogin,
50
54
  runGhAuthRefresh
51
55
  } from "./chunk-FFY5VKNV.js";
56
+ import "./chunk-PKUD2SVX.js";
52
57
  import {
53
58
  WorkflowConfigStore,
54
59
  deriveIssueWorkspaceKeyFromIdentifier,
@@ -59,7 +64,7 @@ import {
59
64
  parseRecentEvents,
60
65
  readJsonFile,
61
66
  safeReadDir
62
- } from "./chunk-RGCSM2KZ.js";
67
+ } from "./chunk-77H5ED5L.js";
63
68
  import {
64
69
  configFilePath,
65
70
  daemonPidPath,
@@ -477,20 +482,22 @@ function parseRepoExplainFlags(args) {
477
482
  var handler3 = async (args, options) => {
478
483
  const parsed = parseRepoExplainFlags(args);
479
484
  if (parsed.error) {
480
- process.stderr.write(`${parsed.error}
481
- `);
482
- process.stderr.write(
483
- "Usage: gh-symphony repo explain <owner/repo#number> [--workflow <path>]\n"
484
- );
485
- process.exitCode = 2;
485
+ writeCliError({
486
+ code: "invalid_arguments",
487
+ message: parsed.error,
488
+ usage: "Usage: gh-symphony repo explain <owner/repo#number> [--workflow <path>]",
489
+ json: options.json,
490
+ exitCode: 2
491
+ });
486
492
  return;
487
493
  }
488
494
  const projectConfig = await loadActiveProjectConfig(options.configDir);
489
495
  if (!projectConfig) {
490
- process.stderr.write(
491
- "No repository runtime configured. Run 'gh-symphony repo init' in the target repository.\n"
492
- );
493
- process.exitCode = 1;
496
+ writeCliError({
497
+ code: "missing_repository_runtime_config",
498
+ message: "No repository runtime configured. Run 'gh-symphony repo init' in the target repository.",
499
+ json: options.json
500
+ });
494
501
  return;
495
502
  }
496
503
  const identifier = parsed.identifier;
@@ -506,14 +513,12 @@ var handler3 = async (args, options) => {
506
513
  token = getGhToken();
507
514
  } catch (error) {
508
515
  if (error instanceof GhAuthError) {
509
- process.stderr.write(
510
- `Error: GitHub authentication is required for repo explain. ${error.message}
511
- `
512
- );
513
- process.stderr.write(
514
- "Run 'gh auth login --scopes repo,read:org,project' or set GITHUB_GRAPHQL_TOKEN, then re-run this command.\n"
515
- );
516
- process.exitCode = 2;
516
+ writeCliError({
517
+ code: "github_auth_required",
518
+ message: `Error: GitHub authentication is required for repo explain. ${error.message} Run 'gh auth login --scopes repo,read:org,project' or set GITHUB_GRAPHQL_TOKEN, then re-run this command.`,
519
+ json: options.json,
520
+ exitCode: 2
521
+ });
517
522
  return;
518
523
  }
519
524
  throw error;
@@ -561,12 +566,12 @@ var handler3 = async (args, options) => {
561
566
  });
562
567
  } catch (error) {
563
568
  if (error instanceof RepoExplainWorkflowError) {
564
- process.stderr.write(`Error: ${error.message}
565
- `);
566
- process.stderr.write(
567
- "Hint: pass --workflow <path-to-WORKFLOW.md> or run 'gh-symphony workflow preview --file <path>' to verify the workflow file.\n"
568
- );
569
- process.exitCode = 2;
569
+ writeCliError({
570
+ code: "workflow_load_failed",
571
+ message: `Error: ${error.message} Hint: pass --workflow <path-to-WORKFLOW.md> or run 'gh-symphony workflow preview --file <path>' to verify the workflow file.`,
572
+ json: options.json,
573
+ exitCode: 2
574
+ });
570
575
  return;
571
576
  }
572
577
  throw error;
@@ -771,22 +776,31 @@ function parseRunArgs(args) {
771
776
  var handler4 = async (args, options) => {
772
777
  const parsed = parseRunArgs(args);
773
778
  if (parsed.error) {
774
- process.stderr.write(`${parsed.error}
775
- `);
776
- process.exitCode = 2;
779
+ writeCliError({
780
+ code: "invalid_arguments",
781
+ message: parsed.error,
782
+ json: options.json,
783
+ exitCode: 2
784
+ });
777
785
  return;
778
786
  }
779
787
  if (!parsed.issue) {
780
- process.stderr.write("Usage: gh-symphony repo run <owner/repo#number>\n");
781
- process.exitCode = 2;
788
+ writeCliError({
789
+ code: "invalid_arguments",
790
+ message: "Issue identifier argument missing",
791
+ usage: "Usage: gh-symphony repo run <owner/repo#number>",
792
+ json: options.json,
793
+ exitCode: 2
794
+ });
782
795
  return;
783
796
  }
784
797
  const projectConfig = await resolveManagedProjectConfig({
785
798
  configDir: options.configDir,
786
- requestedProjectId: parsed.projectId
799
+ requestedProjectId: parsed.projectId,
800
+ json: options.json
787
801
  });
788
802
  if (!projectConfig) {
789
- handleMissingManagedProjectConfig();
803
+ handleMissingManagedProjectConfig({ json: options.json });
790
804
  return;
791
805
  }
792
806
  const runtimeRoot = resolveRuntimeRoot(options.configDir);
@@ -797,19 +811,19 @@ var handler4 = async (args, options) => {
797
811
  ).map((repository) => `${repository.owner}/${repository.name}`);
798
812
  const configuredRepoSet = new Set(configuredRepos);
799
813
  if (configuredRepoSet.size === 0) {
800
- process.stderr.write(
801
- "No repository is configured in this project. Run 'gh-symphony repo init' from the target repository first.\n"
802
- );
803
- process.exitCode = 1;
814
+ writeCliError({
815
+ code: "repository_not_configured",
816
+ message: "No repository is configured in this project. Run 'gh-symphony repo init' from the target repository first.",
817
+ json: options.json
818
+ });
804
819
  return;
805
820
  }
806
821
  if (repoSpec && !configuredRepoSet.has(repoSpec)) {
807
- process.stderr.write(
808
- `Repository "${repoSpec}" is not configured in this project.
809
- Configured repo: ${configuredRepos.join(", ")}
810
- `
811
- );
812
- process.exitCode = 1;
822
+ writeCliError({
823
+ code: "repository_mismatch",
824
+ message: `Repository "${repoSpec}" is not configured in this project. Configured repo: ${configuredRepos.join(", ")}`,
825
+ json: options.json
826
+ });
813
827
  return;
814
828
  }
815
829
  process.stdout.write(`Dispatching issue: ${parsed.issue}
@@ -1972,10 +1986,9 @@ var handler5 = async (args, options) => {
1972
1986
  const runtimeRoot = resolveRuntimeRoot(options.configDir);
1973
1987
  const projectId = projectConfig.projectId;
1974
1988
  let logLevel;
1989
+ const requestedLogLevel = parsed.logLevel ?? (options.verbose ? "verbose" : process.env.SYMPHONY_LOG_LEVEL);
1975
1990
  try {
1976
- logLevel = resolveOrchestratorLogLevel(
1977
- parsed.logLevel ?? process.env.SYMPHONY_LOG_LEVEL
1978
- );
1991
+ logLevel = resolveOrchestratorLogLevel(requestedLogLevel);
1979
1992
  } catch (error) {
1980
1993
  process.stderr.write(
1981
1994
  `${error instanceof Error ? error.message : "Unsupported log level"}
@@ -1994,7 +2007,7 @@ var handler5 = async (args, options) => {
1994
2007
  await startDaemon(
1995
2008
  options,
1996
2009
  projectId,
1997
- parsed.logLevel,
2010
+ parsed.logLevel ?? (options.verbose ? "verbose" : void 0),
1998
2011
  parsed.httpPort,
1999
2012
  parsed.webPort,
2000
2013
  parsed.assignedOnly === true
@@ -2292,6 +2305,7 @@ async function startDaemon(options, projectId, logLevel, httpPort, webPort, assi
2292
2305
  process.argv[1],
2293
2306
  "repo",
2294
2307
  "start",
2308
+ ...options.verbose ? ["--verbose"] : [],
2295
2309
  ...assignedOnly ? ["--assigned-only"] : [],
2296
2310
  ...httpPort !== void 0 ? ["--http", String(httpPort)] : [],
2297
2311
  ...webPort !== void 0 ? ["--web", String(webPort)] : [],
@@ -2707,18 +2721,22 @@ var handler6 = async (args, options) => {
2707
2721
  }
2708
2722
  const parsed = parseStatusArgs(args);
2709
2723
  if (parsed.error) {
2710
- process.stderr.write(`${parsed.error}
2711
- `);
2712
- process.stderr.write("Usage: gh-symphony repo status [--watch]\n");
2713
- process.exitCode = 2;
2724
+ writeCliError({
2725
+ code: "invalid_arguments",
2726
+ message: parsed.error,
2727
+ usage: "Usage: gh-symphony repo status [--watch]",
2728
+ json: options.json,
2729
+ exitCode: 2
2730
+ });
2714
2731
  return;
2715
2732
  }
2716
2733
  const projectConfig = await resolveManagedProjectConfig({
2717
2734
  configDir: options.configDir,
2718
- requestedProjectId: void 0
2735
+ requestedProjectId: void 0,
2736
+ json: options.json
2719
2737
  });
2720
2738
  if (!projectConfig) {
2721
- handleMissingManagedProjectConfig();
2739
+ handleMissingManagedProjectConfig({ json: options.json });
2722
2740
  return;
2723
2741
  }
2724
2742
  const runtimeRoot = resolveRuntimeRoot(options.configDir);
@@ -2783,8 +2801,11 @@ var handler6 = async (args, options) => {
2783
2801
  );
2784
2802
  }
2785
2803
  } else {
2786
- process.stderr.write("Unable to read status snapshot.\n");
2787
- process.exitCode = 1;
2804
+ writeCliError({
2805
+ code: "status_snapshot_unavailable",
2806
+ message: "Unable to read status snapshot.",
2807
+ json: options.json
2808
+ });
2788
2809
  }
2789
2810
  };
2790
2811
  var status_default = handler6;
@@ -2945,14 +2966,13 @@ async function repoInit(args, options) {
2945
2966
  try {
2946
2967
  flags = parseRepoRuntimeFlags(args);
2947
2968
  } catch (error) {
2948
- process.stderr.write(
2949
- `${error instanceof Error ? error.message : "Invalid arguments"}
2950
- `
2951
- );
2952
- process.stderr.write(
2953
- "Usage: gh-symphony repo init [--repo-dir <path>] [--workflow-file <path>]\n"
2954
- );
2955
- process.exitCode = 2;
2969
+ writeCliError({
2970
+ code: "invalid_arguments",
2971
+ message: error instanceof Error ? error.message : "Invalid arguments",
2972
+ usage: "Usage: gh-symphony repo init [--repo-dir <path>] [--workflow-file <path>]",
2973
+ json: options.json,
2974
+ exitCode: 2
2975
+ });
2956
2976
  return;
2957
2977
  }
2958
2978
  try {
@@ -2969,11 +2989,11 @@ async function repoInit(args, options) {
2969
2989
  ].join("\n") + "\n"
2970
2990
  );
2971
2991
  } catch (error) {
2972
- process.stderr.write(
2973
- `${error instanceof Error ? error.message : "Repository initialization failed."}
2974
- `
2975
- );
2976
- process.exitCode = 1;
2992
+ writeCliError({
2993
+ code: error instanceof MissingWorkflowFileError ? "missing_workflow_file" : "repository_initialization_failed",
2994
+ message: error instanceof Error ? error.message : "Repository initialization failed.",
2995
+ json: options.json
2996
+ });
2977
2997
  }
2978
2998
  }
2979
2999
  function formatRepoSpec(repo) {