@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.
@@ -11,12 +11,12 @@ import {
11
11
  listUserProjects,
12
12
  resolveGitHubAuth,
13
13
  validateToken
14
- } from "./chunk-SMNIGNS3.js";
14
+ } from "./chunk-FFY5VKNV.js";
15
15
  import {
16
16
  formatClaudePreflightText,
17
17
  resolveClaudeCommandBinary,
18
18
  runClaudePreflight
19
- } from "./chunk-RGCSM2KZ.js";
19
+ } from "./chunk-PKUD2SVX.js";
20
20
 
21
21
  // src/mapping/smart-defaults.ts
22
22
  var ROLE_PATTERNS = [
@@ -93,6 +93,105 @@ function validateStateMapping(mappings) {
93
93
  return { valid: errors.length === 0, errors, warnings };
94
94
  }
95
95
 
96
+ // src/workflow/workflow-runtime.ts
97
+ var CODEX_RUNTIME_TOKENS = ["codex-app-server", "codex"];
98
+ var CLAUDE_RUNTIME_TOKENS = ["claude-print", "claude-code"];
99
+ var DEFAULT_CLAUDE_PRINT_ARGS = [
100
+ "-p",
101
+ "--output-format",
102
+ "stream-json",
103
+ "--input-format",
104
+ "stream-json",
105
+ "--include-partial-messages",
106
+ "--verbose",
107
+ "--permission-mode",
108
+ "bypassPermissions"
109
+ ];
110
+ function normalizeInitRuntime(runtime) {
111
+ if (runtime === "codex") {
112
+ return "codex-app-server";
113
+ }
114
+ if (runtime === "claude-code") {
115
+ return "claude-print";
116
+ }
117
+ return runtime;
118
+ }
119
+ function isSupportedInitRuntime(runtime) {
120
+ const normalized = normalizeInitRuntime(runtime);
121
+ return normalized === "codex-app-server" || normalized === "claude-print";
122
+ }
123
+ function containsRuntimeToken(runtime, tokens) {
124
+ return tokens.some((token) => {
125
+ const escaped = token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
126
+ return new RegExp(`(^|[\\s"'\\\`])${escaped}(?=$|[\\s"'\\\`])`).test(
127
+ runtime
128
+ );
129
+ });
130
+ }
131
+ function isCodexRuntime(runtime) {
132
+ return normalizeInitRuntime(runtime) === "codex-app-server" || containsRuntimeToken(runtime, CODEX_RUNTIME_TOKENS);
133
+ }
134
+ function isClaudeRuntime(runtime) {
135
+ return normalizeInitRuntime(runtime) === "claude-print" || containsRuntimeToken(runtime, CLAUDE_RUNTIME_TOKENS);
136
+ }
137
+ function resolveRuntimeCommand(runtime) {
138
+ const normalized = normalizeInitRuntime(runtime);
139
+ if (normalized === "codex-app-server") {
140
+ return "codex";
141
+ }
142
+ if (normalized === "claude-print") {
143
+ return "claude";
144
+ }
145
+ return runtime;
146
+ }
147
+ function buildRuntimeFrontMatter(runtime) {
148
+ const normalized = normalizeInitRuntime(runtime);
149
+ if (normalized === "codex-app-server") {
150
+ return [
151
+ "runtime:",
152
+ " kind: codex-app-server",
153
+ " command: codex",
154
+ " args:",
155
+ " - app-server",
156
+ " isolation:",
157
+ " bare: false",
158
+ " strict_mcp_config: false",
159
+ " timeouts:",
160
+ " read_timeout_ms: 5000",
161
+ " turn_timeout_ms: 3600000",
162
+ " stall_timeout_ms: 300000"
163
+ ];
164
+ }
165
+ if (normalized === "claude-print") {
166
+ return [
167
+ "runtime:",
168
+ " kind: claude-print",
169
+ " command: claude",
170
+ " args:",
171
+ ...DEFAULT_CLAUDE_PRINT_ARGS.map((arg) => ` - ${arg}`),
172
+ " isolation:",
173
+ " bare: false",
174
+ " strict_mcp_config: false",
175
+ " timeouts:",
176
+ " read_timeout_ms: 5000",
177
+ " turn_timeout_ms: 3600000",
178
+ " stall_timeout_ms: 900000"
179
+ ];
180
+ }
181
+ return [
182
+ "runtime:",
183
+ " kind: custom",
184
+ ` command: ${runtime}`,
185
+ " isolation:",
186
+ " bare: false",
187
+ " strict_mcp_config: false",
188
+ " timeouts:",
189
+ " read_timeout_ms: 5000",
190
+ " turn_timeout_ms: 3600000",
191
+ " stall_timeout_ms: 300000"
192
+ ];
193
+ }
194
+
96
195
  // src/commands/workflow-init.ts
97
196
  import * as p from "@clack/prompts";
98
197
  import { spawnSync } from "child_process";
@@ -215,105 +314,6 @@ function buildRepositoryValidationGuidance(input) {
215
314
  return lines;
216
315
  }
217
316
 
218
- // src/workflow/workflow-runtime.ts
219
- var CODEX_RUNTIME_TOKENS = ["codex-app-server", "codex"];
220
- var CLAUDE_RUNTIME_TOKENS = ["claude-print", "claude-code"];
221
- var DEFAULT_CLAUDE_PRINT_ARGS = [
222
- "-p",
223
- "--output-format",
224
- "stream-json",
225
- "--input-format",
226
- "stream-json",
227
- "--include-partial-messages",
228
- "--verbose",
229
- "--permission-mode",
230
- "bypassPermissions"
231
- ];
232
- function normalizeInitRuntime(runtime) {
233
- if (runtime === "codex") {
234
- return "codex-app-server";
235
- }
236
- if (runtime === "claude-code") {
237
- return "claude-print";
238
- }
239
- return runtime;
240
- }
241
- function isSupportedInitRuntime(runtime) {
242
- const normalized = normalizeInitRuntime(runtime);
243
- return normalized === "codex-app-server" || normalized === "claude-print";
244
- }
245
- function containsRuntimeToken(runtime, tokens) {
246
- return tokens.some((token) => {
247
- const escaped = token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
248
- return new RegExp(`(^|[\\s"'\\\`])${escaped}(?=$|[\\s"'\\\`])`).test(
249
- runtime
250
- );
251
- });
252
- }
253
- function isCodexRuntime(runtime) {
254
- return normalizeInitRuntime(runtime) === "codex-app-server" || containsRuntimeToken(runtime, CODEX_RUNTIME_TOKENS);
255
- }
256
- function isClaudeRuntime(runtime) {
257
- return normalizeInitRuntime(runtime) === "claude-print" || containsRuntimeToken(runtime, CLAUDE_RUNTIME_TOKENS);
258
- }
259
- function resolveRuntimeCommand(runtime) {
260
- const normalized = normalizeInitRuntime(runtime);
261
- if (normalized === "codex-app-server") {
262
- return "codex";
263
- }
264
- if (normalized === "claude-print") {
265
- return "claude";
266
- }
267
- return runtime;
268
- }
269
- function buildRuntimeFrontMatter(runtime) {
270
- const normalized = normalizeInitRuntime(runtime);
271
- if (normalized === "codex-app-server") {
272
- return [
273
- "runtime:",
274
- " kind: codex-app-server",
275
- " command: codex",
276
- " args:",
277
- " - app-server",
278
- " isolation:",
279
- " bare: false",
280
- " strict_mcp_config: false",
281
- " timeouts:",
282
- " read_timeout_ms: 5000",
283
- " turn_timeout_ms: 3600000",
284
- " stall_timeout_ms: 300000"
285
- ];
286
- }
287
- if (normalized === "claude-print") {
288
- return [
289
- "runtime:",
290
- " kind: claude-print",
291
- " command: claude",
292
- " args:",
293
- ...DEFAULT_CLAUDE_PRINT_ARGS.map((arg) => ` - ${arg}`),
294
- " isolation:",
295
- " bare: false",
296
- " strict_mcp_config: false",
297
- " timeouts:",
298
- " read_timeout_ms: 5000",
299
- " turn_timeout_ms: 3600000",
300
- " stall_timeout_ms: 900000"
301
- ];
302
- }
303
- return [
304
- "runtime:",
305
- " kind: custom",
306
- ` command: ${runtime}`,
307
- " isolation:",
308
- " bare: false",
309
- " strict_mcp_config: false",
310
- " timeouts:",
311
- " read_timeout_ms: 5000",
312
- " turn_timeout_ms: 3600000",
313
- " stall_timeout_ms: 300000"
314
- ];
315
- }
316
-
317
317
  // src/workflow/generate-workflow-md.ts
318
318
  function generateWorkflowMarkdown(input) {
319
319
  const frontMatter = buildFrontMatter(input);
@@ -3537,6 +3537,9 @@ async function runInteractiveStandalone(flags, _options) {
3537
3537
  export {
3538
3538
  toWorkflowLifecycleConfig,
3539
3539
  validateStateMapping,
3540
+ normalizeInitRuntime,
3541
+ isSupportedInitRuntime,
3542
+ resolveRuntimeCommand,
3540
3543
  abortIfCancelled,
3541
3544
  warnDeprecatedSkipContext,
3542
3545
  workflow_init_default,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-3IRPSPAF.js";
5
5
  import {
6
6
  parseWorkflowMarkdown
7
- } from "./chunk-RGCSM2KZ.js";
7
+ } from "./chunk-77H5ED5L.js";
8
8
  import {
9
9
  saveGlobalConfig,
10
10
  saveProjectConfig
@@ -25,6 +25,14 @@ import { basename, dirname, join, resolve } from "path";
25
25
  var INTERNAL_PROJECT_ID = "repository";
26
26
  var RepoRuntimeMigrationError = class extends Error {
27
27
  };
28
+ var MissingWorkflowFileError = class extends Error {
29
+ constructor(workflowPath) {
30
+ super(
31
+ `WORKFLOW.md was not found at ${workflowPath}. Run 'gh-symphony workflow init' in this repository or add a valid WORKFLOW.md at the repo root.`
32
+ );
33
+ this.workflowPath = workflowPath;
34
+ }
35
+ };
28
36
  function parseRepoRuntimeFlags(args) {
29
37
  const flags = { repoDir: process.cwd() };
30
38
  for (let i = 0; i < args.length; i += 1) {
@@ -57,6 +65,9 @@ async function initRepoRuntime(flags) {
57
65
  const runtimeRoot = resolveRepoRuntimeRoot(repoDir);
58
66
  await migrateLegacyRuntime(runtimeRoot);
59
67
  const workflowPath = resolve(repoDir, flags.workflowFile ?? "WORKFLOW.md");
68
+ if (!await pathExists(workflowPath)) {
69
+ throw new MissingWorkflowFileError(workflowPath);
70
+ }
60
71
  const workflow = parseWorkflowMarkdown(await readFile(workflowPath, "utf8"));
61
72
  validateRepoInitWorkflow(workflow);
62
73
  const repository = resolveRepository(repoDir);
@@ -248,6 +259,7 @@ function isMissing(error) {
248
259
  }
249
260
 
250
261
  export {
262
+ MissingWorkflowFileError,
251
263
  parseRepoRuntimeFlags,
252
264
  initRepoRuntime
253
265
  };
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ writeCliError
4
+ } from "./chunk-MAJOIZ5Q.js";
2
5
  import {
3
6
  DEFAULT_LINEAR_GRAPHQL_URL,
4
7
  DEFAULT_MAX_FAILURE_RETRIES,
@@ -13,6 +16,8 @@ import {
13
16
  deriveIssueWorkspaceKeyFromIdentifier,
14
17
  deriveLegacyIssueWorkspaceKey,
15
18
  executeWorkspaceHook,
19
+ formatErrorForTerminal,
20
+ hasVerboseFlag,
16
21
  isFileMissing,
17
22
  isMatchingIssueRun,
18
23
  isOrchestratorChannelEvent,
@@ -30,7 +35,7 @@ import {
30
35
  resolveWorkflowRuntimeTimeouts,
31
36
  safeReadDir,
32
37
  scheduleRetryAt
33
- } from "./chunk-RGCSM2KZ.js";
38
+ } from "./chunk-77H5ED5L.js";
34
39
  import {
35
40
  loadGlobalConfig,
36
41
  loadProjectConfig
@@ -1470,8 +1475,10 @@ var githubProjectTrackerAdapter = {
1470
1475
  return fetchProjectIssueStatesByIds(project, issueIds, dependencies);
1471
1476
  },
1472
1477
  buildWorkerEnvironment(project) {
1478
+ const apiUrl = project.tracker.apiUrl?.trim();
1473
1479
  return {
1474
- GITHUB_PROJECT_ID: requireTrackerSetting(project.tracker, "projectId")
1480
+ GITHUB_PROJECT_ID: requireTrackerSetting(project.tracker, "projectId"),
1481
+ ...apiUrl ? { GITHUB_GRAPHQL_API_URL: apiUrl } : {}
1475
1482
  };
1476
1483
  },
1477
1484
  reviveIssue(project, run) {
@@ -1564,10 +1571,7 @@ function resolveAssignedOnly(tracker, dependencies) {
1564
1571
  if (dependencies.assignedOnly !== void 0) {
1565
1572
  return dependencies.assignedOnly;
1566
1573
  }
1567
- const legacyAssignedOnly = readBooleanTrackerSetting(
1568
- tracker,
1569
- "assignedOnly"
1570
- );
1574
+ const legacyAssignedOnly = readBooleanTrackerSetting(tracker, "assignedOnly");
1571
1575
  if (legacyAssignedOnly) {
1572
1576
  const warningKey = `${tracker.adapter}:${tracker.bindingId}`;
1573
1577
  if (!warnedLegacyAssignedOnlyProjectIds.has(warningKey)) {
@@ -6462,7 +6466,7 @@ function parseArgs(args) {
6462
6466
  for (let index = 0; index < args.length; index += 1) {
6463
6467
  const argument = args[index];
6464
6468
  const value = args[index + 1];
6465
- if (!argument?.startsWith("--")) {
6469
+ if (!argument?.startsWith("-")) {
6466
6470
  continue;
6467
6471
  }
6468
6472
  switch (argument) {
@@ -6493,6 +6497,10 @@ function parseArgs(args) {
6493
6497
  parsed.logLevel = value;
6494
6498
  index += 1;
6495
6499
  break;
6500
+ case "--verbose":
6501
+ case "-v":
6502
+ parsed.logLevel = "verbose";
6503
+ break;
6496
6504
  default:
6497
6505
  throw new Error(`Unknown option: ${argument}`);
6498
6506
  }
@@ -6508,12 +6516,21 @@ function resolveOptionalPath(value) {
6508
6516
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
6509
6517
  main().catch((error) => {
6510
6518
  process.stderr.write(
6511
- `${error instanceof Error ? error.message : "Unknown error"}
6512
- `
6519
+ formatErrorForTerminal(error, {
6520
+ verbose: hasVerboseOrchestratorDiagnostics(process.argv.slice(2))
6521
+ })
6513
6522
  );
6514
6523
  process.exitCode = 1;
6515
6524
  });
6516
6525
  }
6526
+ function hasVerboseOrchestratorDiagnostics(argv) {
6527
+ if (hasVerboseFlag(argv) || process.env.SYMPHONY_LOG_LEVEL === "verbose") {
6528
+ return true;
6529
+ }
6530
+ return argv.some(
6531
+ (arg, index) => arg === "--log-level" && argv[index + 1] === "verbose"
6532
+ );
6533
+ }
6517
6534
 
6518
6535
  // src/project-selection.ts
6519
6536
  import * as p from "@clack/prompts";
@@ -6614,8 +6631,11 @@ async function resolveManagedProjectConfig(input) {
6614
6631
  return loadProjectConfig(input.configDir, projectIds[0]);
6615
6632
  }
6616
6633
  if (!isInteractiveTerminal()) {
6617
- process.stderr.write(explicitProjectRequiredMessage());
6618
- process.exitCode = 1;
6634
+ writeCliError({
6635
+ code: "missing_repository_runtime_config",
6636
+ message: explicitProjectRequiredMessage().trimEnd(),
6637
+ json: input.json
6638
+ });
6619
6639
  return null;
6620
6640
  }
6621
6641
  const projects = await Promise.all(
@@ -6640,14 +6660,15 @@ async function resolveManagedProjectConfig(input) {
6640
6660
  }
6641
6661
  return loadProjectConfig(input.configDir, selected);
6642
6662
  }
6643
- function handleMissingManagedProjectConfig() {
6663
+ function handleMissingManagedProjectConfig(options) {
6644
6664
  if (process.exitCode) {
6645
6665
  return;
6646
6666
  }
6647
- process.stderr.write(
6648
- "No repository runtime config found. Run 'gh-symphony repo init' first.\n"
6649
- );
6650
- process.exitCode = 1;
6667
+ writeCliError({
6668
+ code: "missing_repository_runtime_config",
6669
+ message: options?.message ?? "No repository runtime config found. Run 'gh-symphony repo init' first.",
6670
+ json: options?.json
6671
+ });
6651
6672
  }
6652
6673
 
6653
6674
  export {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/github/client.ts
4
- var DEFAULT_API_URL = "https://api.github.com/graphql";
4
+ var DEFAULT_GITHUB_GRAPHQL_API_URL = "https://api.github.com/graphql";
5
5
  var REST_API_URL = "https://api.github.com";
6
6
  function findLinkedRepository(project, owner, name) {
7
7
  const normalizedOwner = owner.trim().toLowerCase();
@@ -28,13 +28,35 @@ var GitHubScopeError = class extends GitHubApiError {
28
28
  function createClient(token, options) {
29
29
  return {
30
30
  token,
31
- apiUrl: options?.apiUrl ?? DEFAULT_API_URL,
31
+ apiUrl: options?.apiUrl ?? DEFAULT_GITHUB_GRAPHQL_API_URL,
32
32
  fetchImpl: options?.fetchImpl ?? fetch
33
33
  };
34
34
  }
35
+ function deriveGitHubRestApiUrl(graphqlApiUrl) {
36
+ try {
37
+ const url = new URL(graphqlApiUrl);
38
+ const normalizedPath = url.pathname.replace(/\/+$/, "");
39
+ if (url.hostname.toLowerCase() === "api.github.com") {
40
+ return REST_API_URL;
41
+ }
42
+ if (normalizedPath === "/api/graphql") {
43
+ url.pathname = "/api/v3";
44
+ url.search = "";
45
+ url.hash = "";
46
+ return url.toString().replace(/\/$/, "");
47
+ }
48
+ if (normalizedPath.endsWith("/graphql")) {
49
+ url.pathname = normalizedPath.slice(0, -"/graphql".length) || "/";
50
+ url.search = "";
51
+ url.hash = "";
52
+ return url.toString().replace(/\/$/, "");
53
+ }
54
+ } catch {
55
+ }
56
+ return REST_API_URL;
57
+ }
35
58
  async function listRepositoryLabels(client, owner, name) {
36
- const restUrl = client.apiUrl.replace("/graphql", "");
37
- const baseUrl = restUrl === client.apiUrl ? REST_API_URL : restUrl;
59
+ const baseUrl = deriveGitHubRestApiUrl(client.apiUrl);
38
60
  const labels = [];
39
61
  let page = 1;
40
62
  while (true) {
@@ -75,8 +97,7 @@ async function listRepositoryLabels(client, owner, name) {
75
97
  return labels;
76
98
  }
77
99
  async function validateToken(client) {
78
- const restUrl = client.apiUrl.replace("/graphql", "");
79
- const baseUrl = restUrl === client.apiUrl ? REST_API_URL : restUrl;
100
+ const baseUrl = deriveGitHubRestApiUrl(client.apiUrl);
80
101
  const response = await client.fetchImpl(`${baseUrl}/user`, {
81
102
  headers: {
82
103
  authorization: `Bearer ${client.token}`,
@@ -646,12 +667,20 @@ function checkGhInstalled(opts) {
646
667
  throw error;
647
668
  }
648
669
  }
670
+ function ghAuthHostArgs(hostname) {
671
+ const trimmed = hostname?.trim();
672
+ return trimmed ? ["--hostname", trimmed] : [];
673
+ }
649
674
  function checkGhAuthenticated(opts) {
650
675
  const spawnImpl = opts?.spawnImpl ?? spawnSync;
651
- const result = spawnImpl("gh", ["auth", "status"], {
652
- encoding: "utf8",
653
- stdio: ["pipe", "pipe", "pipe"]
654
- });
676
+ const result = spawnImpl(
677
+ "gh",
678
+ ["auth", "status", ...ghAuthHostArgs(opts?.hostname)],
679
+ {
680
+ encoding: "utf8",
681
+ stdio: ["pipe", "pipe", "pipe"]
682
+ }
683
+ );
655
684
  if ((result.status ?? 1) !== 0) {
656
685
  return { authenticated: false };
657
686
  }
@@ -660,10 +689,14 @@ function checkGhAuthenticated(opts) {
660
689
  }
661
690
  function checkGhScopes(opts) {
662
691
  const spawnImpl = opts?.spawnImpl ?? spawnSync;
663
- const result = spawnImpl("gh", ["auth", "status"], {
664
- encoding: "utf8",
665
- stdio: ["pipe", "pipe", "pipe"]
666
- });
692
+ const result = spawnImpl(
693
+ "gh",
694
+ ["auth", "status", ...ghAuthHostArgs(opts?.hostname)],
695
+ {
696
+ encoding: "utf8",
697
+ stdio: ["pipe", "pipe", "pipe"]
698
+ }
699
+ );
667
700
  const output = (result.stdout ?? "").toString();
668
701
  const scopes = parseScopes(output);
669
702
  if (scopes.length === 0) {
@@ -686,7 +719,8 @@ function getGhToken(opts) {
686
719
  }
687
720
  return getGhTokenWithSource({
688
721
  execImpl: opts?.execImpl,
689
- envToken: void 0
722
+ envToken: void 0,
723
+ hostname: opts?.hostname
690
724
  }).token;
691
725
  }
692
726
  function getGhTokenWithSource(opts) {
@@ -697,10 +731,14 @@ function getGhTokenWithSource(opts) {
697
731
  }
698
732
  const execImpl = opts?.execImpl ?? execFileSync;
699
733
  try {
700
- const token = execImpl("gh", ["auth", "token"], {
701
- encoding: "utf8",
702
- stdio: ["pipe", "pipe", "pipe"]
703
- }).toString().trim();
734
+ const token = execImpl(
735
+ "gh",
736
+ ["auth", "token", ...ghAuthHostArgs(opts?.hostname)],
737
+ {
738
+ encoding: "utf8",
739
+ stdio: ["pipe", "pipe", "pipe"]
740
+ }
741
+ ).toString().trim();
704
742
  if (!token) {
705
743
  throw new GhAuthError("token_failed", ghTokenReadErrorMessage());
706
744
  }
@@ -718,7 +756,9 @@ async function validateGitHubToken(token, source, opts) {
718
756
  const checkRequiredScopesImpl = opts?.checkRequiredScopesImpl ?? checkRequiredScopes;
719
757
  let viewer;
720
758
  try {
721
- const client = createClientImpl(token);
759
+ const client = createClientImpl(token, {
760
+ apiUrl: opts?.apiUrl
761
+ });
722
762
  viewer = await validateTokenImpl(client);
723
763
  } catch (error) {
724
764
  throw classifyTokenValidationError(error, source);
@@ -787,7 +827,7 @@ function ensureGhAuth(opts) {
787
827
  { source: "gh" }
788
828
  );
789
829
  }
790
- const auth = checkGhAuthenticated({ spawnImpl });
830
+ const auth = checkGhAuthenticated({ spawnImpl, hostname: opts?.hostname });
791
831
  if (!auth.authenticated) {
792
832
  throw new GhAuthError(
793
833
  "not_authenticated",
@@ -795,7 +835,7 @@ function ensureGhAuth(opts) {
795
835
  { source: "gh" }
796
836
  );
797
837
  }
798
- const scopeCheck = checkGhScopes({ spawnImpl });
838
+ const scopeCheck = checkGhScopes({ spawnImpl, hostname: opts?.hostname });
799
839
  if (!scopeCheck.valid) {
800
840
  throw new GhAuthError(
801
841
  "missing_scopes",
@@ -809,7 +849,8 @@ function ensureGhAuth(opts) {
809
849
  }
810
850
  const { token } = getGhTokenWithSource({
811
851
  execImpl,
812
- envToken: void 0
852
+ envToken: void 0,
853
+ hostname: opts?.hostname
813
854
  });
814
855
  return { login: auth.login ?? "unknown", token, source: "gh" };
815
856
  }
@@ -858,7 +899,7 @@ function runGhAuthRefresh(opts) {
858
899
  }
859
900
  function parseLogin(output) {
860
901
  const matched = output.match(
861
- /Logged in to github\.com account\s+\*?\*?([A-Za-z0-9_-]+)\*?\*?/i
902
+ /Logged in to \S+ account\s+\*?\*?([A-Za-z0-9_-]+)\*?\*?/i
862
903
  );
863
904
  return matched?.[1];
864
905
  }
@@ -871,6 +912,7 @@ function parseScopes(output) {
871
912
  }
872
913
 
873
914
  export {
915
+ DEFAULT_GITHUB_GRAPHQL_API_URL,
874
916
  findLinkedRepository,
875
917
  GitHubApiError,
876
918
  GitHubScopeError,
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/command-exists-on-path.ts
4
+ import { constants } from "fs";
5
+ import { delimiter, isAbsolute, join, resolve } from "path";
6
+ function getCommandCandidates(binary, deps) {
7
+ if (deps.platform !== "win32") {
8
+ return [binary];
9
+ }
10
+ const pathExts = (deps.pathExtEnv ?? ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim()).filter(Boolean);
11
+ const normalizedBinary = binary.toLowerCase();
12
+ if (pathExts.some((ext) => normalizedBinary.endsWith(ext.toLowerCase()))) {
13
+ return [binary];
14
+ }
15
+ return [binary, ...pathExts.map((ext) => `${binary}${ext}`)];
16
+ }
17
+ async function commandExistsOnPath(binary, deps) {
18
+ if (!binary) {
19
+ return false;
20
+ }
21
+ const candidates = getCommandCandidates(binary, deps);
22
+ if (isAbsolute(binary) || binary.includes("/") || binary.includes("\\")) {
23
+ for (const candidate of candidates) {
24
+ try {
25
+ await deps.access(resolve(candidate), constants.X_OK);
26
+ return true;
27
+ } catch {
28
+ continue;
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+ for (const segment of (deps.pathEnv ?? "").split(delimiter)) {
34
+ if (!segment) {
35
+ continue;
36
+ }
37
+ for (const command of candidates) {
38
+ const candidate = join(segment, command);
39
+ try {
40
+ await deps.access(candidate, constants.X_OK);
41
+ return true;
42
+ } catch {
43
+ continue;
44
+ }
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+
50
+ export {
51
+ commandExistsOnPath
52
+ };
@@ -1,16 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- DEFAULT_LINEAR_GRAPHQL_URL,
4
- buildAgentInputRequiredReason,
5
3
  createGitHubGraphQLMcpServerEntry,
6
4
  createLinearGraphQLMcpServerEntry,
5
+ resolveGitHubGraphQLToken
6
+ } from "./chunk-PKUD2SVX.js";
7
+ import {
8
+ DEFAULT_LINEAR_GRAPHQL_URL,
9
+ buildAgentInputRequiredReason,
7
10
  extractEnvForCodex,
8
11
  readAgentCredentialCache,
9
12
  readEnvFile,
10
- resolveGitHubGraphQLToken,
11
13
  shouldReuseAgentCredentialCache,
12
14
  writeAgentCredentialCache
13
- } from "./chunk-RGCSM2KZ.js";
15
+ } from "./chunk-77H5ED5L.js";
14
16
 
15
17
  // ../runtime-codex/src/runtime.ts
16
18
  import { spawn } from "child_process";
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli-error.ts
4
+ function writeCliError(input) {
5
+ const exitCode = input.exitCode ?? 1;
6
+ if (input.json) {
7
+ process.stdout.write(
8
+ JSON.stringify(
9
+ {
10
+ error: {
11
+ code: input.code,
12
+ message: input.message
13
+ }
14
+ },
15
+ null,
16
+ 2
17
+ ) + "\n"
18
+ );
19
+ } else {
20
+ process.stderr.write(`${input.message}
21
+ `);
22
+ if (input.usage) {
23
+ process.stderr.write(`${input.usage}
24
+ `);
25
+ }
26
+ }
27
+ process.exitCode = exitCode;
28
+ }
29
+
30
+ export {
31
+ writeCliError
32
+ };