create-hq 10.10.0 → 10.12.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/commands/{team-sync.md → sync-team.md} +167 -6
- package/dist/__tests__/auth.test.js +176 -186
- package/dist/__tests__/auth.test.js.map +1 -1
- package/dist/__tests__/scaffold.test.js +5 -3
- package/dist/__tests__/scaffold.test.js.map +1 -1
- package/dist/auth.d.ts +57 -129
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +81 -370
- package/dist/auth.js.map +1 -1
- package/dist/fetch-template.d.ts +7 -2
- package/dist/fetch-template.d.ts.map +1 -1
- package/dist/fetch-template.js +27 -15
- package/dist/fetch-template.js.map +1 -1
- package/dist/index.js +7 -17
- package/dist/index.js.map +1 -1
- package/dist/packages.d.ts.map +1 -1
- package/dist/packages.js +1 -1
- package/dist/packages.js.map +1 -1
- package/dist/recommended-packages.d.ts +93 -0
- package/dist/recommended-packages.d.ts.map +1 -0
- package/dist/recommended-packages.js +221 -0
- package/dist/recommended-packages.js.map +1 -0
- package/dist/scaffold.d.ts +4 -2
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +127 -232
- package/dist/scaffold.js.map +1 -1
- package/dist/ui.d.ts +0 -17
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +0 -45
- package/dist/ui.js.map +1 -1
- package/package.json +2 -1
- package/dist/admin-onboarding.d.ts +0 -44
- package/dist/admin-onboarding.d.ts.map +0 -1
- package/dist/admin-onboarding.js +0 -530
- package/dist/admin-onboarding.js.map +0 -1
- package/dist/company-template.d.ts +0 -34
- package/dist/company-template.d.ts.map +0 -1
- package/dist/company-template.js +0 -142
- package/dist/company-template.js.map +0 -1
- package/dist/invite-command.d.ts +0 -10
- package/dist/invite-command.d.ts.map +0 -1
- package/dist/invite-command.js +0 -110
- package/dist/invite-command.js.map +0 -1
- package/dist/invite.d.ts +0 -91
- package/dist/invite.d.ts.map +0 -1
- package/dist/invite.js +0 -230
- package/dist/invite.js.map +0 -1
- package/dist/join-flow.d.ts +0 -32
- package/dist/join-flow.d.ts.map +0 -1
- package/dist/join-flow.js +0 -315
- package/dist/join-flow.js.map +0 -1
- package/dist/team-setup.d.ts +0 -83
- package/dist/team-setup.d.ts.map +0 -1
- package/dist/team-setup.js +0 -353
- package/dist/team-setup.js.map +0 -1
- package/dist/teams-flow.d.ts +0 -41
- package/dist/teams-flow.d.ts.map +0 -1
- package/dist/teams-flow.js +0 -173
- package/dist/teams-flow.js.map +0 -1
package/dist/teams-flow.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Teams flow router.
|
|
3
|
-
*
|
|
4
|
-
* Called by scaffold.ts after the user opts into the HQ Teams path. Handles:
|
|
5
|
-
* - Reusing or refreshing GitHub auth
|
|
6
|
-
* - Routing: invite code → join-by-invite, discovery → auto-discovery, new → admin onboarding
|
|
7
|
-
*
|
|
8
|
-
* The team setup happens *after* core HQ has been installed, so all paths
|
|
9
|
-
* receive a fully scaffolded hqRoot to drop companies/{slug}/ into.
|
|
10
|
-
*/
|
|
11
|
-
import chalk from "chalk";
|
|
12
|
-
import { createInterface } from "readline";
|
|
13
|
-
import { loadGitHubAuth, isGitHubAuthValid, isAppScopedToken, startGitHubDeviceFlow, clearGitHubAuth, openBrowser, } from "./auth.js";
|
|
14
|
-
import { runAdminOnboarding } from "./admin-onboarding.js";
|
|
15
|
-
import { runMemberJoin } from "./team-setup.js";
|
|
16
|
-
import { runJoinByInvite } from "./join-flow.js";
|
|
17
|
-
import { decodeInviteToken } from "./invite.js";
|
|
18
|
-
import { warn, info } from "./ui.js";
|
|
19
|
-
function prompt(question, defaultVal) {
|
|
20
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
21
|
-
const suffix = defaultVal ? ` (${defaultVal})` : "";
|
|
22
|
-
return new Promise((resolve) => {
|
|
23
|
-
rl.question(` ? ${question}${suffix} `, (answer) => {
|
|
24
|
-
rl.close();
|
|
25
|
-
resolve(answer.trim() || defaultVal || "");
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
async function confirm(question, defaultYes) {
|
|
30
|
-
const hint = defaultYes ? "Y/n" : "y/N";
|
|
31
|
-
const answer = await prompt(`${question} (${hint})`);
|
|
32
|
-
if (!answer)
|
|
33
|
-
return defaultYes;
|
|
34
|
-
return answer.toLowerCase().startsWith("y");
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Authenticate the user, reusing a stored HQ App token if it's still valid.
|
|
38
|
-
*
|
|
39
|
-
* Priority:
|
|
40
|
-
* 1. ~/.hq/app-token.json — cached HQ App token from a previous session
|
|
41
|
-
* 2. Device flow — browser-based OAuth through the hq-team-sync GitHub App
|
|
42
|
-
*
|
|
43
|
-
* The user's existing `gh` CLI auth is never read or modified.
|
|
44
|
-
*/
|
|
45
|
-
export async function authenticate() {
|
|
46
|
-
// 1. Try the cached HQ App token
|
|
47
|
-
const existing = loadGitHubAuth();
|
|
48
|
-
if (existing) {
|
|
49
|
-
const valid = await isGitHubAuthValid(existing);
|
|
50
|
-
if (valid) {
|
|
51
|
-
// Double-check it actually has App scopes (not a leftover from the old
|
|
52
|
-
// gh-based flow where a regular OAuth token could end up in the file)
|
|
53
|
-
const appScoped = await isAppScopedToken(existing);
|
|
54
|
-
if (appScoped === "yes") {
|
|
55
|
-
info(`Already signed in as ${chalk.cyan("@" + existing.login)}`);
|
|
56
|
-
return existing;
|
|
57
|
-
}
|
|
58
|
-
if (appScoped === "unknown") {
|
|
59
|
-
// Transient failure (network, 5xx) — keep the cached token and
|
|
60
|
-
// optimistically reuse it. If it truly lacks scopes, the downstream
|
|
61
|
-
// /user/installations call will fail with a clear error.
|
|
62
|
-
info(`Already signed in as ${chalk.cyan("@" + existing.login)} (scope check skipped — GitHub unreachable)`);
|
|
63
|
-
return existing;
|
|
64
|
-
}
|
|
65
|
-
// appScoped === "no" — definitively wrong token type (403)
|
|
66
|
-
info(`Signed in as ${chalk.cyan("@" + existing.login)} but token lacks HQ App permissions`);
|
|
67
|
-
clearGitHubAuth();
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
info("HQ App token expired — re-authenticating");
|
|
71
|
-
clearGitHubAuth();
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// 2. No valid App token — run the device flow
|
|
75
|
-
// Quick check: does the user have a GitHub account?
|
|
76
|
-
console.log();
|
|
77
|
-
const hasGithub = await confirm("Do you have a GitHub account?", true);
|
|
78
|
-
if (!hasGithub) {
|
|
79
|
-
console.log();
|
|
80
|
-
info("HQ Teams uses GitHub for identity, repos, and access control.");
|
|
81
|
-
const create = await confirm("Open github.com/signup in your browser to create one?", true);
|
|
82
|
-
if (!create) {
|
|
83
|
-
warn("A GitHub account is required for HQ Teams. Aborting team setup.");
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
openBrowser("https://github.com/signup");
|
|
87
|
-
console.log();
|
|
88
|
-
info("After creating your account, come back here and press Enter...");
|
|
89
|
-
await prompt("");
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
return await startGitHubDeviceFlow();
|
|
93
|
-
}
|
|
94
|
-
catch (err) {
|
|
95
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
96
|
-
warn(`GitHub sign-in failed: ${message}`);
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Run the teams flow. The mode determines the entry point:
|
|
102
|
-
* - "existing": user said they have an HQ Teams account → prompt for invite code, then discovery
|
|
103
|
-
* - "new": user wants to create a new team → admin onboarding
|
|
104
|
-
*
|
|
105
|
-
* @param joinToken - Pre-supplied invite token (from --join flag). Skips the invite code prompt.
|
|
106
|
-
*/
|
|
107
|
-
export async function runTeamsFlow(mode, hqRoot, hqVersion, preAuth, joinToken) {
|
|
108
|
-
if (mode === "existing") {
|
|
109
|
-
// "existing" path requires App auth upfront for discovery + invite flows
|
|
110
|
-
const auth = preAuth ?? await authenticate();
|
|
111
|
-
if (!auth)
|
|
112
|
-
return null;
|
|
113
|
-
const result = { auth, member: null, admin: null, joinedByInvite: null };
|
|
114
|
-
// Check for a pre-supplied token (--join flag) or prompt for one
|
|
115
|
-
let token = joinToken;
|
|
116
|
-
if (!token) {
|
|
117
|
-
console.log();
|
|
118
|
-
token = await prompt("Enter your invite code (or press Enter to auto-discover)");
|
|
119
|
-
}
|
|
120
|
-
// If the user provided a token, use the invite flow
|
|
121
|
-
if (token) {
|
|
122
|
-
// Validate the token before proceeding
|
|
123
|
-
const decoded = decodeInviteToken(token);
|
|
124
|
-
if (!decoded) {
|
|
125
|
-
warn("That doesn't look like a valid invite code.");
|
|
126
|
-
info("Check that you copied the full code starting with hq_");
|
|
127
|
-
console.log();
|
|
128
|
-
// Fall through to discovery as a courtesy
|
|
129
|
-
info("Trying auto-discovery instead...");
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
result.joinedByInvite = await runJoinByInvite(auth, hqRoot, token);
|
|
133
|
-
if (result.joinedByInvite) {
|
|
134
|
-
return result;
|
|
135
|
-
}
|
|
136
|
-
// Join failed — don't fall through to discovery, the user needs to
|
|
137
|
-
// fix the access issue first
|
|
138
|
-
return result;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
// Auto-discovery: find teams via GitHub App installations
|
|
142
|
-
result.member = await runMemberJoin(auth, hqRoot);
|
|
143
|
-
if (result.member === null) {
|
|
144
|
-
// No teams found at all — offer to create a team
|
|
145
|
-
console.log();
|
|
146
|
-
info("No HQ teams are linked to your GitHub account yet.");
|
|
147
|
-
const create = await confirm("Would you like to create a new team now?", false);
|
|
148
|
-
if (create) {
|
|
149
|
-
// Admin onboarding handles its own auth sequence:
|
|
150
|
-
// gh CLI for org discovery → App device flow after org selection
|
|
151
|
-
result.admin = await runAdminOnboarding(auth, hqRoot, hqVersion);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return result;
|
|
155
|
-
}
|
|
156
|
-
// mode === "new"
|
|
157
|
-
// Admin onboarding handles its own auth sequence:
|
|
158
|
-
// 1. gh CLI token for org discovery (prompt gh auth login if needed)
|
|
159
|
-
// 2. User picks org
|
|
160
|
-
// 3. App device flow auth (for installations + repo management)
|
|
161
|
-
// This avoids the chicken-and-egg problem where the App token can only
|
|
162
|
-
// see orgs it's already installed on.
|
|
163
|
-
const result = { auth: null, member: null, admin: null, joinedByInvite: null };
|
|
164
|
-
result.admin = await runAdminOnboarding(null, hqRoot, hqVersion);
|
|
165
|
-
if (result.admin) {
|
|
166
|
-
// Admin onboarding completed — load the auth it persisted
|
|
167
|
-
const auth = loadGitHubAuth();
|
|
168
|
-
if (auth)
|
|
169
|
-
result.auth = auth;
|
|
170
|
-
}
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
//# sourceMappingURL=teams-flow.js.map
|
package/dist/teams-flow.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"teams-flow.js","sourceRoot":"","sources":["../src/teams-flow.ts"],"names":[],"mappings":"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"}
|