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.
Files changed (58) hide show
  1. package/dist/admin-onboarding.d.ts +42 -0
  2. package/dist/admin-onboarding.d.ts.map +1 -0
  3. package/dist/admin-onboarding.js +445 -0
  4. package/dist/admin-onboarding.js.map +1 -0
  5. package/dist/auth.d.ts +60 -23
  6. package/dist/auth.d.ts.map +1 -1
  7. package/dist/auth.js +219 -116
  8. package/dist/auth.js.map +1 -1
  9. package/dist/company-template.d.ts +34 -0
  10. package/dist/company-template.d.ts.map +1 -0
  11. package/dist/company-template.js +142 -0
  12. package/dist/company-template.js.map +1 -0
  13. package/dist/deps.d.ts +2 -0
  14. package/dist/deps.d.ts.map +1 -1
  15. package/dist/deps.js +42 -30
  16. package/dist/deps.js.map +1 -1
  17. package/dist/fetch-template.d.ts +2 -2
  18. package/dist/fetch-template.d.ts.map +1 -1
  19. package/dist/fetch-template.js +54 -38
  20. package/dist/fetch-template.js.map +1 -1
  21. package/dist/git.d.ts.map +1 -1
  22. package/dist/git.js +28 -4
  23. package/dist/git.js.map +1 -1
  24. package/dist/index.js +18 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/invite-command.d.ts +10 -0
  27. package/dist/invite-command.d.ts.map +1 -0
  28. package/dist/invite-command.js +110 -0
  29. package/dist/invite-command.js.map +1 -0
  30. package/dist/invite.d.ts +91 -0
  31. package/dist/invite.d.ts.map +1 -0
  32. package/dist/invite.js +230 -0
  33. package/dist/invite.js.map +1 -0
  34. package/dist/join-flow.d.ts +32 -0
  35. package/dist/join-flow.d.ts.map +1 -0
  36. package/dist/join-flow.js +194 -0
  37. package/dist/join-flow.js.map +1 -0
  38. package/dist/platform.d.ts +2 -2
  39. package/dist/platform.d.ts.map +1 -1
  40. package/dist/platform.js +14 -1
  41. package/dist/platform.js.map +1 -1
  42. package/dist/scaffold.d.ts +4 -1
  43. package/dist/scaffold.d.ts.map +1 -1
  44. package/dist/scaffold.js +152 -41
  45. package/dist/scaffold.js.map +1 -1
  46. package/dist/team-setup.d.ts +58 -0
  47. package/dist/team-setup.d.ts.map +1 -0
  48. package/dist/team-setup.js +237 -0
  49. package/dist/team-setup.js.map +1 -0
  50. package/dist/teams-flow.d.ts +36 -0
  51. package/dist/teams-flow.d.ts.map +1 -0
  52. package/dist/teams-flow.js +134 -0
  53. package/dist/teams-flow.js.map +1 -0
  54. package/dist/ui.d.ts +17 -0
  55. package/dist/ui.d.ts.map +1 -1
  56. package/dist/ui.js +35 -0
  57. package/dist/ui.js.map +1 -1
  58. package/package.json +49 -49
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Invite system for HQ Teams.
3
+ *
4
+ * Tokens are self-contained (no server) — they encode the team coordinates
5
+ * so a new member can join without discovery. Security comes from GitHub:
6
+ * the member still needs org access to clone the private repo.
7
+ *
8
+ * Token format: "hq_" + base64url({ org, repo, slug, teamName, cloneUrl, invitedBy })
9
+ *
10
+ * Admin flow:
11
+ * 1. Generate token from team metadata
12
+ * 2. Optionally send GitHub org invite by email
13
+ * 3. Share token + instructions with member
14
+ *
15
+ * Member flow:
16
+ * 1. Decode token → get team coordinates
17
+ * 2. Auth via GitHub device flow
18
+ * 3. Verify org membership (wait for invite acceptance if needed)
19
+ * 4. Clone repo into companies/{slug}/
20
+ */
21
+ import { type GitHubAuth } from "./auth.js";
22
+ export interface InvitePayload {
23
+ /** GitHub org login (e.g. "indigoai-us") */
24
+ org: string;
25
+ /** Repo name (e.g. "hq-indigo") */
26
+ repo: string;
27
+ /** Team slug (e.g. "indigo") — maps to companies/{slug}/ */
28
+ slug: string;
29
+ /** Human-readable team name */
30
+ teamName: string;
31
+ /** HTTPS clone URL for the repo */
32
+ cloneUrl: string;
33
+ /** GitHub login of the admin who generated the invite */
34
+ invitedBy: string;
35
+ }
36
+ export declare function encodeInviteToken(payload: InvitePayload): string;
37
+ export declare function decodeInviteToken(token: string): InvitePayload | null;
38
+ interface OrgInviteResponse {
39
+ id: number;
40
+ login?: string;
41
+ email?: string;
42
+ role: string;
43
+ }
44
+ /**
45
+ * Send a GitHub org invitation by email.
46
+ *
47
+ * Requires the authenticated user to be an org admin, and the GitHub App
48
+ * to have "Organization > Members: Write" permission.
49
+ *
50
+ * Returns the invitation on success, or an error message string on failure.
51
+ */
52
+ export declare function sendOrgInviteByEmail(auth: GitHubAuth, orgLogin: string, email: string, role?: "direct_member" | "admin"): Promise<{
53
+ ok: true;
54
+ invite: OrgInviteResponse;
55
+ } | {
56
+ ok: false;
57
+ error: string;
58
+ }>;
59
+ /**
60
+ * Check whether a GitHub user is a member of an org.
61
+ */
62
+ export declare function checkOrgMembership(auth: GitHubAuth, orgLogin: string, username: string): Promise<"active" | "pending" | "none">;
63
+ /**
64
+ * Check whether the authenticated user can access a specific repo.
65
+ */
66
+ export declare function checkRepoAccess(auth: GitHubAuth, orgLogin: string, repoName: string): Promise<boolean>;
67
+ /**
68
+ * Generate a ready-to-share invite message for the admin to send to the
69
+ * new member. Designed to be copy-pasted into Slack, email, or text.
70
+ */
71
+ export declare function formatInviteMessage(payload: InvitePayload, token: string, memberEmail?: string): string;
72
+ /**
73
+ * Print the invite details to the console for the admin.
74
+ */
75
+ export declare function printInviteSummary(payload: InvitePayload, token: string, _emailSent?: boolean, memberEmail?: string): void;
76
+ /**
77
+ * Build a mailto: URL pre-populated with the invite message.
78
+ * Opens in the admin's default email client — they just hit Send.
79
+ */
80
+ export declare function buildMailtoUrl(payload: InvitePayload, token: string, recipientEmail: string): string;
81
+ /**
82
+ * Open the admin's email client with a pre-populated invite email.
83
+ */
84
+ export declare function openInviteEmail(payload: InvitePayload, token: string, recipientEmail: string): void;
85
+ /**
86
+ * Copy text to the system clipboard. Cross-platform: pbcopy (macOS),
87
+ * clip (Windows), xclip/xsel (Linux). Returns true on success.
88
+ */
89
+ export declare function copyToClipboard(text: string): boolean;
90
+ export {};
91
+ //# sourceMappingURL=invite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite.d.ts","sourceRoot":"","sources":["../src/invite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,KAAK,UAAU,EAA0B,MAAM,WAAW,CAAC;AAIpE,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;CACnB;AAmBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAEhE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAwBrE;AAID,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,eAAe,GAAG,OAAyB,GAChD,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCjF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC,CAwBxC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAOlB;AAID;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAoDR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,OAAO,EACpB,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAsBN;AAID;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,MAAM,CAIR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,GACrB,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAmBrD"}
package/dist/invite.js ADDED
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Invite system for HQ Teams.
3
+ *
4
+ * Tokens are self-contained (no server) — they encode the team coordinates
5
+ * so a new member can join without discovery. Security comes from GitHub:
6
+ * the member still needs org access to clone the private repo.
7
+ *
8
+ * Token format: "hq_" + base64url({ org, repo, slug, teamName, cloneUrl, invitedBy })
9
+ *
10
+ * Admin flow:
11
+ * 1. Generate token from team metadata
12
+ * 2. Optionally send GitHub org invite by email
13
+ * 3. Share token + instructions with member
14
+ *
15
+ * Member flow:
16
+ * 1. Decode token → get team coordinates
17
+ * 2. Auth via GitHub device flow
18
+ * 3. Verify org membership (wait for invite acceptance if needed)
19
+ * 4. Clone repo into companies/{slug}/
20
+ */
21
+ import chalk from "chalk";
22
+ import { execSync } from "child_process";
23
+ import { githubApi, openBrowser } from "./auth.js";
24
+ // ─── Token encode / decode ──────────────────────────────────────────────────
25
+ const TOKEN_PREFIX = "hq_";
26
+ function toBase64Url(str) {
27
+ return Buffer.from(str, "utf-8")
28
+ .toString("base64")
29
+ .replace(/\+/g, "-")
30
+ .replace(/\//g, "_")
31
+ .replace(/=+$/, "");
32
+ }
33
+ function fromBase64Url(b64) {
34
+ const padded = b64.replace(/-/g, "+").replace(/_/g, "/");
35
+ return Buffer.from(padded, "base64").toString("utf-8");
36
+ }
37
+ export function encodeInviteToken(payload) {
38
+ return TOKEN_PREFIX + toBase64Url(JSON.stringify(payload));
39
+ }
40
+ export function decodeInviteToken(token) {
41
+ try {
42
+ const raw = token.startsWith(TOKEN_PREFIX)
43
+ ? token.slice(TOKEN_PREFIX.length)
44
+ : token;
45
+ const json = fromBase64Url(raw);
46
+ const parsed = JSON.parse(json);
47
+ // Validate required fields
48
+ if (typeof parsed.org !== "string" ||
49
+ typeof parsed.repo !== "string" ||
50
+ typeof parsed.slug !== "string" ||
51
+ typeof parsed.teamName !== "string" ||
52
+ typeof parsed.cloneUrl !== "string" ||
53
+ typeof parsed.invitedBy !== "string") {
54
+ return null;
55
+ }
56
+ return parsed;
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ /**
63
+ * Send a GitHub org invitation by email.
64
+ *
65
+ * Requires the authenticated user to be an org admin, and the GitHub App
66
+ * to have "Organization > Members: Write" permission.
67
+ *
68
+ * Returns the invitation on success, or an error message string on failure.
69
+ */
70
+ export async function sendOrgInviteByEmail(auth, orgLogin, email, role = "direct_member") {
71
+ try {
72
+ const invite = await githubApi(`/orgs/${orgLogin}/invitations`, auth, {
73
+ method: "POST",
74
+ body: JSON.stringify({
75
+ email,
76
+ role,
77
+ }),
78
+ });
79
+ return { ok: true, invite };
80
+ }
81
+ catch (err) {
82
+ const message = err instanceof Error ? err.message : String(err);
83
+ if (message.includes("404") || message.includes("403")) {
84
+ return {
85
+ ok: false,
86
+ error: "The HQ App doesn't have permission to send org invites. " +
87
+ `Please invite the member manually at: https://github.com/orgs/${orgLogin}/people`,
88
+ };
89
+ }
90
+ if (message.includes("422") && /already/i.test(message)) {
91
+ return {
92
+ ok: false,
93
+ error: "This email has already been invited or is already a member.",
94
+ };
95
+ }
96
+ return { ok: false, error: message };
97
+ }
98
+ }
99
+ /**
100
+ * Check whether a GitHub user is a member of an org.
101
+ */
102
+ export async function checkOrgMembership(auth, orgLogin, username) {
103
+ // Check active membership first
104
+ try {
105
+ await githubApi(`/orgs/${orgLogin}/members/${username}`, auth);
106
+ return "active";
107
+ }
108
+ catch {
109
+ // Not an active member — check pending invitations
110
+ }
111
+ // Check if there's a pending invitation for this user
112
+ try {
113
+ const memberships = await githubApi("/user/memberships/orgs?state=pending&per_page=100", auth);
114
+ const pending = memberships.find((m) => m.organization.login.toLowerCase() === orgLogin.toLowerCase());
115
+ if (pending)
116
+ return "pending";
117
+ }
118
+ catch {
119
+ // Can't check pending — fall through
120
+ }
121
+ return "none";
122
+ }
123
+ /**
124
+ * Check whether the authenticated user can access a specific repo.
125
+ */
126
+ export async function checkRepoAccess(auth, orgLogin, repoName) {
127
+ try {
128
+ await githubApi(`/repos/${orgLogin}/${repoName}`, auth);
129
+ return true;
130
+ }
131
+ catch {
132
+ return false;
133
+ }
134
+ }
135
+ // ─── Invite message template ────────────────────────────────────────────────
136
+ /**
137
+ * Generate a ready-to-share invite message for the admin to send to the
138
+ * new member. Designed to be copy-pasted into Slack, email, or text.
139
+ */
140
+ export function formatInviteMessage(payload, token, memberEmail) {
141
+ const orgInviteUrl = `https://github.com/orgs/${payload.org}/invitation`;
142
+ const lines = [
143
+ `You've been invited to join ${payload.teamName} on HQ!`,
144
+ "",
145
+ ];
146
+ // Step 1: Accept org invite (which handles GitHub account creation too)
147
+ if (memberEmail) {
148
+ lines.push(`Step 1: Accept the GitHub invitation sent to ${memberEmail}`, ` (if you don't have a GitHub account yet, you'll be guided to create one)`, ` Direct link: ${orgInviteUrl}`, "");
149
+ }
150
+ else {
151
+ lines.push(`Step 1: Accept your GitHub organization invite`, ` Direct link: ${orgInviteUrl}`, ` (if you haven't received one, ask @${payload.invitedBy} to send it)`, "");
152
+ }
153
+ // Step 2: Install Node.js (platform-specific instructions)
154
+ lines.push(`Step 2: Install Node.js (if you don't have it already)`, "", ` Windows (PowerShell, run as Administrator):`, ` winget install OpenJS.NodeJS.LTS`, "", ` Mac (Terminal):`, ` brew install node`, ` (if you don't have brew: https://brew.sh)`, "", ` Or download from: https://nodejs.org`, "");
155
+ // Step 3: Single command with token
156
+ lines.push(`Step 3: Open your terminal and run this command:`, "", ` npx create-hq --invite ${token}`, "", ` Then follow the prompts to sign in with GitHub and complete setup.`, "", `---`, `Questions? Ask @${payload.invitedBy} or visit https://getindigo.ai/hq`);
157
+ return lines.join("\n");
158
+ }
159
+ /**
160
+ * Print the invite details to the console for the admin.
161
+ */
162
+ export function printInviteSummary(payload, token, _emailSent, memberEmail) {
163
+ console.log();
164
+ console.log(chalk.bold(" Invite ready!"));
165
+ console.log();
166
+ console.log(` ${chalk.dim("Team:")} ${chalk.cyan(payload.teamName)}`);
167
+ console.log(` ${chalk.dim("Org:")} ${payload.org}`);
168
+ if (memberEmail) {
169
+ console.log(` ${chalk.dim("Email:")} ${memberEmail}`);
170
+ }
171
+ console.log();
172
+ console.log(chalk.bold(" Invite code (share with the new member):"));
173
+ console.log();
174
+ console.log(` ${chalk.cyan(token)}`);
175
+ console.log();
176
+ console.log(chalk.dim(" Full invite message (copy-paste ready):"));
177
+ console.log(chalk.dim(" ─".repeat(30)));
178
+ const msg = formatInviteMessage(payload, token, memberEmail);
179
+ for (const line of msg.split("\n")) {
180
+ console.log(chalk.dim(" ") + line);
181
+ }
182
+ console.log(chalk.dim(" ─".repeat(30)));
183
+ console.log();
184
+ }
185
+ // ─── Mailto helper ──────────────────────────────────────────────────────────
186
+ /**
187
+ * Build a mailto: URL pre-populated with the invite message.
188
+ * Opens in the admin's default email client — they just hit Send.
189
+ */
190
+ export function buildMailtoUrl(payload, token, recipientEmail) {
191
+ const subject = `You're invited to join ${payload.teamName} on HQ`;
192
+ const body = formatInviteMessage(payload, token, recipientEmail);
193
+ return `mailto:${recipientEmail}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
194
+ }
195
+ /**
196
+ * Open the admin's email client with a pre-populated invite email.
197
+ */
198
+ export function openInviteEmail(payload, token, recipientEmail) {
199
+ const url = buildMailtoUrl(payload, token, recipientEmail);
200
+ openBrowser(url);
201
+ }
202
+ /**
203
+ * Copy text to the system clipboard. Cross-platform: pbcopy (macOS),
204
+ * clip (Windows), xclip/xsel (Linux). Returns true on success.
205
+ */
206
+ export function copyToClipboard(text) {
207
+ try {
208
+ const platform = process.platform;
209
+ if (platform === "darwin") {
210
+ execSync("pbcopy", { input: text });
211
+ }
212
+ else if (platform === "win32") {
213
+ execSync("clip", { input: text });
214
+ }
215
+ else {
216
+ // Try xclip first, fall back to xsel
217
+ try {
218
+ execSync("xclip -selection clipboard", { input: text });
219
+ }
220
+ catch {
221
+ execSync("xsel --clipboard --input", { input: text });
222
+ }
223
+ }
224
+ return true;
225
+ }
226
+ catch {
227
+ return false;
228
+ }
229
+ }
230
+ //# sourceMappingURL=invite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite.js","sourceRoot":"","sources":["../src/invite.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Join-via-invite flow for HQ Teams members.
3
+ *
4
+ * When a member has an invite token (from an admin), this flow:
5
+ * 1. Decodes the token to get team coordinates
6
+ * 2. Authenticates via GitHub device flow
7
+ * 3. Checks org membership / repo access (waits if invite is pending)
8
+ * 4. Clones the team repo into companies/{slug}/
9
+ *
10
+ * This is the primary path for non-technical users who received an invite.
11
+ */
12
+ import { type GitHubAuth } from "./auth.js";
13
+ export interface JoinByInviteResult {
14
+ /** Team slug (companies/{slug}/ directory). */
15
+ slug: string;
16
+ /** Human-readable team name. */
17
+ teamName: string;
18
+ /** Local path where the team repo was cloned. */
19
+ companyDir: string;
20
+ /** GitHub HTML URL for the team repo. */
21
+ repoUrl: string;
22
+ }
23
+ /**
24
+ * Run the join-via-invite flow.
25
+ *
26
+ * @param auth - Authenticated GitHub user (already signed in)
27
+ * @param hqRoot - Local HQ root directory (where companies/ lives)
28
+ * @param token - The invite token string (hq_...) or raw base64
29
+ * @returns - Result on success, null on failure/abort
30
+ */
31
+ export declare function runJoinByInvite(auth: GitHubAuth, hqRoot: string, token: string): Promise<JoinByInviteResult | null>;
32
+ //# sourceMappingURL=join-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join-flow.d.ts","sourceRoot":"","sources":["../src/join-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAW5C,MAAM,WAAW,kBAAkB;IACjC,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;CACjB;AAwED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA6HpC"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Join-via-invite flow for HQ Teams members.
3
+ *
4
+ * When a member has an invite token (from an admin), this flow:
5
+ * 1. Decodes the token to get team coordinates
6
+ * 2. Authenticates via GitHub device flow
7
+ * 3. Checks org membership / repo access (waits if invite is pending)
8
+ * 4. Clones the team repo into companies/{slug}/
9
+ *
10
+ * This is the primary path for non-technical users who received an invite.
11
+ */
12
+ import * as fs from "fs";
13
+ import * as path from "path";
14
+ import * as os from "os";
15
+ import { execSync } from "child_process";
16
+ import { createInterface } from "readline";
17
+ import chalk from "chalk";
18
+ import { ensureCompanyStructure } from "./company-template.js";
19
+ import { stepStatus, success, warn, info, step } from "./ui.js";
20
+ import { decodeInviteToken, checkRepoAccess, } from "./invite.js";
21
+ // ─── Prompt helpers ─────────────────────────────────────────────────────────
22
+ function prompt(question, defaultVal) {
23
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
24
+ const suffix = defaultVal ? ` (${defaultVal})` : "";
25
+ return new Promise((resolve) => {
26
+ rl.question(` ? ${question}${suffix} `, (answer) => {
27
+ rl.close();
28
+ resolve(answer.trim() || defaultVal || "");
29
+ });
30
+ });
31
+ }
32
+ function pause(message) {
33
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
34
+ return new Promise((resolve) => {
35
+ rl.question(` ${message}`, () => {
36
+ rl.close();
37
+ resolve();
38
+ });
39
+ });
40
+ }
41
+ // ─── Git helpers (same as team-setup.ts / admin-onboarding.ts) ──────────────
42
+ function runGitWithToken(args, cwd, auth) {
43
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "create-hq-git-"));
44
+ const isWindows = process.platform === "win32";
45
+ const askpassPath = path.join(tmpDir, isWindows ? "askpass.cmd" : "askpass.sh");
46
+ try {
47
+ if (isWindows) {
48
+ fs.writeFileSync(askpassPath, `@echo off\nif "%~1"=="" (echo %GIT_TOKEN%) else (echo %GIT_TOKEN%)\n`, "utf-8");
49
+ }
50
+ else {
51
+ fs.writeFileSync(askpassPath, `#!/bin/sh\necho "$GIT_TOKEN"\n`, "utf-8");
52
+ fs.chmodSync(askpassPath, 0o700);
53
+ }
54
+ execSync(`git ${args.join(" ")}`, {
55
+ cwd,
56
+ stdio: "pipe",
57
+ env: {
58
+ ...process.env,
59
+ GIT_TOKEN: auth.access_token,
60
+ GIT_ASKPASS: askpassPath,
61
+ GIT_TERMINAL_PROMPT: "0",
62
+ GCM_INTERACTIVE: "never",
63
+ },
64
+ });
65
+ }
66
+ finally {
67
+ try {
68
+ fs.rmSync(tmpDir, { recursive: true, force: true });
69
+ }
70
+ catch {
71
+ // ignore
72
+ }
73
+ }
74
+ }
75
+ function tokenAuthUrl(cloneUrl) {
76
+ const u = new URL(cloneUrl);
77
+ u.username = "x-access-token";
78
+ return u.toString();
79
+ }
80
+ // ─── Main flow ──────────────────────────────────────────────────────────────
81
+ /**
82
+ * Run the join-via-invite flow.
83
+ *
84
+ * @param auth - Authenticated GitHub user (already signed in)
85
+ * @param hqRoot - Local HQ root directory (where companies/ lives)
86
+ * @param token - The invite token string (hq_...) or raw base64
87
+ * @returns - Result on success, null on failure/abort
88
+ */
89
+ export async function runJoinByInvite(auth, hqRoot, token) {
90
+ // 1. Decode token
91
+ const payload = decodeInviteToken(token);
92
+ if (!payload) {
93
+ warn("Invalid invite code. Check that you copied it correctly and try again.");
94
+ return null;
95
+ }
96
+ console.log();
97
+ console.log(chalk.bold(" Joining a team"));
98
+ console.log();
99
+ console.log(` ${chalk.dim("Team:")} ${chalk.cyan(payload.teamName)}`);
100
+ console.log(` ${chalk.dim("Org:")} ${payload.org}`);
101
+ console.log(` ${chalk.dim("Invited by:")} @${payload.invitedBy}`);
102
+ console.log();
103
+ // 2. Check repo access (proves org membership + repo visibility)
104
+ const accessLabel = `Checking access to ${payload.org}/${payload.repo}`;
105
+ stepStatus(accessLabel, "running");
106
+ let hasAccess = await checkRepoAccess(auth, payload.org, payload.repo);
107
+ if (!hasAccess) {
108
+ stepStatus(accessLabel, "failed");
109
+ console.log();
110
+ // Guide the user to accept the org invite
111
+ info("You don't have access to this team's repository yet.");
112
+ console.log();
113
+ step("Check your email for a GitHub organization invite from " + chalk.cyan(payload.org));
114
+ step("Accept the invite, then come back here.");
115
+ console.log();
116
+ // Give them up to 3 chances to retry
117
+ for (let attempt = 1; attempt <= 3; attempt++) {
118
+ await pause(`Press Enter after accepting the invite (attempt ${attempt}/3)... `);
119
+ stepStatus(`Re-checking access (attempt ${attempt})`, "running");
120
+ hasAccess = await checkRepoAccess(auth, payload.org, payload.repo);
121
+ if (hasAccess) {
122
+ stepStatus(`Re-checking access (attempt ${attempt})`, "done");
123
+ break;
124
+ }
125
+ else {
126
+ stepStatus(`Re-checking access (attempt ${attempt})`, "failed");
127
+ if (attempt < 3) {
128
+ console.log();
129
+ info("Still no access. Make sure you:");
130
+ step(`Accepted the org invite from ${payload.org} (check email from GitHub)`);
131
+ step("Are signed in to GitHub with the same account you accepted the invite on");
132
+ console.log();
133
+ }
134
+ }
135
+ }
136
+ if (!hasAccess) {
137
+ console.log();
138
+ warn("Could not access the team repository after 3 attempts.");
139
+ info(`Your GitHub username is @${auth.login}`);
140
+ info(`Ask @${payload.invitedBy} to add @${auth.login} to the ${payload.org} organization.`);
141
+ info("Then run create-hq again with the same invite code.");
142
+ return null;
143
+ }
144
+ }
145
+ else {
146
+ stepStatus(accessLabel, "done");
147
+ }
148
+ // 3. Clone the repo into companies/{slug}/
149
+ const companiesDir = path.join(hqRoot, "companies");
150
+ if (!fs.existsSync(companiesDir)) {
151
+ fs.mkdirSync(companiesDir, { recursive: true });
152
+ }
153
+ const companyDir = path.join(companiesDir, payload.slug);
154
+ if (fs.existsSync(companyDir) && fs.readdirSync(companyDir).length > 0) {
155
+ info(`companies/${payload.slug}/ already exists — skipping clone.`);
156
+ }
157
+ else {
158
+ const cloneLabel = `Cloning ${payload.teamName} into companies/${payload.slug}`;
159
+ stepStatus(cloneLabel, "running");
160
+ try {
161
+ const remoteUrl = tokenAuthUrl(payload.cloneUrl);
162
+ runGitWithToken(["clone", `"${remoteUrl}"`, `"${companyDir}"`], companiesDir, auth);
163
+ // Strip the token from the stored remote URL
164
+ execSync(`git remote set-url origin "${payload.cloneUrl}"`, {
165
+ cwd: companyDir,
166
+ stdio: "pipe",
167
+ });
168
+ // Ensure standard company subdirectories exist
169
+ ensureCompanyStructure(companyDir);
170
+ stepStatus(cloneLabel, "done");
171
+ }
172
+ catch (err) {
173
+ stepStatus(cloneLabel, "failed");
174
+ const message = err instanceof Error ? err.message : String(err);
175
+ warn(`Could not clone team repo: ${message}`);
176
+ // Provide actionable guidance
177
+ console.log();
178
+ info("This usually means the repository doesn't exist or your access isn't set up yet.");
179
+ info(`Ask @${payload.invitedBy} to verify the repo exists at: https://github.com/${payload.org}/${payload.repo}`);
180
+ return null;
181
+ }
182
+ }
183
+ const repoUrl = `https://github.com/${payload.org}/${payload.repo}`;
184
+ console.log();
185
+ success(`Joined ${payload.teamName}!`);
186
+ info(`Team workspace: companies/${payload.slug}/`);
187
+ return {
188
+ slug: payload.slug,
189
+ teamName: payload.teamName,
190
+ companyDir,
191
+ repoUrl,
192
+ };
193
+ }
194
+ //# sourceMappingURL=join-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"join-flow.js","sourceRoot":"","sources":["../src/join-flow.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- export type SystemPackageManager = "brew" | "apt" | "dnf" | "yum" | "pacman" | null;
2
- export type OsType = "macos" | "linux-debian" | "linux-fedora" | "linux-arch" | "linux" | "unix";
1
+ export type SystemPackageManager = "brew" | "apt" | "dnf" | "yum" | "pacman" | "winget" | "choco" | null;
2
+ export type OsType = "macos" | "linux-debian" | "linux-fedora" | "linux-arch" | "linux" | "windows" | "unix";
3
3
  export interface PlatformInfo {
4
4
  os: OsType;
5
5
  packageManager: SystemPackageManager;
@@ -1 +1 @@
1
- {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;AAEpF,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAEjG,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,oBAAoB,CAAC;IACrC,YAAY,EAAE,OAAO,CAAC;CACvB;AAmDD,wBAAgB,cAAc,IAAI,YAAY,CAO7C"}
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAEzG,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,cAAc,GAAG,cAAc,GAAG,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE7G,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,oBAAoB,CAAC;IACrC,YAAY,EAAE,OAAO,CAAC;CACvB;AA4DD,wBAAgB,cAAc,IAAI,YAAY,CAO7C"}
package/dist/platform.js CHANGED
@@ -1,7 +1,12 @@
1
1
  import { execSync } from "child_process";
2
2
  function hasBin(name) {
3
3
  try {
4
- execSync(`which ${name}`, { stdio: "pipe" });
4
+ if (process.platform === "win32") {
5
+ execSync(`where ${name}`, { stdio: "pipe" });
6
+ }
7
+ else {
8
+ execSync(`which ${name}`, { stdio: "pipe" });
9
+ }
5
10
  return true;
6
11
  }
7
12
  catch {
@@ -10,6 +15,8 @@ function hasBin(name) {
10
15
  }
11
16
  function detectOs() {
12
17
  const platform = process.platform;
18
+ if (platform === "win32")
19
+ return "windows";
13
20
  if (platform === "darwin")
14
21
  return "macos";
15
22
  if (platform !== "linux")
@@ -31,6 +38,12 @@ function detectOs() {
31
38
  }
32
39
  function detectSystemPm(os) {
33
40
  switch (os) {
41
+ case "windows":
42
+ if (hasBin("winget"))
43
+ return "winget";
44
+ if (hasBin("choco"))
45
+ return "choco";
46
+ return null;
34
47
  case "macos":
35
48
  return hasBin("brew") ? "brew" : null;
36
49
  case "linux-debian":
@@ -1 +1 @@
1
- {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAYzC,SAAS,MAAM,CAAC,IAAY;IAC1B,IAAI,CAAC;QACH,QAAQ,CAAC,SAAS,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,QAAQ;IACf,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IAC1C,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IAExC,6BAA6B;IAC7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,qBAAqB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC9E,IAAI,uCAAuC,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,cAAc,CAAC;QACjF,IAAI,4CAA4C,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,cAAc,CAAC;QACtF,IAAI,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,YAAY,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;IAC5C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,EAAU;IAChC,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,OAAO;YACV,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACxC,KAAK,cAAc;YACjB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACtC,KAAK,cAAc;YACjB,IAAI,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAChC,IAAI,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAChC,OAAO,IAAI,CAAC;QACd,KAAK,YAAY;YACf,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5C;YACE,qCAAqC;YACrC,IAAI,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAChC,IAAI,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAChC,IAAI,MAAM,CAAC,KAAK,CAAC;gBAAE,OAAO,KAAK,CAAC;YAChC,IAAI,MAAM,CAAC,QAAQ,CAAC;gBAAE,OAAO,QAAQ,CAAC;YACtC,IAAI,MAAM,CAAC,MAAM,CAAC;gBAAE,OAAO,MAAM,CAAC;YAClC,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,OAAO;QACL,EAAE;QACF,cAAc,EAAE,cAAc,CAAC,EAAE,CAAC;QAClC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC;KAC5B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"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"}