create-egregore 0.11.1 → 0.12.1

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/lib/auth.js CHANGED
@@ -5,8 +5,8 @@
5
5
 
6
6
  const https = require("node:https");
7
7
 
8
- const CLIENT_ID = "Ov23liYZjJbbbNgnJ9vH";
9
- const SCOPE = "repo,read:org";
8
+ const CLIENT_ID = "Iv23li2obNsAjakoK2RE";
9
+ const SCOPE = ""; // GitHub App — permissions managed via installation, not OAuth scope
10
10
 
11
11
  function post(url, body) {
12
12
  return new Promise((resolve, reject) => {
@@ -135,4 +135,4 @@ async function deviceFlow(ui) {
135
135
  throw new Error("Timed out waiting for authorization (5 minutes)");
136
136
  }
137
137
 
138
- module.exports = { deviceFlow };
138
+ module.exports = { deviceFlow, openBrowser };
package/lib/local.js CHANGED
@@ -6,7 +6,7 @@
6
6
  const fs = require("node:fs");
7
7
  const path = require("node:path");
8
8
  const { execFileSync } = require("node:child_process");
9
- const { deviceFlow } = require("./auth");
9
+ const { deviceFlow, openBrowser } = require("./auth");
10
10
  const {
11
11
  ghApi,
12
12
  acceptPendingInvitations,
@@ -80,6 +80,17 @@ async function waitForRepo(token, owner, repo, timeoutMs = 30000) {
80
80
  return false;
81
81
  }
82
82
 
83
+ async function findEgregoreRepo(token, orgLogin, explicitRepo) {
84
+ if (explicitRepo) {
85
+ if (await repoExists(token, orgLogin, explicitRepo)) return explicitRepo;
86
+ } else {
87
+ for (const candidate of ["egregore", "egregore-core"]) {
88
+ if (await repoExists(token, orgLogin, candidate)) return candidate;
89
+ }
90
+ }
91
+ return null;
92
+ }
93
+
83
94
  async function getFileContent(token, owner, repo, filePath) {
84
95
  const { status, data } = await ghApi("GET", `/repos/${owner}/${repo}/contents/${filePath}`, token);
85
96
  if (status !== 200 || !data.content) return null;
@@ -561,40 +572,43 @@ async function localJoinFlow(orgArg, ui) {
561
572
  // 2. Get user info
562
573
  const user = await getUser(githubToken);
563
574
 
564
- // 3. Accept pending invitations
575
+ // 3. Accept pending invitations (may silently fail with GitHub App tokens)
565
576
  console.log("");
566
577
  const s1 = ui.spinner("Checking for invitations...");
567
578
  await acceptPendingInvitations(githubToken, orgLogin, ui);
568
579
  s1.stop("Checked invitations");
569
580
 
570
581
  // 4. Find egregore repo
571
- const s2 = ui.spinner(`Looking for egregore in ${orgLogin}...`);
572
- let repoName = null;
573
- if (explicitRepo) {
574
- // User specified org/repo — use it directly
575
- if (await repoExists(githubToken, orgLogin, explicitRepo)) {
576
- repoName = explicitRepo;
577
- }
578
- } else {
579
- // Search for known repo names
580
- for (const candidate of ["egregore", "egregore-core"]) {
581
- if (await repoExists(githubToken, orgLogin, candidate)) {
582
- repoName = candidate;
583
- break;
584
- }
582
+ let repoName = await findEgregoreRepo(githubToken, orgLogin, explicitRepo);
583
+
584
+ // 4b. If repo not found, the user likely has a pending invitation that couldn't
585
+ // be accepted automatically. Open the repo page so they can accept with one click.
586
+ if (!repoName && explicitRepo) {
587
+ console.log("");
588
+ ui.info("Accept the repo invitation in your browser.");
589
+ openBrowser(`https://github.com/${orgLogin}/${explicitRepo}`);
590
+ await ui.prompt("Press Enter after accepting...");
591
+
592
+ const s2 = ui.spinner("Retrying...");
593
+ repoName = await findEgregoreRepo(githubToken, orgLogin, explicitRepo);
594
+ if (!repoName) {
595
+ s2.fail(`Still can't access ${orgLogin}/${explicitRepo}`);
596
+ ui.error("Make sure the org admin has set up Egregore and invited you.");
597
+ process.exit(1);
585
598
  }
586
- }
587
- if (!repoName) {
588
- s2.fail(`No egregore repo found in ${orgLogin}${explicitRepo ? `/${explicitRepo}` : ""}`);
599
+ s2.stop("Access confirmed");
600
+ } else if (!repoName) {
601
+ ui.error(`No egregore repo found in ${orgLogin}`);
589
602
  ui.error("Make sure the org admin has set up Egregore and invited you.");
590
603
  ui.info("If the repo has a custom name, use: npx create-egregore join <org>/<repo>");
591
604
  process.exit(1);
592
605
  }
593
606
 
594
607
  // 5. Read egregore.json from remote
608
+ const s3 = ui.spinner(`Reading config from ${orgLogin}/${repoName}...`);
595
609
  const configRaw = await getFileContent(githubToken, orgLogin, repoName, "egregore.json");
596
610
  if (!configRaw) {
597
- s2.fail("Could not read egregore.json");
611
+ s3.fail("Could not read egregore.json");
598
612
  ui.error("The egregore repo exists but has no egregore.json. Ask the admin to set up first.");
599
613
  process.exit(1);
600
614
  }
@@ -602,10 +616,10 @@ async function localJoinFlow(orgArg, ui) {
602
616
  try {
603
617
  config = JSON.parse(configRaw);
604
618
  } catch {
605
- s2.fail("Invalid egregore.json");
619
+ s3.fail("Invalid egregore.json");
606
620
  process.exit(1);
607
621
  }
608
- s2.stop(`Found ${ui.bold(config.org_name || orgLogin)}`);
622
+ s3.stop(`Found ${ui.bold(config.org_name || orgLogin)}`);
609
623
 
610
624
  const orgName = config.org_name || orgLogin;
611
625
  const memoryRepoName = config.memory_repo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-egregore",
3
- "version": "0.11.1",
3
+ "version": "0.12.1",
4
4
  "description": "Set up Egregore for your team in one command",
5
5
  "license": "MIT",
6
6
  "bin": {