create-egregore 0.3.9 → 0.3.11
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/bin/cli.js +35 -9
- package/lib/setup.js +47 -8
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -117,13 +117,22 @@ async function interactiveFlow(api) {
|
|
|
117
117
|
// 3. Build choices
|
|
118
118
|
const choices = [];
|
|
119
119
|
|
|
120
|
-
// Orgs with egregore → join
|
|
120
|
+
// Orgs with egregore → show each instance to join + option to set up another
|
|
121
121
|
for (const org of orgsData.orgs) {
|
|
122
122
|
if (org.has_egregore) {
|
|
123
|
+
for (const inst of org.instances || []) {
|
|
124
|
+
choices.push({
|
|
125
|
+
label: `${org.name || org.login} — ${inst.org_name || inst.repo_name}`,
|
|
126
|
+
description: "Join existing",
|
|
127
|
+
action: "join",
|
|
128
|
+
login: org.login,
|
|
129
|
+
repo_name: inst.repo_name,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
123
132
|
choices.push({
|
|
124
|
-
label: org.name || org.login
|
|
125
|
-
description: "
|
|
126
|
-
action: "
|
|
133
|
+
label: `${org.name || org.login} — new instance`,
|
|
134
|
+
description: "Set up another",
|
|
135
|
+
action: "setup",
|
|
127
136
|
login: org.login,
|
|
128
137
|
});
|
|
129
138
|
}
|
|
@@ -141,13 +150,23 @@ async function interactiveFlow(api) {
|
|
|
141
150
|
}
|
|
142
151
|
}
|
|
143
152
|
|
|
144
|
-
// Personal account
|
|
153
|
+
// Personal account — show join for each existing instance + setup for new
|
|
145
154
|
if (orgsData.personal.has_egregore) {
|
|
155
|
+
for (const inst of orgsData.personal.instances || []) {
|
|
156
|
+
choices.push({
|
|
157
|
+
label: `${orgsData.user.login} (personal) — ${inst.org_name || inst.repo_name}`,
|
|
158
|
+
description: "Join existing",
|
|
159
|
+
action: "join",
|
|
160
|
+
login: orgsData.user.login,
|
|
161
|
+
repo_name: inst.repo_name,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
146
164
|
choices.push({
|
|
147
|
-
label: `${orgsData.user.login} (personal)`,
|
|
148
|
-
description: "
|
|
149
|
-
action: "
|
|
165
|
+
label: `${orgsData.user.login} (personal) — new instance`,
|
|
166
|
+
description: "Set up another",
|
|
167
|
+
action: "setup",
|
|
150
168
|
login: orgsData.user.login,
|
|
169
|
+
is_personal: true,
|
|
151
170
|
});
|
|
152
171
|
} else {
|
|
153
172
|
choices.push({
|
|
@@ -180,6 +199,10 @@ async function setupFlow(api, githubToken, choice) {
|
|
|
180
199
|
const orgName = await ui.prompt(`Organization display name [${choice.login}]:`);
|
|
181
200
|
const name = orgName || choice.login;
|
|
182
201
|
|
|
202
|
+
// Instance name — determines repo names (egregore-{instance}, {instance}-memory)
|
|
203
|
+
const instanceInput = await ui.prompt(`Instance name (e.g. "ops", "research") [leave blank for default]:`);
|
|
204
|
+
const instanceName = instanceInput || undefined;
|
|
205
|
+
|
|
183
206
|
// Repo picker — show org repos for selection
|
|
184
207
|
let selectedRepos = [];
|
|
185
208
|
try {
|
|
@@ -201,6 +224,7 @@ async function setupFlow(api, githubToken, choice) {
|
|
|
201
224
|
org_name: name,
|
|
202
225
|
is_personal: choice.is_personal || false,
|
|
203
226
|
repos: selectedRepos,
|
|
227
|
+
instance_name: instanceName,
|
|
204
228
|
});
|
|
205
229
|
s.stop("Setup complete on GitHub");
|
|
206
230
|
|
|
@@ -220,10 +244,12 @@ async function setupFlow(api, githubToken, choice) {
|
|
|
220
244
|
}
|
|
221
245
|
|
|
222
246
|
async function joinFlow(api, githubToken, choice) {
|
|
223
|
-
const
|
|
247
|
+
const displayName = choice.repo_name ? `${choice.login} (${choice.repo_name})` : choice.login;
|
|
248
|
+
const s = ui.spinner(`Joining ${ui.bold(displayName)}...`);
|
|
224
249
|
try {
|
|
225
250
|
const result = await api.joinOrg(githubToken, {
|
|
226
251
|
github_org: choice.login,
|
|
252
|
+
repo_name: choice.repo_name,
|
|
227
253
|
});
|
|
228
254
|
s.stop("Joined");
|
|
229
255
|
|
package/lib/setup.js
CHANGED
|
@@ -20,11 +20,12 @@ function run(cmd, opts = {}) {
|
|
|
20
20
|
* @param {string} targetDir - where to install (default: cwd)
|
|
21
21
|
*/
|
|
22
22
|
async function install(data, ui, targetDir) {
|
|
23
|
-
const { fork_url, memory_url, github_token, org_name, github_org, slug, api_key, repos = [], telegram_group_link } = data;
|
|
23
|
+
const { fork_url, memory_url, github_token, org_name, github_org, slug, api_key, repos = [], telegram_group_link, github_username, github_name } = data;
|
|
24
24
|
const base = targetDir || process.cwd();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const
|
|
26
|
+
// Directory name from fork URL (what git clone would use), e.g. "egregore-core"
|
|
27
|
+
const forkDirName = fork_url.split("/").pop().replace(/\.git$/, "");
|
|
28
|
+
const egregoreDir = path.join(base, forkDirName);
|
|
28
29
|
const memoryDirName = memory_url
|
|
29
30
|
.split("/")
|
|
30
31
|
.pop()
|
|
@@ -36,23 +37,39 @@ async function install(data, ui, targetDir) {
|
|
|
36
37
|
// Configure git credential helper for HTTPS cloning
|
|
37
38
|
configureGitCredentials(github_token);
|
|
38
39
|
|
|
40
|
+
// Embed token in URLs as fallback for private repos (credential helper may not work)
|
|
41
|
+
const authedForkUrl = embedToken(fork_url, github_token);
|
|
42
|
+
const authedMemoryUrl = embedToken(memory_url, github_token);
|
|
43
|
+
|
|
39
44
|
// 1. Clone fork
|
|
40
45
|
ui.step(1, totalSteps, "Cloning egregore...");
|
|
41
46
|
if (fs.existsSync(egregoreDir)) {
|
|
42
47
|
ui.warn("egregore/ already exists — pulling latest");
|
|
43
48
|
run("git pull", { cwd: egregoreDir });
|
|
44
49
|
} else {
|
|
45
|
-
execFileSync("git", ["clone",
|
|
50
|
+
execFileSync("git", ["clone", authedForkUrl, egregoreDir], { stdio: "pipe", encoding: "utf-8", timeout: 60000 });
|
|
51
|
+
try { run(`git remote set-url origin ${fork_url}`, { cwd: egregoreDir }); } catch {}
|
|
46
52
|
}
|
|
47
53
|
ui.success("Cloned egregore");
|
|
48
54
|
|
|
55
|
+
// Set repo-local git identity from GitHub user (not machine-global config)
|
|
56
|
+
if (github_username) {
|
|
57
|
+
try {
|
|
58
|
+
run(`git config user.name "${github_name || github_username}"`, { cwd: egregoreDir });
|
|
59
|
+
run(`git config user.email "${github_username}@users.noreply.github.com"`, { cwd: egregoreDir });
|
|
60
|
+
} catch {
|
|
61
|
+
// Non-fatal
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
49
65
|
// 2. Clone memory
|
|
50
66
|
ui.step(2, totalSteps, "Cloning shared memory...");
|
|
51
67
|
if (fs.existsSync(memoryDir)) {
|
|
52
68
|
ui.warn(`${memoryDirName}/ already exists — pulling latest`);
|
|
53
69
|
run("git pull", { cwd: memoryDir });
|
|
54
70
|
} else {
|
|
55
|
-
execFileSync("git", ["clone",
|
|
71
|
+
execFileSync("git", ["clone", authedMemoryUrl, memoryDir], { stdio: "pipe", encoding: "utf-8", timeout: 60000 });
|
|
72
|
+
try { run(`git remote set-url origin ${memory_url}`, { cwd: memoryDir }); } catch {}
|
|
56
73
|
}
|
|
57
74
|
ui.success("Cloned memory");
|
|
58
75
|
|
|
@@ -80,9 +97,22 @@ async function install(data, ui, targetDir) {
|
|
|
80
97
|
fs.writeFileSync(envPath, envLines.join("\n") + "\n", { mode: 0o600 });
|
|
81
98
|
ui.success("Credentials saved");
|
|
82
99
|
|
|
100
|
+
// 4b. Save identity to .egregore-state.json (so session-start.sh knows who this is)
|
|
101
|
+
const statePath = path.join(egregoreDir, ".egregore-state.json");
|
|
102
|
+
let state = {};
|
|
103
|
+
if (fs.existsSync(statePath)) {
|
|
104
|
+
try { state = JSON.parse(fs.readFileSync(statePath, "utf-8")); } catch {}
|
|
105
|
+
}
|
|
106
|
+
if (github_username) {
|
|
107
|
+
state.github_username = github_username;
|
|
108
|
+
state.github_name = github_name || github_username;
|
|
109
|
+
}
|
|
110
|
+
state.onboarding_complete = true;
|
|
111
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n");
|
|
112
|
+
|
|
83
113
|
// 5. Register instance + shell alias
|
|
84
114
|
ui.step(5, totalSteps, "Registering instance...");
|
|
85
|
-
registerInstance(
|
|
115
|
+
registerInstance(forkDirName, org_name, egregoreDir);
|
|
86
116
|
const alias = await installShellAlias(egregoreDir, ui);
|
|
87
117
|
|
|
88
118
|
// 6+. Clone managed repos (if any)
|
|
@@ -96,7 +126,8 @@ async function install(data, ui, targetDir) {
|
|
|
96
126
|
run("git pull", { cwd: repoDir });
|
|
97
127
|
} else {
|
|
98
128
|
const repoUrl = `https://github.com/${github_org}/${repoName}.git`;
|
|
99
|
-
execFileSync("git", ["clone", repoUrl, repoDir], { stdio: "pipe", encoding: "utf-8", timeout: 60000 });
|
|
129
|
+
execFileSync("git", ["clone", embedToken(repoUrl, github_token), repoDir], { stdio: "pipe", encoding: "utf-8", timeout: 60000 });
|
|
130
|
+
try { run(`git remote set-url origin ${repoUrl}`, { cwd: repoDir }); } catch {}
|
|
100
131
|
}
|
|
101
132
|
clonedRepos.push(repoName);
|
|
102
133
|
ui.success(`Cloned ${repoName}`);
|
|
@@ -107,7 +138,7 @@ async function install(data, ui, targetDir) {
|
|
|
107
138
|
ui.success(`Egregore is ready for ${ui.bold(org_name)}`);
|
|
108
139
|
console.log("");
|
|
109
140
|
ui.info(`Your workspace:`);
|
|
110
|
-
ui.info(` ${ui.cyan(
|
|
141
|
+
ui.info(` ${ui.cyan(`./${forkDirName}/`)} — Your Egregore instance`);
|
|
111
142
|
ui.info(` ${ui.cyan(`./${memoryDirName}/`)} — Shared knowledge`);
|
|
112
143
|
for (const repoName of clonedRepos) {
|
|
113
144
|
ui.info(` ${ui.cyan(`./${repoName}/`)} — Managed repo`);
|
|
@@ -122,6 +153,14 @@ async function install(data, ui, targetDir) {
|
|
|
122
153
|
console.log("");
|
|
123
154
|
}
|
|
124
155
|
|
|
156
|
+
function embedToken(url, token) {
|
|
157
|
+
try {
|
|
158
|
+
return url.replace("https://github.com/", `https://x-access-token:${token}@github.com/`);
|
|
159
|
+
} catch {
|
|
160
|
+
return url;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
125
164
|
function configureGitCredentials(token) {
|
|
126
165
|
try {
|
|
127
166
|
run("git config credential.helper store");
|