create-egregore 0.1.1 → 0.3.0
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 +15 -0
- package/lib/api.js +12 -4
- package/lib/setup.js +22 -2
- package/lib/ui.js +27 -1
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -173,12 +173,27 @@ async function setupFlow(api, githubToken, choice) {
|
|
|
173
173
|
const orgName = await ui.prompt(`Organization display name [${choice.login}]:`);
|
|
174
174
|
const name = orgName || choice.login;
|
|
175
175
|
|
|
176
|
+
// Repo picker — show org repos for selection
|
|
177
|
+
let selectedRepos = [];
|
|
178
|
+
try {
|
|
179
|
+
const repoData = await api.getOrgRepos(githubToken, choice.login);
|
|
180
|
+
if (repoData.repos && repoData.repos.length > 0) {
|
|
181
|
+
selectedRepos = await ui.multiSelect(
|
|
182
|
+
"Which repos should Egregore manage?",
|
|
183
|
+
repoData.repos,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
} catch {
|
|
187
|
+
// Non-fatal — continue without repos
|
|
188
|
+
}
|
|
189
|
+
|
|
176
190
|
const s = ui.spinner(`Setting up Egregore for ${ui.bold(name)}...`);
|
|
177
191
|
try {
|
|
178
192
|
const result = await api.setupOrg(githubToken, {
|
|
179
193
|
github_org: choice.login,
|
|
180
194
|
org_name: name,
|
|
181
195
|
is_personal: choice.is_personal || false,
|
|
196
|
+
repos: selectedRepos,
|
|
182
197
|
});
|
|
183
198
|
s.stop("Setup complete on GitHub");
|
|
184
199
|
|
package/lib/api.js
CHANGED
|
@@ -73,17 +73,25 @@ class EgregoreAPI {
|
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
async
|
|
76
|
+
async getOrgRepos(githubToken, org) {
|
|
77
|
+
return request("GET", `${this.base}/api/org/setup/repos?org=${encodeURIComponent(org)}`, {
|
|
78
|
+
headers: { Authorization: `Bearer ${githubToken}` },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async setupOrg(githubToken, { github_org, org_name, is_personal = false, repos = [], instance_name }) {
|
|
83
|
+
const body = { github_org, org_name, is_personal, repos };
|
|
84
|
+
if (instance_name) body.instance_name = instance_name;
|
|
77
85
|
return request("POST", `${this.base}/api/org/setup`, {
|
|
78
86
|
headers: { Authorization: `Bearer ${githubToken}` },
|
|
79
|
-
body
|
|
87
|
+
body,
|
|
80
88
|
});
|
|
81
89
|
}
|
|
82
90
|
|
|
83
|
-
async joinOrg(githubToken, { github_org }) {
|
|
91
|
+
async joinOrg(githubToken, { github_org, repo_name = "egregore-core" }) {
|
|
84
92
|
return request("POST", `${this.base}/api/org/join`, {
|
|
85
93
|
headers: { Authorization: `Bearer ${githubToken}` },
|
|
86
|
-
body: { github_org },
|
|
94
|
+
body: { github_org, repo_name },
|
|
87
95
|
});
|
|
88
96
|
}
|
|
89
97
|
|
package/lib/setup.js
CHANGED
|
@@ -20,7 +20,7 @@ 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 } = data;
|
|
23
|
+
const { fork_url, memory_url, github_token, org_name, github_org, slug, api_key, repos = [] } = data;
|
|
24
24
|
const base = targetDir || process.cwd();
|
|
25
25
|
|
|
26
26
|
const dirSlug = (github_org || slug || "egregore").toLowerCase();
|
|
@@ -31,7 +31,7 @@ async function install(data, ui, targetDir) {
|
|
|
31
31
|
.replace(/\.git$/, "");
|
|
32
32
|
const memoryDir = path.join(base, memoryDirName);
|
|
33
33
|
|
|
34
|
-
const totalSteps = 5;
|
|
34
|
+
const totalSteps = 5 + repos.length;
|
|
35
35
|
|
|
36
36
|
// Configure git credential helper for HTTPS cloning
|
|
37
37
|
configureGitCredentials(github_token);
|
|
@@ -80,6 +80,23 @@ async function install(data, ui, targetDir) {
|
|
|
80
80
|
registerInstance(dirSlug, org_name, egregoreDir);
|
|
81
81
|
installShellAlias(egregoreDir, ui);
|
|
82
82
|
|
|
83
|
+
// 6+. Clone managed repos (if any)
|
|
84
|
+
const clonedRepos = [];
|
|
85
|
+
for (let i = 0; i < repos.length; i++) {
|
|
86
|
+
const repoName = repos[i];
|
|
87
|
+
ui.step(6 + i, totalSteps, `Cloning ${repoName}...`);
|
|
88
|
+
const repoDir = path.join(base, repoName);
|
|
89
|
+
if (fs.existsSync(repoDir)) {
|
|
90
|
+
ui.warn(`${repoName}/ already exists — pulling latest`);
|
|
91
|
+
run("git pull", { cwd: repoDir });
|
|
92
|
+
} else {
|
|
93
|
+
const repoUrl = `https://github.com/${github_org}/${repoName}.git`;
|
|
94
|
+
execFileSync("git", ["clone", repoUrl, repoDir], { stdio: "pipe", encoding: "utf-8", timeout: 60000 });
|
|
95
|
+
}
|
|
96
|
+
clonedRepos.push(repoName);
|
|
97
|
+
ui.success(`Cloned ${repoName}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
83
100
|
// Done
|
|
84
101
|
console.log("");
|
|
85
102
|
ui.success(`Egregore is ready for ${ui.bold(org_name)}`);
|
|
@@ -87,6 +104,9 @@ async function install(data, ui, targetDir) {
|
|
|
87
104
|
ui.info(`Your workspace:`);
|
|
88
105
|
ui.info(` ${ui.cyan(`./egregore-${dirSlug}/`)} — Your Egregore instance`);
|
|
89
106
|
ui.info(` ${ui.cyan(`./${memoryDirName}/`)} — Shared knowledge`);
|
|
107
|
+
for (const repoName of clonedRepos) {
|
|
108
|
+
ui.info(` ${ui.cyan(`./${repoName}/`)} — Managed repo`);
|
|
109
|
+
}
|
|
90
110
|
console.log("");
|
|
91
111
|
ui.info(`Next: type ${ui.bold("egregore")} in any terminal to start.`);
|
|
92
112
|
console.log("");
|
package/lib/ui.js
CHANGED
|
@@ -111,7 +111,33 @@ async function choose(question, options) {
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
// Prompt with multi-select (comma-separated numbers, or Enter to skip)
|
|
115
|
+
async function multiSelect(question, options) {
|
|
116
|
+
if (options.length === 0) return [];
|
|
117
|
+
console.log(`\n ${question}\n`);
|
|
118
|
+
for (let i = 0; i < options.length; i++) {
|
|
119
|
+
const { name, language, description } = options[i];
|
|
120
|
+
const lang = language ? `${DIM}(${language})${RESET} ` : "";
|
|
121
|
+
const desc = description ? `${DIM}— ${description}${RESET}` : "";
|
|
122
|
+
console.log(` ${BOLD}${i + 1}.${RESET} ${name} ${lang}${desc}`);
|
|
123
|
+
}
|
|
124
|
+
console.log(`\n ${DIM}Enter numbers (e.g. 1,3,5), 'all', or press Enter to skip${RESET}`);
|
|
125
|
+
|
|
126
|
+
const answer = await prompt("Repos:");
|
|
127
|
+
if (!answer) return [];
|
|
128
|
+
if (answer.toLowerCase() === "all") return options.map((o) => o.name);
|
|
129
|
+
|
|
130
|
+
const selected = [];
|
|
131
|
+
for (const part of answer.split(",")) {
|
|
132
|
+
const n = parseInt(part.trim(), 10);
|
|
133
|
+
if (n >= 1 && n <= options.length) {
|
|
134
|
+
selected.push(options[n - 1].name);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return selected;
|
|
138
|
+
}
|
|
139
|
+
|
|
114
140
|
module.exports = {
|
|
115
141
|
banner, info, success, warn, error, step, dim, bold, cyan,
|
|
116
|
-
spinner, prompt, choose,
|
|
142
|
+
spinner, prompt, choose, multiSelect,
|
|
117
143
|
};
|