hacklab 0.0.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.
Files changed (94) hide show
  1. package/README.md +67 -0
  2. package/dist/api/client.d.ts +118 -0
  3. package/dist/api/client.d.ts.map +1 -0
  4. package/dist/api/client.js +214 -0
  5. package/dist/api/client.js.map +1 -0
  6. package/dist/commands/brag.d.ts +8 -0
  7. package/dist/commands/brag.d.ts.map +1 -0
  8. package/dist/commands/brag.js +318 -0
  9. package/dist/commands/brag.js.map +1 -0
  10. package/dist/commands/brag.utils.d.ts +12 -0
  11. package/dist/commands/brag.utils.d.ts.map +1 -0
  12. package/dist/commands/brag.utils.js +43 -0
  13. package/dist/commands/brag.utils.js.map +1 -0
  14. package/dist/commands/essay.d.ts +18 -0
  15. package/dist/commands/essay.d.ts.map +1 -0
  16. package/dist/commands/essay.js +117 -0
  17. package/dist/commands/essay.js.map +1 -0
  18. package/dist/commands/init.d.ts +16 -0
  19. package/dist/commands/init.d.ts.map +1 -0
  20. package/dist/commands/init.js +237 -0
  21. package/dist/commands/init.js.map +1 -0
  22. package/dist/commands/join.d.ts +10 -0
  23. package/dist/commands/join.d.ts.map +1 -0
  24. package/dist/commands/join.js +314 -0
  25. package/dist/commands/join.js.map +1 -0
  26. package/dist/commands/link.d.ts +17 -0
  27. package/dist/commands/link.d.ts.map +1 -0
  28. package/dist/commands/link.js +36 -0
  29. package/dist/commands/link.js.map +1 -0
  30. package/dist/commands/login.d.ts +15 -0
  31. package/dist/commands/login.d.ts.map +1 -0
  32. package/dist/commands/login.js +108 -0
  33. package/dist/commands/login.js.map +1 -0
  34. package/dist/commands/login.utils.d.ts +3 -0
  35. package/dist/commands/login.utils.d.ts.map +1 -0
  36. package/dist/commands/login.utils.js +13 -0
  37. package/dist/commands/login.utils.js.map +1 -0
  38. package/dist/commands/new.d.ts +15 -0
  39. package/dist/commands/new.d.ts.map +1 -0
  40. package/dist/commands/new.js +172 -0
  41. package/dist/commands/new.js.map +1 -0
  42. package/dist/commands/new.utils.d.ts +7 -0
  43. package/dist/commands/new.utils.d.ts.map +1 -0
  44. package/dist/commands/new.utils.js +50 -0
  45. package/dist/commands/new.utils.js.map +1 -0
  46. package/dist/commands/onboard.d.ts +10 -0
  47. package/dist/commands/onboard.d.ts.map +1 -0
  48. package/dist/commands/onboard.js +93 -0
  49. package/dist/commands/onboard.js.map +1 -0
  50. package/dist/commands/tui.d.ts +12 -0
  51. package/dist/commands/tui.d.ts.map +1 -0
  52. package/dist/commands/tui.js +112 -0
  53. package/dist/commands/tui.js.map +1 -0
  54. package/dist/commands/whoami.d.ts +2 -0
  55. package/dist/commands/whoami.d.ts.map +1 -0
  56. package/dist/commands/whoami.js +23 -0
  57. package/dist/commands/whoami.js.map +1 -0
  58. package/dist/help-format.d.ts +4 -0
  59. package/dist/help-format.d.ts.map +1 -0
  60. package/dist/help-format.js +30 -0
  61. package/dist/help-format.js.map +1 -0
  62. package/dist/index.d.ts +3 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +138 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/lab/config.d.ts +32 -0
  67. package/dist/lab/config.d.ts.map +1 -0
  68. package/dist/lab/config.js +148 -0
  69. package/dist/lab/config.js.map +1 -0
  70. package/dist/lab/contentStatus.d.ts +6 -0
  71. package/dist/lab/contentStatus.d.ts.map +1 -0
  72. package/dist/lab/contentStatus.js +19 -0
  73. package/dist/lab/contentStatus.js.map +1 -0
  74. package/dist/session.d.ts +18 -0
  75. package/dist/session.d.ts.map +1 -0
  76. package/dist/session.js +158 -0
  77. package/dist/session.js.map +1 -0
  78. package/dist/ui/banner.d.ts +2 -0
  79. package/dist/ui/banner.d.ts.map +1 -0
  80. package/dist/ui/banner.js +22 -0
  81. package/dist/ui/banner.js.map +1 -0
  82. package/dist/utils/findRepoRoot.d.ts +2 -0
  83. package/dist/utils/findRepoRoot.d.ts.map +1 -0
  84. package/dist/utils/findRepoRoot.js +17 -0
  85. package/dist/utils/findRepoRoot.js.map +1 -0
  86. package/dist/utils/openBrowser.d.ts +2 -0
  87. package/dist/utils/openBrowser.d.ts.map +1 -0
  88. package/dist/utils/openBrowser.js +29 -0
  89. package/dist/utils/openBrowser.js.map +1 -0
  90. package/dist/utils/pathExists.d.ts +2 -0
  91. package/dist/utils/pathExists.d.ts.map +1 -0
  92. package/dist/utils/pathExists.js +11 -0
  93. package/dist/utils/pathExists.js.map +1 -0
  94. package/package.json +29 -0
@@ -0,0 +1,318 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { mkdir, writeFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { basename, join, resolve } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import { cancel, intro, isCancel, note, outro, select, text } from '@clack/prompts';
7
+ import { loadHacklabConfig } from '../lab/config.js';
8
+ import { DEFAULT_CONTENT_STATUS, DEFAULT_CONTENT_VISIBILITY, } from '../lab/contentStatus.js';
9
+ import { linkHqToAccount, loadKnownAccounts } from '../session.js';
10
+ import { findRepoRoot } from '../utils/findRepoRoot.js';
11
+ import { openBrowser } from '../utils/openBrowser.js';
12
+ import { pathExists } from '../utils/pathExists.js';
13
+ import { getAppUrl } from './login.utils.js';
14
+ import { slugify, titleFromSlug } from './new.utils.js';
15
+ import { defaultAccountOwner, parseGitHubRemote } from './brag.utils.js';
16
+ const execFileAsync = promisify(execFile);
17
+ function currentDate() {
18
+ return new Date().toISOString().slice(0, 10);
19
+ }
20
+ function currentIso() {
21
+ return new Date().toISOString();
22
+ }
23
+ async function readGitRemote(repoRoot) {
24
+ try {
25
+ const result = await execFileAsync('git', ['config', '--get', 'remote.origin.url'], {
26
+ cwd: repoRoot,
27
+ });
28
+ const value = result.stdout.trim();
29
+ return value || null;
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ }
35
+ async function selectAccount(as) {
36
+ const accounts = await loadKnownAccounts();
37
+ if (accounts.length === 0) {
38
+ cancel('not logged in. run `hacklab login` first.');
39
+ process.exit(1);
40
+ }
41
+ if (as) {
42
+ const normalized = as.trim().toLowerCase();
43
+ const matched = accounts.find((account) => {
44
+ return (account.email.toLowerCase() === normalized ||
45
+ account.nickname?.toLowerCase() === normalized);
46
+ });
47
+ if (!matched) {
48
+ cancel(`account "${as}" not found on this machine.`);
49
+ process.exit(1);
50
+ }
51
+ return matched;
52
+ }
53
+ if (accounts.length === 1) {
54
+ return accounts[0];
55
+ }
56
+ const selected = await select({
57
+ message: 'you have multiple accounts. brag as:',
58
+ options: accounts.map((account) => {
59
+ const label = account.nickname
60
+ ? `${account.nickname} <${account.email}>`
61
+ : account.email;
62
+ return {
63
+ value: account.email,
64
+ label,
65
+ };
66
+ }),
67
+ });
68
+ if (isCancel(selected)) {
69
+ cancel('brag cancelled.');
70
+ process.exit(1);
71
+ }
72
+ const matched = accounts.find((account) => account.email === String(selected));
73
+ if (!matched) {
74
+ cancel('selected account is invalid.');
75
+ process.exit(1);
76
+ }
77
+ return matched;
78
+ }
79
+ async function selectHqPath(account, explicitHq) {
80
+ const home = process.env.HOME || homedir();
81
+ const knownPaths = [
82
+ account.activeHqPath,
83
+ ...(account.hqPaths ?? []),
84
+ ].filter((path) => Boolean(path));
85
+ const normalizedKnownPaths = Array.from(new Set(knownPaths.map((path) => {
86
+ if (path.startsWith('~/')) {
87
+ return resolve(home, path.slice(2));
88
+ }
89
+ return resolve(path);
90
+ })));
91
+ const fallback = account.nickname ? `~/gh/${account.nickname}-hq` : '~/gh/my-hq';
92
+ let candidatePath = explicitHq
93
+ ? explicitHq.startsWith('~/')
94
+ ? resolve(home, explicitHq.slice(2))
95
+ : resolve(explicitHq)
96
+ : normalizedKnownPaths[0];
97
+ while (true) {
98
+ if (candidatePath) {
99
+ const confirm = await select({
100
+ message: `use hq at ${candidatePath}?`,
101
+ options: [
102
+ {
103
+ value: 'yes',
104
+ label: 'yes, continue',
105
+ },
106
+ {
107
+ value: 'change',
108
+ label: 'change location',
109
+ },
110
+ {
111
+ value: 'exit',
112
+ label: 'exit',
113
+ },
114
+ ],
115
+ });
116
+ if (isCancel(confirm) || String(confirm) === 'exit') {
117
+ cancel('brag cancelled.');
118
+ process.exit(1);
119
+ }
120
+ if (String(confirm) === 'yes') {
121
+ return candidatePath;
122
+ }
123
+ }
124
+ const input = await text({
125
+ message: 'where is your hq repo?',
126
+ placeholder: fallback,
127
+ });
128
+ if (isCancel(input)) {
129
+ cancel('brag cancelled.');
130
+ process.exit(1);
131
+ }
132
+ const value = String(input).trim();
133
+ if (!value) {
134
+ cancel('hq path is required. run `hacklab join` if you do not have an hq yet.');
135
+ process.exit(1);
136
+ }
137
+ candidatePath = value.startsWith('~/') ? resolve(home, value.slice(2)) : resolve(value);
138
+ }
139
+ }
140
+ function buildProjectDraft(options) {
141
+ const date = currentDate();
142
+ const lines = [
143
+ '---',
144
+ `title: ${options.title}`,
145
+ 'type: project',
146
+ `status: ${DEFAULT_CONTENT_STATUS}`,
147
+ `visibility: ${DEFAULT_CONTENT_VISIBILITY}`,
148
+ 'authors:',
149
+ ` - ${options.owner}`,
150
+ options.sourceRepo ? `source_repo: ${options.sourceRepo}` : null,
151
+ options.sourceUrl ? `source_url: ${options.sourceUrl}` : null,
152
+ `created_at: ${date}`,
153
+ `updated_at: ${date}`,
154
+ '---',
155
+ '',
156
+ `# ${options.title}`,
157
+ '',
158
+ options.description,
159
+ '',
160
+ '## why this project',
161
+ '',
162
+ options.pitch || 'share why this project matters.',
163
+ '',
164
+ '## what i learned',
165
+ '',
166
+ options.lesson || 'write what you learned while building this.',
167
+ '',
168
+ ].filter((line) => line !== null);
169
+ return lines.join('\n');
170
+ }
171
+ export async function bragCommand(options = {}) {
172
+ intro('brag your project');
173
+ const repoRoot = await findRepoRoot();
174
+ if (!(await pathExists(join(repoRoot, '.git')))) {
175
+ cancel('this command must be run inside a git repository.');
176
+ process.exit(1);
177
+ }
178
+ const account = await selectAccount(options.as);
179
+ let hqPath = '';
180
+ let hqConfig = null;
181
+ while (!hqConfig) {
182
+ hqPath = await selectHqPath(account, options.hq);
183
+ hqConfig = await loadHacklabConfig(hqPath);
184
+ if (!hqConfig) {
185
+ note(`could not find a valid hacklab hq at ${hqPath}. run \`hacklab join\` or \`hacklab init\` there first.`, 'hq');
186
+ options.hq = undefined;
187
+ }
188
+ }
189
+ await linkHqToAccount(account.email, hqPath);
190
+ let remoteUrl = await readGitRemote(repoRoot);
191
+ let parsedRemote = remoteUrl ? parseGitHubRemote(remoteUrl) : null;
192
+ if (!parsedRemote) {
193
+ const remoteInput = await text({
194
+ message: 'github repository url',
195
+ placeholder: 'https://github.com/owner/repo',
196
+ });
197
+ if (isCancel(remoteInput)) {
198
+ cancel('brag cancelled.');
199
+ process.exit(1);
200
+ }
201
+ remoteUrl = String(remoteInput).trim();
202
+ parsedRemote = parseGitHubRemote(remoteUrl);
203
+ if (!parsedRemote) {
204
+ cancel('invalid github repository url.');
205
+ process.exit(1);
206
+ }
207
+ }
208
+ const repoName = parsedRemote?.repo || basename(repoRoot);
209
+ const defaultSlug = slugify(repoName);
210
+ const defaultTitle = titleFromSlug(defaultSlug || 'my-project');
211
+ const titleInput = await text({
212
+ message: 'project title',
213
+ placeholder: defaultTitle,
214
+ });
215
+ if (isCancel(titleInput)) {
216
+ cancel('brag cancelled.');
217
+ process.exit(1);
218
+ }
219
+ const title = String(titleInput).trim() || defaultTitle;
220
+ const descriptionInput = await text({
221
+ message: 'one-line description',
222
+ placeholder: 'what did you build?',
223
+ });
224
+ if (isCancel(descriptionInput)) {
225
+ cancel('brag cancelled.');
226
+ process.exit(1);
227
+ }
228
+ const description = String(descriptionInput).trim();
229
+ if (!description) {
230
+ cancel('description is required.');
231
+ process.exit(1);
232
+ }
233
+ const pitchInput = await text({
234
+ message: 'why is this cool? (optional)',
235
+ });
236
+ if (isCancel(pitchInput)) {
237
+ cancel('brag cancelled.');
238
+ process.exit(1);
239
+ }
240
+ const lessonInput = await text({
241
+ message: 'what did you learn? (optional)',
242
+ });
243
+ if (isCancel(lessonInput)) {
244
+ cancel('brag cancelled.');
245
+ process.exit(1);
246
+ }
247
+ const owner = defaultAccountOwner(account);
248
+ const projectSlug = defaultSlug || slugify(title) || 'project';
249
+ const targetPath = join(hqPath, hqConfig.contentDirs.projects, projectSlug, 'README.mdx');
250
+ if (await pathExists(targetPath)) {
251
+ const action = await select({
252
+ message: 'project already exists in hq. what now?',
253
+ options: [
254
+ { value: 'update', label: 'update existing draft' },
255
+ { value: 'cancel', label: 'cancel' },
256
+ ],
257
+ });
258
+ if (isCancel(action) || String(action) === 'cancel') {
259
+ cancel('brag cancelled.');
260
+ process.exit(1);
261
+ }
262
+ }
263
+ await mkdir(join(repoRoot, '.hacklab'), { recursive: true });
264
+ const manifest = {
265
+ schemaVersion: 1,
266
+ repoType: 'project',
267
+ hq: {
268
+ ...(hqConfig.labId ? { labId: hqConfig.labId } : {}),
269
+ labSlug: hqConfig.labSlug,
270
+ path: hqPath,
271
+ },
272
+ owner,
273
+ authors: [owner],
274
+ source: {
275
+ provider: 'github',
276
+ ...(parsedRemote?.fullName ? { repo: parsedRemote.fullName } : {}),
277
+ ...(parsedRemote?.httpsUrl
278
+ ? { url: parsedRemote.httpsUrl }
279
+ : remoteUrl
280
+ ? { url: remoteUrl }
281
+ : {}),
282
+ },
283
+ project: {
284
+ title,
285
+ description,
286
+ pitch: String(pitchInput).trim() || undefined,
287
+ lesson: String(lessonInput).trim() || undefined,
288
+ },
289
+ createdAt: currentIso(),
290
+ updatedAt: currentIso(),
291
+ };
292
+ await writeFile(join(repoRoot, '.hacklab', 'repo.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
293
+ await mkdir(join(hqPath, hqConfig.contentDirs.projects, projectSlug), {
294
+ recursive: true,
295
+ });
296
+ const draft = buildProjectDraft({
297
+ title,
298
+ description,
299
+ owner,
300
+ sourceRepo: parsedRemote?.fullName,
301
+ sourceUrl: parsedRemote?.httpsUrl,
302
+ pitch: String(pitchInput).trim() || undefined,
303
+ lesson: String(lessonInput).trim() || undefined,
304
+ });
305
+ await writeFile(targetPath, draft, 'utf8');
306
+ note(`saved repo manifest at ${join(repoRoot, '.hacklab', 'repo.json')}`, 'manifest');
307
+ note(`created draft in hq at ${targetPath}`, 'hq draft');
308
+ const previewUrl = `${getAppUrl(options.appUrl)}/cli/draft?title=${encodeURIComponent(title)}&slug=${encodeURIComponent(projectSlug)}&type=project`;
309
+ const opened = await openBrowser(previewUrl);
310
+ if (opened) {
311
+ note('opened project draft on hacklab website.', 'preview');
312
+ }
313
+ else {
314
+ note(`open this url:\n${previewUrl}`, 'preview');
315
+ }
316
+ outro('project added to hacklab as draft.');
317
+ }
318
+ //# sourceMappingURL=brag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brag.js","sourceRoot":"","sources":["../../src/commands/brag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export type ParsedGitHubRemote = {
2
+ owner: string;
3
+ repo: string;
4
+ fullName: string;
5
+ httpsUrl: string;
6
+ };
7
+ export declare function parseGitHubRemote(remoteUrl: string): ParsedGitHubRemote | null;
8
+ export declare function defaultAccountOwner(input: {
9
+ nickname?: string;
10
+ email: string;
11
+ }): string;
12
+ //# sourceMappingURL=brag.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brag.utils.d.ts","sourceRoot":"","sources":["../../src/commands/brag.utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACnB,CAAA;AAMD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAqC9E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CAChB,GAAG,MAAM,CAST"}
@@ -0,0 +1,43 @@
1
+ function sanitizeRepoName(value) {
2
+ return value.trim().replace(/\.git$/i, '').replace(/\/$/, '');
3
+ }
4
+ export function parseGitHubRemote(remoteUrl) {
5
+ const value = remoteUrl.trim();
6
+ if (!value) {
7
+ return null;
8
+ }
9
+ const patterns = [
10
+ /^git@github\.com:([^/]+)\/(.+)$/i,
11
+ /^ssh:\/\/git@github\.com\/([^/]+)\/(.+)$/i,
12
+ /^https?:\/\/github\.com\/([^/]+)\/(.+)$/i,
13
+ /^git:\/\/github\.com\/([^/]+)\/(.+)$/i,
14
+ ];
15
+ for (const pattern of patterns) {
16
+ const match = value.match(pattern);
17
+ if (!match) {
18
+ continue;
19
+ }
20
+ const owner = match[1].trim();
21
+ const repo = sanitizeRepoName(match[2]);
22
+ if (!owner || !repo) {
23
+ return null;
24
+ }
25
+ return {
26
+ owner,
27
+ repo,
28
+ fullName: `${owner}/${repo}`,
29
+ httpsUrl: `https://github.com/${owner}/${repo}`,
30
+ };
31
+ }
32
+ return null;
33
+ }
34
+ export function defaultAccountOwner(input) {
35
+ if (input.nickname) {
36
+ return input.nickname;
37
+ }
38
+ const email = input.email.trim().toLowerCase();
39
+ const local = email.split('@')[0] || '';
40
+ const normalized = local.replace(/[^a-z0-9._-]/g, '');
41
+ return normalized || 'unknown';
42
+ }
43
+ //# sourceMappingURL=brag.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brag.utils.js","sourceRoot":"","sources":["../../src/commands/brag.utils.ts"],"names":[],"mappings":"AAOA,SAAS,gBAAgB,CAAC,KAAa;IACnC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IAC/C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAA;IAE9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,OAAO,IAAI,CAAA;IACf,CAAC;IAED,MAAM,QAAQ,GAAG;QACb,kCAAkC;QAClC,2CAA2C;QAC3C,0CAA0C;QAC1C,uCAAuC;KAC1C,CAAA;IAED,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAElC,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,SAAQ;QACZ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7B,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAEvC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAA;QACf,CAAC;QAED,OAAO;YACH,KAAK;YACL,IAAI;YACJ,QAAQ,EAAE,GAAG,KAAK,IAAI,IAAI,EAAE;YAC5B,QAAQ,EAAE,sBAAsB,KAAK,IAAI,IAAI,EAAE;SAClD,CAAA;IACL,CAAC;IAED,OAAO,IAAI,CAAA;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAGnC;IACG,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjB,OAAO,KAAK,CAAC,QAAQ,CAAA;IACzB,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACvC,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAA;IACrD,OAAO,UAAU,IAAI,SAAS,CAAA;AAClC,CAAC"}
@@ -0,0 +1,18 @@
1
+ type EssayOptions = {
2
+ appUrl?: string;
3
+ lab?: string;
4
+ title?: string;
5
+ summary?: string;
6
+ body?: string;
7
+ file?: string;
8
+ publish?: boolean;
9
+ };
10
+ export declare function getInitialLabSlug(explicitLabSlug: string | undefined, configLabSlug: string | undefined): string | undefined;
11
+ export declare function readEssayBody(options: {
12
+ file?: string;
13
+ body?: string;
14
+ title: string;
15
+ }): Promise<string>;
16
+ export declare function essayCommand(options?: EssayOptions): Promise<void>;
17
+ export {};
18
+ //# sourceMappingURL=essay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"essay.d.ts","sourceRoot":"","sources":["../../src/commands/essay.ts"],"names":[],"mappings":"AAmBA,KAAK,YAAY,GAAG;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,wBAAgB,iBAAiB,CAC7B,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,aAAa,EAAE,MAAM,GAAG,SAAS,GAClC,MAAM,GAAG,SAAS,CAYpB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE;IACzC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAYlB;AA6BD,wBAAsB,YAAY,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2E5E"}
@@ -0,0 +1,117 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { cancel, intro, isCancel, note, outro, select, text, } from '@clack/prompts';
4
+ import { createCliEssay, fetchCliLabs } from '../api/client.js';
5
+ import { loadHacklabConfig } from '../lab/config.js';
6
+ import { loadSession } from '../session.js';
7
+ import { findRepoRoot } from '../utils/findRepoRoot.js';
8
+ import { getAppUrl } from './login.utils.js';
9
+ export function getInitialLabSlug(explicitLabSlug, configLabSlug) {
10
+ const fromFlag = explicitLabSlug?.trim();
11
+ if (fromFlag) {
12
+ return fromFlag;
13
+ }
14
+ const fromConfig = configLabSlug?.trim();
15
+ if (fromConfig) {
16
+ return fromConfig;
17
+ }
18
+ return undefined;
19
+ }
20
+ export async function readEssayBody(options) {
21
+ if (options.file) {
22
+ const filePath = resolve(options.file);
23
+ return await readFile(filePath, 'utf8');
24
+ }
25
+ const body = options.body?.trim();
26
+ if (body) {
27
+ return options.body || '';
28
+ }
29
+ return [`# ${options.title}`, '', 'write your essay here.', ''].join('\n');
30
+ }
31
+ async function pickLabFromList(labs) {
32
+ if (labs.length === 1) {
33
+ return labs[0];
34
+ }
35
+ const selected = await select({
36
+ message: 'select lab',
37
+ options: labs.map((lab) => ({
38
+ value: lab.slug,
39
+ label: `${lab.name} (${lab.slug})`,
40
+ })),
41
+ });
42
+ if (isCancel(selected)) {
43
+ cancel('essay creation cancelled.');
44
+ process.exit(1);
45
+ }
46
+ const selectedLab = labs.find((lab) => lab.slug === String(selected));
47
+ if (!selectedLab) {
48
+ cancel('selected lab is invalid.');
49
+ process.exit(1);
50
+ }
51
+ return selectedLab;
52
+ }
53
+ export async function essayCommand(options = {}) {
54
+ intro('add essay to studio');
55
+ const session = await loadSession();
56
+ if (!session) {
57
+ outro('not logged in. run `hacklab login`.');
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+ const appUrl = getAppUrl(options.appUrl || session.appUrl);
62
+ const repoRoot = await findRepoRoot();
63
+ const config = await loadHacklabConfig(repoRoot);
64
+ const initialLabSlug = getInitialLabSlug(options.lab, config?.labSlug);
65
+ const labs = await fetchCliLabs(appUrl, session.token);
66
+ if (labs.length === 0) {
67
+ cancel('no labs found. run `hacklab onboard` first.');
68
+ process.exit(1);
69
+ }
70
+ let selectedLab;
71
+ if (initialLabSlug) {
72
+ const explicitLab = labs.find((lab) => lab.slug === initialLabSlug);
73
+ if (!explicitLab) {
74
+ note(labs.map((lab) => `- ${lab.slug}`).join('\n'), 'available labs');
75
+ cancel(`lab "${initialLabSlug}" not found. run \`hacklab onboard\` if needed.`);
76
+ process.exit(1);
77
+ }
78
+ selectedLab = explicitLab;
79
+ }
80
+ else {
81
+ selectedLab = await pickLabFromList(labs);
82
+ }
83
+ note(`${selectedLab.name} (${selectedLab.slug})`, 'lab');
84
+ let title = options.title?.trim();
85
+ if (!title) {
86
+ const titleInput = await text({
87
+ message: 'essay title',
88
+ placeholder: 'my first essay',
89
+ });
90
+ if (isCancel(titleInput)) {
91
+ cancel('essay creation cancelled.');
92
+ process.exit(1);
93
+ }
94
+ title = String(titleInput).trim();
95
+ }
96
+ if (!title || title.length < 2) {
97
+ cancel('essay title must be at least 2 characters.');
98
+ process.exit(1);
99
+ }
100
+ const body = await readEssayBody({
101
+ file: options.file,
102
+ body: options.body,
103
+ title,
104
+ });
105
+ const created = await createCliEssay(appUrl, session.token, {
106
+ labSlug: selectedLab.slug,
107
+ title,
108
+ summary: options.summary,
109
+ body,
110
+ publish: options.publish,
111
+ });
112
+ const absoluteUrl = `${appUrl}${created.essay.url}`;
113
+ note(created.essay.slug, 'essay');
114
+ note(created.essay.status.toLowerCase(), 'status');
115
+ outro(`created "${created.essay.title}"\n${absoluteUrl}`);
116
+ }
117
+ //# sourceMappingURL=essay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"essay.js","sourceRoot":"","sources":["../../src/commands/essay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type HacklabConfig } from '../lab/config.js';
2
+ export type InitOptions = {
3
+ name?: string;
4
+ force?: boolean;
5
+ };
6
+ export type InitializeRepositoryResult = {
7
+ status: 'already-initialized';
8
+ configPath: string;
9
+ } | {
10
+ status: 'initialized';
11
+ configPath: string;
12
+ config: HacklabConfig;
13
+ };
14
+ export declare function initializeRepository(repoRoot: string, options?: InitOptions): Promise<InitializeRepositoryResult>;
15
+ export declare function initCommand(options?: InitOptions): Promise<void>;
16
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAWA,OAAO,EAKH,KAAK,aAAa,EACrB,MAAM,kBAAkB,CAAA;AAIzB,MAAM,MAAM,WAAW,GAAG;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAChC;IACI,MAAM,EAAE,qBAAqB,CAAA;IAC7B,UAAU,EAAE,MAAM,CAAA;CACrB,GACD;IACI,MAAM,EAAE,aAAa,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,aAAa,CAAA;CACxB,CAAA;AAsIP,wBAAsB,oBAAoB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GAC1B,OAAO,CAAC,0BAA0B,CAAC,CA+HrC;AAED,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC1E"}