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
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { scaffold } from "./scaffold.js";
|
|
5
|
+
import { runInviteCommand } from "./invite-command.js";
|
|
5
6
|
const require = createRequire(import.meta.url);
|
|
6
7
|
const pkg = require("../package.json");
|
|
7
8
|
const program = new Command();
|
|
@@ -9,12 +10,15 @@ program
|
|
|
9
10
|
.name("create-hq")
|
|
10
11
|
.description("Create a new HQ by Indigo — Personal OS for AI Workers")
|
|
11
12
|
.version(pkg.version)
|
|
12
|
-
.argument("[directory]", "where to create HQ
|
|
13
|
+
.argument("[directory]", "where to create HQ (prompts if omitted)")
|
|
13
14
|
.option("--skip-deps", "skip dependency checks")
|
|
14
15
|
.option("--skip-cli", "don't install @indigoai-us/hq-cli globally")
|
|
15
16
|
.option("--skip-sync", "don't prompt for cloud sync setup")
|
|
17
|
+
.option("--skip-packages", "don't prompt for package discovery and installation")
|
|
16
18
|
.option("--tag <version>", "fetch a specific HQ version tag (e.g. v9.1.0)")
|
|
17
19
|
.option("--local-template <path>", "use a local template directory instead of fetching from GitHub")
|
|
20
|
+
.option("--join <token>", "join a team with an invite token (interactive prompt)")
|
|
21
|
+
.option("--invite <token>", "join a team via invite — direct, no extra prompts")
|
|
18
22
|
.action(async (directory, options) => {
|
|
19
23
|
try {
|
|
20
24
|
await scaffold(directory, options);
|
|
@@ -24,5 +28,18 @@ program
|
|
|
24
28
|
process.exit(1);
|
|
25
29
|
}
|
|
26
30
|
});
|
|
31
|
+
// Standalone invite subcommand for admins to generate invites
|
|
32
|
+
program
|
|
33
|
+
.command("invite")
|
|
34
|
+
.description("Generate an invite code for a new team member")
|
|
35
|
+
.action(async () => {
|
|
36
|
+
try {
|
|
37
|
+
await runInviteCommand();
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.error(err instanceof Error ? err.message : "An unexpected error occurred");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
27
44
|
program.parse();
|
|
28
45
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAE9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,wDAAwD,CAAC;KACrE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,QAAQ,CAAC,aAAa,EAAE,yCAAyC,CAAC;KAClE,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;KAC/C,MAAM,CAAC,YAAY,EAAE,4CAA4C,CAAC;KAClE,MAAM,CAAC,aAAa,EAAE,mCAAmC,CAAC;KAC1D,MAAM,CAAC,iBAAiB,EAAE,qDAAqD,CAAC;KAChF,MAAM,CAAC,iBAAiB,EAAE,+CAA+C,CAAC;KAC1E,MAAM,CAAC,yBAAyB,EAAE,gEAAgE,CAAC;KACnG,MAAM,CAAC,gBAAgB,EAAE,uDAAuD,CAAC;KACjF,MAAM,CAAC,kBAAkB,EAAE,mDAAmD,CAAC;KAC/E,MAAM,CAAC,KAAK,EAAE,SAA6B,EAAE,OAAO,EAAE,EAAE;IACvD,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CACpE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,8DAA8D;AAC9D,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,gBAAgB,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CACpE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone invite command for admins.
|
|
3
|
+
*
|
|
4
|
+
* Usage: create-hq invite
|
|
5
|
+
*
|
|
6
|
+
* Finds team metadata from the current HQ directory, authenticates
|
|
7
|
+
* the admin, and generates an invite code plus optional org invite.
|
|
8
|
+
*/
|
|
9
|
+
export declare function runInviteCommand(): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=invite-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite-command.d.ts","sourceRoot":"","sources":["../src/invite-command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA6EH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA8CtD"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone invite command for admins.
|
|
3
|
+
*
|
|
4
|
+
* Usage: create-hq invite
|
|
5
|
+
*
|
|
6
|
+
* Finds team metadata from the current HQ directory, authenticates
|
|
7
|
+
* the admin, and generates an invite code plus optional org invite.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
import { execSync } from "child_process";
|
|
12
|
+
import { createInterface } from "readline";
|
|
13
|
+
import chalk from "chalk";
|
|
14
|
+
import { authenticate } from "./teams-flow.js";
|
|
15
|
+
import { inviteLoop } from "./admin-onboarding.js";
|
|
16
|
+
import { warn, info } from "./ui.js";
|
|
17
|
+
function prompt(question, defaultVal) {
|
|
18
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
19
|
+
const suffix = defaultVal ? ` (${defaultVal})` : "";
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
rl.question(` ? ${question}${suffix} `, (answer) => {
|
|
22
|
+
rl.close();
|
|
23
|
+
resolve(answer.trim() || defaultVal || "");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Find team.json files in companies/ walking up from cwd.
|
|
29
|
+
*/
|
|
30
|
+
function findTeams() {
|
|
31
|
+
let dir = process.cwd();
|
|
32
|
+
const root = path.parse(dir).root;
|
|
33
|
+
const teams = [];
|
|
34
|
+
while (dir !== root) {
|
|
35
|
+
const companiesDir = path.join(dir, "companies");
|
|
36
|
+
if (fs.existsSync(companiesDir) && fs.statSync(companiesDir).isDirectory()) {
|
|
37
|
+
for (const entry of fs.readdirSync(companiesDir)) {
|
|
38
|
+
const teamJsonPath = path.join(companiesDir, entry, "team.json");
|
|
39
|
+
if (fs.existsSync(teamJsonPath)) {
|
|
40
|
+
try {
|
|
41
|
+
const meta = JSON.parse(fs.readFileSync(teamJsonPath, "utf-8"));
|
|
42
|
+
let cloneUrl = `https://github.com/${meta.org_login}/hq-${meta.team_slug}.git`;
|
|
43
|
+
try {
|
|
44
|
+
const remote = execSync("git remote get-url origin", {
|
|
45
|
+
cwd: path.join(companiesDir, entry),
|
|
46
|
+
stdio: "pipe",
|
|
47
|
+
})
|
|
48
|
+
.toString()
|
|
49
|
+
.trim();
|
|
50
|
+
if (remote)
|
|
51
|
+
cloneUrl = remote;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Use constructed URL
|
|
55
|
+
}
|
|
56
|
+
teams.push({
|
|
57
|
+
meta,
|
|
58
|
+
cloneUrl,
|
|
59
|
+
companyDir: path.join(companiesDir, entry),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Skip malformed team.json
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
dir = path.dirname(dir);
|
|
70
|
+
}
|
|
71
|
+
return teams;
|
|
72
|
+
}
|
|
73
|
+
export async function runInviteCommand() {
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(chalk.bold(" Generate a team invite"));
|
|
76
|
+
console.log();
|
|
77
|
+
const teams = findTeams();
|
|
78
|
+
if (teams.length === 0) {
|
|
79
|
+
warn("No teams found. Run this from your HQ directory (must have companies/*/team.json).");
|
|
80
|
+
info("If you haven't created a team yet, run: npx create-hq");
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
let selected;
|
|
84
|
+
if (teams.length === 1) {
|
|
85
|
+
selected = teams[0];
|
|
86
|
+
info(`Team: ${chalk.cyan(selected.meta.team_name)} (${selected.meta.org_login})`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.log(" Which team?");
|
|
90
|
+
for (let i = 0; i < teams.length; i++) {
|
|
91
|
+
console.log(chalk.cyan(` [${i + 1}] `) +
|
|
92
|
+
chalk.white(teams[i].meta.team_name) +
|
|
93
|
+
chalk.dim(` (${teams[i].meta.org_login})`));
|
|
94
|
+
}
|
|
95
|
+
const choice = await prompt(`Select (1-${teams.length})`, "1");
|
|
96
|
+
const idx = parseInt(choice, 10) - 1;
|
|
97
|
+
if (idx < 0 || idx >= teams.length) {
|
|
98
|
+
warn("Invalid selection.");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
selected = teams[idx];
|
|
102
|
+
}
|
|
103
|
+
const auth = await authenticate();
|
|
104
|
+
if (!auth) {
|
|
105
|
+
warn("Authentication required to generate invites.");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
await inviteLoop(auth, selected.meta, selected.cloneUrl);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=invite-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite-command.js","sourceRoot":"","sources":["../src/invite-command.ts"],"names":[],"mappings":"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"}
|
package/dist/invite.d.ts
ADDED
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAmB,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAmBpE,+EAA+E;AAE/E,MAAM,YAAY,GAAG,KAAK,CAAC;AAE3B,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC;SAC7B,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACzD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAsB;IACtD,OAAO,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC;YACxC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC;YAClC,CAAC,CAAC,KAAK,CAAC;QACV,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEhC,2BAA2B;QAC3B,IACE,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;YAC9B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAC/B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;YAC/B,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;YACnC,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;YACnC,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EACpC,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,MAAuB,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAgB,EAChB,QAAgB,EAChB,KAAa,EACb,OAAkC,eAAe;IAEjD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAC5B,SAAS,QAAQ,cAAc,EAC/B,IAAI,EACJ;YACE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,IAAI;aACL,CAAC;SACH,CACF,CAAC;QACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC9B,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;QAEjE,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EACH,0DAA0D;oBAC1D,iEAAiE,QAAQ,SAAS;aACrF,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACxD,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,6DAA6D;aACrE,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACvC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAgB,EAChB,QAAgB,EAChB,QAAgB;IAEhB,gCAAgC;IAChC,IAAI,CAAC;QACH,MAAM,SAAS,CAAU,SAAS,QAAQ,YAAY,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;QACxE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;IACrD,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,SAAS,CACjC,mDAAmD,EACnD,IAAI,CACL,CAAC;QACF,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,CACrE,CAAC;QACF,IAAI,OAAO;YAAE,OAAO,SAAS,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,qCAAqC;IACvC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAgB,EAChB,QAAgB,EAChB,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,SAAS,CAAU,UAAU,QAAQ,IAAI,QAAQ,EAAE,EAAE,IAAI,CAAC,CAAC;QACjE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAsB,EACtB,KAAa,EACb,WAAoB;IAEpB,MAAM,YAAY,GAAG,2BAA2B,OAAO,CAAC,GAAG,aAAa,CAAC;IACzE,MAAM,KAAK,GAAa;QACtB,+BAA+B,OAAO,CAAC,QAAQ,SAAS;QACxD,EAAE;KACH,CAAC;IAEF,wEAAwE;IACxE,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,CAAC,IAAI,CACR,gDAAgD,WAAW,EAAE,EAC7D,kFAAkF,EAClF,wBAAwB,YAAY,EAAE,EACtC,EAAE,CACH,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CACR,gDAAgD,EAChD,wBAAwB,YAAY,EAAE,EACtC,8CAA8C,OAAO,CAAC,SAAS,cAAc,EAC7E,EAAE,CACH,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,IAAI,CACR,wDAAwD,EACxD,EAAE,EACF,gDAAgD,EAChD,uCAAuC,EACvC,EAAE,EACF,oBAAoB,EACpB,wBAAwB,EACxB,gDAAgD,EAChD,EAAE,EACF,yCAAyC,EACzC,EAAE,CACH,CAAC;IAEF,oCAAoC;IACpC,KAAK,CAAC,IAAI,CACR,kDAAkD,EAClD,EAAE,EACF,6BAA6B,KAAK,EAAE,EACpC,EAAE,EACF,uEAAuE,EACvE,EAAE,EACF,KAAK,EACL,mBAAmB,OAAO,CAAC,SAAS,mCAAmC,CACxE,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAsB,EACtB,KAAa,EACb,UAAoB,EACpB,WAAoB;IAEpB,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1D,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,WAAW,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC,CAAC;IACpE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,GAAG,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IAC7D,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAsB,EACtB,KAAa,EACb,cAAsB;IAEtB,MAAM,OAAO,GAAG,0BAA0B,OAAO,CAAC,QAAQ,QAAQ,CAAC;IACnE,MAAM,IAAI,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IACjE,OAAO,UAAU,cAAc,YAAY,kBAAkB,CAAC,OAAO,CAAC,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5G,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAsB,EACtB,KAAa,EACb,cAAsB;IAEtB,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IAC3D,WAAW,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,QAAQ,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;aAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YAChC,QAAQ,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,qCAAqC;YACrC,IAAI,CAAC;gBACH,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1D,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -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"}
|