create-hq 10.1.0 → 10.7.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/dist/admin-onboarding.d.ts +42 -0
- package/dist/admin-onboarding.d.ts.map +1 -0
- package/dist/admin-onboarding.js +460 -0
- package/dist/admin-onboarding.js.map +1 -0
- package/dist/art.d.ts +17 -0
- package/dist/art.d.ts.map +1 -0
- package/dist/art.js +171 -0
- package/dist/art.js.map +1 -0
- package/dist/auth.d.ts +60 -23
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +219 -116
- package/dist/auth.js.map +1 -1
- package/dist/cloud.d.ts +26 -0
- package/dist/cloud.d.ts.map +1 -0
- package/dist/cloud.js +126 -0
- package/dist/cloud.js.map +1 -0
- package/dist/company-template.d.ts +34 -0
- package/dist/company-template.d.ts.map +1 -0
- package/dist/company-template.js +142 -0
- package/dist/company-template.js.map +1 -0
- package/dist/deps.d.ts +2 -0
- package/dist/deps.d.ts.map +1 -1
- package/dist/deps.js +42 -30
- package/dist/deps.js.map +1 -1
- package/dist/fetch-template.d.ts +2 -2
- package/dist/fetch-template.d.ts.map +1 -1
- package/dist/fetch-template.js +54 -38
- package/dist/fetch-template.js.map +1 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +28 -4
- package/dist/git.js.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/invite-command.d.ts +10 -0
- package/dist/invite-command.d.ts.map +1 -0
- package/dist/invite-command.js +110 -0
- package/dist/invite-command.js.map +1 -0
- package/dist/invite.d.ts +91 -0
- package/dist/invite.d.ts.map +1 -0
- package/dist/invite.js +230 -0
- package/dist/invite.js.map +1 -0
- package/dist/join-flow.d.ts +32 -0
- package/dist/join-flow.d.ts.map +1 -0
- package/dist/join-flow.js +194 -0
- package/dist/join-flow.js.map +1 -0
- package/dist/platform.d.ts +2 -2
- package/dist/platform.d.ts.map +1 -1
- package/dist/platform.js +14 -1
- package/dist/platform.js.map +1 -1
- package/dist/scaffold.d.ts +4 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +152 -41
- package/dist/scaffold.js.map +1 -1
- package/dist/team-setup.d.ts +58 -0
- package/dist/team-setup.d.ts.map +1 -0
- package/dist/team-setup.js +237 -0
- package/dist/team-setup.js.map +1 -0
- package/dist/teams-flow.d.ts +36 -0
- package/dist/teams-flow.d.ts.map +1 -0
- package/dist/teams-flow.js +134 -0
- package/dist/teams-flow.js.map +1 -0
- package/dist/tui.d.ts +8 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +86 -0
- package/dist/tui.js.map +1 -0
- package/dist/ui.d.ts +17 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +45 -0
- package/dist/ui.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin onboarding flow — for users creating a brand new HQ team.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. List user's GitHub orgs (only those where they can create repos)
|
|
6
|
+
* 2. Let user pick an existing org or create a new one (browser hand-off)
|
|
7
|
+
* 3. Verify the HQ App is installed on the chosen org (browser hand-off if not)
|
|
8
|
+
* 4. Prompt for team name (default = org display name)
|
|
9
|
+
* 5. Create the {org}/hq private repo
|
|
10
|
+
* 6. Seed the repo locally with the company template + push
|
|
11
|
+
* 7. Clone the repo into companies/{slug}/ as a nested git
|
|
12
|
+
* 8. Return team metadata for the orientation summary
|
|
13
|
+
*/
|
|
14
|
+
import { type GitHubAuth } from "./auth.js";
|
|
15
|
+
import { type TeamMetadata } from "./company-template.js";
|
|
16
|
+
export interface AdminOnboardingResult {
|
|
17
|
+
team: TeamMetadata;
|
|
18
|
+
/** Local path where the team repo was cloned. */
|
|
19
|
+
companyDir: string;
|
|
20
|
+
/** GitHub HTML URL for the new team repo. */
|
|
21
|
+
repoHtmlUrl: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function slugify(input: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Run the admin onboarding flow.
|
|
26
|
+
*
|
|
27
|
+
* @param auth - Authenticated GitHub user
|
|
28
|
+
* @param hqRoot - Local HQ root directory (where companies/ lives)
|
|
29
|
+
* @param hqVersion - HQ template version (for team metadata)
|
|
30
|
+
*/
|
|
31
|
+
export declare function runAdminOnboarding(auth: GitHubAuth, hqRoot: string, hqVersion: string): Promise<AdminOnboardingResult | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Interactive invite generation for a single member. Prompts for email,
|
|
34
|
+
* sends org invite, generates token, and prints instructions.
|
|
35
|
+
*/
|
|
36
|
+
export declare function generateInviteInteractive(auth: GitHubAuth, meta: TeamMetadata, cloneUrl: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Invite loop — asks "Invite a team member?" and repeats until the admin
|
|
39
|
+
* says no. Used after team creation and from the standalone invite command.
|
|
40
|
+
*/
|
|
41
|
+
export declare function inviteLoop(auth: GitHubAuth, meta: TeamMetadata, cloneUrl: string): Promise<void>;
|
|
42
|
+
//# sourceMappingURL=admin-onboarding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-onboarding.d.ts","sourceRoot":"","sources":["../src/admin-onboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,OAAO,EACL,KAAK,UAAU,EAIhB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiDhF,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,YAAY,CAAC;IACnB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;CACrB;AA+KD,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM7C;AAID;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CA+PvC;AAID;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAqDf;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAaf"}
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin onboarding flow — for users creating a brand new HQ team.
|
|
3
|
+
*
|
|
4
|
+
* Steps:
|
|
5
|
+
* 1. List user's GitHub orgs (only those where they can create repos)
|
|
6
|
+
* 2. Let user pick an existing org or create a new one (browser hand-off)
|
|
7
|
+
* 3. Verify the HQ App is installed on the chosen org (browser hand-off if not)
|
|
8
|
+
* 4. Prompt for team name (default = org display name)
|
|
9
|
+
* 5. Create the {org}/hq private repo
|
|
10
|
+
* 6. Seed the repo locally with the company template + push
|
|
11
|
+
* 7. Clone the repo into companies/{slug}/ as a nested git
|
|
12
|
+
* 8. Return team metadata for the orientation summary
|
|
13
|
+
*/
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import * as path from "path";
|
|
16
|
+
import * as os from "os";
|
|
17
|
+
import * as crypto from "crypto";
|
|
18
|
+
import { execSync } from "child_process";
|
|
19
|
+
import { createInterface } from "readline";
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
import { HQ_GITHUB_APP_SLUG, githubApi, openBrowser, } from "./auth.js";
|
|
22
|
+
import { writeCompanyTemplate } from "./company-template.js";
|
|
23
|
+
import { stepStatus, success, warn, info } from "./ui.js";
|
|
24
|
+
import { encodeInviteToken, printInviteSummary, openInviteEmail, formatInviteMessage, copyToClipboard, sendOrgInviteByEmail, } from "./invite.js";
|
|
25
|
+
// ─── Prompt helpers ─────────────────────────────────────────────────────────
|
|
26
|
+
function prompt(question, defaultVal) {
|
|
27
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
28
|
+
const suffix = defaultVal ? ` (${defaultVal})` : "";
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
rl.question(` ? ${question}${suffix} `, (answer) => {
|
|
31
|
+
rl.close();
|
|
32
|
+
resolve(answer.trim() || defaultVal || "");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function pause(message) {
|
|
37
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
rl.question(` ${message} `, () => {
|
|
40
|
+
rl.close();
|
|
41
|
+
resolve();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// ─── GitHub helpers ─────────────────────────────────────────────────────────
|
|
46
|
+
/**
|
|
47
|
+
* Fetch the orgs the user is an active admin of. Uses
|
|
48
|
+
* /user/memberships/orgs which (unlike /user/orgs) tells us our role.
|
|
49
|
+
*
|
|
50
|
+
* Requires the App's "Organization > Members: Read" permission. If the App
|
|
51
|
+
* isn't permitted, this returns an empty array (and we tell the user to
|
|
52
|
+
* check their App permissions).
|
|
53
|
+
*/
|
|
54
|
+
async function fetchAdminOrgs(auth) {
|
|
55
|
+
try {
|
|
56
|
+
const memberships = await githubApi("/user/memberships/orgs?state=active&per_page=100", auth);
|
|
57
|
+
return memberships
|
|
58
|
+
.filter((m) => m.role === "admin")
|
|
59
|
+
.map((m) => ({
|
|
60
|
+
login: m.organization.login,
|
|
61
|
+
id: m.organization.id,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
// Permission errors come back as 403/404 — surface as empty list, the
|
|
66
|
+
// caller will guide the user to fix App permissions or create an org.
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function fetchInstallations(auth) {
|
|
71
|
+
const data = await githubApi("/user/installations?per_page=100", auth);
|
|
72
|
+
return data.installations ?? [];
|
|
73
|
+
}
|
|
74
|
+
function findHqInstallation(installations, orgLogin) {
|
|
75
|
+
return (installations.find((i) => i.app_slug === HQ_GITHUB_APP_SLUG &&
|
|
76
|
+
i.account?.login?.toLowerCase() === orgLogin.toLowerCase()) ?? null);
|
|
77
|
+
}
|
|
78
|
+
async function createOrgRepo(auth, orgLogin, repoName, description) {
|
|
79
|
+
return githubApi(`/orgs/${orgLogin}/repos`, auth, {
|
|
80
|
+
method: "POST",
|
|
81
|
+
body: JSON.stringify({
|
|
82
|
+
name: repoName,
|
|
83
|
+
private: true,
|
|
84
|
+
description,
|
|
85
|
+
auto_init: false,
|
|
86
|
+
has_issues: true,
|
|
87
|
+
has_projects: false,
|
|
88
|
+
has_wiki: false,
|
|
89
|
+
}),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
async function getExistingRepo(auth, orgLogin, repoName) {
|
|
93
|
+
try {
|
|
94
|
+
return await githubApi(`/repos/${orgLogin}/${repoName}`, auth);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// ─── Git helpers ────────────────────────────────────────────────────────────
|
|
101
|
+
/**
|
|
102
|
+
* Run a git command, embedding the user's GitHub token via a one-shot
|
|
103
|
+
* credential helper so the token never appears in argv or remote URLs.
|
|
104
|
+
*
|
|
105
|
+
* The token is passed via an environment variable to a tiny inline askpass
|
|
106
|
+
* script written to a temp file, which git invokes via GIT_ASKPASS.
|
|
107
|
+
*/
|
|
108
|
+
function runGitWithToken(args, cwd, auth, inputEnv = {}) {
|
|
109
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "create-hq-git-"));
|
|
110
|
+
const isWindows = process.platform === "win32";
|
|
111
|
+
const askpassPath = path.join(tmpDir, isWindows ? "askpass.cmd" : "askpass.sh");
|
|
112
|
+
try {
|
|
113
|
+
if (isWindows) {
|
|
114
|
+
// Windows batch script: stdout the token (for Password) or username
|
|
115
|
+
fs.writeFileSync(askpassPath, `@echo off\nif "%~1"=="" (echo %GIT_TOKEN%) else (echo %GIT_TOKEN%)\n`, "utf-8");
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
fs.writeFileSync(askpassPath, `#!/bin/sh\necho "$GIT_TOKEN"\n`, "utf-8");
|
|
119
|
+
fs.chmodSync(askpassPath, 0o700);
|
|
120
|
+
}
|
|
121
|
+
execSync(`git -c credential.helper= ${args.join(" ")}`, {
|
|
122
|
+
cwd,
|
|
123
|
+
stdio: "pipe",
|
|
124
|
+
env: {
|
|
125
|
+
...process.env,
|
|
126
|
+
...inputEnv,
|
|
127
|
+
GIT_TOKEN: auth.access_token,
|
|
128
|
+
GIT_ASKPASS: askpassPath,
|
|
129
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
130
|
+
// Prevent any system credential helper from caching the token
|
|
131
|
+
GCM_INTERACTIVE: "never",
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
try {
|
|
137
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// ignore
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build an HTTPS URL with the username embedded so git's askpass only
|
|
146
|
+
* needs to provide the password (the token). We use "x-access-token" as
|
|
147
|
+
* the username — GitHub's recommended convention for token auth.
|
|
148
|
+
*/
|
|
149
|
+
function tokenAuthUrl(cloneUrl) {
|
|
150
|
+
const u = new URL(cloneUrl);
|
|
151
|
+
u.username = "x-access-token";
|
|
152
|
+
// Don't put the token in the URL — askpass handles it
|
|
153
|
+
return u.toString();
|
|
154
|
+
}
|
|
155
|
+
// ─── Slug helper ────────────────────────────────────────────────────────────
|
|
156
|
+
export function slugify(input) {
|
|
157
|
+
return input
|
|
158
|
+
.toLowerCase()
|
|
159
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
160
|
+
.replace(/^-+|-+$/g, "")
|
|
161
|
+
.slice(0, 50) || "team";
|
|
162
|
+
}
|
|
163
|
+
// ─── Main flow ──────────────────────────────────────────────────────────────
|
|
164
|
+
/**
|
|
165
|
+
* Run the admin onboarding flow.
|
|
166
|
+
*
|
|
167
|
+
* @param auth - Authenticated GitHub user
|
|
168
|
+
* @param hqRoot - Local HQ root directory (where companies/ lives)
|
|
169
|
+
* @param hqVersion - HQ template version (for team metadata)
|
|
170
|
+
*/
|
|
171
|
+
export async function runAdminOnboarding(auth, hqRoot, hqVersion) {
|
|
172
|
+
console.log();
|
|
173
|
+
console.log(chalk.bold(" Create a new HQ team"));
|
|
174
|
+
console.log();
|
|
175
|
+
// 1. Fetch admin orgs
|
|
176
|
+
const orgsLabel = "Looking up your GitHub organizations";
|
|
177
|
+
stepStatus(orgsLabel, "running");
|
|
178
|
+
let orgs = await fetchAdminOrgs(auth);
|
|
179
|
+
stepStatus(orgsLabel, "done");
|
|
180
|
+
// 2. Pick or create org
|
|
181
|
+
let chosenOrg = null;
|
|
182
|
+
while (!chosenOrg) {
|
|
183
|
+
if (orgs.length === 0) {
|
|
184
|
+
console.log();
|
|
185
|
+
info("You aren't an admin of any GitHub organization yet.");
|
|
186
|
+
info("HQ Teams need a GitHub org to host the shared workspace repo.");
|
|
187
|
+
console.log();
|
|
188
|
+
const create = await prompt("Open browser to create one now? (Y/n)", "y");
|
|
189
|
+
if (!create.toLowerCase().startsWith("y")) {
|
|
190
|
+
warn("Skipping team creation — you can run create-hq again after creating an org.");
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
openBrowser("https://github.com/organizations/new");
|
|
194
|
+
await pause("Press Enter when you have finished creating the org...");
|
|
195
|
+
stepStatus("Re-checking organizations", "running");
|
|
196
|
+
orgs = await fetchAdminOrgs(auth);
|
|
197
|
+
stepStatus("Re-checking organizations", "done");
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
console.log();
|
|
201
|
+
console.log(chalk.bold(" Choose an organization:"));
|
|
202
|
+
for (let i = 0; i < orgs.length; i++) {
|
|
203
|
+
console.log(chalk.cyan(` [${i + 1}] `) + chalk.white(orgs[i].login));
|
|
204
|
+
}
|
|
205
|
+
console.log(chalk.cyan(` [${orgs.length + 1}] `) + chalk.dim("Create a new GitHub organization"));
|
|
206
|
+
console.log();
|
|
207
|
+
const answer = await prompt(`Select (1-${orgs.length + 1})`, "1");
|
|
208
|
+
const idx = parseInt(answer, 10) - 1;
|
|
209
|
+
if (idx === orgs.length) {
|
|
210
|
+
// Create new org
|
|
211
|
+
openBrowser("https://github.com/organizations/new");
|
|
212
|
+
await pause("Press Enter when you have finished creating the org...");
|
|
213
|
+
stepStatus("Re-checking organizations", "running");
|
|
214
|
+
orgs = await fetchAdminOrgs(auth);
|
|
215
|
+
stepStatus("Re-checking organizations", "done");
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (idx < 0 || idx >= orgs.length) {
|
|
219
|
+
warn("Invalid selection. Try again.");
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
chosenOrg = orgs[idx];
|
|
223
|
+
}
|
|
224
|
+
// 3. Verify HQ App is installed on the org
|
|
225
|
+
let installation = null;
|
|
226
|
+
while (!installation) {
|
|
227
|
+
const installLabel = `Checking HQ App on ${chosenOrg.login}`;
|
|
228
|
+
stepStatus(installLabel, "running");
|
|
229
|
+
const installations = await fetchInstallations(auth);
|
|
230
|
+
installation = findHqInstallation(installations, chosenOrg.login);
|
|
231
|
+
if (installation) {
|
|
232
|
+
stepStatus(installLabel, "done");
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
stepStatus(installLabel, "failed");
|
|
236
|
+
console.log();
|
|
237
|
+
info(`The HQ GitHub App isn't installed on ${chalk.cyan(chosenOrg.login)} yet.`);
|
|
238
|
+
info("Installing it gives HQ permission to manage the team workspace repo.");
|
|
239
|
+
console.log();
|
|
240
|
+
const installUrl = `https://github.com/apps/${HQ_GITHUB_APP_SLUG}/installations/new/permissions?target_id=${chosenOrg.id}`;
|
|
241
|
+
const proceed = await prompt("Open the install page in your browser? (Y/n)", "y");
|
|
242
|
+
if (!proceed.toLowerCase().startsWith("y")) {
|
|
243
|
+
warn("HQ App is required to create a team. Aborting team creation.");
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
openBrowser(installUrl);
|
|
247
|
+
await pause("Press Enter when the App has been installed...");
|
|
248
|
+
}
|
|
249
|
+
// 4. Prompt for team name
|
|
250
|
+
console.log();
|
|
251
|
+
const defaultName = chosenOrg.login;
|
|
252
|
+
const teamName = (await prompt("Team name", defaultName)) || defaultName;
|
|
253
|
+
const teamSlug = slugify(teamName);
|
|
254
|
+
const teamId = crypto.randomUUID();
|
|
255
|
+
const meta = {
|
|
256
|
+
team_id: teamId,
|
|
257
|
+
team_name: teamName,
|
|
258
|
+
team_slug: teamSlug,
|
|
259
|
+
org_login: chosenOrg.login,
|
|
260
|
+
org_id: chosenOrg.id,
|
|
261
|
+
created_by: auth.login,
|
|
262
|
+
created_at: new Date().toISOString(),
|
|
263
|
+
hq_version: hqVersion,
|
|
264
|
+
};
|
|
265
|
+
// 5. Create the {org}/hq-{teamSlug} repo
|
|
266
|
+
const repoName = `hq-${teamSlug}`;
|
|
267
|
+
const repoLabel = `Creating ${chosenOrg.login}/${repoName} private repo`;
|
|
268
|
+
stepStatus(repoLabel, "running");
|
|
269
|
+
let repo = null;
|
|
270
|
+
try {
|
|
271
|
+
repo = await createOrgRepo(auth, chosenOrg.login, repoName, `HQ Teams workspace for ${teamName}`);
|
|
272
|
+
stepStatus(repoLabel, "done");
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
276
|
+
if (message.includes("422") && /already exists/i.test(message)) {
|
|
277
|
+
// Repo already exists — could be from a prior run. Confirm before reusing.
|
|
278
|
+
stepStatus(repoLabel, "done");
|
|
279
|
+
console.log();
|
|
280
|
+
info(`${chosenOrg.login}/${repoName} already exists.`);
|
|
281
|
+
const reuse = await prompt("Reuse this repo? (Y/n)", "y");
|
|
282
|
+
if (!reuse.toLowerCase().startsWith("y")) {
|
|
283
|
+
warn("Aborting — choose a different team name next time to avoid the conflict.");
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
repo = await getExistingRepo(auth, chosenOrg.login, repoName);
|
|
287
|
+
if (!repo) {
|
|
288
|
+
stepStatus(repoLabel, "failed");
|
|
289
|
+
warn(`Could not load existing ${chosenOrg.login}/${repoName}: ${message}`);
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
stepStatus(repoLabel, "failed");
|
|
295
|
+
warn(`Could not create repo: ${message}`);
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// 6. Seed locally and push
|
|
300
|
+
const seedLabel = "Seeding team workspace";
|
|
301
|
+
stepStatus(seedLabel, "running");
|
|
302
|
+
const seedDir = fs.mkdtempSync(path.join(os.tmpdir(), "create-hq-seed-"));
|
|
303
|
+
try {
|
|
304
|
+
// git init in seed dir
|
|
305
|
+
execSync(`git init -b main`, { cwd: seedDir, stdio: "pipe" });
|
|
306
|
+
execSync(`git config user.email "${auth.email || `${auth.login}@users.noreply.github.com`}"`, {
|
|
307
|
+
cwd: seedDir,
|
|
308
|
+
stdio: "pipe",
|
|
309
|
+
});
|
|
310
|
+
execSync(`git config user.name "${auth.name || auth.login}"`, {
|
|
311
|
+
cwd: seedDir,
|
|
312
|
+
stdio: "pipe",
|
|
313
|
+
});
|
|
314
|
+
writeCompanyTemplate(seedDir, meta);
|
|
315
|
+
execSync(`git add -A`, { cwd: seedDir, stdio: "pipe" });
|
|
316
|
+
execSync(`git commit -m "chore: bootstrap HQ team workspace"`, { cwd: seedDir, stdio: "pipe" });
|
|
317
|
+
const remoteUrl = tokenAuthUrl(repo.clone_url);
|
|
318
|
+
execSync(`git remote add origin "${remoteUrl}"`, { cwd: seedDir, stdio: "pipe" });
|
|
319
|
+
runGitWithToken(["push", "-u", "origin", "main"], seedDir, auth);
|
|
320
|
+
stepStatus(seedLabel, "done");
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
stepStatus(seedLabel, "failed");
|
|
324
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
325
|
+
warn(`Failed to seed team repo: ${message}`);
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
try {
|
|
330
|
+
fs.rmSync(seedDir, { recursive: true, force: true });
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// ignore
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// 7. Clone into companies/{slug}/
|
|
337
|
+
const companiesDir = path.join(hqRoot, "companies");
|
|
338
|
+
if (!fs.existsSync(companiesDir)) {
|
|
339
|
+
fs.mkdirSync(companiesDir, { recursive: true });
|
|
340
|
+
}
|
|
341
|
+
const companyDir = path.join(companiesDir, teamSlug);
|
|
342
|
+
if (fs.existsSync(companyDir) && fs.readdirSync(companyDir).length > 0) {
|
|
343
|
+
warn(`companies/${teamSlug}/ already exists and is not empty — skipping clone.`);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
const cloneLabel = `Cloning into companies/${teamSlug}`;
|
|
347
|
+
stepStatus(cloneLabel, "running");
|
|
348
|
+
try {
|
|
349
|
+
const remoteUrl = tokenAuthUrl(repo.clone_url);
|
|
350
|
+
runGitWithToken(["clone", `"${remoteUrl}"`, `"${companyDir}"`], companiesDir, auth);
|
|
351
|
+
// Strip token from the stored remote URL
|
|
352
|
+
execSync(`git remote set-url origin "${repo.clone_url}"`, {
|
|
353
|
+
cwd: companyDir,
|
|
354
|
+
stdio: "pipe",
|
|
355
|
+
});
|
|
356
|
+
stepStatus(cloneLabel, "done");
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
stepStatus(cloneLabel, "failed");
|
|
360
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
361
|
+
warn(`Could not clone into companies/${teamSlug}/: ${message}`);
|
|
362
|
+
// Team repo was created on GitHub — still return success so the user
|
|
363
|
+
// gets the admin orientation (with repo URL) instead of generic next steps.
|
|
364
|
+
// They can clone manually later.
|
|
365
|
+
console.log();
|
|
366
|
+
success(`Team "${teamName}" created at ${repo.html_url}`);
|
|
367
|
+
info("Local clone failed — clone manually with:");
|
|
368
|
+
info(` git clone ${repo.clone_url} companies/${teamSlug}`);
|
|
369
|
+
// Still offer invite generation
|
|
370
|
+
await inviteLoop(auth, meta, repo.clone_url);
|
|
371
|
+
return {
|
|
372
|
+
team: meta,
|
|
373
|
+
companyDir,
|
|
374
|
+
repoHtmlUrl: repo.html_url,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
console.log();
|
|
379
|
+
success(`Team "${teamName}" created — ${repo.html_url}`);
|
|
380
|
+
// 8. Offer to generate member invites
|
|
381
|
+
await inviteLoop(auth, meta, repo.clone_url);
|
|
382
|
+
return {
|
|
383
|
+
team: meta,
|
|
384
|
+
companyDir,
|
|
385
|
+
repoHtmlUrl: repo.html_url,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
// ─── Invite generation (used by admin onboarding + standalone) ──────────────
|
|
389
|
+
/**
|
|
390
|
+
* Interactive invite generation for a single member. Prompts for email,
|
|
391
|
+
* sends org invite, generates token, and prints instructions.
|
|
392
|
+
*/
|
|
393
|
+
export async function generateInviteInteractive(auth, meta, cloneUrl) {
|
|
394
|
+
const payload = {
|
|
395
|
+
org: meta.org_login,
|
|
396
|
+
repo: `hq-${meta.team_slug}`,
|
|
397
|
+
slug: meta.team_slug,
|
|
398
|
+
teamName: meta.team_name,
|
|
399
|
+
cloneUrl,
|
|
400
|
+
invitedBy: auth.login,
|
|
401
|
+
};
|
|
402
|
+
const token = encodeInviteToken(payload);
|
|
403
|
+
// Ask for email — used for the mailto invite, not for API calls
|
|
404
|
+
const email = await prompt("New member's email (or press Enter to skip)");
|
|
405
|
+
printInviteSummary(payload, token, false, email || undefined);
|
|
406
|
+
// Copy invite message to clipboard
|
|
407
|
+
const msg = formatInviteMessage(payload, token, email || undefined);
|
|
408
|
+
const copied = copyToClipboard(msg);
|
|
409
|
+
// Try to open mailto: with pre-populated email (works well on macOS/first use)
|
|
410
|
+
if (email) {
|
|
411
|
+
openInviteEmail(payload, token, email);
|
|
412
|
+
}
|
|
413
|
+
// Always show clipboard status — mailto: is unreliable on Windows after first use
|
|
414
|
+
if (copied) {
|
|
415
|
+
success("Invite message copied to clipboard — if your email client didn't open, just paste into a new email and send.");
|
|
416
|
+
}
|
|
417
|
+
else if (!email) {
|
|
418
|
+
info("No email provided — share the invite message above via email, Slack, or text.");
|
|
419
|
+
}
|
|
420
|
+
// Send the GitHub org invite via API (required for the member to accept)
|
|
421
|
+
if (email) {
|
|
422
|
+
const result = await sendOrgInviteByEmail(auth, meta.org_login, email);
|
|
423
|
+
if (result.ok) {
|
|
424
|
+
success(`GitHub org invite sent to ${email}`);
|
|
425
|
+
}
|
|
426
|
+
else {
|
|
427
|
+
warn(`Could not send org invite automatically: ${result.error}`);
|
|
428
|
+
console.log();
|
|
429
|
+
info(`Send the invite manually (required for access):`);
|
|
430
|
+
info(` https://github.com/orgs/${meta.org_login}/people`);
|
|
431
|
+
info(` Click "Invite member" and enter: ${email}`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
console.log();
|
|
436
|
+
info(`Send them a GitHub org invite (required for access):`);
|
|
437
|
+
info(` https://github.com/orgs/${meta.org_login}/people`);
|
|
438
|
+
info(` Click "Invite member" and enter their email or GitHub username`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Invite loop — asks "Invite a team member?" and repeats until the admin
|
|
443
|
+
* says no. Used after team creation and from the standalone invite command.
|
|
444
|
+
*/
|
|
445
|
+
export async function inviteLoop(auth, meta, cloneUrl) {
|
|
446
|
+
let first = true;
|
|
447
|
+
while (true) {
|
|
448
|
+
console.log();
|
|
449
|
+
const question = first
|
|
450
|
+
? "Invite a team member now? (Y/n)"
|
|
451
|
+
: "Invite another team member? (y/N)";
|
|
452
|
+
const defaultAnswer = first ? "y" : "n";
|
|
453
|
+
const answer = await prompt(question, defaultAnswer);
|
|
454
|
+
if (!answer.toLowerCase().startsWith("y"))
|
|
455
|
+
break;
|
|
456
|
+
await generateInviteInteractive(auth, meta, cloneUrl);
|
|
457
|
+
first = false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
//# sourceMappingURL=admin-onboarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-onboarding.js","sourceRoot":"","sources":["../src/admin-onboarding.ts"],"names":[],"mappings":"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"}
|
package/dist/art.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw banner lines without ANSI codes — testable.
|
|
3
|
+
*/
|
|
4
|
+
export declare function bannerLines(): string[];
|
|
5
|
+
/**
|
|
6
|
+
* Raw compact banner lines without ANSI codes — testable.
|
|
7
|
+
*/
|
|
8
|
+
export declare function compactBannerLines(): string[];
|
|
9
|
+
/**
|
|
10
|
+
* Full-width ASCII art banner (80 cols) — retro office building + INDIGO HQ
|
|
11
|
+
*/
|
|
12
|
+
export declare function banner(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Compact banner for narrow terminals (< 80 cols)
|
|
15
|
+
*/
|
|
16
|
+
export declare function compactBanner(): void;
|
|
17
|
+
//# sourceMappingURL=art.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"art.d.ts","sourceRoot":"","sources":["../src/art.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAuCtC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CA4B7C;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,IAAI,CAkD7B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAuCpC"}
|