@gh-symphony/cli 0.0.18 → 0.0.19

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.
@@ -3,38 +3,33 @@ import {
3
3
  abortIfCancelled,
4
4
  generateProjectId,
5
5
  writeConfig
6
- } from "./chunk-5YLETHMR.js";
6
+ } from "./chunk-RN2PACNV.js";
7
7
  import {
8
+ start_default
9
+ } from "./chunk-GKENCODJ.js";
10
+ import {
11
+ GhAuthError,
8
12
  GitHubScopeError,
9
13
  checkRequiredScopes,
10
14
  createClient,
15
+ getGhTokenWithSource,
11
16
  getProjectDetail,
12
17
  listUserProjects,
18
+ resolveGitHubAuth,
13
19
  validateToken
14
- } from "./chunk-62L6QQE6.js";
15
- import {
16
- start_default
17
- } from "./chunk-ZYYY55WB.js";
18
- import {
19
- GhAuthError,
20
- ensureGhAuth,
21
- getGhToken
22
- } from "./chunk-7UBUBSMH.js";
23
- import {
24
- stop_default
25
- } from "./chunk-Y6TYJMNT.js";
20
+ } from "./chunk-TILHWBP6.js";
26
21
  import {
27
22
  status_default
28
23
  } from "./chunk-XN5ABWZ6.js";
29
24
  import {
30
25
  stripAnsi
31
26
  } from "./chunk-MVRF7BES.js";
32
- import "./chunk-LZE6YUSB.js";
33
- import "./chunk-OL73UN2X.js";
34
27
  import {
35
28
  resolveRuntimeRoot
36
29
  } from "./chunk-5NV3LSAJ.js";
37
- import "./chunk-C7G7RJ4G.js";
30
+ import {
31
+ stop_default
32
+ } from "./chunk-Y6TYJMNT.js";
38
33
  import {
39
34
  daemonPidPath,
40
35
  httpStatusPath,
@@ -68,7 +63,7 @@ Then re-run: ${retryCommand}`,
68
63
  );
69
64
  }
70
65
  function parseProjectAddFlags(args) {
71
- const flags = { nonInteractive: false, assignedOnly: false };
66
+ const flags = { nonInteractive: false };
72
67
  for (let i = 0; i < args.length; i += 1) {
73
68
  const arg = args[i];
74
69
  const next = args[i + 1];
@@ -308,12 +303,12 @@ async function projectAdd(args, options) {
308
303
  await projectAddNonInteractive(flags, options);
309
304
  return;
310
305
  }
311
- await projectAddInteractive(options);
306
+ await projectAddInteractive(flags, options);
312
307
  }
313
308
  async function projectAddNonInteractive(flags, options) {
314
309
  let token;
315
310
  try {
316
- token = getGhToken();
311
+ token = getGhTokenWithSource().token;
317
312
  } catch {
318
313
  process.stderr.write(
319
314
  "Error: GitHub token not found. Run 'gh auth login --scopes repo,read:org,project' or set GITHUB_GRAPHQL_TOKEN.\n"
@@ -381,7 +376,7 @@ async function projectAddNonInteractive(flags, options) {
381
376
  `);
382
377
  }
383
378
  }
384
- async function projectAddInteractive(options) {
379
+ async function projectAddInteractive(flags, options) {
385
380
  p.intro("gh-symphony - Project Setup");
386
381
  const defaultWorkspaceDir = join(options.configDir, "workspaces");
387
382
  const existingConfig = await loadGlobalConfig(options.configDir);
@@ -399,32 +394,19 @@ async function projectAddInteractive(options) {
399
394
  }
400
395
  }
401
396
  const s1 = p.spinner();
402
- s1.start("Checking gh CLI authentication...");
397
+ s1.start("Checking GitHub authentication...");
403
398
  let login;
404
399
  let client;
405
400
  try {
406
- const { login: ghLogin, token } = ensureGhAuth();
407
- login = ghLogin;
408
- client = createClient(token);
409
- s1.stop(`Authenticated as ${login}`);
401
+ const auth = await resolveGitHubAuth();
402
+ const sourceLabel = auth.source === "env" ? "GITHUB_GRAPHQL_TOKEN" : "gh CLI";
403
+ login = auth.login;
404
+ client = createClient(auth.token);
405
+ s1.stop(`Authenticated via ${sourceLabel} as ${login}`);
410
406
  } catch (error) {
411
407
  s1.stop("Authentication failed.");
412
408
  if (error instanceof GhAuthError) {
413
- if (error.code === "not_installed") {
414
- p.log.error(
415
- "gh CLI\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. https://cli.github.com \uC5D0\uC11C \uC124\uCE58\uD558\uC138\uC694."
416
- );
417
- } else if (error.code === "not_authenticated") {
418
- p.log.error(
419
- "gh auth login --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694."
420
- );
421
- } else if (error.code === "missing_scopes") {
422
- p.log.error(
423
- "gh auth refresh --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694."
424
- );
425
- } else {
426
- p.log.error(error.message);
427
- }
409
+ p.log.error(error.message);
428
410
  } else {
429
411
  p.log.error(error instanceof Error ? error.message : "Unknown error");
430
412
  }
@@ -486,10 +468,64 @@ async function projectAddInteractive(options) {
486
468
  process.exitCode = 1;
487
469
  return;
488
470
  }
471
+ const {
472
+ assignedOnly: promptAssignedOnly,
473
+ selectedRepos,
474
+ workspaceDir
475
+ } = await promptProjectRegistrationOptions({
476
+ projectDetail,
477
+ defaultWorkspaceDir,
478
+ assignedOnlyMessage: "Step 2/2 - Only process issues assigned to the authenticated GitHub user?",
479
+ assignedOnlyInitialValue: flags.assignedOnly
480
+ });
481
+ const assignedOnly = flags.assignedOnly || promptAssignedOnly;
482
+ const repoSummary = selectedRepos.length === projectDetail.linkedRepositories.length ? `${selectedRepos.map((repo) => `${repo.owner}/${repo.name}`).join(", ")} (all ${selectedRepos.length} linked)` : `${selectedRepos.map((repo) => `${repo.owner}/${repo.name}`).join(", ")} (${selectedRepos.length} of ${projectDetail.linkedRepositories.length} linked)`;
483
+ p.note(
484
+ renderProjectRegistrationSummary({
485
+ login,
486
+ projectTitle: projectDetail.title,
487
+ repoSummary,
488
+ assignedOnly,
489
+ workspaceDir
490
+ }),
491
+ "Configuration Summary"
492
+ );
493
+ const confirmed = await abortIfCancelled(
494
+ p.confirm({ message: "Apply this configuration?" })
495
+ );
496
+ if (!confirmed) {
497
+ p.cancel("Setup cancelled.");
498
+ process.exitCode = 130;
499
+ return;
500
+ }
501
+ const projectId = generateProjectId(projectDetail.title, projectDetail.id);
502
+ const s6 = p.spinner();
503
+ s6.start("Writing configuration...");
504
+ try {
505
+ await writeConfig(options.configDir, {
506
+ projectId,
507
+ project: projectDetail,
508
+ repos: selectedRepos,
509
+ workspaceDir,
510
+ assignedOnly
511
+ });
512
+ s6.stop("Configuration saved.");
513
+ } catch (error) {
514
+ s6.stop("Failed to write configuration.");
515
+ p.log.error(error instanceof Error ? error.message : "Unknown error");
516
+ process.exitCode = 1;
517
+ return;
518
+ }
519
+ p.outro(
520
+ `Project "${projectId}" created.
521
+ Run 'gh-symphony start' to begin orchestration.`
522
+ );
523
+ }
524
+ async function promptProjectRegistrationOptions(input) {
489
525
  const assignedOnly = await abortIfCancelled(
490
526
  p.confirm({
491
- message: "Step 2/2 - Only process issues assigned to the authenticated GitHub user?",
492
- initialValue: false
527
+ message: input.assignedOnlyMessage ?? "Only process issues assigned to the authenticated GitHub user?",
528
+ initialValue: input.assignedOnlyInitialValue ?? false
493
529
  })
494
530
  );
495
531
  const customizeAdvancedOptions = await abortIfCancelled(
@@ -498,8 +534,8 @@ async function projectAddInteractive(options) {
498
534
  initialValue: false
499
535
  })
500
536
  );
501
- let selectedRepos = projectDetail.linkedRepositories;
502
- let workspaceDir = defaultWorkspaceDir;
537
+ let selectedRepos = input.projectDetail.linkedRepositories;
538
+ let workspaceDir = input.defaultWorkspaceDir;
503
539
  if (customizeAdvancedOptions) {
504
540
  const filterRepositories = await abortIfCancelled(
505
541
  p.confirm({
@@ -511,7 +547,7 @@ async function projectAddInteractive(options) {
511
547
  selectedRepos = await abortIfCancelled(
512
548
  p.multiselect({
513
549
  message: "Select repositories to orchestrate:",
514
- options: projectDetail.linkedRepositories.map((repo) => ({
550
+ options: input.projectDetail.linkedRepositories.map((repo) => ({
515
551
  value: repo,
516
552
  label: `${repo.owner}/${repo.name}`
517
553
  })),
@@ -522,55 +558,28 @@ async function projectAddInteractive(options) {
522
558
  workspaceDir = await abortIfCancelled(
523
559
  p.text({
524
560
  message: "Workspace root directory:",
525
- placeholder: defaultWorkspaceDir,
526
- defaultValue: defaultWorkspaceDir,
561
+ placeholder: input.defaultWorkspaceDir,
562
+ defaultValue: input.defaultWorkspaceDir,
527
563
  validate(value) {
528
564
  return value.trim().length > 0 ? void 0 : "Workspace directory is required.";
529
565
  }
530
566
  })
531
567
  );
532
568
  }
533
- const repoSummary = selectedRepos.length === projectDetail.linkedRepositories.length ? `${selectedRepos.map((repo) => `${repo.owner}/${repo.name}`).join(", ")} (all ${selectedRepos.length} linked)` : `${selectedRepos.map((repo) => `${repo.owner}/${repo.name}`).join(", ")} (${selectedRepos.length} of ${projectDetail.linkedRepositories.length} linked)`;
534
- p.note(
535
- [
536
- `User: ${login}`,
537
- `Project: ${projectDetail.title}`,
538
- `Repos: ${repoSummary}`,
539
- `Assigned: ${assignedOnly ? `Only issues assigned to ${login}` : "All project issues"}`,
540
- `Workspace: ${workspaceDir}`
541
- ].join("\n"),
542
- "Configuration Summary"
543
- );
544
- const confirmed = await abortIfCancelled(
545
- p.confirm({ message: "Apply this configuration?" })
546
- );
547
- if (!confirmed) {
548
- p.cancel("Setup cancelled.");
549
- process.exitCode = 130;
550
- return;
551
- }
552
- const projectId = generateProjectId(projectDetail.title, projectDetail.id);
553
- const s6 = p.spinner();
554
- s6.start("Writing configuration...");
555
- try {
556
- await writeConfig(options.configDir, {
557
- projectId,
558
- project: projectDetail,
559
- repos: selectedRepos,
560
- workspaceDir,
561
- assignedOnly
562
- });
563
- s6.stop("Configuration saved.");
564
- } catch (error) {
565
- s6.stop("Failed to write configuration.");
566
- p.log.error(error instanceof Error ? error.message : "Unknown error");
567
- process.exitCode = 1;
568
- return;
569
- }
570
- p.outro(
571
- `Project "${projectId}" created.
572
- Run 'gh-symphony start' to begin orchestration.`
573
- );
569
+ return {
570
+ assignedOnly,
571
+ selectedRepos,
572
+ workspaceDir
573
+ };
574
+ }
575
+ function renderProjectRegistrationSummary(input) {
576
+ return [
577
+ `User: ${input.login}`,
578
+ `Project: ${input.projectTitle}`,
579
+ `Repos: ${input.repoSummary}`,
580
+ `Assigned: ${input.assignedOnly ? `Only issues assigned to ${input.login}` : "All project issues"}`,
581
+ `Workspace: ${input.workspaceDir}`
582
+ ].join("\n");
574
583
  }
575
584
  async function projectList(options) {
576
585
  const global = await loadGlobalConfig(options.configDir);
@@ -650,7 +659,9 @@ async function projectRemove(args, options) {
650
659
  async function projectSwitch(options) {
651
660
  const global = await loadGlobalConfig(options.configDir);
652
661
  if (!global || global.projects.length === 0) {
653
- process.stderr.write("No projects configured. Run 'gh-symphony init'.\n");
662
+ process.stderr.write(
663
+ "No projects configured. Run 'gh-symphony workflow init'.\n"
664
+ );
654
665
  process.exitCode = 1;
655
666
  return;
656
667
  }
@@ -676,6 +687,9 @@ async function projectSwitch(options) {
676
687
  process.stdout.write(`Switched to project: ${selected}
677
688
  `);
678
689
  }
690
+
679
691
  export {
680
- project_default as default
692
+ project_default,
693
+ promptProjectRegistrationOptions,
694
+ renderProjectRegistrationSummary
681
695
  };