create-hq 10.7.1 → 10.8.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.
@@ -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
+ ```