@gh-symphony/cli 0.2.4 → 0.2.5

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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  workflow_init_default
4
- } from "./chunk-PLBG7TZA.js";
4
+ } from "./chunk-DTPIJO6S.js";
5
5
  import {
6
6
  fetchGithubProjectIssueByRepositoryAndNumber,
7
7
  inspectManagedProjectSelection,
@@ -14,7 +14,7 @@ import {
14
14
  getGhTokenWithSource,
15
15
  getProjectDetail,
16
16
  validateGitHubToken
17
- } from "./chunk-BOM2BYZQ.js";
17
+ } from "./chunk-SMNIGNS3.js";
18
18
  import {
19
19
  buildPromptVariables,
20
20
  parseWorkflowMarkdown,
@@ -11,7 +11,7 @@ import {
11
11
  listUserProjects,
12
12
  resolveGitHubAuth,
13
13
  validateToken
14
- } from "./chunk-BOM2BYZQ.js";
14
+ } from "./chunk-SMNIGNS3.js";
15
15
  import {
16
16
  formatClaudePreflightText,
17
17
  resolveClaudeCommandBinary,
@@ -517,9 +517,10 @@ var PROJECT_ITEMS_PAGE_QUERY = `
517
517
  import { execFileSync, spawnSync } from "child_process";
518
518
  var REQUIRED_GH_SCOPES = ["repo", "read:org", "project"];
519
519
  var GhAuthError = class extends Error {
520
- constructor(code, message) {
520
+ constructor(code, message, details = {}) {
521
521
  super(message);
522
522
  this.code = code;
523
+ this.details = details;
523
524
  this.name = "GhAuthError";
524
525
  }
525
526
  };
@@ -527,7 +528,77 @@ function ghTokenReadErrorMessage() {
527
528
  return "Failed to read a GitHub token from gh CLI. Run 'gh auth status' and try again.";
528
529
  }
529
530
  function missingGhScopesMessage(missing) {
530
- return `Run 'gh auth refresh --scopes repo,read:org,project'. Missing scopes: ${missing.join(", ")}`;
531
+ return `Run 'gh auth refresh --scopes ${REQUIRED_GH_SCOPES.join(",")}'. Missing scopes: ${missing.join(", ")}`;
532
+ }
533
+ function parseMissingScopes(message) {
534
+ const matched = message.match(/Missing scopes:\s*([^.\n]+)/i);
535
+ if (!matched) {
536
+ return [];
537
+ }
538
+ return matched[1].split(",").map((scope) => scope.trim()).filter((scope) => scope.length > 0);
539
+ }
540
+ function formatGhAuthRemediation(error, opts) {
541
+ const retryCommand = opts?.retryCommand ?? "gh-symphony repo start";
542
+ switch (error.code) {
543
+ case "not_installed":
544
+ return {
545
+ title: "GitHub authentication is not available",
546
+ message: error.message,
547
+ hint: "Install gh CLI from https://cli.github.com or set GITHUB_GRAPHQL_TOKEN."
548
+ };
549
+ case "not_authenticated": {
550
+ const command = `gh auth login --scopes ${REQUIRED_GH_SCOPES.join(",")}`;
551
+ return {
552
+ title: "GitHub authentication is required",
553
+ message: error.message,
554
+ command,
555
+ hint: `Run '${command}', then re-run '${retryCommand}'.`
556
+ };
557
+ }
558
+ case "missing_scopes": {
559
+ if (error.details.source === "env") {
560
+ return {
561
+ title: "GitHub token is missing required scopes",
562
+ message: error.message,
563
+ hint: `Update GITHUB_GRAPHQL_TOKEN with a token that has ${REQUIRED_GH_SCOPES.join(",")} scopes, or unset it to use gh CLI auth, then re-run '${retryCommand}'.`
564
+ };
565
+ }
566
+ const currentSet = new Set(
567
+ (error.details.currentScopes ?? []).map((scope) => scope.toLowerCase())
568
+ );
569
+ const inferredMissing = currentSet.size > 0 ? REQUIRED_GH_SCOPES.filter((scope) => !currentSet.has(scope)) : [];
570
+ const missing = error.details.missingScopes?.length ? error.details.missingScopes : inferredMissing.length > 0 ? inferredMissing : parseMissingScopes(error.message);
571
+ const scopeArg = missing.length > 0 ? missing.join(",") : REQUIRED_GH_SCOPES.join(",");
572
+ const command = `gh auth refresh --scopes ${scopeArg}`;
573
+ return {
574
+ title: "GitHub token is missing required scopes",
575
+ message: error.message,
576
+ command,
577
+ hint: `Run '${command}', then re-run '${retryCommand}'.`
578
+ };
579
+ }
580
+ case "invalid_token":
581
+ case "token_failed": {
582
+ if (error.details.source === "env") {
583
+ return {
584
+ title: "GitHub token validation failed",
585
+ message: error.message,
586
+ hint: `Update or unset GITHUB_GRAPHQL_TOKEN, then re-run '${retryCommand}'.`
587
+ };
588
+ }
589
+ const command = `gh auth login --scopes ${REQUIRED_GH_SCOPES.join(",")}`;
590
+ return {
591
+ title: "GitHub token validation failed",
592
+ message: error.message,
593
+ command,
594
+ hint: `Run '${command}' to re-authenticate, then re-run '${retryCommand}'.`
595
+ };
596
+ }
597
+ default: {
598
+ const exhaustive = error.code;
599
+ throw new Error(`Unhandled GhAuthError code: ${exhaustive}`);
600
+ }
601
+ }
531
602
  }
532
603
  function classifyTokenValidationError(error, source) {
533
604
  if (error instanceof GhAuthError) {
@@ -537,19 +608,25 @@ function classifyTokenValidationError(error, source) {
537
608
  if (error.status === 401) {
538
609
  return new GhAuthError(
539
610
  source === "env" ? "invalid_token" : "token_failed",
540
- source === "env" ? "GITHUB_GRAPHQL_TOKEN is invalid or expired." : ghTokenReadErrorMessage()
611
+ source === "env" ? "GITHUB_GRAPHQL_TOKEN is invalid or expired." : ghTokenReadErrorMessage(),
612
+ { source }
541
613
  );
542
614
  }
543
615
  const prefix = source === "env" ? "GITHUB_GRAPHQL_TOKEN could not be validated" : "gh CLI token could not be validated";
544
- return new GhAuthError("token_failed", `${prefix}: ${error.message}`);
616
+ return new GhAuthError("token_failed", `${prefix}: ${error.message}`, {
617
+ source
618
+ });
545
619
  }
546
620
  if (error instanceof Error) {
547
621
  const prefix = source === "env" ? "GITHUB_GRAPHQL_TOKEN could not be validated" : "gh CLI token could not be validated";
548
- return new GhAuthError("token_failed", `${prefix}: ${error.message}`);
622
+ return new GhAuthError("token_failed", `${prefix}: ${error.message}`, {
623
+ source
624
+ });
549
625
  }
550
626
  return new GhAuthError(
551
627
  "token_failed",
552
- source === "env" ? "GITHUB_GRAPHQL_TOKEN could not be validated." : "gh CLI token could not be validated."
628
+ source === "env" ? "GITHUB_GRAPHQL_TOKEN could not be validated." : "gh CLI token could not be validated.",
629
+ { source }
553
630
  );
554
631
  }
555
632
  function getEnvGitHubToken() {
@@ -651,12 +728,22 @@ async function validateGitHubToken(token, source, opts) {
651
728
  if (source === "env") {
652
729
  throw new GhAuthError(
653
730
  "missing_scopes",
654
- `GITHUB_GRAPHQL_TOKEN is missing required scopes: ${scopeCheck.missing.join(", ")}`
731
+ `GITHUB_GRAPHQL_TOKEN is missing required scopes: ${scopeCheck.missing.join(", ")}`,
732
+ {
733
+ missingScopes: [...scopeCheck.missing],
734
+ currentScopes: viewer.scopes,
735
+ source
736
+ }
655
737
  );
656
738
  }
657
739
  throw new GhAuthError(
658
740
  "missing_scopes",
659
- missingGhScopesMessage(scopeCheck.missing)
741
+ missingGhScopesMessage(scopeCheck.missing),
742
+ {
743
+ missingScopes: [...scopeCheck.missing],
744
+ currentScopes: viewer.scopes,
745
+ source
746
+ }
660
747
  );
661
748
  }
662
749
  return {
@@ -696,21 +783,28 @@ function ensureGhAuth(opts) {
696
783
  if (!checkGhInstalled({ execImpl })) {
697
784
  throw new GhAuthError(
698
785
  "not_installed",
699
- "gh CLI is not installed. Install it from https://cli.github.com or set GITHUB_GRAPHQL_TOKEN."
786
+ "gh CLI is not installed. Install it from https://cli.github.com or set GITHUB_GRAPHQL_TOKEN.",
787
+ { source: "gh" }
700
788
  );
701
789
  }
702
790
  const auth = checkGhAuthenticated({ spawnImpl });
703
791
  if (!auth.authenticated) {
704
792
  throw new GhAuthError(
705
793
  "not_authenticated",
706
- "Run 'gh auth login --scopes repo,read:org,project' or set GITHUB_GRAPHQL_TOKEN."
794
+ "Run 'gh auth login --scopes repo,read:org,project' or set GITHUB_GRAPHQL_TOKEN.",
795
+ { source: "gh" }
707
796
  );
708
797
  }
709
798
  const scopeCheck = checkGhScopes({ spawnImpl });
710
799
  if (!scopeCheck.valid) {
711
800
  throw new GhAuthError(
712
801
  "missing_scopes",
713
- missingGhScopesMessage(scopeCheck.missing)
802
+ missingGhScopesMessage(scopeCheck.missing),
803
+ {
804
+ missingScopes: [...scopeCheck.missing],
805
+ currentScopes: scopeCheck.scopes,
806
+ source: "gh"
807
+ }
714
808
  );
715
809
  }
716
810
  const { token } = getGhTokenWithSource({
@@ -789,6 +883,7 @@ export {
789
883
  getProjectDetail,
790
884
  REQUIRED_GH_SCOPES,
791
885
  GhAuthError,
886
+ formatGhAuthRemediation,
792
887
  getEnvGitHubToken,
793
888
  checkGhInstalled,
794
889
  checkGhAuthenticated,
@@ -5,8 +5,8 @@ import {
5
5
  parseIssueReference,
6
6
  readGitHubProjectBinding,
7
7
  renderIssueWorkflowPreview
8
- } from "./chunk-7Z7WYGDL.js";
9
- import "./chunk-PLBG7TZA.js";
8
+ } from "./chunk-5U36B7FC.js";
9
+ import "./chunk-DTPIJO6S.js";
10
10
  import {
11
11
  fetchGithubProjectIssueByRepositoryAndNumber,
12
12
  fetchGithubProjectIssues,
@@ -31,7 +31,7 @@ import {
31
31
  runGhAuthLogin,
32
32
  runGhAuthRefresh,
33
33
  validateGitHubToken
34
- } from "./chunk-BOM2BYZQ.js";
34
+ } from "./chunk-SMNIGNS3.js";
35
35
  import {
36
36
  isClaudeRuntimeCommand,
37
37
  parseWorkflowMarkdown,
package/dist/index.js CHANGED
@@ -282,7 +282,7 @@ var HELP_SECTIONS = [
282
282
  },
283
283
  {
284
284
  name: "repo start",
285
- description: "Start the orchestrator (foreground)"
285
+ description: "Start the orchestrator after validating tracker authentication"
286
286
  },
287
287
  {
288
288
  name: "repo start --daemon",
@@ -417,13 +417,13 @@ function createRemovedCommandHandler(message) {
417
417
 
418
418
  // src/index.ts
419
419
  var COMMANDS = {
420
- workflow: () => import("./workflow-7Y6GTV2C.js"),
421
- setup: () => import("./setup-KZ3U53PY.js"),
422
- doctor: () => import("./doctor-MD4MD6SZ.js"),
423
- upgrade: () => import("./upgrade-2WPPOUZL.js"),
424
- repo: () => import("./repo-CK2IDMZF.js"),
420
+ workflow: () => import("./workflow-AV676KAP.js"),
421
+ setup: () => import("./setup-T2QENR26.js"),
422
+ doctor: () => import("./doctor-TQR54KNZ.js"),
423
+ upgrade: () => import("./upgrade-7452LZXX.js"),
424
+ repo: () => import("./repo-Y6EF2DZP.js"),
425
425
  config: () => import("./config-cmd-AOZVS6GU.js"),
426
- version: () => import("./version-Z2T42H5M.js")
426
+ version: () => import("./version-D3FB3PXO.js")
427
427
  };
428
428
  function addGlobalOptions(command) {
429
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");
@@ -41,8 +41,14 @@ import {
41
41
  } from "./chunk-RZ3WO7OV.js";
42
42
  import {
43
43
  GhAuthError,
44
- getGhToken
45
- } from "./chunk-BOM2BYZQ.js";
44
+ GitHubApiError,
45
+ GitHubScopeError,
46
+ formatGhAuthRemediation,
47
+ getGhToken,
48
+ resolveGitHubAuth,
49
+ runGhAuthLogin,
50
+ runGhAuthRefresh
51
+ } from "./chunk-SMNIGNS3.js";
46
52
  import {
47
53
  WorkflowConfigStore,
48
54
  deriveIssueWorkspaceKeyFromIdentifier,
@@ -765,6 +771,7 @@ import { writeFile, mkdir, readFile as readFile5, rm } from "fs/promises";
765
771
  import { dirname as dirname2, join as join6 } from "path";
766
772
  import { spawn } from "child_process";
767
773
  import { createServer as createServer3 } from "http";
774
+ import * as p from "@clack/prompts";
768
775
 
769
776
  // ../dashboard/src/store.ts
770
777
  import { open } from "fs/promises";
@@ -1437,6 +1444,149 @@ function logLine(icon, msg) {
1437
1444
  process.stdout.write(`${timestamp()} ${icon} ${msg}
1438
1445
  `);
1439
1446
  }
1447
+ var REPO_START_COMMAND = "gh-symphony repo start";
1448
+ function isInteractiveTerminal() {
1449
+ return process.stdin.isTTY === true && process.stdout.isTTY === true;
1450
+ }
1451
+ function displayGhAuthError(error) {
1452
+ const remediation = formatGhAuthRemediation(error, {
1453
+ retryCommand: REPO_START_COMMAND
1454
+ });
1455
+ process.stderr.write(`${remediation.title}: ${remediation.message}
1456
+ `);
1457
+ process.stderr.write(`${remediation.hint}
1458
+ `);
1459
+ }
1460
+ function formatAuthSource(source) {
1461
+ return source === "env" ? "GITHUB_GRAPHQL_TOKEN" : "gh CLI";
1462
+ }
1463
+ function displayGitHubAuthSuccess(auth) {
1464
+ process.stdout.write(
1465
+ `Authenticated via ${formatAuthSource(auth.source)} as ${auth.login}
1466
+ `
1467
+ );
1468
+ }
1469
+ async function resolveRepoStartGitHubAuth(input) {
1470
+ try {
1471
+ const auth = await resolveGitHubAuth();
1472
+ process.env.GITHUB_GRAPHQL_TOKEN = auth.token;
1473
+ displayGitHubAuthSuccess(auth);
1474
+ return { ok: true, githubAuthSource: auth.source };
1475
+ } catch (error) {
1476
+ if (!(error instanceof GhAuthError)) {
1477
+ throw error;
1478
+ }
1479
+ displayGhAuthError(error);
1480
+ const remediation = formatGhAuthRemediation(error, {
1481
+ retryCommand: REPO_START_COMMAND
1482
+ });
1483
+ const canRemediate = input.allowInteractiveRemediation && isInteractiveTerminal() && remediation.command !== void 0 && error.details.source !== "env";
1484
+ if (!canRemediate) {
1485
+ process.exitCode = 1;
1486
+ return { ok: false };
1487
+ }
1488
+ const shouldRun = await p.confirm({
1489
+ message: `Run '${remediation.command}' now?`,
1490
+ initialValue: true
1491
+ });
1492
+ if (p.isCancel(shouldRun) || shouldRun !== true) {
1493
+ process.exitCode = 1;
1494
+ return { ok: false };
1495
+ }
1496
+ const result = error.code === "missing_scopes" ? runGhAuthRefresh({ interactive: true }) : runGhAuthLogin({ interactive: true });
1497
+ process.stderr.write(`${result.summary}
1498
+ `);
1499
+ if (result.status !== "applied") {
1500
+ process.exitCode = 1;
1501
+ return { ok: false };
1502
+ }
1503
+ try {
1504
+ const auth = await resolveGitHubAuth();
1505
+ process.env.GITHUB_GRAPHQL_TOKEN = auth.token;
1506
+ displayGitHubAuthSuccess(auth);
1507
+ return { ok: true, githubAuthSource: auth.source };
1508
+ } catch (retryError) {
1509
+ if (retryError instanceof GhAuthError) {
1510
+ displayGhAuthError(retryError);
1511
+ process.exitCode = 1;
1512
+ return { ok: false };
1513
+ }
1514
+ throw retryError;
1515
+ }
1516
+ }
1517
+ }
1518
+ async function preflightRepoStartAuth(projectConfig, input) {
1519
+ if (projectConfig.tracker.adapter === "github-project") {
1520
+ return resolveRepoStartGitHubAuth({
1521
+ allowInteractiveRemediation: !input.daemon
1522
+ });
1523
+ }
1524
+ if (projectConfig.tracker.adapter === "linear") {
1525
+ if (process.env.LINEAR_API_KEY?.trim()) {
1526
+ return { ok: true };
1527
+ }
1528
+ process.stderr.write(
1529
+ "Linear authentication is required. Set LINEAR_API_KEY in the environment before running 'gh-symphony repo start'.\n"
1530
+ );
1531
+ process.exitCode = 1;
1532
+ return { ok: false };
1533
+ }
1534
+ return { ok: true };
1535
+ }
1536
+ function isGitHubAuthRuntimeError(error) {
1537
+ if (error instanceof GitHubScopeError) {
1538
+ return true;
1539
+ }
1540
+ if (error instanceof GhAuthError) {
1541
+ return error.code === "missing_scopes" || error.code === "invalid_token";
1542
+ }
1543
+ if (error instanceof GitHubApiError) {
1544
+ return error.status === 401;
1545
+ }
1546
+ if (error instanceof Error) {
1547
+ const maybeStatus = error.status;
1548
+ if (maybeStatus === 401) {
1549
+ return true;
1550
+ }
1551
+ const message = error.message.toLowerCase();
1552
+ return message.includes("missing required github scopes") || message.includes("missing required scopes") || message.includes("missing required scope") || message.includes("missing_scopes") || message.includes("bad credentials") || message.includes("invalid token") || message.includes("authentication failed") || message.includes("status 401") || message.includes("401 unauthorized");
1553
+ }
1554
+ return false;
1555
+ }
1556
+ function ghRuntimeErrorToAuthError(error, source) {
1557
+ if (error instanceof GhAuthError) {
1558
+ return error;
1559
+ }
1560
+ if (error instanceof GitHubScopeError) {
1561
+ return new GhAuthError(
1562
+ "missing_scopes",
1563
+ `GitHub token is missing required scopes: ${error.requiredScopes.join(", ")}`,
1564
+ {
1565
+ missingScopes: [...error.requiredScopes],
1566
+ currentScopes: [...error.currentScopes],
1567
+ source
1568
+ }
1569
+ );
1570
+ }
1571
+ if (error.message.toLowerCase().includes("missing required github scopes") || error.message.toLowerCase().includes("missing required scopes") || error.message.toLowerCase().includes("missing_scopes")) {
1572
+ return new GhAuthError("missing_scopes", error.message, { source });
1573
+ }
1574
+ return new GhAuthError(
1575
+ "invalid_token",
1576
+ error.message || "GitHub token validation failed.",
1577
+ { source }
1578
+ );
1579
+ }
1580
+ function displayRuntimeAuthShutdown(error, source) {
1581
+ const authError = ghRuntimeErrorToAuthError(error, source);
1582
+ displayGhAuthError(authError);
1583
+ process.stderr.write(
1584
+ "Stopping repo start because GitHub authentication can no longer be validated.\n"
1585
+ );
1586
+ }
1587
+ function shouldElevateGitHubAuthRuntimeError(projectConfig, error) {
1588
+ return projectConfig.tracker.adapter === "github-project" && isGitHubAuthRuntimeError(error);
1589
+ }
1440
1590
  var DEFAULT_HTTP_PORT = 4680;
1441
1591
  var HTTP_HOST = "0.0.0.0";
1442
1592
  function parseStartArgs(args) {
@@ -1762,6 +1912,12 @@ var handler5 = async (args, options) => {
1762
1912
  process.exitCode = 2;
1763
1913
  return;
1764
1914
  }
1915
+ const authPreflight = await preflightRepoStartAuth(projectConfig, {
1916
+ daemon: parsed.daemon
1917
+ });
1918
+ if (!authPreflight.ok) {
1919
+ return;
1920
+ }
1765
1921
  if (parsed.daemon) {
1766
1922
  await startDaemon(
1767
1923
  options,
@@ -1773,12 +1929,6 @@ var handler5 = async (args, options) => {
1773
1929
  );
1774
1930
  return;
1775
1931
  }
1776
- if (!process.env.GITHUB_GRAPHQL_TOKEN) {
1777
- try {
1778
- process.env.GITHUB_GRAPHQL_TOKEN = getGhToken();
1779
- } catch {
1780
- }
1781
- }
1782
1932
  let projectLock = null;
1783
1933
  try {
1784
1934
  projectLock = await acquireProjectLock({
@@ -1789,11 +1939,29 @@ var handler5 = async (args, options) => {
1789
1939
  const store = createStore(runtimeRoot);
1790
1940
  let prevSnapshot = null;
1791
1941
  let isFirst = true;
1942
+ let requestShutdown = null;
1943
+ let authShutdownRequested = false;
1792
1944
  const service = new OrchestratorService(store, projectConfig, {
1793
1945
  logLevel,
1794
1946
  assignedOnly: parsed.assignedOnly,
1795
1947
  onTick: async (snapshot) => {
1796
1948
  try {
1949
+ if (authShutdownRequested) {
1950
+ return;
1951
+ }
1952
+ if (projectConfig.tracker.adapter === "github-project" && snapshot.lastError) {
1953
+ const runtimeError = new Error(snapshot.lastError);
1954
+ if (isGitHubAuthRuntimeError(runtimeError)) {
1955
+ authShutdownRequested = true;
1956
+ displayRuntimeAuthShutdown(
1957
+ runtimeError,
1958
+ authPreflight.githubAuthSource
1959
+ );
1960
+ process.exitCode = 1;
1961
+ requestShutdown?.();
1962
+ return;
1963
+ }
1964
+ }
1797
1965
  logTickResult(snapshot, prevSnapshot, isFirst);
1798
1966
  if (!isFirst) {
1799
1967
  const currentRunIds = new Set(
@@ -1813,6 +1981,13 @@ var handler5 = async (args, options) => {
1813
1981
  prevSnapshot = snapshot;
1814
1982
  isFirst = false;
1815
1983
  } catch (error) {
1984
+ if (shouldElevateGitHubAuthRuntimeError(projectConfig, error)) {
1985
+ authShutdownRequested = true;
1986
+ displayRuntimeAuthShutdown(error, authPreflight.githubAuthSource);
1987
+ process.exitCode = 1;
1988
+ requestShutdown?.();
1989
+ return;
1990
+ }
1816
1991
  logLine(
1817
1992
  red("\u2717"),
1818
1993
  red(
@@ -1850,6 +2025,9 @@ var handler5 = async (args, options) => {
1850
2025
  const handleSigterm = () => {
1851
2026
  void shutdown();
1852
2027
  };
2028
+ requestShutdown = () => {
2029
+ void shutdown();
2030
+ };
1853
2031
  process.on("SIGINT", handleSigint);
1854
2032
  process.on("SIGTERM", handleSigterm);
1855
2033
  try {
@@ -1923,6 +2101,13 @@ var handler5 = async (args, options) => {
1923
2101
  if (shuttingDown) {
1924
2102
  break;
1925
2103
  }
2104
+ if (shouldElevateGitHubAuthRuntimeError(projectConfig, error)) {
2105
+ authShutdownRequested = true;
2106
+ displayRuntimeAuthShutdown(error, authPreflight.githubAuthSource);
2107
+ process.exitCode = 1;
2108
+ await shutdown();
2109
+ return;
2110
+ }
1926
2111
  logLine(
1927
2112
  red("\u2717"),
1928
2113
  red(
@@ -1998,7 +2183,7 @@ async function shutdownForegroundOrchestrator(input) {
1998
2183
  `Failed to release project lock: ${error instanceof Error ? error.message : "Unknown error"}`
1999
2184
  );
2000
2185
  }
2001
- return (input.exit ?? process.exit)(0);
2186
+ return (input.exit ?? process.exit)(process.exitCode ?? 0);
2002
2187
  }
2003
2188
  function hasConfiguredRepository(config) {
2004
2189
  return Boolean(config.repository?.owner && config.repository.name);
@@ -12,7 +12,7 @@ import {
12
12
  validateStateMapping,
13
13
  writeEcosystem,
14
14
  writeWorkflowPlan
15
- } from "./chunk-PLBG7TZA.js";
15
+ } from "./chunk-DTPIJO6S.js";
16
16
  import {
17
17
  initRepoRuntime
18
18
  } from "./chunk-DLZ2XHWY.js";
@@ -20,6 +20,7 @@ import "./chunk-RZ3WO7OV.js";
20
20
  import {
21
21
  GhAuthError,
22
22
  GitHubScopeError,
23
+ REQUIRED_GH_SCOPES,
23
24
  checkRequiredScopes,
24
25
  createClient,
25
26
  ensureGhAuth,
@@ -27,14 +28,13 @@ import {
27
28
  getProjectDetail,
28
29
  listUserProjects,
29
30
  validateToken
30
- } from "./chunk-BOM2BYZQ.js";
31
+ } from "./chunk-SMNIGNS3.js";
31
32
  import "./chunk-3SKN5L3I.js";
32
33
  import "./chunk-4ICDSQCJ.js";
33
34
 
34
35
  // src/commands/setup.ts
35
36
  import * as p from "@clack/prompts";
36
37
  import { resolve } from "path";
37
- var KNOWN_REQUIRED_SCOPES = ["repo", "read:org", "project"];
38
38
  function parseSetupFlags(args) {
39
39
  const flags = {
40
40
  nonInteractive: false,
@@ -74,7 +74,7 @@ function displayScopeError(error, retryCommand) {
74
74
  `Token is missing required scope${plural}: ${error.requiredScopes.join(", ")}`
75
75
  );
76
76
  const currentSet = new Set(error.currentScopes.map((s) => s.toLowerCase()));
77
- const scopesToAdd = KNOWN_REQUIRED_SCOPES.filter((s) => !currentSet.has(s));
77
+ const scopesToAdd = REQUIRED_GH_SCOPES.filter((s) => !currentSet.has(s));
78
78
  const scopeArg = scopesToAdd.length > 0 ? scopesToAdd.join(",") : error.requiredScopes.join(",");
79
79
  p.note(
80
80
  `gh auth refresh --scopes ${scopeArg}
@@ -283,11 +283,17 @@ async function runInteractive(flags, _options) {
283
283
  authSpinner.stop("Authentication failed.");
284
284
  if (error instanceof GhAuthError) {
285
285
  if (error.code === "not_installed") {
286
- p.log.error("gh CLI\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. https://cli.github.com \uC5D0\uC11C \uC124\uCE58\uD558\uC138\uC694.");
286
+ p.log.error(
287
+ "gh CLI\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. https://cli.github.com \uC5D0\uC11C \uC124\uCE58\uD558\uC138\uC694."
288
+ );
287
289
  } else if (error.code === "not_authenticated") {
288
- p.log.error("gh auth login --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694.");
290
+ p.log.error(
291
+ "gh auth login --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694."
292
+ );
289
293
  } else if (error.code === "missing_scopes") {
290
- p.log.error("gh auth refresh --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694.");
294
+ p.log.error(
295
+ "gh auth refresh --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694."
296
+ );
291
297
  } else {
292
298
  p.log.error(error.message);
293
299
  }
@@ -409,7 +415,9 @@ async function runInteractive(flags, _options) {
409
415
  repoDir: process.cwd(),
410
416
  workflowFile: workflowPath
411
417
  });
412
- writeSpinner.stop(`Setup saved for ${runtime.repository.owner}/${runtime.repository.name}.`);
418
+ writeSpinner.stop(
419
+ `Setup saved for ${runtime.repository.owner}/${runtime.repository.name}.`
420
+ );
413
421
  } catch (error) {
414
422
  writeSpinner.stop("Setup failed.");
415
423
  p.log.error(error instanceof Error ? error.message : "Unknown error");
@@ -16,8 +16,8 @@ function execFileAsync(file, args, execFileImpl = execFileCallback) {
16
16
  });
17
17
  }
18
18
  function resolveCurrentCliVersion() {
19
- if ("0.2.4".length > 0) {
20
- return "0.2.4";
19
+ if ("0.2.5".length > 0) {
20
+ return "0.2.5";
21
21
  }
22
22
  const pkg = JSON.parse(
23
23
  readFileSync(new URL("../../package.json", import.meta.url), "utf8")
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/commands/version.ts
4
4
  var handler = async (_args, options) => {
5
- const version = "0.2.4";
5
+ const version = "0.2.5";
6
6
  if (options.json) {
7
7
  process.stdout.write(JSON.stringify({ version }) + "\n");
8
8
  } else {
@@ -6,11 +6,11 @@ import {
6
6
  resetWorkflowCommandDependenciesForTest,
7
7
  setWorkflowCommandDependenciesForTest,
8
8
  workflow_default
9
- } from "./chunk-7Z7WYGDL.js";
10
- import "./chunk-PLBG7TZA.js";
9
+ } from "./chunk-5U36B7FC.js";
10
+ import "./chunk-DTPIJO6S.js";
11
11
  import "./chunk-NRABQNAX.js";
12
12
  import "./chunk-FAU72YC2.js";
13
- import "./chunk-BOM2BYZQ.js";
13
+ import "./chunk-SMNIGNS3.js";
14
14
  import "./chunk-3SKN5L3I.js";
15
15
  import "./chunk-4ICDSQCJ.js";
16
16
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gh-symphony/cli",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "license": "MIT",
5
5
  "author": "hojinzs",
6
6
  "description": "Interactive CLI for GitHub Symphony orchestration",
@@ -41,13 +41,13 @@
41
41
  },
42
42
  "devDependencies": {
43
43
  "tsup": "^8.5.1",
44
- "@gh-symphony/control-plane": "0.0.15",
45
44
  "@gh-symphony/core": "0.0.14",
46
- "@gh-symphony/orchestrator": "0.0.14",
47
45
  "@gh-symphony/dashboard": "0.0.14",
46
+ "@gh-symphony/control-plane": "0.0.15",
47
+ "@gh-symphony/orchestrator": "0.0.14",
48
48
  "@gh-symphony/runtime-claude": "0.0.14",
49
- "@gh-symphony/worker": "0.0.14",
50
- "@gh-symphony/tracker-github": "0.0.14"
49
+ "@gh-symphony/tracker-github": "0.0.14",
50
+ "@gh-symphony/worker": "0.0.14"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "tsup",