create-egregore 0.12.0 → 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
@@ -6,7 +6,7 @@
6
6
  const https = require("node:https");
7
7
 
8
8
  const CLIENT_ID = "Iv23li2obNsAjakoK2RE";
9
- const SCOPE = "";
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) => {
package/lib/local.js CHANGED
@@ -22,9 +22,6 @@ const {
22
22
  const TEMPLATE_OWNER = "egregore-labs";
23
23
  const TEMPLATE_REPO = "egregore";
24
24
 
25
- // GitHub App installation URL
26
- const APP_INSTALL_URL = "https://github.com/apps/egregore-labs/installations/new";
27
-
28
25
  // ── GitHub API helpers ──────────────────────────────────────────────
29
26
 
30
27
  async function getUser(token) {
@@ -83,6 +80,17 @@ async function waitForRepo(token, owner, repo, timeoutMs = 30000) {
83
80
  return false;
84
81
  }
85
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
+
86
94
  async function getFileContent(token, owner, repo, filePath) {
87
95
  const { status, data } = await ghApi("GET", `/repos/${owner}/${repo}/contents/${filePath}`, token);
88
96
  if (status !== 200 || !data.content) return null;
@@ -182,15 +190,8 @@ function createSymlink(egregoreDir, memoryDir, ui) {
182
190
  // ── Flow 1: Founder (local mode) ───────────────────────────────────
183
191
 
184
192
  async function localFounderFlow(ui) {
185
- // 1. Install GitHub App — grants Egregore access to the repos the user selects
186
- ui.info("Let's set up Egregore.\n");
187
- ui.info("First, install the Egregore app on your GitHub account.");
188
- ui.info("You'll choose exactly which repos to share.\n");
189
- openBrowser(APP_INSTALL_URL);
190
- await ui.prompt("Press Enter when done...");
191
-
192
- // 2. GitHub auth (auto-approved — user just authorized during App install)
193
- ui.info("");
193
+ // 1. GitHub auth
194
+ ui.info("Let's set up Egregore. First, sign in with GitHub.\n");
194
195
  let githubToken;
195
196
  try {
196
197
  githubToken = await deviceFlow(ui);
@@ -571,40 +572,43 @@ async function localJoinFlow(orgArg, ui) {
571
572
  // 2. Get user info
572
573
  const user = await getUser(githubToken);
573
574
 
574
- // 3. Accept pending invitations
575
+ // 3. Accept pending invitations (may silently fail with GitHub App tokens)
575
576
  console.log("");
576
577
  const s1 = ui.spinner("Checking for invitations...");
577
578
  await acceptPendingInvitations(githubToken, orgLogin, ui);
578
579
  s1.stop("Checked invitations");
579
580
 
580
581
  // 4. Find egregore repo
581
- const s2 = ui.spinner(`Looking for egregore in ${orgLogin}...`);
582
- let repoName = null;
583
- if (explicitRepo) {
584
- // User specified org/repo — use it directly
585
- if (await repoExists(githubToken, orgLogin, explicitRepo)) {
586
- repoName = explicitRepo;
587
- }
588
- } else {
589
- // Search for known repo names
590
- for (const candidate of ["egregore", "egregore-core"]) {
591
- if (await repoExists(githubToken, orgLogin, candidate)) {
592
- repoName = candidate;
593
- break;
594
- }
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);
595
598
  }
596
- }
597
- if (!repoName) {
598
- 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}`);
599
602
  ui.error("Make sure the org admin has set up Egregore and invited you.");
600
603
  ui.info("If the repo has a custom name, use: npx create-egregore join <org>/<repo>");
601
604
  process.exit(1);
602
605
  }
603
606
 
604
607
  // 5. Read egregore.json from remote
608
+ const s3 = ui.spinner(`Reading config from ${orgLogin}/${repoName}...`);
605
609
  const configRaw = await getFileContent(githubToken, orgLogin, repoName, "egregore.json");
606
610
  if (!configRaw) {
607
- s2.fail("Could not read egregore.json");
611
+ s3.fail("Could not read egregore.json");
608
612
  ui.error("The egregore repo exists but has no egregore.json. Ask the admin to set up first.");
609
613
  process.exit(1);
610
614
  }
@@ -612,10 +616,10 @@ async function localJoinFlow(orgArg, ui) {
612
616
  try {
613
617
  config = JSON.parse(configRaw);
614
618
  } catch {
615
- s2.fail("Invalid egregore.json");
619
+ s3.fail("Invalid egregore.json");
616
620
  process.exit(1);
617
621
  }
618
- s2.stop(`Found ${ui.bold(config.org_name || orgLogin)}`);
622
+ s3.stop(`Found ${ui.bold(config.org_name || orgLogin)}`);
619
623
 
620
624
  const orgName = config.org_name || orgLogin;
621
625
  const memoryRepoName = config.memory_repo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-egregore",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Set up Egregore for your team in one command",
5
5
  "license": "MIT",
6
6
  "bin": {