hacklab 0.0.2 → 0.3.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 (154) hide show
  1. package/README.md +44 -3
  2. package/bin/ddd +19 -0
  3. package/dist/commands/brag.d.ts +3 -6
  4. package/dist/commands/brag.d.ts.map +1 -1
  5. package/dist/commands/brag.js +68 -299
  6. package/dist/commands/brag.js.map +1 -1
  7. package/dist/commands/config.d.ts +2 -0
  8. package/dist/commands/config.d.ts.map +1 -0
  9. package/dist/commands/config.js +48 -0
  10. package/dist/commands/config.js.map +1 -0
  11. package/dist/commands/drop.d.ts +2 -0
  12. package/dist/commands/drop.d.ts.map +1 -0
  13. package/dist/commands/drop.js +29 -0
  14. package/dist/commands/drop.js.map +1 -0
  15. package/dist/commands/exam.d.ts +5 -0
  16. package/dist/commands/exam.d.ts.map +1 -0
  17. package/dist/commands/exam.js +224 -0
  18. package/dist/commands/exam.js.map +1 -0
  19. package/dist/commands/join.d.ts +10 -9
  20. package/dist/commands/join.d.ts.map +1 -1
  21. package/dist/commands/join.js +213 -285
  22. package/dist/commands/join.js.map +1 -1
  23. package/dist/commands/login.d.ts +1 -15
  24. package/dist/commands/login.d.ts.map +1 -1
  25. package/dist/commands/login.js +69 -133
  26. package/dist/commands/login.js.map +1 -1
  27. package/dist/commands/scan-profile.d.ts +33 -0
  28. package/dist/commands/scan-profile.d.ts.map +1 -0
  29. package/dist/commands/scan-profile.js +279 -0
  30. package/dist/commands/scan-profile.js.map +1 -0
  31. package/dist/commands/sync.d.ts +2 -0
  32. package/dist/commands/sync.d.ts.map +1 -0
  33. package/dist/commands/sync.js +55 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/commands/whoami.d.ts +1 -3
  36. package/dist/commands/whoami.d.ts.map +1 -1
  37. package/dist/commands/whoami.js +10 -37
  38. package/dist/commands/whoami.js.map +1 -1
  39. package/dist/config.d.ts +7 -0
  40. package/dist/config.d.ts.map +1 -0
  41. package/dist/config.js +18 -0
  42. package/dist/config.js.map +1 -0
  43. package/dist/dd.d.ts +3 -0
  44. package/dist/dd.d.ts.map +1 -0
  45. package/dist/dd.js +28 -0
  46. package/dist/dd.js.map +1 -0
  47. package/dist/index.js +117 -112
  48. package/dist/index.js.map +1 -1
  49. package/dist/project-brag.d.ts +58 -0
  50. package/dist/project-brag.d.ts.map +1 -0
  51. package/dist/project-brag.js +270 -0
  52. package/dist/project-brag.js.map +1 -0
  53. package/dist/scanners/index.d.ts +24 -0
  54. package/dist/scanners/index.d.ts.map +1 -0
  55. package/dist/scanners/index.js +543 -0
  56. package/dist/scanners/index.js.map +1 -0
  57. package/dist/scanners/util.d.ts +83 -0
  58. package/dist/scanners/util.d.ts.map +1 -0
  59. package/dist/scanners/util.js +129 -0
  60. package/dist/scanners/util.js.map +1 -0
  61. package/dist/session.d.ts +17 -13
  62. package/dist/session.d.ts.map +1 -1
  63. package/dist/session.js +46 -155
  64. package/dist/session.js.map +1 -1
  65. package/dist/share-card.d.ts +29 -0
  66. package/dist/share-card.d.ts.map +1 -0
  67. package/dist/share-card.js +401 -0
  68. package/dist/share-card.js.map +1 -0
  69. package/dist/sync.d.ts +64 -0
  70. package/dist/sync.d.ts.map +1 -0
  71. package/dist/sync.js +805 -0
  72. package/dist/sync.js.map +1 -0
  73. package/dist/ui.d.ts +10 -0
  74. package/dist/ui.d.ts.map +1 -0
  75. package/dist/ui.js +21 -0
  76. package/dist/ui.js.map +1 -0
  77. package/dist/utils/openBrowser.js.map +1 -1
  78. package/package.json +36 -29
  79. package/dist/api/client.d.ts +0 -150
  80. package/dist/api/client.d.ts.map +0 -1
  81. package/dist/api/client.js +0 -246
  82. package/dist/api/client.js.map +0 -1
  83. package/dist/commands/admin-waitlist.d.ts +0 -12
  84. package/dist/commands/admin-waitlist.d.ts.map +0 -1
  85. package/dist/commands/admin-waitlist.js +0 -96
  86. package/dist/commands/admin-waitlist.js.map +0 -1
  87. package/dist/commands/brag.utils.d.ts +0 -12
  88. package/dist/commands/brag.utils.d.ts.map +0 -1
  89. package/dist/commands/brag.utils.js +0 -43
  90. package/dist/commands/brag.utils.js.map +0 -1
  91. package/dist/commands/essay.d.ts +0 -18
  92. package/dist/commands/essay.d.ts.map +0 -1
  93. package/dist/commands/essay.js +0 -117
  94. package/dist/commands/essay.js.map +0 -1
  95. package/dist/commands/explore.d.ts +0 -9
  96. package/dist/commands/explore.d.ts.map +0 -1
  97. package/dist/commands/explore.js +0 -32
  98. package/dist/commands/explore.js.map +0 -1
  99. package/dist/commands/init.d.ts +0 -16
  100. package/dist/commands/init.d.ts.map +0 -1
  101. package/dist/commands/init.js +0 -237
  102. package/dist/commands/init.js.map +0 -1
  103. package/dist/commands/link.d.ts +0 -17
  104. package/dist/commands/link.d.ts.map +0 -1
  105. package/dist/commands/link.js +0 -36
  106. package/dist/commands/link.js.map +0 -1
  107. package/dist/commands/login.utils.d.ts +0 -3
  108. package/dist/commands/login.utils.d.ts.map +0 -1
  109. package/dist/commands/login.utils.js +0 -13
  110. package/dist/commands/login.utils.js.map +0 -1
  111. package/dist/commands/new.d.ts +0 -15
  112. package/dist/commands/new.d.ts.map +0 -1
  113. package/dist/commands/new.js +0 -172
  114. package/dist/commands/new.js.map +0 -1
  115. package/dist/commands/new.utils.d.ts +0 -7
  116. package/dist/commands/new.utils.d.ts.map +0 -1
  117. package/dist/commands/new.utils.js +0 -50
  118. package/dist/commands/new.utils.js.map +0 -1
  119. package/dist/commands/onboard.d.ts +0 -10
  120. package/dist/commands/onboard.d.ts.map +0 -1
  121. package/dist/commands/onboard.js +0 -93
  122. package/dist/commands/onboard.js.map +0 -1
  123. package/dist/commands/publish.d.ts +0 -8
  124. package/dist/commands/publish.d.ts.map +0 -1
  125. package/dist/commands/publish.js +0 -47
  126. package/dist/commands/publish.js.map +0 -1
  127. package/dist/commands/tui.d.ts +0 -12
  128. package/dist/commands/tui.d.ts.map +0 -1
  129. package/dist/commands/tui.js +0 -112
  130. package/dist/commands/tui.js.map +0 -1
  131. package/dist/help-format.d.ts +0 -4
  132. package/dist/help-format.d.ts.map +0 -1
  133. package/dist/help-format.js +0 -30
  134. package/dist/help-format.js.map +0 -1
  135. package/dist/lab/config.d.ts +0 -32
  136. package/dist/lab/config.d.ts.map +0 -1
  137. package/dist/lab/config.js +0 -148
  138. package/dist/lab/config.js.map +0 -1
  139. package/dist/lab/contentStatus.d.ts +0 -6
  140. package/dist/lab/contentStatus.d.ts.map +0 -1
  141. package/dist/lab/contentStatus.js +0 -19
  142. package/dist/lab/contentStatus.js.map +0 -1
  143. package/dist/ui/banner.d.ts +0 -2
  144. package/dist/ui/banner.d.ts.map +0 -1
  145. package/dist/ui/banner.js +0 -22
  146. package/dist/ui/banner.js.map +0 -1
  147. package/dist/utils/findRepoRoot.d.ts +0 -2
  148. package/dist/utils/findRepoRoot.d.ts.map +0 -1
  149. package/dist/utils/findRepoRoot.js +0 -17
  150. package/dist/utils/findRepoRoot.js.map +0 -1
  151. package/dist/utils/pathExists.d.ts +0 -2
  152. package/dist/utils/pathExists.d.ts.map +0 -1
  153. package/dist/utils/pathExists.js +0 -11
  154. package/dist/utils/pathExists.js.map +0 -1
@@ -1,140 +1,76 @@
1
- import { cancel, intro, isCancel, note, outro, spinner, text, } from '@clack/prompts';
2
- import { exchangeCliAuth, fetchCliWhoAmI, startCliAuth } from '../api/client.js';
3
- import { saveSession } from '../session.js';
1
+ import { createServer } from 'node:http';
2
+ import * as clack from '@clack/prompts';
3
+ import { getAppUrl, saveSession } from '../session.js';
4
+ import { dim, info, success } from '../ui.js';
4
5
  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
- if (options.token) {
41
- const accessToken = options.token.trim();
42
- if (!accessToken) {
43
- cancel('token is required.');
44
- process.exit(1);
45
- }
46
- const identity = await fetchCliWhoAmI(appUrl, accessToken);
47
- if (!identity) {
48
- cancel('invalid token. run `hacklab login` to authenticate again.');
49
- process.exit(1);
50
- }
51
- const nickname = options.nickname || deriveNicknameFromIdentity(identity.user);
52
- await saveSession({
53
- email: identity.user.email,
54
- token: accessToken,
55
- loggedInAt: new Date().toISOString(),
56
- systemMode: identity.user.systemMode,
57
- appUrl,
58
- nickname,
6
+ export async function login() {
7
+ clack.intro('hacklab login');
8
+ const appUrl = getAppUrl();
9
+ // Start a tiny local server to receive the callback
10
+ const { token, email, handle, expiresAt } = await new Promise((resolve, reject) => {
11
+ let timeout;
12
+ const server = createServer((req, res) => {
13
+ const url = new URL(req.url ?? '/', `http://localhost`);
14
+ const token = url.searchParams.get('token');
15
+ const email = url.searchParams.get('email');
16
+ const handle = url.searchParams.get('handle');
17
+ const expiresAt = normalizeDateParam(url.searchParams.get('expiresAt'));
18
+ if (!token || !email) {
19
+ res.writeHead(400, { 'Content-Type': 'text/html' });
20
+ res.end('<h1>login failed</h1><p>missing token. try again.</p>');
21
+ return;
22
+ }
23
+ res.writeHead(200, { 'Content-Type': 'text/html' });
24
+ res.end('<h1>logged in!</h1><p>you can close this tab and go back to your terminal.</p>');
25
+ stopServer();
26
+ resolve({
27
+ token,
28
+ email,
29
+ handle: handle ?? undefined,
30
+ expiresAt,
31
+ });
59
32
  });
60
- if (options.showSuccess !== false) {
61
- const nicknameLabel = nickname ? ` (${nickname})` : '';
62
- outro(mode === 'join'
63
- ? `joined with token as ${identity.user.email}${nicknameLabel}`
64
- : `logged in with token as ${identity.user.email}${nicknameLabel}`);
33
+ server.listen(0, '127.0.0.1', () => {
34
+ const addr = server.address();
35
+ if (!addr || typeof addr === 'string') {
36
+ stopServer();
37
+ reject(new Error('failed to start callback server'));
38
+ return;
39
+ }
40
+ const callbackUrl = `http://127.0.0.1:${addr.port}`;
41
+ const loginUrl = `${appUrl}/cli/auth?callback=${encodeURIComponent(callbackUrl)}`;
42
+ info(`opening browser...`);
43
+ info(`if it doesn't open, visit:`);
44
+ info(` ${loginUrl}`);
45
+ openBrowser(loginUrl);
46
+ });
47
+ // Timeout after 2 minutes
48
+ timeout = setTimeout(() => {
49
+ stopServer();
50
+ reject(new Error('login timed out. try again.'));
51
+ }, 120_000);
52
+ function stopServer() {
53
+ if (timeout)
54
+ clearTimeout(timeout);
55
+ server.close();
65
56
  }
66
- return {
67
- email: identity.user.email,
68
- nickname,
69
- };
70
- }
71
- const startPayload = await startCliAuth(appUrl, {
72
- nickname: options.nickname,
73
57
  });
74
- const opened = await openBrowser(startPayload.authorizeUrl);
75
- if (!opened) {
76
- note(`open this url to continue with github:\n${startPayload.authorizeUrl}`, `github ${authNoun}`);
77
- }
78
- else {
79
- note(options.showAuthorizeUrlWhenOpened === false
80
- ? `browser opened for github ${authNoun}.`
81
- : `browser opened for github ${authNoun}:\n${startPayload.authorizeUrl}`, `github ${authNoun}`);
82
- }
83
- const enterValue = await text({
84
- message: `finish github ${authNoun} in browser, then press enter`,
85
- placeholder: 'press enter',
58
+ await saveSession({
59
+ token,
60
+ email,
61
+ handle,
62
+ appUrl,
63
+ savedAt: new Date().toISOString(),
64
+ expiresAt,
86
65
  });
87
- if (isCancel(enterValue)) {
88
- cancel(`${commandLabel} cancelled.`);
89
- process.exit(1);
90
- }
91
- const waitSpinner = spinner();
92
- waitSpinner.start('waiting for browser approval...');
93
- const deadline = Date.now() + 2 * 60_000;
94
- while (Date.now() < deadline) {
95
- const exchange = await exchangeCliAuth(appUrl, startPayload.requestId);
96
- if (exchange.status === 'approved') {
97
- const nickname = options.nickname || deriveNicknameFromIdentity(exchange.user);
98
- await saveSession({
99
- email: exchange.user.email,
100
- token: exchange.accessToken,
101
- loggedInAt: new Date().toISOString(),
102
- systemMode: exchange.user.systemMode,
103
- appUrl,
104
- nickname,
105
- });
106
- waitSpinner.stop(`github ${authNoun} approved.`);
107
- if (options.showSuccess !== false) {
108
- const nicknameLabel = nickname ? ` (${nickname})` : '';
109
- outro(mode === 'join'
110
- ? `joined as ${exchange.user.email}${nicknameLabel}`
111
- : `logged in as ${exchange.user.email}${nicknameLabel}`);
112
- }
113
- return {
114
- email: exchange.user.email,
115
- nickname,
116
- };
117
- }
118
- if (exchange.status === 'pending') {
119
- await sleep(1_500);
120
- continue;
121
- }
122
- if (exchange.status === 'expired') {
123
- waitSpinner.stop(`cli ${commandLabel} request expired.`);
124
- cancel(`request expired. run \`hacklab ${commandLabel}\` again.`);
125
- process.exit(1);
126
- }
127
- if (exchange.status === 'consumed') {
128
- waitSpinner.stop(`cli ${commandLabel} request already used.`);
129
- cancel(`request already consumed. run \`hacklab ${commandLabel}\` again.`);
130
- process.exit(1);
131
- }
132
- waitSpinner.stop(`cli ${commandLabel} request not found.`);
133
- cancel(`request not found. run \`hacklab ${commandLabel}\` again.`);
134
- process.exit(1);
135
- }
136
- waitSpinner.stop('timed out waiting for approval.');
137
- cancel(`timed out waiting for ${commandLabel} approval. run \`hacklab ${commandLabel}\` again.`);
138
- process.exit(1);
66
+ const label = handle ? `${email} (${handle})` : email;
67
+ success(`logged in as ${label}`);
68
+ clack.outro(dim('hack the planet.'));
69
+ }
70
+ function normalizeDateParam(value) {
71
+ if (!value)
72
+ return undefined;
73
+ const date = new Date(value);
74
+ return Number.isNaN(date.getTime()) ? undefined : date.toISOString();
139
75
  }
140
76
  //# sourceMappingURL=login.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ type SkillDetection = {
2
+ skillClass: string;
3
+ skill: string;
4
+ level: number;
5
+ };
6
+ type GitHubData = {
7
+ bio: string | null;
8
+ avatarUrl: string | null;
9
+ blogUrl: string | null;
10
+ repos: Array<{
11
+ name: string;
12
+ description: string | null;
13
+ url: string;
14
+ language: string | null;
15
+ stars: number;
16
+ updatedAt: string;
17
+ }>;
18
+ };
19
+ /**
20
+ * Scan local git repos for languages and frameworks.
21
+ * Looks in common workspace directories.
22
+ */
23
+ export declare function scanSkillTree(): Promise<SkillDetection[]>;
24
+ /**
25
+ * Fetch GitHub profile data using gh CLI (already authenticated).
26
+ */
27
+ export declare function scanGitHub(): Promise<GitHubData | null>;
28
+ /**
29
+ * Run the full profile scan and submit to hacklab.
30
+ */
31
+ export declare function scanProfile(): Promise<void>;
32
+ export {};
33
+ //# sourceMappingURL=scan-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-profile.d.ts","sourceRoot":"","sources":["../../src/commands/scan-profile.ts"],"names":[],"mappings":"AAQA,KAAK,cAAc,GAAG;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,UAAU,GAAG;IAChB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAA;QACZ,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;QAC1B,GAAG,EAAE,MAAM,CAAA;QACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;QACvB,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,MAAM,CAAA;KAClB,CAAC,CAAA;CACH,CAAA;AA2DD;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CA2F/D;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA2B7D;AAED;;GAEG;AACH,wBAAsB,WAAW,kBA+GhC"}
@@ -0,0 +1,279 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { readdir, stat } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { loadSession } from '../session.js';
6
+ import { bold, dim, error, info, success } from '../ui.js';
7
+ // Map file extensions and config files to skill class + skill name
8
+ const LANGUAGE_SKILL_MAP = {
9
+ ts: { skillClass: 'builder', skill: 'TypeScript' },
10
+ tsx: { skillClass: 'builder', skill: 'React' },
11
+ js: { skillClass: 'builder', skill: 'JavaScript' },
12
+ jsx: { skillClass: 'builder', skill: 'React' },
13
+ py: { skillClass: 'hacker', skill: 'Python' },
14
+ go: { skillClass: 'builder', skill: 'Go' },
15
+ rs: { skillClass: 'builder', skill: 'Rust' },
16
+ swift: { skillClass: 'builder', skill: 'Swift' },
17
+ kt: { skillClass: 'builder', skill: 'Kotlin' },
18
+ java: { skillClass: 'builder', skill: 'Java' },
19
+ rb: { skillClass: 'builder', skill: 'Ruby' },
20
+ php: { skillClass: 'builder', skill: 'PHP' },
21
+ cs: { skillClass: 'builder', skill: 'C#' },
22
+ cpp: { skillClass: 'builder', skill: 'C++' },
23
+ c: { skillClass: 'builder', skill: 'C' },
24
+ sol: { skillClass: 'hacker', skill: 'Solidity' },
25
+ sql: { skillClass: 'operator', skill: 'SQL' },
26
+ prisma: { skillClass: 'operator', skill: 'Prisma' },
27
+ proto: { skillClass: 'builder', skill: 'Protobuf' },
28
+ };
29
+ const CONFIG_FILE_SKILL_MAP = {
30
+ 'next.config.js': { skillClass: 'builder', skill: 'Next.js' },
31
+ 'next.config.ts': { skillClass: 'builder', skill: 'Next.js' },
32
+ 'next.config.mjs': { skillClass: 'builder', skill: 'Next.js' },
33
+ 'nuxt.config.ts': { skillClass: 'builder', skill: 'Nuxt' },
34
+ 'svelte.config.js': { skillClass: 'builder', skill: 'Svelte' },
35
+ 'astro.config.mjs': { skillClass: 'builder', skill: 'Astro' },
36
+ 'tailwind.config.js': { skillClass: 'designer', skill: 'Tailwind CSS' },
37
+ 'tailwind.config.ts': { skillClass: 'designer', skill: 'Tailwind CSS' },
38
+ 'postcss.config.js': { skillClass: 'designer', skill: 'CSS' },
39
+ Dockerfile: { skillClass: 'operator', skill: 'Docker' },
40
+ 'docker-compose.yml': { skillClass: 'operator', skill: 'Docker' },
41
+ 'docker-compose.yaml': { skillClass: 'operator', skill: 'Docker' },
42
+ '.github': { skillClass: 'operator', skill: 'GitHub Actions' },
43
+ 'fly.toml': { skillClass: 'operator', skill: 'Fly.io' },
44
+ 'vercel.json': { skillClass: 'operator', skill: 'Vercel' },
45
+ 'terraform.tf': { skillClass: 'operator', skill: 'Terraform' },
46
+ 'go.mod': { skillClass: 'builder', skill: 'Go' },
47
+ 'Cargo.toml': { skillClass: 'builder', skill: 'Rust' },
48
+ 'pyproject.toml': { skillClass: 'hacker', skill: 'Python' },
49
+ 'requirements.txt': { skillClass: 'hacker', skill: 'Python' },
50
+ Gemfile: { skillClass: 'builder', skill: 'Ruby' },
51
+ 'CLAUDE.md': { skillClass: 'hacker', skill: 'Claude Code' },
52
+ '.cursor': { skillClass: 'hacker', skill: 'Cursor' },
53
+ 'AGENTS.md': { skillClass: 'hacker', skill: 'Codex' },
54
+ 'DESIGN.md': { skillClass: 'designer', skill: 'Design Systems' },
55
+ };
56
+ /**
57
+ * Scan local git repos for languages and frameworks.
58
+ * Looks in common workspace directories.
59
+ */
60
+ export async function scanSkillTree() {
61
+ const home = homedir();
62
+ const searchDirs = [
63
+ join(home, 'gh'),
64
+ join(home, 'projects'),
65
+ join(home, 'code'),
66
+ join(home, 'dev'),
67
+ join(home, 'src'),
68
+ join(home, 'repos'),
69
+ join(home, 'workspace'),
70
+ join(home, 'Developer'),
71
+ join(home, 'Documents', 'GitHub'),
72
+ ];
73
+ const skillCounts = new Map();
74
+ for (const searchDir of searchDirs) {
75
+ try {
76
+ await stat(searchDir);
77
+ }
78
+ catch {
79
+ continue;
80
+ }
81
+ try {
82
+ const entries = await readdir(searchDir, {
83
+ withFileTypes: true,
84
+ });
85
+ for (const entry of entries) {
86
+ if (!entry.isDirectory())
87
+ continue;
88
+ const repoDir = join(searchDir, entry.name);
89
+ // Check if it's a git repo
90
+ try {
91
+ await stat(join(repoDir, '.git'));
92
+ }
93
+ catch {
94
+ continue;
95
+ }
96
+ // Scan for config files
97
+ try {
98
+ const files = await readdir(repoDir);
99
+ for (const file of files) {
100
+ const mapping = CONFIG_FILE_SKILL_MAP[file];
101
+ if (mapping) {
102
+ const key = `${mapping.skillClass}:${mapping.skill}`;
103
+ skillCounts.set(key, (skillCounts.get(key) ?? 0) + 1);
104
+ }
105
+ }
106
+ }
107
+ catch {
108
+ // skip
109
+ }
110
+ // Quick scan for file extensions (top level + src/)
111
+ const dirsToScan = [repoDir, join(repoDir, 'src')];
112
+ for (const dir of dirsToScan) {
113
+ try {
114
+ const files = await readdir(dir);
115
+ for (const file of files) {
116
+ const ext = file.split('.').pop();
117
+ if (ext && LANGUAGE_SKILL_MAP[ext]) {
118
+ const mapping = LANGUAGE_SKILL_MAP[ext];
119
+ const key = `${mapping.skillClass}:${mapping.skill}`;
120
+ skillCounts.set(key, (skillCounts.get(key) ?? 0) + 1);
121
+ }
122
+ }
123
+ }
124
+ catch {
125
+ // skip
126
+ }
127
+ }
128
+ }
129
+ }
130
+ catch {
131
+ // can't read dir
132
+ }
133
+ }
134
+ // Convert counts to skill levels (more repos = higher level)
135
+ const skills = [];
136
+ for (const [key, count] of skillCounts) {
137
+ const [skillClass, skill] = key.split(':');
138
+ // Level: 1 repo = 1, 3+ repos = 2, 6+ repos = 3, 10+ = 4, 20+ = 5
139
+ let level = 1;
140
+ if (count >= 20)
141
+ level = 5;
142
+ else if (count >= 10)
143
+ level = 4;
144
+ else if (count >= 6)
145
+ level = 3;
146
+ else if (count >= 3)
147
+ level = 2;
148
+ skills.push({ skillClass: skillClass, skill: skill, level });
149
+ }
150
+ return skills.sort((a, b) => b.level - a.level);
151
+ }
152
+ /**
153
+ * Fetch GitHub profile data using gh CLI (already authenticated).
154
+ */
155
+ export async function scanGitHub() {
156
+ try {
157
+ // Get user profile
158
+ const profileRaw = execSync("gh api user --jq '{ login: .login, bio: .bio, avatar_url: .avatar_url, blog: .blog }'", { encoding: 'utf8', timeout: 10000 }).trim();
159
+ const profile = JSON.parse(profileRaw);
160
+ // Get top repos (by stars, recently updated)
161
+ const reposRaw = execSync('gh api "user/repos?sort=updated&per_page=20&type=owner" --jq \'[.[] | select(.fork == false) | { name: .name, description: .description, url: .html_url, language: .language, stars: .stargazers_count, updatedAt: .updated_at }]\'', { encoding: 'utf8', timeout: 15000 }).trim();
162
+ const repos = JSON.parse(reposRaw);
163
+ return {
164
+ bio: profile.bio || null,
165
+ avatarUrl: profile.avatar_url || null,
166
+ blogUrl: profile.blog || null,
167
+ repos,
168
+ };
169
+ }
170
+ catch {
171
+ return null;
172
+ }
173
+ }
174
+ /**
175
+ * Run the full profile scan and submit to hacklab.
176
+ */
177
+ export async function scanProfile() {
178
+ const session = await loadSession();
179
+ if (!session) {
180
+ error('not logged in');
181
+ info(`run ${dim('hacklab login')} first`);
182
+ process.exit(1);
183
+ }
184
+ const handle = session.handle ?? 'you';
185
+ const appUrl = session.appUrl.replace(/\/$/, '');
186
+ console.log('');
187
+ console.log(bold(' Building your profile...'));
188
+ console.log(dim(' Scanning repos, GitHub, and blog. Takes a moment.'));
189
+ console.log('');
190
+ // 1. Skill tree
191
+ info('scanning local repos for skills...');
192
+ const skills = await scanSkillTree();
193
+ if (skills.length > 0) {
194
+ info(` found ${bold(String(skills.length))} skills across ${new Set(skills.map((s) => s.skillClass)).size} classes`);
195
+ for (const s of skills.slice(0, 8)) {
196
+ info(` ${dim(s.skillClass)} / ${s.skill} (lv.${s.level})`);
197
+ }
198
+ if (skills.length > 8) {
199
+ info(` ${dim(`...and ${skills.length - 8} more`)}`);
200
+ }
201
+ }
202
+ else {
203
+ info(` ${dim('no repos found in common directories')}`);
204
+ }
205
+ console.log('');
206
+ // 2. GitHub
207
+ info('fetching GitHub profile...');
208
+ const github = await scanGitHub();
209
+ if (github) {
210
+ info(` bio: ${github.bio ?? dim('(none)')}`);
211
+ info(` blog: ${github.blogUrl ?? dim('(none)')}`);
212
+ info(` repos: ${github.repos.length} (non-fork, recent)`);
213
+ const topRepos = github.repos.sort((a, b) => b.stars - a.stars).slice(0, 5);
214
+ for (const r of topRepos) {
215
+ info(` ${r.name} ${r.language ? dim(`(${r.language})`) : ''} ${r.stars > 0 ? `${r.stars}*` : ''}`);
216
+ }
217
+ }
218
+ else {
219
+ info(` ${dim('gh CLI not found or not authenticated. run gh auth login')}`);
220
+ }
221
+ console.log('');
222
+ // 3. Submit skills
223
+ if (skills.length > 0) {
224
+ info('submitting skills...');
225
+ const res = await fetch(`${appUrl}/api/skills`, {
226
+ method: 'POST',
227
+ headers: {
228
+ 'Content-Type': 'application/json',
229
+ Authorization: `Bearer ${session.token}`,
230
+ },
231
+ body: JSON.stringify({ skills }),
232
+ });
233
+ if (res.ok) {
234
+ success(`${skills.length} skills synced`);
235
+ }
236
+ else {
237
+ info(` ${dim('skills API not available yet (will sync later)')}`);
238
+ }
239
+ }
240
+ // 4. Submit GitHub repos as projects
241
+ if (github && github.repos.length > 0) {
242
+ info('syncing top repos as projects...');
243
+ let synced = 0;
244
+ for (const repo of github.repos.slice(0, 10)) {
245
+ const res = await fetch(`${appUrl}/api/projects`, {
246
+ method: 'POST',
247
+ headers: {
248
+ 'Content-Type': 'application/json',
249
+ Authorization: `Bearer ${session.token}`,
250
+ },
251
+ body: JSON.stringify({
252
+ slug: repo.name,
253
+ title: repo.name,
254
+ description: repo.description,
255
+ repoUrl: repo.url,
256
+ tags: repo.language ? [repo.language] : [],
257
+ }),
258
+ });
259
+ if (res.ok)
260
+ synced++;
261
+ }
262
+ if (synced > 0) {
263
+ success(`${synced} repos synced as projects`);
264
+ }
265
+ else {
266
+ info(` ${dim('projects API not available yet (will sync later)')}`);
267
+ }
268
+ }
269
+ // 5. Set blog URL if found
270
+ if (github?.blogUrl) {
271
+ info(`blog detected: ${bold(github.blogUrl)}`);
272
+ info(` ${dim('RSS sync will start automatically after profile is set up')}`);
273
+ }
274
+ console.log('');
275
+ success('profile scan complete');
276
+ info(`view: ${bold(`${appUrl}/${handle}`)}`);
277
+ console.log('');
278
+ }
279
+ //# sourceMappingURL=scan-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-profile.js","sourceRoot":"","sources":["../../src/commands/scan-profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAsB1D,mEAAmE;AACnE,MAAM,kBAAkB,GAGpB;IACF,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE;IAClD,GAAG,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;IAC9C,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE;IAClD,GAAG,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;IAC9C,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC7C,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE;IAC1C,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IAC5C,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;IAChD,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC9C,IAAI,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IAC9C,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IAC5C,GAAG,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE;IAC5C,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE;IAC1C,GAAG,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE;IAC5C,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;IACxC,GAAG,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE;IAChD,GAAG,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE;IAC7C,MAAM,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;IACnD,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE;CACpD,CAAA;AAED,MAAM,qBAAqB,GAGvB;IACF,gBAAgB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;IAC7D,gBAAgB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;IAC7D,iBAAiB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;IAC9D,gBAAgB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IAC1D,kBAAkB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC9D,kBAAkB,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;IAC7D,oBAAoB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,EAAE;IACvE,oBAAoB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,cAAc,EAAE;IACvE,mBAAmB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE;IAC7D,UAAU,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;IACvD,oBAAoB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;IACjE,qBAAqB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;IAClE,SAAS,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,gBAAgB,EAAE;IAC9D,UAAU,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;IACvD,aAAa,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC1D,cAAc,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE;IAC9D,QAAQ,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE;IAChD,YAAY,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IACtD,gBAAgB,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC3D,kBAAkB,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IAC7D,OAAO,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE;IACjD,WAAW,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE;IAC3D,SAAS,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;IACpD,WAAW,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE;IACrD,WAAW,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,gBAAgB,EAAE;CACjE,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,IAAI,GAAG,OAAO,EAAE,CAAA;IACtB,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;QAChB,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC;QACtB,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC;QACjB,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;QACnB,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC;KAClC,CAAA;IAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAA;IAE7C,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,SAAS,CAAC,CAAA;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE;gBACvC,aAAa,EAAE,IAAI;aACpB,CAAC,CAAA;YAEF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;oBAAE,SAAQ;gBAClC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;gBAE3C,2BAA2B;gBAC3B,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;gBACnC,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAQ;gBACV,CAAC;gBAED,wBAAwB;gBACxB,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;oBACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;wBACzB,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAA;wBAC3C,IAAI,OAAO,EAAE,CAAC;4BACZ,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAA;4BACpD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;wBACvD,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO;gBACT,CAAC;gBAED,oDAAoD;gBACpD,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAA;gBAClD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;oBAC7B,IAAI,CAAC;wBACH,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;wBAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;4BACzB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;4BACjC,IAAI,GAAG,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;gCACnC,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAE,CAAA;gCACxC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAA;gCACpD,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;4BACvD,CAAC;wBACH,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,OAAO;oBACT,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iBAAiB;QACnB,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,MAAM,MAAM,GAAqB,EAAE,CAAA;IACnC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;QACvC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC1C,kEAAkE;QAClE,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,IAAI,KAAK,IAAI,EAAE;YAAE,KAAK,GAAG,CAAC,CAAA;aACrB,IAAI,KAAK,IAAI,EAAE;YAAE,KAAK,GAAG,CAAC,CAAA;aAC1B,IAAI,KAAK,IAAI,CAAC;YAAE,KAAK,GAAG,CAAC,CAAA;aACzB,IAAI,KAAK,IAAI,CAAC;YAAE,KAAK,GAAG,CAAC,CAAA;QAE9B,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,UAAW,EAAE,KAAK,EAAE,KAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAChE,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,CAAC;QACH,mBAAmB;QACnB,MAAM,UAAU,GAAG,QAAQ,CACzB,uFAAuF,EACvF,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CACrC,CAAC,IAAI,EAAE,CAAA;QAER,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QAEtC,6CAA6C;QAC7C,MAAM,QAAQ,GAAG,QAAQ,CACvB,qOAAqO,EACrO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CACrC,CAAC,IAAI,EAAE,CAAA;QAER,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;QAElC,OAAO;YACL,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI;YACxB,SAAS,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI;YACrC,OAAO,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;YAC7B,KAAK;SACN,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAA;IAEnC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,KAAK,CAAC,eAAe,CAAC,CAAA;QACtB,IAAI,CAAC,OAAO,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;QACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAA;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAEhD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAA;IAC/C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC,CAAA;IACvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAEf,gBAAgB;IAChB,IAAI,CAAC,oCAAoC,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAA;IACpC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,IAAI,CACF,WAAW,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,kBAAkB,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,CAChH,CAAA;QACD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,KAAK,GAAG,CAAC,CAAA;QAC/D,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,GAAG,CAAC,UAAU,MAAM,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,KAAK,GAAG,CAAC,sCAAsC,CAAC,EAAE,CAAC,CAAA;IAC1D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAEf,YAAY;IACZ,IAAI,CAAC,4BAA4B,CAAC,CAAA;IAClC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;IACjC,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC,UAAU,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC7C,IAAI,CAAC,WAAW,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,YAAY,MAAM,CAAC,KAAK,CAAC,MAAM,qBAAqB,CAAC,CAAA;QAC1D,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC3E,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,CACF,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAChG,CAAA;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,KAAK,GAAG,CAAC,0DAA0D,CAAC,EAAE,CAAC,CAAA;IAC9E,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAEf,mBAAmB;IACnB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,IAAI,CAAC,sBAAsB,CAAC,CAAA;QAC5B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,aAAa,EAAE;YAC9C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;aACzC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;SACjC,CAAC,CAAA;QACF,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,gBAAgB,CAAC,CAAA;QAC3C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,GAAG,CAAC,gDAAgD,CAAC,EAAE,CAAC,CAAA;QACpE,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,kCAAkC,CAAC,CAAA;QACxC,IAAI,MAAM,GAAG,CAAC,CAAA;QACd,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC7C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,eAAe,EAAE;gBAChD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE;iBACzC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,IAAI;oBAChB,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,OAAO,EAAE,IAAI,CAAC,GAAG;oBACjB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;iBAC3C,CAAC;aACH,CAAC,CAAA;YACF,IAAI,GAAG,CAAC,EAAE;gBAAE,MAAM,EAAE,CAAA;QACtB,CAAC;QACD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,MAAM,2BAA2B,CAAC,CAAA;QAC/C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,GAAG,CAAC,kDAAkD,CAAC,EAAE,CAAC,CAAA;QACtE,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC,kBAAkB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC9C,IAAI,CACF,KAAK,GAAG,CAAC,2DAA2D,CAAC,EAAE,CACxE,CAAA;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACf,OAAO,CAAC,uBAAuB,CAAC,CAAA;IAChC,IAAI,CAAC,SAAS,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC,EAAE,CAAC,CAAA;IAC5C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function sync(): Promise<void>;
2
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAMA,wBAAsB,IAAI,kBAiEzB"}
@@ -0,0 +1,55 @@
1
+ import * as clack from '@clack/prompts';
2
+ import { loadSessionState } from '../session.js';
3
+ import { checkSession, formatTokens, runSync } from '../sync.js';
4
+ import { bold, dim, error, info, success } from '../ui.js';
5
+ export async function sync() {
6
+ const sessionState = await loadSessionState();
7
+ const session = sessionState.session;
8
+ if (!session) {
9
+ error(sessionState.status === 'expired' ? 'login expired' : 'not logged in');
10
+ info(`run ${dim('hacklab login')} first`);
11
+ process.exit(1);
12
+ }
13
+ const sessionCheck = await checkSession(session);
14
+ if (sessionCheck.status === 'unauthorized') {
15
+ error('login expired');
16
+ info(`run ${dim('hacklab login')} again`);
17
+ process.exit(1);
18
+ }
19
+ if (sessionCheck.status === 'failed') {
20
+ error(sessionCheck.message);
21
+ process.exit(1);
22
+ }
23
+ console.log('');
24
+ console.log(bold(' hacklab sync'));
25
+ console.log(dim(' scanning local AI tool usage...'));
26
+ console.log('');
27
+ let result;
28
+ try {
29
+ result = await runSync(session);
30
+ }
31
+ catch (e) {
32
+ error(e instanceof Error ? e.message : 'sync failed');
33
+ process.exit(1);
34
+ }
35
+ const { claudeTotal, codexTotal, cursorTotal, openclawTotal, hermesTotal, opencodeTotal, result: r, } = result;
36
+ if (claudeTotal > 0)
37
+ info(` Claude Code ${formatTokens(claudeTotal)} tokens`);
38
+ if (codexTotal > 0)
39
+ info(` Codex ${formatTokens(codexTotal)} tokens`);
40
+ if (cursorTotal > 0)
41
+ info(` Cursor ${formatTokens(cursorTotal)} tokens`);
42
+ if (openclawTotal > 0)
43
+ info(` OpenClaw ${formatTokens(openclawTotal)} tokens`);
44
+ if (hermesTotal > 0)
45
+ info(` Hermes ${formatTokens(hermesTotal)} tokens`);
46
+ if (opencodeTotal > 0)
47
+ info(` OpenCode ${formatTokens(opencodeTotal)} tokens`);
48
+ console.log('');
49
+ success(` ${bold(String(r.title))} lv.${r.level} — ${formatTokens(Number(r.tokensTotal))} total`);
50
+ if (Number(r.tokensDelta) > 0) {
51
+ info(` +${formatTokens(Number(r.tokensDelta))} since last sync`);
52
+ }
53
+ clack.outro(dim('synced.'));
54
+ }
55
+ //# sourceMappingURL=sync.js.map