create-hq 10.7.1 → 10.9.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/invite.md +215 -0
- package/commands/promote.md +161 -0
- package/commands/team-sync.md +431 -0
- package/dist/__tests__/auth.test.d.ts +2 -0
- package/dist/__tests__/auth.test.d.ts.map +1 -0
- package/dist/__tests__/auth.test.js +201 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/scaffold.test.js +14 -1
- package/dist/__tests__/scaffold.test.js.map +1 -1
- package/dist/admin-onboarding.d.ts.map +1 -1
- package/dist/admin-onboarding.js +11 -0
- package/dist/admin-onboarding.js.map +1 -1
- package/dist/auth.d.ts +58 -13
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +105 -29
- package/dist/auth.js.map +1 -1
- package/dist/fetch-template.d.ts +3 -3
- package/dist/fetch-template.d.ts.map +1 -1
- package/dist/fetch-template.js +93 -71
- package/dist/fetch-template.js.map +1 -1
- package/dist/git.d.ts +12 -1
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js +40 -20
- package/dist/git.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/join-flow.d.ts.map +1 -1
- package/dist/join-flow.js +11 -0
- package/dist/join-flow.js.map +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +48 -13
- package/dist/scaffold.js.map +1 -1
- package/dist/team-setup.d.ts +25 -0
- package/dist/team-setup.d.ts.map +1 -1
- package/dist/team-setup.js +113 -0
- package/dist/team-setup.js.map +1 -1
- package/dist/teams-flow.d.ts +7 -2
- package/dist/teams-flow.d.ts.map +1 -1
- package/dist/teams-flow.js +31 -8
- package/dist/teams-flow.js.map +1 -1
- package/dist/ui.d.ts +3 -0
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +79 -3
- package/dist/ui.js.map +1 -1
- package/package.json +3 -2
- package/dist/art.d.ts +0 -17
- package/dist/art.d.ts.map +0 -1
- package/dist/art.js +0 -171
- package/dist/art.js.map +0 -1
- package/dist/cloud.d.ts +0 -26
- package/dist/cloud.d.ts.map +0 -1
- package/dist/cloud.js +0 -126
- package/dist/cloud.js.map +0 -1
- package/dist/tui.d.ts +0 -8
- package/dist/tui.d.ts.map +0 -1
- package/dist/tui.js +0 -86
- package/dist/tui.js.map +0 -1
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Invite a Team Member
|
|
2
|
+
|
|
3
|
+
Send an invite for a new team member. Only org admins can invite — members are guided to contact their admin.
|
|
4
|
+
|
|
5
|
+
**Usage:** `/invite`
|
|
6
|
+
|
|
7
|
+
**Requires:** `gh` CLI authenticated (`gh auth status`)
|
|
8
|
+
|
|
9
|
+
## Process
|
|
10
|
+
|
|
11
|
+
1. Find team metadata from `companies/*/team.json`
|
|
12
|
+
2. If multiple teams, ask which team
|
|
13
|
+
3. Check if the current user is an org admin
|
|
14
|
+
4. If admin: generate invite token + send GitHub org invite
|
|
15
|
+
5. If not admin: show a message to contact the admin with a prepared email
|
|
16
|
+
|
|
17
|
+
## Invite Token
|
|
18
|
+
|
|
19
|
+
The token is a self-contained `hq_`-prefixed base64url string encoding:
|
|
20
|
+
- org (GitHub org login)
|
|
21
|
+
- repo (team repo name, e.g. hq-indigo)
|
|
22
|
+
- slug (team slug for companies/{slug}/)
|
|
23
|
+
- teamName (human-readable)
|
|
24
|
+
- cloneUrl (HTTPS clone URL)
|
|
25
|
+
- invitedBy (admin's GitHub login)
|
|
26
|
+
|
|
27
|
+
## Steps
|
|
28
|
+
|
|
29
|
+
### 1. Verify gh CLI
|
|
30
|
+
|
|
31
|
+
Check that `gh` is installed and authenticated:
|
|
32
|
+
```bash
|
|
33
|
+
gh auth status 2>&1
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If `gh` is not found:
|
|
37
|
+
```
|
|
38
|
+
GitHub CLI (gh) is required for team commands.
|
|
39
|
+
Install it: https://cli.github.com
|
|
40
|
+
```
|
|
41
|
+
Stop here.
|
|
42
|
+
|
|
43
|
+
If not authenticated:
|
|
44
|
+
```
|
|
45
|
+
GitHub CLI is not authenticated. Run:
|
|
46
|
+
gh auth login
|
|
47
|
+
Then try /invite again.
|
|
48
|
+
```
|
|
49
|
+
Stop here.
|
|
50
|
+
|
|
51
|
+
Get the current user's login:
|
|
52
|
+
```bash
|
|
53
|
+
gh api user --jq .login
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Store as `{login}`.
|
|
57
|
+
|
|
58
|
+
### 2. Discover teams
|
|
59
|
+
|
|
60
|
+
Find all team.json files:
|
|
61
|
+
```bash
|
|
62
|
+
find companies/*/team.json -maxdepth 0 2>/dev/null
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
If no files found:
|
|
66
|
+
```
|
|
67
|
+
No teams found. Create a team first:
|
|
68
|
+
npx create-hq
|
|
69
|
+
```
|
|
70
|
+
Stop here.
|
|
71
|
+
|
|
72
|
+
### 3. Select team
|
|
73
|
+
|
|
74
|
+
If multiple teams exist, present a numbered list and ask the user to select one.
|
|
75
|
+
|
|
76
|
+
If only one team exists, use it automatically.
|
|
77
|
+
|
|
78
|
+
### 4. Extract team metadata
|
|
79
|
+
|
|
80
|
+
Read the selected `companies/{slug}/team.json` and extract:
|
|
81
|
+
- `team_name` — human-readable team name
|
|
82
|
+
- `team_slug` — directory slug under `companies/`
|
|
83
|
+
- `org_login` — GitHub org login (e.g. `indigoai-us`)
|
|
84
|
+
- `created_by` — GitHub username of the team admin/creator
|
|
85
|
+
|
|
86
|
+
Get the clone URL:
|
|
87
|
+
```bash
|
|
88
|
+
git -C companies/{slug} remote get-url origin
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 5. Check org role
|
|
92
|
+
|
|
93
|
+
Check the current user's org membership:
|
|
94
|
+
```bash
|
|
95
|
+
gh api "orgs/{org_login}/memberships/{login}" --jq .role 2>&1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Parse the result:
|
|
99
|
+
- If `"admin"` → continue to step 6 (admin flow)
|
|
100
|
+
- If `"member"` → go to step 5a (non-admin flow)
|
|
101
|
+
- If error (403 — not a member) → tell the user they're not a member of `{org_login}` and suggest `npx create-hq` to join
|
|
102
|
+
- If error (404 or other) → go to step 5a (non-admin flow)
|
|
103
|
+
|
|
104
|
+
### 5a. Non-admin: contact your admin
|
|
105
|
+
|
|
106
|
+
If the user is not an org admin, they cannot send invitations.
|
|
107
|
+
|
|
108
|
+
#### Find the admin's email
|
|
109
|
+
|
|
110
|
+
Try these sources in order until an email is found:
|
|
111
|
+
|
|
112
|
+
1. **Git log** — the admin created the team repo, so the first commit has their email:
|
|
113
|
+
```bash
|
|
114
|
+
git -C companies/{slug} log --format='%ae' --reverse | head -1
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
2. **GitHub profile** — check public profile (often null, but worth trying):
|
|
118
|
+
```bash
|
|
119
|
+
gh api "users/{created_by}" --jq .email 2>/dev/null
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
3. **Fallback** — if both return nothing, use `{created_by}@users.noreply.github.com`.
|
|
123
|
+
|
|
124
|
+
Use the first non-null email found as `{admin_email}`.
|
|
125
|
+
|
|
126
|
+
#### Show message and copy draft to clipboard
|
|
127
|
+
|
|
128
|
+
Show:
|
|
129
|
+
```
|
|
130
|
+
Only org admins can invite new members to {team_name}.
|
|
131
|
+
|
|
132
|
+
Your team admin is @{created_by} ({admin_email}).
|
|
133
|
+
I've prepared an email draft and copied it to your clipboard.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Build the email draft:
|
|
137
|
+
```
|
|
138
|
+
Hey {created_by},
|
|
139
|
+
|
|
140
|
+
Could you invite a new member to our {team_name} HQ team?
|
|
141
|
+
You can run /invite from your HQ to generate an invite code,
|
|
142
|
+
or go to https://github.com/orgs/{org_login}/people to add them directly.
|
|
143
|
+
|
|
144
|
+
Thanks!
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Copy the draft to the clipboard:
|
|
148
|
+
```bash
|
|
149
|
+
printf 'Hey {created_by},\n\nCould you invite a new member to our {team_name} HQ team?\nYou can run /invite from your HQ to generate an invite code,\nor go to https://github.com/orgs/{org_login}/people to add them directly.\n\nThanks!' | pbcopy 2>/dev/null || true
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Then open a pre-populated mailto link (macOS):
|
|
153
|
+
```bash
|
|
154
|
+
open "mailto:{admin_email}?subject=HQ%20team%20invite%20request%20%E2%80%94%20{team_name}&body=Hey%20{created_by}%2C%0A%0ACould%20you%20invite%20a%20new%20member%20to%20our%20{team_name}%20HQ%20team%3F%0AYou%20can%20run%20%2Finvite%20from%20your%20HQ%20to%20generate%20an%20invite%20code%2C%0Aor%20go%20to%20https%3A%2F%2Fgithub.com%2Forgs%2F{org_login}%2Fpeople%20to%20add%20them%20directly.%0A%0AThanks!" 2>/dev/null || true
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
If `pbcopy` is not available (Linux), try `xclip -selection clipboard` or `xsel --clipboard` instead.
|
|
158
|
+
|
|
159
|
+
**Stop here** — do not proceed to token generation.
|
|
160
|
+
|
|
161
|
+
### 6. Ask for email (admin only)
|
|
162
|
+
|
|
163
|
+
Ask: **"New member's email address? (leave blank to skip GitHub org invite)"**
|
|
164
|
+
|
|
165
|
+
### 7. Send GitHub org invite (if email provided)
|
|
166
|
+
|
|
167
|
+
If the user provided an email, send the org invitation:
|
|
168
|
+
```bash
|
|
169
|
+
gh api "orgs/{org_login}/invitations" -X POST -f email="{email}" -f role="direct_member" 2>&1
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- On success (2xx): note that the invite was sent
|
|
173
|
+
- On failure (403/404): fall back to manual instructions:
|
|
174
|
+
```
|
|
175
|
+
Could not send org invite automatically.
|
|
176
|
+
Invite them manually: https://github.com/orgs/{org_login}/people
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 8. Generate invite token
|
|
180
|
+
|
|
181
|
+
Build the token using python3:
|
|
182
|
+
```bash
|
|
183
|
+
python3 -c "
|
|
184
|
+
import json, base64
|
|
185
|
+
payload = {
|
|
186
|
+
'org': '{org_login}',
|
|
187
|
+
'repo': 'hq-{slug}',
|
|
188
|
+
'slug': '{slug}',
|
|
189
|
+
'teamName': '{team_name}',
|
|
190
|
+
'cloneUrl': '{clone_url}',
|
|
191
|
+
'invitedBy': '{login}'
|
|
192
|
+
}
|
|
193
|
+
token = 'hq_' + base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip('=')
|
|
194
|
+
print(token)
|
|
195
|
+
"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 9. Output results
|
|
199
|
+
|
|
200
|
+
Display the invite code and a ready-to-share message block.
|
|
201
|
+
|
|
202
|
+
If the GitHub org invite was sent, include a confirmation line.
|
|
203
|
+
|
|
204
|
+
## Ready-to-Share Message Template
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
You've been invited to join {teamName} on HQ!
|
|
208
|
+
|
|
209
|
+
Step 1: Accept the GitHub organization invite (check your email from GitHub)
|
|
210
|
+
Step 2: Install Node.js if you don't have it: https://nodejs.org
|
|
211
|
+
Step 3: Open your terminal and run: npx create-hq
|
|
212
|
+
Step 4: When asked "Do you have an HQ Teams account?", choose Yes
|
|
213
|
+
Step 5: Paste this invite code when prompted: {token}
|
|
214
|
+
Step 6: Follow the remaining prompts to complete setup
|
|
215
|
+
```
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Promote a Team Member to Admin
|
|
2
|
+
|
|
3
|
+
Give a team member org admin privileges so they can invite new members and manage the team.
|
|
4
|
+
|
|
5
|
+
**Usage:** `/promote` or `/promote @username`
|
|
6
|
+
|
|
7
|
+
**Requires:** `gh` CLI authenticated (`gh auth status`)
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
### 1. Verify gh CLI
|
|
12
|
+
|
|
13
|
+
Check that `gh` is installed and authenticated:
|
|
14
|
+
```bash
|
|
15
|
+
gh auth status 2>&1
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
If `gh` is not found:
|
|
19
|
+
```
|
|
20
|
+
GitHub CLI (gh) is required for team commands.
|
|
21
|
+
Install it: https://cli.github.com
|
|
22
|
+
```
|
|
23
|
+
Stop here.
|
|
24
|
+
|
|
25
|
+
If not authenticated:
|
|
26
|
+
```
|
|
27
|
+
GitHub CLI is not authenticated. Run:
|
|
28
|
+
gh auth login
|
|
29
|
+
Then try /promote again.
|
|
30
|
+
```
|
|
31
|
+
Stop here.
|
|
32
|
+
|
|
33
|
+
Get the current user's login:
|
|
34
|
+
```bash
|
|
35
|
+
gh api user --jq .login
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Store as `{login}`.
|
|
39
|
+
|
|
40
|
+
### 2. Discover teams
|
|
41
|
+
|
|
42
|
+
Find all team.json files:
|
|
43
|
+
```bash
|
|
44
|
+
find companies/*/team.json -maxdepth 0 2>/dev/null
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If no files found:
|
|
48
|
+
```
|
|
49
|
+
No teams found. Create a team first:
|
|
50
|
+
npx create-hq
|
|
51
|
+
```
|
|
52
|
+
Stop here.
|
|
53
|
+
|
|
54
|
+
### 3. Select team
|
|
55
|
+
|
|
56
|
+
If multiple teams exist, present a numbered list and ask the user to select one.
|
|
57
|
+
|
|
58
|
+
If only one team exists, use it automatically.
|
|
59
|
+
|
|
60
|
+
### 4. Extract team metadata
|
|
61
|
+
|
|
62
|
+
Read the selected `companies/{slug}/team.json` and extract:
|
|
63
|
+
- `team_name` — human-readable team name
|
|
64
|
+
- `org_login` — GitHub org login (e.g. `indigoai-us`)
|
|
65
|
+
|
|
66
|
+
### 5. Verify current user is an admin
|
|
67
|
+
|
|
68
|
+
Check the org role:
|
|
69
|
+
```bash
|
|
70
|
+
gh api "orgs/{org_login}/memberships/{login}" --jq .role 2>&1
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If `role` is not `"admin"`:
|
|
74
|
+
```
|
|
75
|
+
Only org admins can promote members.
|
|
76
|
+
Your team admin is @{created_by} — ask them to run /promote.
|
|
77
|
+
```
|
|
78
|
+
Stop here.
|
|
79
|
+
|
|
80
|
+
### 6. List org members
|
|
81
|
+
|
|
82
|
+
Fetch current non-admin org members:
|
|
83
|
+
```bash
|
|
84
|
+
gh api "orgs/{org_login}/members?role=member&per_page=100" --jq '.[].login' 2>&1
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If no non-admin members found:
|
|
88
|
+
```
|
|
89
|
+
No members to promote — everyone in {org_login} is already an admin.
|
|
90
|
+
```
|
|
91
|
+
Stop here.
|
|
92
|
+
|
|
93
|
+
If the user provided a `@username` argument, look for that username in the list. If found, skip to step 7 with that user. If not found:
|
|
94
|
+
```
|
|
95
|
+
@{username} is not a member of {org_login}, or is already an admin.
|
|
96
|
+
```
|
|
97
|
+
Stop here.
|
|
98
|
+
|
|
99
|
+
If no argument was provided, present a numbered list:
|
|
100
|
+
```
|
|
101
|
+
Members of {team_name} ({org_login}):
|
|
102
|
+
|
|
103
|
+
1. @alice
|
|
104
|
+
2. @bob
|
|
105
|
+
3. @charlie
|
|
106
|
+
|
|
107
|
+
Which member should become an admin?
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 7. Confirm promotion
|
|
111
|
+
|
|
112
|
+
Show what will happen:
|
|
113
|
+
```
|
|
114
|
+
Promote @{target_username} to admin of {org_login}?
|
|
115
|
+
|
|
116
|
+
This will allow them to:
|
|
117
|
+
- Invite new members to the org
|
|
118
|
+
- Manage repository settings
|
|
119
|
+
- Promote other members
|
|
120
|
+
|
|
121
|
+
Type "yes" to confirm:
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Wait for explicit "yes" confirmation. Any other response cancels.
|
|
125
|
+
|
|
126
|
+
### 8. Send promotion API call
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
gh api "orgs/{org_login}/memberships/{target_username}" -X PUT -f role="admin" 2>&1
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Check the response:
|
|
133
|
+
- If `role` is `"admin"` in response: success
|
|
134
|
+
- If 403: insufficient permissions (the GitHub App may not have the required scope)
|
|
135
|
+
- If 404: user not found in org
|
|
136
|
+
|
|
137
|
+
### 9. Report result
|
|
138
|
+
|
|
139
|
+
**On success:**
|
|
140
|
+
```
|
|
141
|
+
@{target_username} is now an admin of {org_login}.
|
|
142
|
+
|
|
143
|
+
They can now:
|
|
144
|
+
- Run /invite to add new team members
|
|
145
|
+
- Run /promote to make other members admin
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**On failure (403):**
|
|
149
|
+
```
|
|
150
|
+
Could not promote @{target_username} — insufficient permissions.
|
|
151
|
+
|
|
152
|
+
You can promote them manually:
|
|
153
|
+
https://github.com/orgs/{org_login}/people
|
|
154
|
+
Find @{target_username} → Change role → Owner
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**On failure (404):**
|
|
158
|
+
```
|
|
159
|
+
@{target_username} is not a member of {org_login}.
|
|
160
|
+
Invite them first with /invite, then promote after they join.
|
|
161
|
+
```
|