create-hq 10.1.0 → 10.7.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/dist/admin-onboarding.d.ts +42 -0
- package/dist/admin-onboarding.d.ts.map +1 -0
- package/dist/admin-onboarding.js +445 -0
- package/dist/admin-onboarding.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/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/ui.d.ts +17 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +35 -0
- package/dist/ui.js.map +1 -1
- package/package.json +49 -49
|
@@ -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;AAgDhF,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,CAwCf;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,445 @@
|
|
|
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, } 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 ${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
|
+
// Remind admin to send the GitHub org invite
|
|
421
|
+
console.log();
|
|
422
|
+
info(`Send them a GitHub org invite (required for access):`);
|
|
423
|
+
info(` https://github.com/orgs/${meta.org_login}/people`);
|
|
424
|
+
info(` Click "Invite member" and enter${email ? ": " + email : " their email or GitHub username"}`);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Invite loop — asks "Invite a team member?" and repeats until the admin
|
|
428
|
+
* says no. Used after team creation and from the standalone invite command.
|
|
429
|
+
*/
|
|
430
|
+
export async function inviteLoop(auth, meta, cloneUrl) {
|
|
431
|
+
let first = true;
|
|
432
|
+
while (true) {
|
|
433
|
+
console.log();
|
|
434
|
+
const question = first
|
|
435
|
+
? "Invite a team member now? (Y/n)"
|
|
436
|
+
: "Invite another team member? (y/N)";
|
|
437
|
+
const defaultAnswer = first ? "y" : "n";
|
|
438
|
+
const answer = await prompt(question, defaultAnswer);
|
|
439
|
+
if (!answer.toLowerCase().startsWith("y"))
|
|
440
|
+
break;
|
|
441
|
+
await generateInviteInteractive(auth, meta, cloneUrl);
|
|
442
|
+
first = false;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
//# sourceMappingURL=admin-onboarding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-onboarding.js","sourceRoot":"","sources":["../src/admin-onboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,kBAAkB,EAClB,SAAS,EACT,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,oBAAoB,EAAqB,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,EACnB,eAAe,GAEhB,MAAM,aAAa,CAAC;AA+CrB,+EAA+E;AAE/E,SAAS,MAAM,CAAC,QAAgB,EAAE,UAAmB;IACnD,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,OAAO,QAAQ,GAAG,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE;YAClD,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,UAAU,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CAAC,OAAe;IAC5B,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,KAAK,OAAO,GAAG,EAAE,GAAG,EAAE;YAChC,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAE/E;;;;;;;GAOG;AACH,KAAK,UAAU,cAAc,CAAC,IAAgB;IAC5C,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,SAAS,CACjC,kDAAkD,EAClD,IAAI,CACL,CAAC;QACF,OAAO,WAAW;aACf,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;aACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACX,KAAK,EAAE,CAAC,CAAC,YAAY,CAAC,KAAK;YAC3B,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE;SACtB,CAAC,CAAC,CAAC;IACR,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,sEAAsE;QACtE,sEAAsE;QACtE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,IAAgB;IAChD,MAAM,IAAI,GAAG,MAAM,SAAS,CAC1B,kCAAkC,EAClC,IAAI,CACL,CAAC;IACF,OAAO,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,SAAS,kBAAkB,CACzB,aAAmC,EACnC,QAAgB;IAEhB,OAAO,CACL,aAAa,CAAC,IAAI,CAChB,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,QAAQ,KAAK,kBAAkB;QACjC,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,CAC7D,IAAI,IAAI,CACV,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,IAAgB,EAChB,QAAgB,EAChB,QAAgB,EAChB,WAAmB;IAEnB,OAAO,SAAS,CAAqB,SAAS,QAAQ,QAAQ,EAAE,IAAI,EAAE;QACpE,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,IAAI;YACb,WAAW;YACX,SAAS,EAAE,KAAK;YAChB,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,KAAK;YACnB,QAAQ,EAAE,KAAK;SAChB,CAAC;KACH,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,IAAgB,EAChB,QAAgB,EAChB,QAAgB;IAEhB,IAAI,CAAC;QACH,OAAO,MAAM,SAAS,CAAqB,UAAU,QAAQ,IAAI,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E;;;;;;GAMG;AACH,SAAS,eAAe,CACtB,IAAc,EACd,GAAW,EACX,IAAgB,EAChB,WAA8B,EAAE;IAEhC,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;IAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IAEhF,IAAI,CAAC;QACH,IAAI,SAAS,EAAE,CAAC;YACd,oEAAoE;YACpE,EAAE,CAAC,aAAa,CACd,WAAW,EACX,sEAAsE,EACtE,OAAO,CACR,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,gCAAgC,EAAE,OAAO,CAAC,CAAC;YACzE,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,QAAQ,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;YAChC,GAAG;YACH,KAAK,EAAE,MAAM;YACb,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,GAAG,QAAQ;gBACX,SAAS,EAAE,IAAI,CAAC,YAAY;gBAC5B,WAAW,EAAE,WAAW;gBACxB,mBAAmB,EAAE,GAAG;gBACxB,8DAA8D;gBAC9D,eAAe,EAAE,OAAO;aACzB;SACF,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,QAAgB;IACpC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC,CAAC,QAAQ,GAAG,gBAAgB,CAAC;IAC9B,sDAAsD;IACtD,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,+EAA+E;AAE/E,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC;AAC5B,CAAC;AAED,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAgB,EAChB,MAAc,EACd,SAAiB;IAEjB,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,sBAAsB;IACtB,MAAM,SAAS,GAAG,sCAAsC,CAAC;IACzD,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACjC,IAAI,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IACtC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAE9B,wBAAwB;IACxB,IAAI,SAAS,GAAqB,IAAI,CAAC;IACvC,OAAO,CAAC,SAAS,EAAE,CAAC;QAClB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,qDAAqD,CAAC,CAAC;YAC5D,IAAI,CAAC,+DAA+D,CAAC,CAAC;YACtE,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;YAC1E,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC1C,IAAI,CAAC,6EAA6E,CAAC,CAAC;gBACpF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,WAAW,CAAC,sCAAsC,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC,wDAAwD,CAAC,CAAC;YAEtE,UAAU,CAAC,2BAA2B,EAAE,SAAS,CAAC,CAAC;YACnD,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;YAClC,UAAU,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YAChD,SAAS;QACX,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CACzD,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC,CAAC;QACnG,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,MAAM,MAAM,GAAG,MAAM,MAAM,CACzB,aAAa,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,EAC/B,GAAG,CACJ,CAAC;QACF,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YACxB,iBAAiB;YACjB,WAAW,CAAC,sCAAsC,CAAC,CAAC;YACpD,MAAM,KAAK,CAAC,wDAAwD,CAAC,CAAC;YACtE,UAAU,CAAC,2BAA2B,EAAE,SAAS,CAAC,CAAC;YACnD,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;YAClC,UAAU,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;YAChD,SAAS;QACX,CAAC;QAED,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAClC,IAAI,CAAC,+BAA+B,CAAC,CAAC;YACtC,SAAS;QACX,CAAC;QAED,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,2CAA2C;IAC3C,IAAI,YAAY,GAA8B,IAAI,CAAC;IACnD,OAAO,CAAC,YAAY,EAAE,CAAC;QACrB,MAAM,YAAY,GAAG,sBAAsB,SAAS,CAAC,KAAK,EAAE,CAAC;QAC7D,UAAU,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QACpC,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACrD,YAAY,GAAG,kBAAkB,CAAC,aAAa,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;QAElE,IAAI,YAAY,EAAE,CAAC;YACjB,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;YACjC,MAAM;QACR,CAAC;QAED,UAAU,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,IAAI,CAAC,wCAAwC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjF,IAAI,CAAC,sEAAsE,CAAC,CAAC;QAC7E,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,MAAM,UAAU,GAAG,2BAA2B,kBAAkB,4CAA4C,SAAS,CAAC,EAAE,EAAE,CAAC;QAC3H,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,8CAA8C,EAAE,GAAG,CAAC,CAAC;QAClF,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3C,IAAI,CAAC,8DAA8D,CAAC,CAAC;YACrE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,WAAW,CAAC,UAAU,CAAC,CAAC;QACxB,MAAM,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAChE,CAAC;IAED,0BAA0B;IAC1B,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC;IACpC,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,IAAI,WAAW,CAAC;IACzE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAEnC,MAAM,IAAI,GAAiB;QACzB,OAAO,EAAE,MAAM;QACf,SAAS,EAAE,QAAQ;QACnB,SAAS,EAAE,QAAQ;QACnB,SAAS,EAAE,SAAS,CAAC,KAAK;QAC1B,MAAM,EAAE,SAAS,CAAC,EAAE;QACpB,UAAU,EAAE,IAAI,CAAC,KAAK;QACtB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,UAAU,EAAE,SAAS;KACtB,CAAC;IAEF,yCAAyC;IACzC,MAAM,QAAQ,GAAG,MAAM,QAAQ,EAAE,CAAC;IAClC,MAAM,SAAS,GAAG,YAAY,SAAS,CAAC,KAAK,IAAI,QAAQ,eAAe,CAAC;IACzE,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEjC,IAAI,IAAI,GAA8B,IAAI,CAAC;IAC3C,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,aAAa,CACxB,IAAI,EACJ,SAAS,CAAC,KAAK,EACf,QAAQ,EACR,0BAA0B,QAAQ,EAAE,CACrC,CAAC;QACF,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/D,2EAA2E;YAC3E,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAC9B,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,SAAS,CAAC,KAAK,IAAI,QAAQ,kBAAkB,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;YAC1D,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,IAAI,CAAC,0EAA0E,CAAC,CAAC;gBACjF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC9D,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBAChC,IAAI,CAAC,2BAA2B,SAAS,CAAC,KAAK,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;gBAC3E,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAChC,IAAI,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,MAAM,SAAS,GAAG,wBAAwB,CAAC;IAC3C,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAEjC,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC1E,IAAI,CAAC;QACH,uBAAuB;QACvB,QAAQ,CAAC,kBAAkB,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9D,QAAQ,CAAC,0BAA0B,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC,KAAK,2BAA2B,GAAG,EAAE;YAC5F,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QACH,QAAQ,CAAC,yBAAyB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,GAAG,EAAE;YAC5D,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QAEH,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAEpC,QAAQ,CAAC,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACxD,QAAQ,CACN,oDAAoD,EACpD,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAChC,CAAC;QAEF,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,QAAQ,CAAC,0BAA0B,SAAS,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAClF,eAAe,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAEjE,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IAErD,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,aAAa,QAAQ,qDAAqD,CAAC,CAAC;IACnF,CAAC;SAAM,CAAC;QACN,MAAM,UAAU,GAAG,0BAA0B,QAAQ,EAAE,CAAC;QACxD,UAAU,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC/C,eAAe,CACb,CAAC,OAAO,EAAE,IAAI,SAAS,GAAG,EAAE,IAAI,UAAU,GAAG,CAAC,EAC9C,YAAY,EACZ,IAAI,CACL,CAAC;YACF,yCAAyC;YACzC,QAAQ,CAAC,8BAA8B,IAAI,CAAC,SAAS,GAAG,EAAE;gBACxD,GAAG,EAAE,UAAU;gBACf,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;YACH,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACjC,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,kCAAkC,QAAQ,MAAM,OAAO,EAAE,CAAC,CAAC;YAChE,qEAAqE;YACrE,4EAA4E;YAC5E,iCAAiC;YACjC,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,SAAS,QAAQ,gBAAgB,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC1D,IAAI,CAAC,2CAA2C,CAAC,CAAC;YAClD,IAAI,CAAC,eAAe,IAAI,CAAC,SAAS,cAAc,QAAQ,EAAE,CAAC,CAAC;YAE5D,gCAAgC;YAChC,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAE7C,OAAO;gBACL,IAAI,EAAE,IAAI;gBACV,UAAU;gBACV,WAAW,EAAE,IAAI,CAAC,QAAQ;aAC3B,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,SAAS,QAAQ,eAAe,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEzD,sCAAsC;IACtC,MAAM,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAE7C,OAAO;QACL,IAAI,EAAE,IAAI;QACV,UAAU;QACV,WAAW,EAAE,IAAI,CAAC,QAAQ;KAC3B,CAAC;AACJ,CAAC;AAED,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAAgB,EAChB,IAAkB,EAClB,QAAgB;IAEhB,MAAM,OAAO,GAAkB;QAC7B,GAAG,EAAE,IAAI,CAAC,SAAS;QACnB,IAAI,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE;QAC5B,IAAI,EAAE,IAAI,CAAC,SAAS;QACpB,QAAQ,EAAE,IAAI,CAAC,SAAS;QACxB,QAAQ;QACR,SAAS,EAAE,IAAI,CAAC,KAAK;KACtB,CAAC;IAEF,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEzC,gEAAgE;IAChE,MAAM,KAAK,GAAG,MAAM,MAAM,CACxB,6CAA6C,CAC9C,CAAC;IAEF,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,SAAS,CAAC,CAAC;IAE9D,mCAAmC;IACnC,MAAM,GAAG,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,SAAS,CAAC,CAAC;IACpE,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IAEpC,+EAA+E;IAC/E,IAAI,KAAK,EAAE,CAAC;QACV,eAAe,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,kFAAkF;IAClF,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,8GAA8G,CAAC,CAAC;IAC1H,CAAC;SAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,+EAA+E,CAAC,CAAC;IACxF,CAAC;IAED,6CAA6C;IAC7C,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,IAAI,CAAC,sDAAsD,CAAC,CAAC;IAC7D,IAAI,CAAC,6BAA6B,IAAI,CAAC,SAAS,SAAS,CAAC,CAAC;IAC3D,IAAI,CAAC,oCAAoC,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,iCAAiC,EAAE,CAAC,CAAC;AACvG,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAgB,EAChB,IAAkB,EAClB,QAAgB;IAEhB,IAAI,KAAK,GAAG,IAAI,CAAC;IACjB,OAAO,IAAI,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,KAAK;YACpB,CAAC,CAAC,iCAAiC;YACnC,CAAC,CAAC,mCAAmC,CAAC;QACxC,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACrD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,MAAM;QACjD,MAAM,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACtD,KAAK,GAAG,KAAK,CAAC;IAChB,CAAC;AACH,CAAC"}
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,32 +1,69 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* GitHub App device flow auth for create-hq.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Talks directly to github.com — no backend involved.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. POST github.com/login/device/code with our App's client_id
|
|
8
|
+
* 2. Display user_code, open verification_uri in browser
|
|
9
|
+
* 3. Poll github.com/login/oauth/access_token at the GitHub-specified interval
|
|
10
|
+
* 4. On success: GET api.github.com/user → store { access_token, login, id, name, email }
|
|
11
|
+
*
|
|
12
|
+
* Token is stored at ~/.hq/credentials.json (mode 0600). Tokens are
|
|
13
|
+
* GitHub App user-to-server tokens (ghu_…), so they ignore OAuth scopes —
|
|
14
|
+
* permissions are configured on the App settings page.
|
|
7
15
|
*
|
|
8
16
|
* Token values are NEVER written to stdout or logs.
|
|
9
17
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
/** hq-team-sync GitHub App client ID (public — safe to commit). */
|
|
19
|
+
export declare const HQ_GITHUB_APP_CLIENT_ID = "Iv23liSdkCBQYhrNcRmI";
|
|
20
|
+
export declare const HQ_GITHUB_APP_SLUG = "hq-team-sync";
|
|
21
|
+
/** Stored credentials for the authenticated GitHub user. */
|
|
22
|
+
export interface GitHubAuth {
|
|
23
|
+
/** ghu_ user-to-server token from GitHub App device flow. */
|
|
24
|
+
access_token: string;
|
|
25
|
+
/** GitHub login (username). */
|
|
26
|
+
login: string;
|
|
27
|
+
/** GitHub numeric user ID. */
|
|
28
|
+
id: number;
|
|
29
|
+
/** Display name (may be null on GitHub, fall back to login). */
|
|
30
|
+
name: string | null;
|
|
31
|
+
/** Public email (may be null if user has it private). */
|
|
32
|
+
email: string | null;
|
|
33
|
+
/** ISO timestamp the token was issued. */
|
|
34
|
+
issued_at: string;
|
|
15
35
|
}
|
|
16
|
-
/** Save auth token to ~/.hq/auth.json with 0600 permissions. */
|
|
17
|
-
export declare function saveToken(token: AuthToken): void;
|
|
18
|
-
/** Load auth token from ~/.hq/auth.json. Returns null if missing/invalid. */
|
|
19
|
-
export declare function loadToken(): AuthToken | null;
|
|
20
|
-
/** Check if a token is expired or within 5 minutes of expiry. */
|
|
21
|
-
export declare function isTokenExpired(token: AuthToken): boolean;
|
|
22
36
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
* Backwards-compat alias used by older modules. Will be removed once all
|
|
38
|
+
* callers have migrated. New code should use GitHubAuth.
|
|
39
|
+
*/
|
|
40
|
+
export type AuthToken = GitHubAuth;
|
|
41
|
+
/** Save credentials to ~/.hq/credentials.json with 0600 perms. */
|
|
42
|
+
export declare function saveGitHubAuth(auth: GitHubAuth): void;
|
|
43
|
+
/** Load credentials, or null if missing/invalid. */
|
|
44
|
+
export declare function loadGitHubAuth(): GitHubAuth | null;
|
|
45
|
+
/** Remove stored credentials. */
|
|
46
|
+
export declare function clearGitHubAuth(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Quick liveness probe — does the stored token still work?
|
|
49
|
+
* Calls api.github.com/user with the token; returns true on 200.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isGitHubAuthValid(auth: GitHubAuth): Promise<boolean>;
|
|
52
|
+
/** Open a URL in the user's default browser. Best-effort, never throws. */
|
|
53
|
+
export declare function openBrowser(url: string): void;
|
|
54
|
+
/**
|
|
55
|
+
* Run the GitHub App device authorization flow.
|
|
56
|
+
*
|
|
57
|
+
* Throws on:
|
|
58
|
+
* - Network errors talking to github.com
|
|
59
|
+
* - User-denied authorization (access_denied)
|
|
60
|
+
* - Device code expiration
|
|
61
|
+
* - Failure to fetch the user profile
|
|
62
|
+
*/
|
|
63
|
+
export declare function startGitHubDeviceFlow(): Promise<GitHubAuth>;
|
|
64
|
+
/**
|
|
65
|
+
* Authenticated fetch against api.github.com. Throws on non-2xx with
|
|
66
|
+
* the response body included for diagnostics.
|
|
30
67
|
*/
|
|
31
|
-
export declare function
|
|
68
|
+
export declare function githubApi<T>(pathname: string, auth: GitHubAuth, init?: RequestInit): Promise<T>;
|
|
32
69
|
//# sourceMappingURL=auth.d.ts.map
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,mEAAmE;AACnE,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAC9D,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAWjD,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,yDAAyD;IACzD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC;AAkCnC,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAKrD;AAED,oDAAoD;AACpD,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CAelD;AAED,iCAAiC;AACjC,wBAAgB,eAAe,IAAI,IAAI,CAQtC;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAc1E;AAID,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAkB7C;AAQD;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,UAAU,CAAC,CAyHjE;AAID;;;GAGG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,CAAC,CAAC,CAwBZ"}
|