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,15 @@
1
+ type LoginOptions = {
2
+ appUrl?: string;
3
+ nickname?: string;
4
+ mode?: 'login' | 'join';
5
+ showIntro?: boolean;
6
+ showSuccess?: boolean;
7
+ showAuthorizeUrlWhenOpened?: boolean;
8
+ };
9
+ export type LoginResult = {
10
+ email: string;
11
+ nickname?: string;
12
+ };
13
+ export declare function loginCommand(options?: LoginOptions): Promise<LoginResult>;
14
+ export {};
15
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAeA,KAAK,YAAY,GAAG;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAA;CACvC,CAAA;AAsCD,MAAM,MAAM,WAAW,GAAG;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsGnF"}
@@ -0,0 +1,108 @@
1
+ import { cancel, intro, isCancel, note, outro, spinner, text, } from '@clack/prompts';
2
+ import { exchangeCliAuth, startCliAuth } from '../api/client.js';
3
+ import { saveSession } from '../session.js';
4
+ import { openBrowser } from '../utils/openBrowser.js';
5
+ import { getAppUrl } from './login.utils.js';
6
+ function sleep(ms) {
7
+ return new Promise((resolve) => {
8
+ setTimeout(resolve, ms);
9
+ });
10
+ }
11
+ function normalizeNickname(rawValue) {
12
+ return rawValue
13
+ .trim()
14
+ .toLowerCase()
15
+ .replace(/\s+/g, '-')
16
+ .replace(/[^a-z0-9._-]/g, '');
17
+ }
18
+ function deriveNicknameFromIdentity(user) {
19
+ const email = user.email.trim().toLowerCase();
20
+ const emailLocal = email.split('@')[0] || '';
21
+ const noReplyMatch = email.match(/^[0-9]+\+([^@]+)@users\.noreply\.github\.com$/);
22
+ const fromNoReply = noReplyMatch?.[1] || '';
23
+ const candidates = [fromNoReply, user.name || '', emailLocal];
24
+ for (const candidate of candidates) {
25
+ const normalized = normalizeNickname(candidate);
26
+ if (normalized.length >= 2) {
27
+ return normalized;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+ export async function loginCommand(options = {}) {
33
+ const mode = options.mode ?? 'login';
34
+ const authNoun = mode === 'join' ? 'signup' : 'login';
35
+ const commandLabel = mode === 'join' ? 'join' : 'login';
36
+ if (options.showIntro !== false) {
37
+ intro(mode === 'join' ? 'join hacklab' : 'hacklab cli login');
38
+ }
39
+ const appUrl = getAppUrl(options.appUrl);
40
+ const startPayload = await startCliAuth(appUrl, {
41
+ nickname: options.nickname,
42
+ });
43
+ const opened = await openBrowser(startPayload.authorizeUrl);
44
+ if (!opened) {
45
+ note(`open this url to continue with github:\n${startPayload.authorizeUrl}`, `github ${authNoun}`);
46
+ }
47
+ else {
48
+ note(options.showAuthorizeUrlWhenOpened === false
49
+ ? `browser opened for github ${authNoun}.`
50
+ : `browser opened for github ${authNoun}:\n${startPayload.authorizeUrl}`, `github ${authNoun}`);
51
+ }
52
+ const enterValue = await text({
53
+ message: `finish github ${authNoun} in browser, then press enter`,
54
+ placeholder: 'press enter',
55
+ });
56
+ if (isCancel(enterValue)) {
57
+ cancel(`${commandLabel} cancelled.`);
58
+ process.exit(1);
59
+ }
60
+ const waitSpinner = spinner();
61
+ waitSpinner.start('waiting for browser approval...');
62
+ const deadline = Date.now() + 2 * 60_000;
63
+ while (Date.now() < deadline) {
64
+ const exchange = await exchangeCliAuth(appUrl, startPayload.requestId);
65
+ if (exchange.status === 'approved') {
66
+ const nickname = options.nickname || deriveNicknameFromIdentity(exchange.user);
67
+ await saveSession({
68
+ email: exchange.user.email,
69
+ token: exchange.accessToken,
70
+ loggedInAt: new Date().toISOString(),
71
+ appUrl,
72
+ nickname,
73
+ });
74
+ waitSpinner.stop(`github ${authNoun} approved.`);
75
+ if (options.showSuccess !== false) {
76
+ const nicknameLabel = nickname ? ` (${nickname})` : '';
77
+ outro(mode === 'join'
78
+ ? `joined as ${exchange.user.email}${nicknameLabel}`
79
+ : `logged in as ${exchange.user.email}${nicknameLabel}`);
80
+ }
81
+ return {
82
+ email: exchange.user.email,
83
+ nickname,
84
+ };
85
+ }
86
+ if (exchange.status === 'pending') {
87
+ await sleep(1_500);
88
+ continue;
89
+ }
90
+ if (exchange.status === 'expired') {
91
+ waitSpinner.stop(`cli ${commandLabel} request expired.`);
92
+ cancel(`request expired. run \`hacklab ${commandLabel}\` again.`);
93
+ process.exit(1);
94
+ }
95
+ if (exchange.status === 'consumed') {
96
+ waitSpinner.stop(`cli ${commandLabel} request already used.`);
97
+ cancel(`request already consumed. run \`hacklab ${commandLabel}\` again.`);
98
+ process.exit(1);
99
+ }
100
+ waitSpinner.stop(`cli ${commandLabel} request not found.`);
101
+ cancel(`request not found. run \`hacklab ${commandLabel}\` again.`);
102
+ process.exit(1);
103
+ }
104
+ waitSpinner.stop('timed out waiting for approval.');
105
+ cancel(`timed out waiting for ${commandLabel} approval. run \`hacklab ${commandLabel}\` again.`);
106
+ process.exit(1);
107
+ }
108
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_APP_URL = "http://localhost:3000";
2
+ export declare function getAppUrl(appUrl?: string): string;
3
+ //# sourceMappingURL=login.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.utils.d.ts","sourceRoot":"","sources":["../../src/commands/login.utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,0BAA0B,CAAA;AAEtD,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAYjD"}
@@ -0,0 +1,13 @@
1
+ export const DEFAULT_APP_URL = 'http://localhost:3000';
2
+ export function getAppUrl(appUrl) {
3
+ const normalizedOption = appUrl?.trim();
4
+ if (normalizedOption) {
5
+ return normalizedOption.replace(/\/$/, '');
6
+ }
7
+ const envUrl = process.env.HACKLAB_APP_URL?.trim();
8
+ if (envUrl) {
9
+ return envUrl.replace(/\/$/, '');
10
+ }
11
+ return DEFAULT_APP_URL;
12
+ }
13
+ //# sourceMappingURL=login.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.utils.js","sourceRoot":"","sources":["../../src/commands/login.utils.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAuB,CAAA;AAEtD,MAAM,UAAU,SAAS,CAAC,MAAe;IACrC,MAAM,gBAAgB,GAAG,MAAM,EAAE,IAAI,EAAE,CAAA;IACvC,IAAI,gBAAgB,EAAE,CAAC;QACnB,OAAO,gBAAgB,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC9C,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAA;IAClD,IAAI,MAAM,EAAE,CAAC;QACT,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACpC,CAAC;IAED,OAAO,eAAe,CAAA;AAC1B,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type EntryType } from './new.utils.js';
2
+ type NewOptions = {
3
+ title?: string;
4
+ showIntro?: boolean;
5
+ showOutput?: boolean;
6
+ };
7
+ export type NewCommandResult = {
8
+ entryType: EntryType;
9
+ slug: string;
10
+ title: string;
11
+ targetPath: string;
12
+ };
13
+ export declare function newCommand(rawType?: string, rawSlug?: string, options?: NewOptions): Promise<NewCommandResult>;
14
+ export {};
15
+ //# sourceMappingURL=new.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"AAYA,OAAO,EAKH,KAAK,SAAS,EACjB,MAAM,gBAAgB,CAAA;AAEvB,KAAK,UAAU,GAAG;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,SAAS,EAAE,SAAS,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA;AAoJD,wBAAsB,UAAU,CAC5B,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,EAChB,OAAO,GAAE,UAAe,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA6D3B"}
@@ -0,0 +1,172 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ import { cancel, intro, isCancel, note, outro, select, text } from '@clack/prompts';
4
+ import { DEFAULT_CONTENT_STATUS, DEFAULT_CONTENT_VISIBILITY, } from '../lab/contentStatus.js';
5
+ import { loadHacklabConfig } from '../lab/config.js';
6
+ import { findRepoRoot } from '../utils/findRepoRoot.js';
7
+ import { pathExists } from '../utils/pathExists.js';
8
+ import { getEntryTypeLabel, parseEntryType, slugify, titleFromSlug, } from './new.utils.js';
9
+ function currentDate() {
10
+ return new Date().toISOString().slice(0, 10);
11
+ }
12
+ function buildFrontmatter(entryType, title) {
13
+ const date = currentDate();
14
+ return [
15
+ '---',
16
+ `title: ${title}`,
17
+ `type: ${entryType}`,
18
+ `status: ${DEFAULT_CONTENT_STATUS}`,
19
+ `visibility: ${DEFAULT_CONTENT_VISIBILITY}`,
20
+ `created_at: ${date}`,
21
+ `updated_at: ${date}`,
22
+ '---',
23
+ ].join('\n');
24
+ }
25
+ function getTargetPath(entryType, baseDir, slug) {
26
+ if (entryType === 'essay' || entryType === 'research-paper') {
27
+ return join(baseDir, `${slug}.mdx`);
28
+ }
29
+ return join(baseDir, slug, 'README.mdx');
30
+ }
31
+ function getTemplate(entryType, title) {
32
+ const frontmatter = buildFrontmatter(entryType, title);
33
+ if (entryType === 'essay') {
34
+ return [
35
+ frontmatter,
36
+ '',
37
+ `# ${title}`,
38
+ '',
39
+ 'write your essay here.',
40
+ '',
41
+ ].join('\n');
42
+ }
43
+ if (entryType === 'research-paper') {
44
+ return [
45
+ frontmatter,
46
+ '',
47
+ `# ${title}`,
48
+ '',
49
+ 'abstract:',
50
+ '',
51
+ '## notes',
52
+ '',
53
+ ].join('\n');
54
+ }
55
+ return [frontmatter, '', `# ${title}`, '', `this is a new ${entryType}.`, ''].join('\n');
56
+ }
57
+ function getBaseDirectory(entryType, dirs) {
58
+ if (entryType === 'project') {
59
+ return dirs.projects;
60
+ }
61
+ if (entryType === 'guide') {
62
+ return dirs.guides;
63
+ }
64
+ if (entryType === 'course') {
65
+ return dirs.courses;
66
+ }
67
+ if (entryType === 'essay') {
68
+ return dirs.essays;
69
+ }
70
+ return dirs.research;
71
+ }
72
+ async function promptForEntryType() {
73
+ const value = await select({
74
+ message: 'what do you want to create?',
75
+ options: [
76
+ {
77
+ value: 'essay',
78
+ label: 'essay',
79
+ },
80
+ {
81
+ value: 'guide',
82
+ label: 'guide',
83
+ },
84
+ {
85
+ value: 'course',
86
+ label: 'course',
87
+ },
88
+ {
89
+ value: 'research-paper',
90
+ label: 'research paper',
91
+ },
92
+ {
93
+ value: 'project',
94
+ label: 'project',
95
+ },
96
+ ],
97
+ });
98
+ if (isCancel(value)) {
99
+ cancel('creation cancelled.');
100
+ process.exit(1);
101
+ }
102
+ const entryType = parseEntryType(String(value));
103
+ if (!entryType) {
104
+ cancel('invalid content type selected.');
105
+ process.exit(1);
106
+ }
107
+ return entryType;
108
+ }
109
+ async function promptForSlug(entryType) {
110
+ const label = getEntryTypeLabel(entryType);
111
+ const value = await text({
112
+ message: `name your ${label}`,
113
+ placeholder: `my-${label.replace(/\s+/g, '-')}`,
114
+ });
115
+ if (isCancel(value)) {
116
+ cancel('creation cancelled.');
117
+ process.exit(1);
118
+ }
119
+ const slug = slugify(String(value));
120
+ if (!slug) {
121
+ cancel('invalid name. use letters, numbers, spaces, underscores, or dashes.');
122
+ process.exit(1);
123
+ }
124
+ return slug;
125
+ }
126
+ export async function newCommand(rawType, rawSlug, options = {}) {
127
+ const showIntro = options.showIntro !== false;
128
+ const showOutput = options.showOutput !== false;
129
+ if (showIntro) {
130
+ intro('create new hacklab content');
131
+ }
132
+ const entryType = rawType
133
+ ? parseEntryType(rawType)
134
+ : await promptForEntryType();
135
+ if (!entryType) {
136
+ cancel(`unknown content type "${rawType}". use one of: project, guide, course, essay, research-paper.`);
137
+ process.exit(1);
138
+ }
139
+ const slug = rawSlug ? slugify(rawSlug) : await promptForSlug(entryType);
140
+ if (!slug) {
141
+ cancel('invalid slug. use letters, numbers, spaces, underscores, or dashes.');
142
+ process.exit(1);
143
+ }
144
+ const repoRoot = await findRepoRoot();
145
+ const config = await loadHacklabConfig(repoRoot);
146
+ if (!config) {
147
+ cancel('hacklab is not initialized. run `hacklab init` first.');
148
+ process.exit(1);
149
+ }
150
+ const baseDirectory = getBaseDirectory(entryType, config.contentDirs);
151
+ const basePath = join(repoRoot, baseDirectory);
152
+ const targetPath = getTargetPath(entryType, basePath, slug);
153
+ if (await pathExists(targetPath)) {
154
+ cancel(`target already exists: ${targetPath}`);
155
+ process.exit(1);
156
+ }
157
+ await mkdir(dirname(targetPath), { recursive: true });
158
+ const title = options.title?.trim() || titleFromSlug(slug);
159
+ const template = getTemplate(entryType, title);
160
+ await writeFile(targetPath, template, 'utf8');
161
+ if (showOutput) {
162
+ note(targetPath, 'created');
163
+ outro(`created ${getEntryTypeLabel(entryType)} "${slug}".`);
164
+ }
165
+ return {
166
+ entryType,
167
+ slug,
168
+ title,
169
+ targetPath,
170
+ };
171
+ }
172
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.js","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const ENTRY_TYPES: readonly ["project", "guide", "course", "essay", "research-paper"];
2
+ export type EntryType = (typeof ENTRY_TYPES)[number];
3
+ export declare function parseEntryType(value: string): EntryType | null;
4
+ export declare function getEntryTypeLabel(entryType: EntryType): string;
5
+ export declare function slugify(value: string): string;
6
+ export declare function titleFromSlug(slug: string): string;
7
+ //# sourceMappingURL=new.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.utils.d.ts","sourceRoot":"","sources":["../../src/commands/new.utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,oEAMd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpD,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAwB9D;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAM9D;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU7C;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD"}
@@ -0,0 +1,50 @@
1
+ export const ENTRY_TYPES = [
2
+ 'project',
3
+ 'guide',
4
+ 'course',
5
+ 'essay',
6
+ 'research-paper',
7
+ ];
8
+ export function parseEntryType(value) {
9
+ const normalized = value.trim().toLowerCase();
10
+ if (!normalized) {
11
+ return null;
12
+ }
13
+ if (normalized === 'guides') {
14
+ return 'guide';
15
+ }
16
+ if (normalized === 'research' || normalized === 'paper') {
17
+ return 'research-paper';
18
+ }
19
+ if (normalized === 'research paper') {
20
+ return 'research-paper';
21
+ }
22
+ if (ENTRY_TYPES.includes(normalized)) {
23
+ return normalized;
24
+ }
25
+ return null;
26
+ }
27
+ export function getEntryTypeLabel(entryType) {
28
+ if (entryType === 'research-paper') {
29
+ return 'research paper';
30
+ }
31
+ return entryType;
32
+ }
33
+ export function slugify(value) {
34
+ const normalized = value
35
+ .trim()
36
+ .toLowerCase()
37
+ .replace(/[^a-z0-9\s-_]/g, '')
38
+ .replace(/[\s_]+/g, '-')
39
+ .replace(/-+/g, '-')
40
+ .replace(/^-|-$/g, '');
41
+ return normalized;
42
+ }
43
+ export function titleFromSlug(slug) {
44
+ return slug
45
+ .split('-')
46
+ .filter(Boolean)
47
+ .map((part) => `${part[0].toUpperCase()}${part.slice(1)}`)
48
+ .join(' ');
49
+ }
50
+ //# sourceMappingURL=new.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.utils.js","sourceRoot":"","sources":["../../src/commands/new.utils.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IACvB,SAAS;IACT,OAAO;IACP,QAAQ;IACR,OAAO;IACP,gBAAgB;CACV,CAAA;AAIV,MAAM,UAAU,cAAc,CAAC,KAAa;IACxC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAE7C,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,OAAO,IAAI,CAAA;IACf,CAAC;IAED,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAA;IAClB,CAAC;IAED,IAAI,UAAU,KAAK,UAAU,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QACtD,OAAO,gBAAgB,CAAA;IAC3B,CAAC;IAED,IAAI,UAAU,KAAK,gBAAgB,EAAE,CAAC;QAClC,OAAO,gBAAgB,CAAA;IAC3B,CAAC;IAED,IAAK,WAAiC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1D,OAAO,UAAuB,CAAA;IAClC,CAAC;IAED,OAAO,IAAI,CAAA;AACf,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAoB;IAClD,IAAI,SAAS,KAAK,gBAAgB,EAAE,CAAC;QACjC,OAAO,gBAAgB,CAAA;IAC3B,CAAC;IAED,OAAO,SAAS,CAAA;AACpB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa;IACjC,MAAM,UAAU,GAAG,KAAK;SACnB,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;SAC7B,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IAE1B,OAAO,UAAU,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACtC,OAAO,IAAI;SACN,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,IAAI,CAAC,GAAG,CAAC,CAAA;AAClB,CAAC"}
@@ -0,0 +1,10 @@
1
+ type OnboardOptions = {
2
+ appUrl?: string;
3
+ username?: string;
4
+ bio?: string;
5
+ labName?: string;
6
+ };
7
+ export declare function getDefaultUsername(email: string): string;
8
+ export declare function onboardCommand(options?: OnboardOptions): Promise<void>;
9
+ export {};
10
+ //# sourceMappingURL=onboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.d.ts","sourceRoot":"","sources":["../../src/commands/onboard.ts"],"names":[],"mappings":"AAUA,KAAK,cAAc,GAAG;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,wBAAsB,cAAc,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuGhF"}
@@ -0,0 +1,93 @@
1
+ import { cancel, intro, isCancel, note, outro, text } from '@clack/prompts';
2
+ import { createCliLab, fetchCliLabs, fetchCliMe, updateCliMe, } from '../api/client.js';
3
+ import { loadSession } from '../session.js';
4
+ import { getAppUrl } from './login.utils.js';
5
+ export function getDefaultUsername(email) {
6
+ const localPart = email.trim().toLowerCase().split('@')[0] || 'hacker';
7
+ return localPart.replace(/[^a-z0-9._-]/g, '') || 'hacker';
8
+ }
9
+ export async function onboardCommand(options = {}) {
10
+ intro('hacklab onboarding');
11
+ const session = await loadSession();
12
+ if (!session) {
13
+ outro('not logged in. run `hacklab login`.');
14
+ process.exitCode = 1;
15
+ return;
16
+ }
17
+ const appUrl = getAppUrl(options.appUrl || session.appUrl);
18
+ const me = await fetchCliMe(appUrl, session.token);
19
+ if (!me) {
20
+ outro('your cli session is invalid or expired. run `hacklab login`.');
21
+ process.exitCode = 1;
22
+ return;
23
+ }
24
+ let username = options.username?.trim();
25
+ let bio = options.bio;
26
+ if (!me.name && !username) {
27
+ const usernameInput = await text({
28
+ message: 'username',
29
+ placeholder: getDefaultUsername(me.email),
30
+ });
31
+ if (isCancel(usernameInput)) {
32
+ cancel('onboarding cancelled.');
33
+ process.exit(1);
34
+ }
35
+ username = String(usernameInput).trim();
36
+ }
37
+ if (me.bio === null && bio === undefined) {
38
+ const bioInput = await text({
39
+ message: 'bio (optional)',
40
+ placeholder: 'builder, hacker, explorer',
41
+ });
42
+ if (isCancel(bioInput)) {
43
+ cancel('onboarding cancelled.');
44
+ process.exit(1);
45
+ }
46
+ bio = String(bioInput);
47
+ }
48
+ const shouldUpdateUsername = Boolean(username && username !== me.name);
49
+ const shouldUpdateBio = bio !== undefined && bio !== me.bio;
50
+ if (shouldUpdateUsername || shouldUpdateBio) {
51
+ const updated = await updateCliMe(appUrl, session.token, {
52
+ ...(shouldUpdateUsername ? { username } : {}),
53
+ ...(shouldUpdateBio ? { bio } : {}),
54
+ });
55
+ note(updated.name || '-', 'username');
56
+ }
57
+ else {
58
+ note(me.name || '-', 'username');
59
+ }
60
+ let labs = await fetchCliLabs(appUrl, session.token);
61
+ if (labs.length === 0) {
62
+ let labName = options.labName?.trim();
63
+ if (!labName) {
64
+ const labNameInput = await text({
65
+ message: 'lab name',
66
+ placeholder: `${(username || me.name || 'my').trim()} lab`,
67
+ });
68
+ if (isCancel(labNameInput)) {
69
+ cancel('onboarding cancelled.');
70
+ process.exit(1);
71
+ }
72
+ labName = String(labNameInput).trim();
73
+ }
74
+ if (!labName) {
75
+ cancel('lab name is required.');
76
+ process.exit(1);
77
+ }
78
+ const created = await createCliLab(appUrl, session.token, {
79
+ name: labName,
80
+ });
81
+ note(created.lab.slug, created.created ? 'lab created' : 'lab');
82
+ labs = [created.lab];
83
+ }
84
+ else {
85
+ note(labs[0].slug, 'lab');
86
+ }
87
+ const firstLab = labs[0];
88
+ outro([
89
+ 'onboarding complete.',
90
+ `studio: ${appUrl}/studio/lab/${firstLab.slug}`,
91
+ ].join('\n'));
92
+ }
93
+ //# sourceMappingURL=onboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../src/commands/onboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAC3E,OAAO,EACH,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,WAAW,GACd,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAS5C,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAA;IACtE,OAAO,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,IAAI,QAAQ,CAAA;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAA0B,EAAE;IAC7D,KAAK,CAAC,oBAAoB,CAAC,CAAA;IAE3B,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAA;IACnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,KAAK,CAAC,qCAAqC,CAAC,CAAA;QAC5C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpB,OAAM;IACV,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC1D,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IAElD,IAAI,CAAC,EAAE,EAAE,CAAC;QACN,KAAK,CAAC,8DAA8D,CAAC,CAAA;QACrE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QACpB,OAAM;IACV,CAAC;IAED,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAA;IACvC,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IAErB,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACxB,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC;YAC7B,OAAO,EAAE,UAAU;YACnB,WAAW,EAAE,kBAAkB,CAAC,EAAE,CAAC,KAAK,CAAC;SAC5C,CAAC,CAAA;QAEF,IAAI,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,uBAAuB,CAAC,CAAA;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QAED,QAAQ,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAA;IAC3C,CAAC;IAED,IAAI,EAAE,CAAC,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC;YACxB,OAAO,EAAE,gBAAgB;YACzB,WAAW,EAAE,2BAA2B;SAC3C,CAAC,CAAA;QAEF,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,uBAAuB,CAAC,CAAA;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QAED,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC1B,CAAC;IAED,MAAM,oBAAoB,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,KAAK,EAAE,CAAC,IAAI,CAAC,CAAA;IACtE,MAAM,eAAe,GAAG,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE,CAAC,GAAG,CAAA;IAE3D,IAAI,oBAAoB,IAAI,eAAe,EAAE,CAAC;QAC1C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE;YACrD,GAAG,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7C,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtC,CAAC,CAAA;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,UAAU,CAAC,CAAA;IACzC,CAAC;SAAM,CAAC;QACJ,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,GAAG,EAAE,UAAU,CAAC,CAAA;IACpC,CAAC;IAED,IAAI,IAAI,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IACpD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,CAAA;QAErC,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC;gBAC5B,OAAO,EAAE,UAAU;gBACnB,WAAW,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM;aAC7D,CAAC,CAAA;YAEF,IAAI,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,uBAAuB,CAAC,CAAA;gBAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACnB,CAAC;YAED,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAA;QACzC,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,MAAM,CAAC,uBAAuB,CAAC,CAAA;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE;YACtD,IAAI,EAAE,OAAO;SAChB,CAAC,CAAA;QAEF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;QAC/D,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;SAAM,CAAC;QACJ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC7B,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;IACxB,KAAK,CACD;QACI,sBAAsB;QACtB,WAAW,MAAM,eAAe,QAAQ,CAAC,IAAI,EAAE;KAClD,CAAC,IAAI,CAAC,IAAI,CAAC,CACf,CAAA;AACL,CAAC"}
@@ -0,0 +1,12 @@
1
+ type SlashCommandDefinition = {
2
+ command: '/new' | '/help' | '/exit';
3
+ description: string;
4
+ };
5
+ export declare function parseSlashCommand(rawInput: string): {
6
+ command: string;
7
+ args: string[];
8
+ };
9
+ export declare function getSlashCommandMatches(query: string): SlashCommandDefinition[];
10
+ export declare function tuiCommand(): Promise<void>;
11
+ export {};
12
+ //# sourceMappingURL=tui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../../src/commands/tui.ts"],"names":[],"mappings":"AAKA,KAAK,sBAAsB,GAAG;IAC1B,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;IACnC,WAAW,EAAE,MAAM,CAAA;CACtB,CAAA;AAiBD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACjD,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,EAAE,CAAA;CACjB,CAMA;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,sBAAsB,EAAE,CAQ9E;AAuDD,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CA6ChD"}