hacklab 0.22.3 → 26.921.2

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 (259) hide show
  1. package/README.md +39 -415
  2. package/dist/index.js +317 -23
  3. package/package.json +22 -40
  4. package/LICENSE +0 -21
  5. package/dist/agent-handoff.d.ts +0 -51
  6. package/dist/agent-handoff.d.ts.map +0 -1
  7. package/dist/agent-handoff.js +0 -91
  8. package/dist/agent-handoff.js.map +0 -1
  9. package/dist/api-client.d.ts +0 -18
  10. package/dist/api-client.d.ts.map +0 -1
  11. package/dist/api-client.js +0 -40
  12. package/dist/api-client.js.map +0 -1
  13. package/dist/belt.d.ts +0 -25
  14. package/dist/belt.d.ts.map +0 -1
  15. package/dist/belt.js +0 -113
  16. package/dist/belt.js.map +0 -1
  17. package/dist/card.d.ts +0 -66
  18. package/dist/card.d.ts.map +0 -1
  19. package/dist/card.js +0 -151
  20. package/dist/card.js.map +0 -1
  21. package/dist/cli.d.ts +0 -2
  22. package/dist/cli.d.ts.map +0 -1
  23. package/dist/cli.js +0 -238
  24. package/dist/cli.js.map +0 -1
  25. package/dist/commands/book.d.ts +0 -14
  26. package/dist/commands/book.d.ts.map +0 -1
  27. package/dist/commands/book.js +0 -90
  28. package/dist/commands/book.js.map +0 -1
  29. package/dist/commands/chat.d.ts +0 -36
  30. package/dist/commands/chat.d.ts.map +0 -1
  31. package/dist/commands/chat.js +0 -642
  32. package/dist/commands/chat.js.map +0 -1
  33. package/dist/commands/config.d.ts +0 -2
  34. package/dist/commands/config.d.ts.map +0 -1
  35. package/dist/commands/config.js +0 -84
  36. package/dist/commands/config.js.map +0 -1
  37. package/dist/commands/daemon.d.ts +0 -19
  38. package/dist/commands/daemon.d.ts.map +0 -1
  39. package/dist/commands/daemon.js +0 -72
  40. package/dist/commands/daemon.js.map +0 -1
  41. package/dist/commands/drop.d.ts +0 -12
  42. package/dist/commands/drop.d.ts.map +0 -1
  43. package/dist/commands/drop.js +0 -103
  44. package/dist/commands/drop.js.map +0 -1
  45. package/dist/commands/drops.d.ts +0 -9
  46. package/dist/commands/drops.d.ts.map +0 -1
  47. package/dist/commands/drops.js +0 -96
  48. package/dist/commands/drops.js.map +0 -1
  49. package/dist/commands/essay.d.ts +0 -40
  50. package/dist/commands/essay.d.ts.map +0 -1
  51. package/dist/commands/essay.js +0 -651
  52. package/dist/commands/essay.js.map +0 -1
  53. package/dist/commands/hackathon.d.ts +0 -2
  54. package/dist/commands/hackathon.d.ts.map +0 -1
  55. package/dist/commands/hackathon.js +0 -893
  56. package/dist/commands/hackathon.js.map +0 -1
  57. package/dist/commands/hacker.d.ts +0 -2
  58. package/dist/commands/hacker.d.ts.map +0 -1
  59. package/dist/commands/hacker.js +0 -87
  60. package/dist/commands/hacker.js.map +0 -1
  61. package/dist/commands/jobs.d.ts +0 -18
  62. package/dist/commands/jobs.d.ts.map +0 -1
  63. package/dist/commands/jobs.js +0 -138
  64. package/dist/commands/jobs.js.map +0 -1
  65. package/dist/commands/keys.d.ts +0 -2
  66. package/dist/commands/keys.d.ts.map +0 -1
  67. package/dist/commands/keys.js +0 -138
  68. package/dist/commands/keys.js.map +0 -1
  69. package/dist/commands/login.d.ts +0 -83
  70. package/dist/commands/login.d.ts.map +0 -1
  71. package/dist/commands/login.js +0 -236
  72. package/dist/commands/login.js.map +0 -1
  73. package/dist/commands/logout.d.ts +0 -2
  74. package/dist/commands/logout.d.ts.map +0 -1
  75. package/dist/commands/logout.js +0 -22
  76. package/dist/commands/logout.js.map +0 -1
  77. package/dist/commands/org-jobs.d.ts +0 -50
  78. package/dist/commands/org-jobs.d.ts.map +0 -1
  79. package/dist/commands/org-jobs.js +0 -383
  80. package/dist/commands/org-jobs.js.map +0 -1
  81. package/dist/commands/org.d.ts +0 -67
  82. package/dist/commands/org.d.ts.map +0 -1
  83. package/dist/commands/org.js +0 -1244
  84. package/dist/commands/org.js.map +0 -1
  85. package/dist/commands/ping.d.ts +0 -2
  86. package/dist/commands/ping.d.ts.map +0 -1
  87. package/dist/commands/ping.js +0 -50
  88. package/dist/commands/ping.js.map +0 -1
  89. package/dist/commands/profile.d.ts +0 -72
  90. package/dist/commands/profile.d.ts.map +0 -1
  91. package/dist/commands/profile.js +0 -672
  92. package/dist/commands/profile.js.map +0 -1
  93. package/dist/commands/project.d.ts +0 -2
  94. package/dist/commands/project.d.ts.map +0 -1
  95. package/dist/commands/project.js +0 -583
  96. package/dist/commands/project.js.map +0 -1
  97. package/dist/commands/referral.d.ts +0 -6
  98. package/dist/commands/referral.d.ts.map +0 -1
  99. package/dist/commands/referral.js +0 -93
  100. package/dist/commands/referral.js.map +0 -1
  101. package/dist/commands/rtfm.d.ts +0 -9
  102. package/dist/commands/rtfm.d.ts.map +0 -1
  103. package/dist/commands/rtfm.js +0 -114
  104. package/dist/commands/rtfm.js.map +0 -1
  105. package/dist/commands/scan.d.ts +0 -13
  106. package/dist/commands/scan.d.ts.map +0 -1
  107. package/dist/commands/scan.js +0 -286
  108. package/dist/commands/scan.js.map +0 -1
  109. package/dist/commands/scout.d.ts +0 -18
  110. package/dist/commands/scout.d.ts.map +0 -1
  111. package/dist/commands/scout.js +0 -232
  112. package/dist/commands/scout.js.map +0 -1
  113. package/dist/commands/setup-rail.d.ts +0 -58
  114. package/dist/commands/setup-rail.d.ts.map +0 -1
  115. package/dist/commands/setup-rail.js +0 -135
  116. package/dist/commands/setup-rail.js.map +0 -1
  117. package/dist/commands/setup.d.ts +0 -29
  118. package/dist/commands/setup.d.ts.map +0 -1
  119. package/dist/commands/setup.js +0 -442
  120. package/dist/commands/setup.js.map +0 -1
  121. package/dist/commands/sync.d.ts +0 -9
  122. package/dist/commands/sync.d.ts.map +0 -1
  123. package/dist/commands/sync.js +0 -345
  124. package/dist/commands/sync.js.map +0 -1
  125. package/dist/commands/update.d.ts +0 -2
  126. package/dist/commands/update.d.ts.map +0 -1
  127. package/dist/commands/update.js +0 -92
  128. package/dist/commands/update.js.map +0 -1
  129. package/dist/commands/whoami.d.ts +0 -2
  130. package/dist/commands/whoami.d.ts.map +0 -1
  131. package/dist/commands/whoami.js +0 -41
  132. package/dist/commands/whoami.js.map +0 -1
  133. package/dist/config.d.ts +0 -78
  134. package/dist/config.d.ts.map +0 -1
  135. package/dist/config.js +0 -93
  136. package/dist/config.js.map +0 -1
  137. package/dist/daily-sync.d.ts +0 -150
  138. package/dist/daily-sync.d.ts.map +0 -1
  139. package/dist/daily-sync.js +0 -665
  140. package/dist/daily-sync.js.map +0 -1
  141. package/dist/dossier.d.ts +0 -73
  142. package/dist/dossier.d.ts.map +0 -1
  143. package/dist/dossier.js +0 -141
  144. package/dist/dossier.js.map +0 -1
  145. package/dist/field-normalize.d.ts +0 -4
  146. package/dist/field-normalize.d.ts.map +0 -1
  147. package/dist/field-normalize.js +0 -8
  148. package/dist/field-normalize.js.map +0 -1
  149. package/dist/index.d.ts +0 -3
  150. package/dist/index.d.ts.map +0 -1
  151. package/dist/index.js.map +0 -1
  152. package/dist/job-fields.d.ts +0 -47
  153. package/dist/job-fields.d.ts.map +0 -1
  154. package/dist/job-fields.js +0 -148
  155. package/dist/job-fields.js.map +0 -1
  156. package/dist/machine.d.ts +0 -15
  157. package/dist/machine.d.ts.map +0 -1
  158. package/dist/machine.js +0 -64
  159. package/dist/machine.js.map +0 -1
  160. package/dist/org-fields.d.ts +0 -57
  161. package/dist/org-fields.d.ts.map +0 -1
  162. package/dist/org-fields.js +0 -167
  163. package/dist/org-fields.js.map +0 -1
  164. package/dist/posthog.d.ts +0 -38
  165. package/dist/posthog.d.ts.map +0 -1
  166. package/dist/posthog.js +0 -224
  167. package/dist/posthog.js.map +0 -1
  168. package/dist/project-fields.d.ts +0 -40
  169. package/dist/project-fields.d.ts.map +0 -1
  170. package/dist/project-fields.js +0 -79
  171. package/dist/project-fields.js.map +0 -1
  172. package/dist/prompt-consent.d.ts +0 -73
  173. package/dist/prompt-consent.d.ts.map +0 -1
  174. package/dist/prompt-consent.js +0 -191
  175. package/dist/prompt-consent.js.map +0 -1
  176. package/dist/prompt-stats.d.ts +0 -226
  177. package/dist/prompt-stats.d.ts.map +0 -1
  178. package/dist/prompt-stats.js +0 -561
  179. package/dist/prompt-stats.js.map +0 -1
  180. package/dist/referral.d.ts +0 -14
  181. package/dist/referral.d.ts.map +0 -1
  182. package/dist/referral.js +0 -28
  183. package/dist/referral.js.map +0 -1
  184. package/dist/registry.d.ts +0 -15
  185. package/dist/registry.d.ts.map +0 -1
  186. package/dist/registry.js +0 -180
  187. package/dist/registry.js.map +0 -1
  188. package/dist/resolve-command.d.ts +0 -20
  189. package/dist/resolve-command.d.ts.map +0 -1
  190. package/dist/resolve-command.js +0 -21
  191. package/dist/resolve-command.js.map +0 -1
  192. package/dist/scanners/antigravity.d.ts +0 -41
  193. package/dist/scanners/antigravity.d.ts.map +0 -1
  194. package/dist/scanners/antigravity.js +0 -210
  195. package/dist/scanners/antigravity.js.map +0 -1
  196. package/dist/scanners/github-copilot-telemetry.d.ts +0 -23
  197. package/dist/scanners/github-copilot-telemetry.d.ts.map +0 -1
  198. package/dist/scanners/github-copilot-telemetry.js +0 -220
  199. package/dist/scanners/github-copilot-telemetry.js.map +0 -1
  200. package/dist/scanners/github-copilot.d.ts +0 -68
  201. package/dist/scanners/github-copilot.d.ts.map +0 -1
  202. package/dist/scanners/github-copilot.js +0 -262
  203. package/dist/scanners/github-copilot.js.map +0 -1
  204. package/dist/scanners/incremental.d.ts +0 -282
  205. package/dist/scanners/incremental.d.ts.map +0 -1
  206. package/dist/scanners/incremental.js +0 -788
  207. package/dist/scanners/incremental.js.map +0 -1
  208. package/dist/scanners/index.d.ts +0 -116
  209. package/dist/scanners/index.d.ts.map +0 -1
  210. package/dist/scanners/index.js +0 -726
  211. package/dist/scanners/index.js.map +0 -1
  212. package/dist/scanners/sqlite.d.ts +0 -18
  213. package/dist/scanners/sqlite.d.ts.map +0 -1
  214. package/dist/scanners/sqlite.js +0 -63
  215. package/dist/scanners/sqlite.js.map +0 -1
  216. package/dist/scanners/util.d.ts +0 -112
  217. package/dist/scanners/util.d.ts.map +0 -1
  218. package/dist/scanners/util.js +0 -167
  219. package/dist/scanners/util.js.map +0 -1
  220. package/dist/session.d.ts +0 -106
  221. package/dist/session.d.ts.map +0 -1
  222. package/dist/session.js +0 -191
  223. package/dist/session.js.map +0 -1
  224. package/dist/share-card-colors.d.ts +0 -19
  225. package/dist/share-card-colors.d.ts.map +0 -1
  226. package/dist/share-card-colors.js +0 -36
  227. package/dist/share-card-colors.js.map +0 -1
  228. package/dist/share-card.d.ts +0 -31
  229. package/dist/share-card.d.ts.map +0 -1
  230. package/dist/share-card.js +0 -380
  231. package/dist/share-card.js.map +0 -1
  232. package/dist/share.d.ts +0 -17
  233. package/dist/share.d.ts.map +0 -1
  234. package/dist/share.js +0 -75
  235. package/dist/share.js.map +0 -1
  236. package/dist/sync.d.ts +0 -100
  237. package/dist/sync.d.ts.map +0 -1
  238. package/dist/sync.js +0 -304
  239. package/dist/sync.js.map +0 -1
  240. package/dist/ui.d.ts +0 -33
  241. package/dist/ui.d.ts.map +0 -1
  242. package/dist/ui.js +0 -127
  243. package/dist/ui.js.map +0 -1
  244. package/dist/utils/npmGlobal.d.ts +0 -30
  245. package/dist/utils/npmGlobal.d.ts.map +0 -1
  246. package/dist/utils/npmGlobal.js +0 -69
  247. package/dist/utils/npmGlobal.js.map +0 -1
  248. package/dist/utils/openBrowser.d.ts +0 -14
  249. package/dist/utils/openBrowser.d.ts.map +0 -1
  250. package/dist/utils/openBrowser.js +0 -47
  251. package/dist/utils/openBrowser.js.map +0 -1
  252. package/dist/utils/updateCheck.d.ts +0 -16
  253. package/dist/utils/updateCheck.d.ts.map +0 -1
  254. package/dist/utils/updateCheck.js +0 -111
  255. package/dist/utils/updateCheck.js.map +0 -1
  256. package/dist/utils/waitForEnter.d.ts +0 -12
  257. package/dist/utils/waitForEnter.d.ts.map +0 -1
  258. package/dist/utils/waitForEnter.js +0 -43
  259. package/dist/utils/waitForEnter.js.map +0 -1
@@ -1,893 +0,0 @@
1
- import { readFile, writeFile } from 'node:fs/promises';
2
- import { apiErrorMessage, emitJsonError, requireSession, } from '../api-client.js';
3
- import { resolveCommand } from '../resolve-command.js';
4
- import { fetchApi } from '../sync.js';
5
- import { bold, dim, error, hint, info, mint, success } from '../ui.js';
6
- // `hacklab hackathon` — RSVP, team up, and submit for a hacklab hackathon from
7
- // the terminal. Every response from `<appUrl>/api/hackathons` is enveloped as
8
- // `{schemaVersion:1, ...}` (errors as `{schemaVersion:1, error:{code,message}}`),
9
- // so every subcommand relays the server's own body verbatim in `--json` mode
10
- // instead of reshaping it — this side only picks fields out for the human
11
- // renderers, defensively, since the exact field names are the server's call.
12
- const SUBCOMMANDS = [
13
- 'list',
14
- 'view',
15
- 'rsvp',
16
- 'invite',
17
- 'team',
18
- 'track',
19
- 'tracks',
20
- 'submit',
21
- 'export',
22
- ];
23
- const TEAM_SUBCOMMANDS = ['create', 'join', 'accept', 'reject', 'list'];
24
- const BASE = '/api/hackathons';
25
- function usage(exitCode = 1) {
26
- const header = 'usage: hacklab hackathon <list|view|rsvp|invite|team|track|tracks|submit|export>';
27
- if (exitCode === 0)
28
- info(header);
29
- else
30
- error(header);
31
- info(` hacklab hackathon ${dim('list [--past] [--json]')}`);
32
- info(` hacklab hackathon ${dim('view <slug> [--json]')}`);
33
- info(` hacklab hackathon ${dim('rsvp <slug> [--token <t>] [--json]')}`);
34
- info(` hacklab hackathon ${dim('invite <slug> --file <path> | --emails a@b.com,c@d.com [--json]')}`);
35
- info(` hacklab hackathon ${dim('team create <slug> --name "X" [--summary S] [--max N] [--closed] [--json]')}`);
36
- info(` hacklab hackathon ${dim('team join <slug> <teamSlug> [--json]')}`);
37
- info(` hacklab hackathon ${dim('team accept|reject <slug> <teamSlug> <handle> [--json]')}`);
38
- info(` hacklab hackathon ${dim('team list <slug> [--json]')}`);
39
- info(` hacklab hackathon ${dim('track <slug> <teamSlug> <trackSlug> [--json]')}`);
40
- info(` hacklab hackathon ${dim('tracks <slug> [--json]')}`);
41
- info(` hacklab hackathon ${dim('submit <slug> <teamSlug> --title T --description D [--repo/--video/--site/--track] [--json]')}`);
42
- info(` hacklab hackathon ${dim('export <slug> [--format csv|json] [--out <path>] [--json]')}`);
43
- process.exit(exitCode);
44
- }
45
- function teamUsage() {
46
- error('usage: hacklab hackathon team <create|join|accept|reject|list>');
47
- info(` hacklab hackathon ${dim('team create <slug> --name "X" [--summary S] [--max N] [--closed]')}`);
48
- info(` hacklab hackathon ${dim('team join <slug> <teamSlug>')}`);
49
- info(` hacklab hackathon ${dim('team accept|reject <slug> <teamSlug> <handle>')}`);
50
- info(` hacklab hackathon ${dim('team list <slug>')}`);
51
- process.exit(1);
52
- }
53
- function printJson(data) {
54
- console.log(JSON.stringify({ schemaVersion: 1, ...data }, null, 2));
55
- }
56
- /** Pull `--flag <value>` out of argv; returns the value and the rest (mirrors org.ts's extractOption). */
57
- function extractFlag(args, name) {
58
- const rest = [];
59
- let value;
60
- for (let i = 0; i < args.length; i++) {
61
- if (args[i] === name) {
62
- value = args[++i];
63
- continue;
64
- }
65
- rest.push(args[i]);
66
- }
67
- return { value, rest };
68
- }
69
- async function apiGet(session, path) {
70
- return fetchApi(session, path, {
71
- headers: { Authorization: `Bearer ${session.token}` },
72
- });
73
- }
74
- async function apiPost(session, path, body) {
75
- return fetchApi(session, path, {
76
- method: 'POST',
77
- headers: {
78
- 'Content-Type': 'application/json',
79
- Authorization: `Bearer ${session.token}`,
80
- },
81
- body: JSON.stringify(body),
82
- });
83
- }
84
- /** Generic non-2xx handling: relay the server envelope verbatim in --json, apiErrorMessage in human mode. */
85
- async function handleApiError(res, json, session) {
86
- const body = (await res.json().catch(() => null));
87
- if (json) {
88
- console.log(JSON.stringify(body ?? {
89
- schemaVersion: 1,
90
- error: { code: 'error', message: `failed (${res.status})` },
91
- }));
92
- process.exit(1);
93
- }
94
- error(apiErrorMessage(res.status, body ?? null, session));
95
- process.exit(1);
96
- }
97
- /**
98
- * rsvp gets its own error path. The two refusals a real person actually hits
99
- * are "you are not on the list" and "your address does not match the one you
100
- * were invited under", and both are resolved by the organizer rather than by
101
- * retrying, so each gets a hint pointing there.
102
- */
103
- async function handleRsvpError(res, json, session) {
104
- const body = (await res.json().catch(() => null));
105
- if (json) {
106
- console.log(JSON.stringify(body ?? {
107
- schemaVersion: 1,
108
- error: { code: 'error', message: `failed (${res.status})` },
109
- }));
110
- process.exit(1);
111
- }
112
- if (body?.error?.code === 'not_invited' && body.error.message) {
113
- error(body.error.message);
114
- hint('ask the organizer to add this address, or your @handle, to the list.');
115
- process.exit(1);
116
- }
117
- // A link alone never admits anyone: the address has to match too.
118
- if (body?.error?.code === 'email_mismatch' && body.error.message) {
119
- error(body.error.message);
120
- hint(`you are signed in as ${session.email}.`);
121
- hint('ask the organizer to add that address, or your @handle, to the list.');
122
- process.exit(1);
123
- }
124
- error(apiErrorMessage(res.status, body ?? null, session));
125
- process.exit(1);
126
- }
127
- async function networkFail(err, json) {
128
- const message = err instanceof Error ? err.message : String(err);
129
- if (json)
130
- emitJsonError('network', message);
131
- error(message);
132
- process.exit(1);
133
- }
134
- function str(value) {
135
- return typeof value === 'string' && value ? value : null;
136
- }
137
- function formatDate(value) {
138
- const raw = str(value);
139
- if (!raw)
140
- return '(tbd)';
141
- const d = new Date(raw);
142
- if (Number.isNaN(d.getTime()))
143
- return raw;
144
- return d.toLocaleString(undefined, {
145
- dateStyle: 'medium',
146
- timeStyle: 'short',
147
- });
148
- }
149
- function formatDateRange(start, end) {
150
- const s = str(start);
151
- const e = str(end);
152
- if (!s && !e)
153
- return '(dates tbd)';
154
- const fmt = (v) => {
155
- const d = new Date(v);
156
- return Number.isNaN(d.getTime())
157
- ? v
158
- : d.toLocaleDateString(undefined, {
159
- month: 'short',
160
- day: 'numeric',
161
- year: 'numeric',
162
- });
163
- };
164
- if (s && e)
165
- return `${fmt(s)} – ${fmt(e)}`;
166
- if (s)
167
- return `from ${fmt(s)}`;
168
- return `until ${fmt(e)}`;
169
- }
170
- // Field names aren't finalized on the server yet — check a `deadlines` object
171
- // first, then fall back to flat fields, and accept a couple of aliases per
172
- // deadline so this doesn't break on the first naming choice the API ships with.
173
- function pickDeadlines(h) {
174
- const source = (typeof h.deadlines === 'object' && h.deadlines !== null ? h.deadlines : h);
175
- const specs = [
176
- {
177
- label: 'RSVP closes',
178
- keys: ['rsvpClosesAt', 'rsvpCloses', 'rsvpDeadline'],
179
- },
180
- { label: 'teams lock', keys: ['teamsLockAt', 'teamLockAt', 'teamsLock'] },
181
- {
182
- label: 'tracks lock',
183
- keys: ['tracksLockAt', 'trackLockAt', 'tracksLock'],
184
- },
185
- {
186
- label: 'submissions due',
187
- keys: ['submissionsDueAt', 'submissionDeadline', 'submissionsDue'],
188
- },
189
- ];
190
- return specs.map(({ label, keys }) => {
191
- const key = keys.find((k) => typeof source[k] === 'string');
192
- return { label, at: key ? source[key] : null };
193
- });
194
- }
195
- function nextDeadline(rows, now = new Date()) {
196
- const upcoming = rows
197
- .filter((r) => {
198
- if (!r.at)
199
- return false;
200
- const t = new Date(r.at).getTime();
201
- return !Number.isNaN(t) && t > now.getTime();
202
- })
203
- .sort((a, b) => new Date(a.at).getTime() - new Date(b.at).getTime());
204
- return upcoming[0] ?? null;
205
- }
206
- function renderHackathon(h) {
207
- const lines = [];
208
- lines.push(` ${bold(h.title)} ${dim(`(${h.slug})`)}`);
209
- const phase = str(h.phase);
210
- if (phase)
211
- lines.push(` ${dim('phase')} ${phase}`);
212
- lines.push(` ${dim('dates')} ${formatDateRange(h.startsAt, h.endsAt)}`);
213
- lines.push('');
214
- const rows = pickDeadlines(h);
215
- const next = nextDeadline(rows);
216
- const width = Math.max(...rows.map((r) => r.label.length));
217
- for (const row of rows) {
218
- const line = ` ${dim(row.label.padEnd(width))} ${formatDate(row.at)}`;
219
- lines.push(row === next || (next && row.label === next.label)
220
- ? `${line} ${mint('← next')}`
221
- : line);
222
- }
223
- return lines;
224
- }
225
- function challengeLabel(mode) {
226
- return mode === 'theme' ? 'Theme' : 'Tracks';
227
- }
228
- function renderTrackEntries(tracks) {
229
- return tracks.map((t) => {
230
- const name = str(t.name) ?? str(t.slug) ?? '(unnamed)';
231
- const slug = str(t.slug);
232
- return ` ${bold(name)}${slug && slug !== name ? ` ${dim(`(${slug})`)}` : ''}`;
233
- });
234
- }
235
- // ── list ──────────────────────────────────────────────────────────────────
236
- async function hackathonList(args) {
237
- const json = args.includes('--json');
238
- const past = args.includes('--past');
239
- const session = await requireSession(json);
240
- let res;
241
- try {
242
- res = await apiGet(session, `${BASE}${past ? '?view=past' : ''}`);
243
- }
244
- catch (err) {
245
- return networkFail(err, json);
246
- }
247
- if (!res.ok)
248
- return handleApiError(res, json, session);
249
- const body = (await res.json().catch(() => null));
250
- if (!body?.hackathons) {
251
- if (json)
252
- return emitJsonError('bad_response', 'malformed response');
253
- error('got a malformed response from hacklab');
254
- process.exit(1);
255
- }
256
- if (json) {
257
- printJson(body);
258
- return;
259
- }
260
- if (body.hackathons.length === 0) {
261
- info(past ? 'no past hackathons' : 'no upcoming hackathons');
262
- return;
263
- }
264
- const width = Math.max(...body.hackathons.map((h) => h.slug.length));
265
- for (const h of body.hackathons) {
266
- const dates = formatDateRange(h.startsAt, h.endsAt);
267
- const phase = str(h.phase);
268
- console.log(` ${bold(h.slug.padEnd(width))} ${h.title} ${dim(dates)}${phase ? ` ${dim(`[${phase}]`)}` : ''}`);
269
- }
270
- }
271
- // ── view ──────────────────────────────────────────────────────────────────
272
- async function hackathonView(args) {
273
- const json = args.includes('--json');
274
- const slug = args.find((a) => !a.startsWith('-'));
275
- if (!slug) {
276
- if (json)
277
- return emitJsonError('usage', 'usage: hacklab hackathon view <slug>');
278
- error('usage: hacklab hackathon view <slug>');
279
- process.exit(1);
280
- }
281
- const session = await requireSession(json);
282
- let res;
283
- try {
284
- res = await apiGet(session, `${BASE}/${encodeURIComponent(slug)}`);
285
- }
286
- catch (err) {
287
- return networkFail(err, json);
288
- }
289
- if (!res.ok)
290
- return handleApiError(res, json, session);
291
- const body = (await res.json().catch(() => null));
292
- if (!body?.hackathon) {
293
- if (json)
294
- return emitJsonError('bad_response', 'malformed response');
295
- error('got a malformed response from hacklab');
296
- process.exit(1);
297
- }
298
- if (json) {
299
- printJson(body);
300
- return;
301
- }
302
- const lines = renderHackathon(body.hackathon);
303
- const mode = str(body.hackathon.challengeMode);
304
- const visible = body.hackathon.challengeVisible === true;
305
- lines.push('');
306
- if (!mode || mode === 'open') {
307
- lines.push(` ${dim('challenge')} open — no theme or tracks, build anything`);
308
- console.log(lines.join('\n'));
309
- return;
310
- }
311
- const label = challengeLabel(mode);
312
- if (!visible) {
313
- lines.push(` ${dim(label)} announced when the hackathon starts`);
314
- console.log(lines.join('\n'));
315
- return;
316
- }
317
- let tracksRes;
318
- try {
319
- tracksRes = await apiGet(session, `${BASE}/${encodeURIComponent(slug)}/tracks`);
320
- }
321
- catch (err) {
322
- return networkFail(err, json);
323
- }
324
- if (!tracksRes.ok)
325
- return handleApiError(tracksRes, json, session);
326
- const tracksBody = (await tracksRes
327
- .json()
328
- .catch(() => null));
329
- const tracks = tracksBody?.tracks ?? [];
330
- lines.push(` ${bold(label)}`);
331
- lines.push(...(tracks.length > 0
332
- ? renderTrackEntries(tracks)
333
- : [` ${dim('(none yet)')}`]));
334
- console.log(lines.join('\n'));
335
- }
336
- // ── rsvp ──────────────────────────────────────────────────────────────────
337
- async function hackathonRsvp(args) {
338
- const json = args.includes('--json');
339
- const { value: token, rest } = extractFlag(args.filter((a) => a !== '--json'), '--token');
340
- const slug = rest.find((a) => !a.startsWith('-'));
341
- if (!slug) {
342
- if (json) {
343
- return emitJsonError('usage', 'usage: hacklab hackathon rsvp <slug> [--token <t>]');
344
- }
345
- error('usage: hacklab hackathon rsvp <slug> [--token <t>]');
346
- process.exit(1);
347
- }
348
- const session = await requireSession(json);
349
- let res;
350
- try {
351
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/rsvp`, token ? { token } : {});
352
- }
353
- catch (err) {
354
- return networkFail(err, json);
355
- }
356
- if (!res.ok)
357
- return handleRsvpError(res, json, session);
358
- const body = (await res.json().catch(() => null));
359
- if (json) {
360
- printJson(body ?? { rsvped: true });
361
- return;
362
- }
363
- success(`you're in — RSVPed to ${slug}`);
364
- }
365
- // ── invite ────────────────────────────────────────────────────────────────
366
- async function hackathonInvite(args) {
367
- const json = args.includes('--json');
368
- const filtered = args.filter((a) => a !== '--json');
369
- const { value: filePath, rest: r1 } = extractFlag(filtered, '--file');
370
- const { value: emailsRaw, rest } = extractFlag(r1, '--emails');
371
- const slug = rest.find((a) => !a.startsWith('-'));
372
- if (!slug) {
373
- const message = 'usage: hacklab hackathon invite <slug> --file <path> | --emails a@b.com,c@d.com';
374
- if (json)
375
- return emitJsonError('usage', message);
376
- error(message);
377
- process.exit(1);
378
- }
379
- if (!filePath && !emailsRaw) {
380
- const message = 'pass --file <path> or --emails a@b.com,c@d.com';
381
- if (json)
382
- return emitJsonError('invalid_args', message);
383
- error(message);
384
- process.exit(1);
385
- }
386
- if (filePath && emailsRaw) {
387
- const message = 'use either --file or --emails, not both';
388
- if (json)
389
- return emitJsonError('invalid_args', message);
390
- error(message);
391
- process.exit(1);
392
- }
393
- let body;
394
- if (filePath) {
395
- let text;
396
- try {
397
- text = await readFile(filePath, 'utf8');
398
- }
399
- catch (err) {
400
- const code = err.code;
401
- const message = code === 'ENOENT'
402
- ? `file not found: ${filePath}`
403
- : `could not read ${filePath}`;
404
- if (json)
405
- return emitJsonError('read_failed', message);
406
- error(message);
407
- process.exit(1);
408
- }
409
- body = { text };
410
- }
411
- else {
412
- const emails = emailsRaw
413
- .split(',')
414
- .map((e) => e.trim())
415
- .filter(Boolean);
416
- body = { emails };
417
- }
418
- const session = await requireSession(json);
419
- let res;
420
- try {
421
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/invites`, body);
422
- }
423
- catch (err) {
424
- return networkFail(err, json);
425
- }
426
- if (!res.ok)
427
- return handleApiError(res, json, session);
428
- const data = (await res.json().catch(() => null));
429
- if (json) {
430
- printJson(data ?? { invited: 0, skipped: 0, rejected: [] });
431
- return;
432
- }
433
- const invited = data?.invited ?? 0;
434
- const skipped = data?.skipped ?? 0;
435
- success(`invited ${invited}${skipped ? `, skipped ${skipped}` : ''}`);
436
- const rejected = data?.rejected ?? [];
437
- if (rejected.length > 0) {
438
- error(`rejected ${rejected.length} line${rejected.length === 1 ? '' : 's'}:`);
439
- for (const r of rejected) {
440
- if (typeof r === 'string')
441
- console.log(` ${r}`);
442
- else {
443
- console.log(` ${r.line ?? '(unknown)'}${r.reason ? dim(` — ${r.reason}`) : ''}`);
444
- }
445
- }
446
- }
447
- }
448
- // ── team ──────────────────────────────────────────────────────────────────
449
- async function teamCreate(args) {
450
- const json = args.includes('--json');
451
- const closed = args.includes('--closed');
452
- let rest = args.filter((a) => a !== '--json' && a !== '--closed');
453
- const { value: name, rest: r1 } = extractFlag(rest, '--name');
454
- const { value: summary, rest: r2 } = extractFlag(r1, '--summary');
455
- const { value: maxRaw, rest: r3 } = extractFlag(r2, '--max');
456
- rest = r3;
457
- const slug = rest.find((a) => !a.startsWith('-'));
458
- if (!slug) {
459
- const message = 'usage: hacklab hackathon team create <slug> --name "X"';
460
- if (json)
461
- return emitJsonError('usage', message);
462
- error(message);
463
- process.exit(1);
464
- }
465
- if (!name) {
466
- const message = 'pass --name "Team Name"';
467
- if (json)
468
- return emitJsonError('invalid_args', message);
469
- error(message);
470
- process.exit(1);
471
- }
472
- let maxSize;
473
- if (maxRaw !== undefined) {
474
- const n = Number(maxRaw);
475
- if (!Number.isInteger(n) || n < 1) {
476
- const message = '--max must be a positive whole number';
477
- if (json)
478
- return emitJsonError('invalid_args', message);
479
- error(message);
480
- process.exit(1);
481
- }
482
- maxSize = n;
483
- }
484
- const session = await requireSession(json);
485
- let res;
486
- try {
487
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/teams`, {
488
- name,
489
- summary: summary || undefined,
490
- maxSize,
491
- closed: closed || undefined,
492
- });
493
- }
494
- catch (err) {
495
- return networkFail(err, json);
496
- }
497
- if (!res.ok)
498
- return handleApiError(res, json, session);
499
- const body = (await res.json().catch(() => null));
500
- if (json) {
501
- printJson(body ?? { created: true });
502
- return;
503
- }
504
- success(`created team ${bold(name)}`);
505
- }
506
- async function teamJoin(args) {
507
- const json = args.includes('--json');
508
- const positional = args.filter((a) => !a.startsWith('-'));
509
- const [slug, teamSlug] = positional;
510
- if (!slug || !teamSlug) {
511
- const message = 'usage: hacklab hackathon team join <slug> <teamSlug>';
512
- if (json)
513
- return emitJsonError('usage', message);
514
- error(message);
515
- process.exit(1);
516
- }
517
- const session = await requireSession(json);
518
- let res;
519
- try {
520
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/teams/${encodeURIComponent(teamSlug)}/requests`, { action: 'request' });
521
- }
522
- catch (err) {
523
- return networkFail(err, json);
524
- }
525
- if (!res.ok)
526
- return handleApiError(res, json, session);
527
- const body = (await res.json().catch(() => null));
528
- if (json) {
529
- printJson(body ?? { requested: true });
530
- return;
531
- }
532
- success(`requested to join ${bold(teamSlug)}`);
533
- }
534
- async function teamRequestAction(args, action) {
535
- const json = args.includes('--json');
536
- const positional = args.filter((a) => !a.startsWith('-'));
537
- const [slug, teamSlug, handle] = positional;
538
- if (!slug || !teamSlug || !handle) {
539
- const message = `usage: hacklab hackathon team ${action} <slug> <teamSlug> <handle>`;
540
- if (json)
541
- return emitJsonError('usage', message);
542
- error(message);
543
- process.exit(1);
544
- }
545
- const session = await requireSession(json);
546
- let res;
547
- try {
548
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/teams/${encodeURIComponent(teamSlug)}/requests`, { action, applicantHandle: handle });
549
- }
550
- catch (err) {
551
- return networkFail(err, json);
552
- }
553
- if (!res.ok)
554
- return handleApiError(res, json, session);
555
- const body = (await res.json().catch(() => null));
556
- if (json) {
557
- printJson(body ?? { [action + 'ed']: true });
558
- return;
559
- }
560
- success(`${action === 'accept' ? 'accepted' : 'rejected'} ${bold(handle)}`);
561
- }
562
- async function teamList(args) {
563
- const json = args.includes('--json');
564
- const slug = args.find((a) => !a.startsWith('-'));
565
- if (!slug) {
566
- const message = 'usage: hacklab hackathon team list <slug>';
567
- if (json)
568
- return emitJsonError('usage', message);
569
- error(message);
570
- process.exit(1);
571
- }
572
- const session = await requireSession(json);
573
- let res;
574
- try {
575
- res = await apiGet(session, `${BASE}/${encodeURIComponent(slug)}/teams`);
576
- }
577
- catch (err) {
578
- return networkFail(err, json);
579
- }
580
- if (!res.ok)
581
- return handleApiError(res, json, session);
582
- const body = (await res.json().catch(() => null));
583
- if (!body?.teams) {
584
- if (json)
585
- return emitJsonError('bad_response', 'malformed response');
586
- error('got a malformed response from hacklab');
587
- process.exit(1);
588
- }
589
- if (json) {
590
- printJson(body);
591
- return;
592
- }
593
- if (body.teams.length === 0) {
594
- info('no teams yet');
595
- return;
596
- }
597
- for (const t of body.teams) {
598
- const name = str(t.name) ?? str(t.slug) ?? '(unnamed)';
599
- const teamSlug = str(t.slug);
600
- const closedTag = t.closed ? dim(' [closed]') : '';
601
- console.log(` ${bold(name)}${teamSlug ? ` ${dim(`(${teamSlug})`)}` : ''}${closedTag}`);
602
- }
603
- }
604
- async function hackathonTeam(args) {
605
- const [subToken, ...rest] = args;
606
- if (!subToken)
607
- teamUsage();
608
- const resolved = resolveCommand(subToken, TEAM_SUBCOMMANDS);
609
- if (resolved.kind === 'ambiguous') {
610
- error(`ambiguous: hackathon team ${subToken} (${resolved.matches.join(', ')})`);
611
- process.exit(1);
612
- }
613
- if (resolved.kind === 'unknown') {
614
- error(`unknown subcommand: hackathon team ${subToken}`);
615
- teamUsage();
616
- }
617
- if (resolved.name === 'create')
618
- return teamCreate(rest);
619
- if (resolved.name === 'join')
620
- return teamJoin(rest);
621
- if (resolved.name === 'accept')
622
- return teamRequestAction(rest, 'accept');
623
- if (resolved.name === 'reject')
624
- return teamRequestAction(rest, 'reject');
625
- if (resolved.name === 'list')
626
- return teamList(rest);
627
- }
628
- // ── track ─────────────────────────────────────────────────────────────────
629
- /**
630
- * track_locked means the server refused to set a track, for one of two
631
- * reasons: this hackathon isn't in `tracks` mode (nothing to pick), or it is
632
- * but the challenge hasn't been revealed yet. Best-effort look up the actual
633
- * hackathon to tell the two apart; if that lookup fails or the fields aren't
634
- * there, fall back to relaying the server's own message with no invented hint.
635
- */
636
- async function handleTrackError(res, json, session, slug) {
637
- const body = (await res.json().catch(() => null));
638
- if (json) {
639
- console.log(JSON.stringify(body ?? {
640
- schemaVersion: 1,
641
- error: { code: 'error', message: `failed (${res.status})` },
642
- }));
643
- process.exit(1);
644
- }
645
- if (body?.error?.code === 'track_locked' && body.error.message) {
646
- error(body.error.message);
647
- try {
648
- const hRes = await apiGet(session, `${BASE}/${encodeURIComponent(slug)}`);
649
- if (hRes.ok) {
650
- const hBody = (await hRes.json().catch(() => null));
651
- const mode = str(hBody?.hackathon?.challengeMode);
652
- const visible = hBody?.hackathon?.challengeVisible === true;
653
- if (mode && mode !== 'tracks') {
654
- hint(`${slug} is running in "${mode}" mode — there are no tracks to pick.`);
655
- }
656
- else if (mode === 'tracks' && !visible) {
657
- hint('tracks have not been revealed yet — check back once the hackathon starts.');
658
- }
659
- }
660
- }
661
- catch {
662
- // best-effort only: no hint beats an invented one.
663
- }
664
- process.exit(1);
665
- }
666
- error(apiErrorMessage(res.status, body ?? null, session));
667
- process.exit(1);
668
- }
669
- async function hackathonTrack(args) {
670
- const json = args.includes('--json');
671
- const positional = args.filter((a) => !a.startsWith('-'));
672
- const [slug, teamSlug, trackSlug] = positional;
673
- if (!slug || !teamSlug || !trackSlug) {
674
- const message = 'usage: hacklab hackathon track <slug> <teamSlug> <trackSlug>';
675
- if (json)
676
- return emitJsonError('usage', message);
677
- error(message);
678
- process.exit(1);
679
- }
680
- const session = await requireSession(json);
681
- let res;
682
- try {
683
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/teams/${encodeURIComponent(teamSlug)}/track`, { trackSlug });
684
- }
685
- catch (err) {
686
- return networkFail(err, json);
687
- }
688
- if (!res.ok)
689
- return handleTrackError(res, json, session, slug);
690
- const body = (await res.json().catch(() => null));
691
- if (json) {
692
- printJson(body ?? { track: trackSlug });
693
- return;
694
- }
695
- success(`set ${bold(teamSlug)}'s track to ${bold(trackSlug)}`);
696
- }
697
- // ── tracks ────────────────────────────────────────────────────────────────
698
- async function hackathonTracks(args) {
699
- const json = args.includes('--json');
700
- const slug = args.find((a) => !a.startsWith('-'));
701
- if (!slug) {
702
- const message = 'usage: hacklab hackathon tracks <slug>';
703
- if (json)
704
- return emitJsonError('usage', message);
705
- error(message);
706
- process.exit(1);
707
- }
708
- const session = await requireSession(json);
709
- let res;
710
- try {
711
- res = await apiGet(session, `${BASE}/${encodeURIComponent(slug)}/tracks`);
712
- }
713
- catch (err) {
714
- return networkFail(err, json);
715
- }
716
- if (!res.ok)
717
- return handleApiError(res, json, session);
718
- const body = (await res.json().catch(() => null));
719
- if (!body) {
720
- if (json)
721
- return emitJsonError('bad_response', 'malformed response');
722
- error('got a malformed response from hacklab');
723
- process.exit(1);
724
- }
725
- if (json) {
726
- printJson(body);
727
- return;
728
- }
729
- const mode = body.challengeMode;
730
- if (!mode || mode === 'open') {
731
- info('open — no theme or tracks, build anything');
732
- return;
733
- }
734
- const label = challengeLabel(mode);
735
- if (!body.challengeVisible) {
736
- info(`${label.toLowerCase()} announced when the hackathon starts`);
737
- return;
738
- }
739
- const tracks = body.tracks ?? [];
740
- if (tracks.length === 0) {
741
- info(`no ${label.toLowerCase()} yet`);
742
- return;
743
- }
744
- console.log(` ${bold(label)}`);
745
- for (const line of renderTrackEntries(tracks))
746
- console.log(line);
747
- }
748
- // ── submit ────────────────────────────────────────────────────────────────
749
- async function hackathonSubmit(args) {
750
- const json = args.includes('--json');
751
- let rest = args.filter((a) => a !== '--json');
752
- const { value: title, rest: r1 } = extractFlag(rest, '--title');
753
- const { value: description, rest: r2 } = extractFlag(r1, '--description');
754
- const { value: repo, rest: r3 } = extractFlag(r2, '--repo');
755
- const { value: video, rest: r4 } = extractFlag(r3, '--video');
756
- const { value: site, rest: r5 } = extractFlag(r4, '--site');
757
- const { value: track, rest: r6 } = extractFlag(r5, '--track');
758
- rest = r6;
759
- const [slug, teamSlug] = rest.filter((a) => !a.startsWith('-'));
760
- if (!slug || !teamSlug) {
761
- const message = 'usage: hacklab hackathon submit <slug> <teamSlug> --title T --description D';
762
- if (json)
763
- return emitJsonError('usage', message);
764
- error(message);
765
- process.exit(1);
766
- }
767
- if (!title || !description) {
768
- const message = 'pass --title and --description';
769
- if (json)
770
- return emitJsonError('invalid_args', message);
771
- error(message);
772
- process.exit(1);
773
- }
774
- const session = await requireSession(json);
775
- let res;
776
- try {
777
- res = await apiPost(session, `${BASE}/${encodeURIComponent(slug)}/teams/${encodeURIComponent(teamSlug)}/submission`, {
778
- title,
779
- description,
780
- repoUrl: repo || undefined,
781
- videoUrl: video || undefined,
782
- siteUrl: site || undefined,
783
- trackSlug: track || undefined,
784
- });
785
- }
786
- catch (err) {
787
- return networkFail(err, json);
788
- }
789
- if (!res.ok)
790
- return handleApiError(res, json, session);
791
- const body = (await res.json().catch(() => null));
792
- if (json) {
793
- printJson(body ?? { submitted: true });
794
- return;
795
- }
796
- success(`submitted ${bold(title)} for ${bold(teamSlug)}`);
797
- }
798
- // ── export ────────────────────────────────────────────────────────────────
799
- async function hackathonExport(args) {
800
- const json = args.includes('--json');
801
- const filtered = args.filter((a) => a !== '--json');
802
- const { value: formatFlag, rest: r1 } = extractFlag(filtered, '--format');
803
- const { value: out, rest } = extractFlag(r1, '--out');
804
- const slug = rest.find((a) => !a.startsWith('-'));
805
- if (!slug) {
806
- const message = 'usage: hacklab hackathon export <slug> [--format csv|json] [--out <path>]';
807
- if (json)
808
- return emitJsonError('usage', message);
809
- error(message);
810
- process.exit(1);
811
- }
812
- const format = formatFlag ?? (json ? 'json' : 'csv');
813
- if (format !== 'csv' && format !== 'json') {
814
- const message = '--format must be csv or json';
815
- if (json)
816
- return emitJsonError('invalid_args', message);
817
- error(message);
818
- process.exit(1);
819
- }
820
- const session = await requireSession(json);
821
- let res;
822
- try {
823
- res = await apiGet(session, `${BASE}/${encodeURIComponent(slug)}/export?format=${format}`);
824
- }
825
- catch (err) {
826
- return networkFail(err, json);
827
- }
828
- if (!res.ok)
829
- return handleApiError(res, json, session);
830
- const text = await res.text();
831
- if (out) {
832
- await writeFile(out, text, 'utf8');
833
- if (json) {
834
- printJson({ wrote: out, format, bytes: Buffer.byteLength(text, 'utf8') });
835
- return;
836
- }
837
- info('this file contains participants’ personal data — handle it carefully.');
838
- success(`wrote ${format} export to ${out}`);
839
- return;
840
- }
841
- process.stdout.write(text.endsWith('\n') ? text : `${text}\n`);
842
- }
843
- // ── dispatch ──────────────────────────────────────────────────────────────
844
- export async function hackathon(args = []) {
845
- const [subToken, ...rest] = args;
846
- // Bare `hacklab hackathon` prints the help — listing the events is an
847
- // explicit `list` away. `help`/`--help`/`-h` land here too, exiting 0.
848
- if (!subToken ||
849
- subToken === 'help' ||
850
- subToken === '--help' ||
851
- subToken === '-h') {
852
- usage(0);
853
- }
854
- // Any other flag with no subcommand (e.g. a lone `--json`) is a usage error.
855
- if (subToken.startsWith('-')) {
856
- usage();
857
- }
858
- // `teams` is a natural slip for `team list`, and nothing else resolves from
859
- // it, so point straight there instead of a bare "unknown subcommand".
860
- if (subToken === 'teams') {
861
- error('unknown subcommand: hackathon teams');
862
- hint(`did you mean ${dim('hacklab hackathon team list')}?`);
863
- process.exit(1);
864
- }
865
- const resolved = resolveCommand(subToken, SUBCOMMANDS);
866
- if (resolved.kind === 'ambiguous') {
867
- error(`ambiguous: hackathon ${subToken} (${resolved.matches.join(', ')})`);
868
- process.exit(1);
869
- }
870
- if (resolved.kind === 'unknown') {
871
- error(`unknown subcommand: hackathon ${subToken}`);
872
- usage();
873
- }
874
- if (resolved.name === 'list')
875
- return hackathonList(rest);
876
- if (resolved.name === 'view')
877
- return hackathonView(rest);
878
- if (resolved.name === 'rsvp')
879
- return hackathonRsvp(rest);
880
- if (resolved.name === 'invite')
881
- return hackathonInvite(rest);
882
- if (resolved.name === 'team')
883
- return hackathonTeam(rest);
884
- if (resolved.name === 'track')
885
- return hackathonTrack(rest);
886
- if (resolved.name === 'tracks')
887
- return hackathonTracks(rest);
888
- if (resolved.name === 'submit')
889
- return hackathonSubmit(rest);
890
- if (resolved.name === 'export')
891
- return hackathonExport(rest);
892
- }
893
- //# sourceMappingURL=hackathon.js.map