@hackersbaby/plugin 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
9
16
  var __copyProps = (to, from, except, desc) => {
10
17
  if (from && typeof from === "object" || typeof from === "function") {
11
18
  for (let key of __getOwnPropNames(from))
@@ -24,12 +31,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
31
  ));
25
32
 
26
33
  // src/config.ts
27
- var import_fs = __toESM(require("fs"));
28
- var import_path = __toESM(require("path"));
29
- var import_os = __toESM(require("os"));
30
- var CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
31
- var CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
32
- var QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
33
34
  function ensureConfigDir() {
34
35
  if (!import_fs.default.existsSync(CONFIG_DIR)) {
35
36
  import_fs.default.mkdirSync(CONFIG_DIR, { recursive: true });
@@ -48,119 +49,146 @@ function saveConfig(config) {
48
49
  ensureConfigDir();
49
50
  import_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
50
51
  }
52
+ var import_fs, import_path, import_os, CONFIG_DIR, CONFIG_FILE, QUEUE_FILE;
53
+ var init_config = __esm({
54
+ "src/config.ts"() {
55
+ "use strict";
56
+ import_fs = __toESM(require("fs"));
57
+ import_path = __toESM(require("path"));
58
+ import_os = __toESM(require("os"));
59
+ CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
60
+ CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
61
+ QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
62
+ }
63
+ });
51
64
 
52
65
  // src/api-client.ts
53
- var APIClient = class {
54
- config = loadConfig();
55
- get headers() {
56
- return {
57
- "Content-Type": "application/json",
58
- Authorization: `Bearer ${this.config?.token || ""}`
59
- };
60
- }
61
- async sendBatch(batch) {
62
- try {
63
- const server = this.config?.server || "https://hackers.baby";
64
- const res = await fetch(`${server}/api/scores/batch`, {
65
- method: "POST",
66
- headers: this.headers,
67
- body: JSON.stringify(batch)
68
- });
69
- return res.ok;
70
- } catch {
71
- return false;
72
- }
73
- }
74
- async refreshTokenIfNeeded() {
75
- if (!this.config) return;
76
- try {
77
- const parts = this.config.token.split(".");
78
- if (parts.length !== 3) return;
79
- const payload = JSON.parse(Buffer.from(parts[1], "base64").toString("utf-8"));
80
- const expMs = payload.exp * 1e3;
81
- const oneDayMs = 24 * 60 * 60 * 1e3;
82
- if (Date.now() + oneDayMs < expMs) return;
83
- const res = await fetch(`${this.config.server}/api/auth/cli-token/refresh`, {
84
- method: "POST",
85
- headers: this.headers,
86
- body: JSON.stringify({ refresh_token: this.config.refresh_token })
87
- });
88
- if (res.ok) {
89
- const data = await res.json();
90
- if (data.token) {
91
- this.config.token = data.token;
92
- if (data.refresh_token) this.config.refresh_token = data.refresh_token;
93
- saveConfig(this.config);
66
+ var api_client_exports = {};
67
+ __export(api_client_exports, {
68
+ APIClient: () => APIClient
69
+ });
70
+ var APIClient;
71
+ var init_api_client = __esm({
72
+ "src/api-client.ts"() {
73
+ "use strict";
74
+ init_config();
75
+ APIClient = class {
76
+ config = loadConfig();
77
+ get headers() {
78
+ return {
79
+ "Content-Type": "application/json",
80
+ Authorization: `Bearer ${this.config?.token || ""}`
81
+ };
82
+ }
83
+ async sendBatch(batch) {
84
+ try {
85
+ const server = this.config?.server || "https://hackers.baby";
86
+ const res = await fetch(`${server}/api/scores/batch`, {
87
+ method: "POST",
88
+ headers: this.headers,
89
+ body: JSON.stringify(batch)
90
+ });
91
+ return res.ok;
92
+ } catch {
93
+ return false;
94
94
  }
95
95
  }
96
- } catch {
97
- }
98
- }
99
- async getStatus() {
100
- const server = this.config?.server || "https://hackers.baby";
101
- const res = await fetch(`${server}/api/users/me`, { headers: this.headers });
102
- if (!res.ok) throw new Error(`getStatus failed: ${res.status}`);
103
- return res.json();
104
- }
105
- async getRank() {
106
- const server = this.config?.server || "https://hackers.baby";
107
- const res = await fetch(`${server}/api/users/me/rank`, { headers: this.headers });
108
- if (!res.ok) throw new Error(`getRank failed: ${res.status}`);
109
- return res.json();
110
- }
111
- async getLeaderboard() {
112
- const server = this.config?.server || "https://hackers.baby";
113
- const res = await fetch(`${server}/api/leaderboard/global?limit=10`, { headers: this.headers });
114
- if (!res.ok) throw new Error(`getLeaderboard failed: ${res.status}`);
115
- return res.json();
116
- }
117
- async getPublicStats() {
118
- try {
119
- const server = this.config?.server || "https://hackers.baby";
120
- const res = await fetch(`${server}/api/stats/public`);
121
- if (!res.ok) return null;
122
- return res.json();
123
- } catch {
124
- return null;
125
- }
126
- }
127
- async getNotifications() {
128
- try {
129
- const server = this.config?.server || "https://hackers.baby";
130
- const res = await fetch(`${server}/api/users/me/notifications`, { headers: this.headers });
131
- if (!res.ok) return null;
132
- return res.json();
133
- } catch {
134
- return null;
135
- }
136
- }
137
- async claimReferral(code) {
138
- try {
139
- const server = this.config?.server || "https://hackers.baby";
140
- const res = await fetch(`${server}/api/referral/claim`, {
141
- method: "POST",
142
- headers: this.headers,
143
- body: JSON.stringify({ referral_code: code })
144
- });
145
- if (!res.ok) return null;
146
- return res.json();
147
- } catch {
148
- return null;
149
- }
150
- }
151
- async getReferralStats() {
152
- try {
153
- const server = this.config?.server || "https://hackers.baby";
154
- const res = await fetch(`${server}/api/referral/stats`, { headers: this.headers });
155
- if (!res.ok) return null;
156
- return res.json();
157
- } catch {
158
- return null;
159
- }
96
+ async refreshTokenIfNeeded() {
97
+ if (!this.config) return;
98
+ try {
99
+ const parts = this.config.token.split(".");
100
+ if (parts.length !== 3) return;
101
+ const payload = JSON.parse(Buffer.from(parts[1], "base64").toString("utf-8"));
102
+ const expMs = payload.exp * 1e3;
103
+ const oneDayMs = 24 * 60 * 60 * 1e3;
104
+ if (Date.now() + oneDayMs < expMs) return;
105
+ const res = await fetch(`${this.config.server}/api/auth/cli-token/refresh`, {
106
+ method: "POST",
107
+ headers: this.headers,
108
+ body: JSON.stringify({ refresh_token: this.config.refresh_token })
109
+ });
110
+ if (res.ok) {
111
+ const data = await res.json();
112
+ if (data.token) {
113
+ this.config.token = data.token;
114
+ if (data.refresh_token) this.config.refresh_token = data.refresh_token;
115
+ saveConfig(this.config);
116
+ }
117
+ }
118
+ } catch {
119
+ }
120
+ }
121
+ async getStatus() {
122
+ const server = this.config?.server || "https://hackers.baby";
123
+ const res = await fetch(`${server}/api/users/me`, { headers: this.headers });
124
+ if (!res.ok) throw new Error(`getStatus failed: ${res.status}`);
125
+ return res.json();
126
+ }
127
+ async getRank() {
128
+ const server = this.config?.server || "https://hackers.baby";
129
+ const res = await fetch(`${server}/api/users/me/rank`, { headers: this.headers });
130
+ if (!res.ok) throw new Error(`getRank failed: ${res.status}`);
131
+ return res.json();
132
+ }
133
+ async getLeaderboard() {
134
+ const server = this.config?.server || "https://hackers.baby";
135
+ const res = await fetch(`${server}/api/leaderboard/global?limit=10`, { headers: this.headers });
136
+ if (!res.ok) throw new Error(`getLeaderboard failed: ${res.status}`);
137
+ return res.json();
138
+ }
139
+ async getPublicStats() {
140
+ try {
141
+ const server = this.config?.server || "https://hackers.baby";
142
+ const res = await fetch(`${server}/api/stats/public`);
143
+ if (!res.ok) return null;
144
+ return res.json();
145
+ } catch {
146
+ return null;
147
+ }
148
+ }
149
+ async getNotifications() {
150
+ try {
151
+ const server = this.config?.server || "https://hackers.baby";
152
+ const res = await fetch(`${server}/api/users/me/notifications`, { headers: this.headers });
153
+ if (!res.ok) return null;
154
+ return res.json();
155
+ } catch {
156
+ return null;
157
+ }
158
+ }
159
+ async claimReferral(code) {
160
+ try {
161
+ const server = this.config?.server || "https://hackers.baby";
162
+ const res = await fetch(`${server}/api/referral/claim`, {
163
+ method: "POST",
164
+ headers: this.headers,
165
+ body: JSON.stringify({ referral_code: code })
166
+ });
167
+ if (!res.ok) return null;
168
+ return res.json();
169
+ } catch {
170
+ return null;
171
+ }
172
+ }
173
+ async getReferralStats() {
174
+ try {
175
+ const server = this.config?.server || "https://hackers.baby";
176
+ const res = await fetch(`${server}/api/referral/stats`, { headers: this.headers });
177
+ if (!res.ok) return null;
178
+ return res.json();
179
+ } catch {
180
+ return null;
181
+ }
182
+ }
183
+ };
160
184
  }
161
- };
185
+ });
186
+
187
+ // src/cli.ts
188
+ init_config();
162
189
 
163
190
  // src/commands/status.ts
191
+ init_api_client();
164
192
  async function statusCommand() {
165
193
  const client = new APIClient();
166
194
  try {
@@ -178,6 +206,7 @@ async function statusCommand() {
178
206
  }
179
207
 
180
208
  // src/commands/leaderboard.ts
209
+ init_api_client();
181
210
  async function leaderboardCommand() {
182
211
  const client = new APIClient();
183
212
  try {
@@ -194,6 +223,7 @@ async function leaderboardCommand() {
194
223
  }
195
224
 
196
225
  // src/commands/dashboard.ts
226
+ init_config();
197
227
  var import_child_process = require("child_process");
198
228
  async function dashboardCommand() {
199
229
  const config = loadConfig();
@@ -206,6 +236,8 @@ async function dashboardCommand() {
206
236
  }
207
237
 
208
238
  // src/commands/flex.ts
239
+ init_config();
240
+ init_api_client();
209
241
  var import_child_process2 = require("child_process");
210
242
  async function flexCommand(args2) {
211
243
  const config = loadConfig();
@@ -340,21 +372,57 @@ async function init() {
340
372
  const refresh_token = await question("Refresh Token: ");
341
373
  try {
342
374
  const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64").toString());
375
+ console.log("\nWhich tool do you use?");
376
+ console.log(" 1) Claude Code");
377
+ console.log(" 2) Cursor");
378
+ console.log(" 3) Both");
379
+ const choice = await question("> ");
380
+ let targets;
381
+ switch (choice.trim()) {
382
+ case "2":
383
+ targets = ["cursor"];
384
+ break;
385
+ case "3":
386
+ targets = ["claude", "cursor"];
387
+ break;
388
+ default:
389
+ targets = ["claude"];
390
+ break;
391
+ }
343
392
  saveConfig({
344
393
  token,
345
394
  refresh_token,
346
395
  user_id: payload.userId,
347
396
  server,
397
+ targets,
348
398
  preferences: { dashboard_port: 3847, batch_interval_ms: 1e4 }
349
399
  });
350
400
  console.log("Configuration saved! hackers.baby is active.");
351
- registerHooks();
401
+ if (targets.includes("claude")) {
402
+ registerClaudeHooks();
403
+ }
404
+ if (targets.includes("cursor")) {
405
+ registerCursorHooks();
406
+ }
407
+ const refFlag = args.find((a) => a.startsWith("--ref="))?.split("=")[1];
408
+ const refCode = refFlag || process.env.HACKERSBABY_REF;
409
+ if (refCode) {
410
+ try {
411
+ const { APIClient: APIClient2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
412
+ const client = new APIClient2();
413
+ const result = await client.claimReferral(refCode);
414
+ if (result) {
415
+ console.log(`\x1B[32m\u{1F381} Referral claimed! 2x multiplier active for 24 hours.\x1B[0m`);
416
+ }
417
+ } catch {
418
+ }
419
+ }
352
420
  } catch {
353
421
  console.error("Invalid token format");
354
422
  }
355
423
  rl.close();
356
424
  }
357
- function registerHooks() {
425
+ function registerClaudeHooks() {
358
426
  const claudeSettingsPath = import_path2.default.join(process.env.HOME || "", ".claude", "settings.json");
359
427
  let settings = {};
360
428
  if (import_fs2.default.existsSync(claudeSettingsPath)) {
@@ -385,5 +453,35 @@ function registerHooks() {
385
453
  import_fs2.default.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2));
386
454
  console.log("Claude Code hooks registered.");
387
455
  }
456
+ function registerCursorHooks() {
457
+ const cursorDir = import_path2.default.join(process.env.HOME || "", ".cursor");
458
+ if (!import_fs2.default.existsSync(cursorDir)) {
459
+ import_fs2.default.mkdirSync(cursorDir, { recursive: true });
460
+ }
461
+ const cursorHooksPath = import_path2.default.join(cursorDir, "hooks.json");
462
+ let hooksConfig = {};
463
+ if (import_fs2.default.existsSync(cursorHooksPath)) {
464
+ hooksConfig = JSON.parse(import_fs2.default.readFileSync(cursorHooksPath, "utf-8"));
465
+ }
466
+ if (!hooksConfig.hooks) hooksConfig.hooks = {};
467
+ const distDir = import_path2.default.resolve(__dirname);
468
+ const hookEntries = {
469
+ sessionStart: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "session-start.js")}`, timeout: 1e4 },
470
+ beforeSubmitPrompt: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "prompt-submit.js")}`, timeout: 5e3 },
471
+ postToolUse: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "tool-call.js")}`, timeout: 5e3 },
472
+ stop: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "stop.js")}`, timeout: 5e3 },
473
+ subagentStart: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "subagent.js")}`, timeout: 5e3 },
474
+ preCompact: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "compact.js")}`, timeout: 5e3 },
475
+ sessionEnd: { command: `node ${import_path2.default.join(distDir, "hooks", "cursor", "session-end.js")}`, timeout: 3e4 }
476
+ };
477
+ for (const [event, cfg] of Object.entries(hookEntries)) {
478
+ if (!hooksConfig.hooks[event]) hooksConfig.hooks[event] = [];
479
+ const hookDef = { command: cfg.command, timeout: cfg.timeout };
480
+ const exists = hooksConfig.hooks[event].some((entry) => entry.command === cfg.command);
481
+ if (!exists) hooksConfig.hooks[event].push(hookDef);
482
+ }
483
+ import_fs2.default.writeFileSync(cursorHooksPath, JSON.stringify(hooksConfig, null, 2));
484
+ console.log("Cursor hooks registered.");
485
+ }
388
486
  main().catch(console.error);
389
487
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/api-client.ts","../src/commands/status.ts","../src/commands/leaderboard.ts","../src/commands/dashboard.ts","../src/commands/flex.ts","../src/cli.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport os from 'os';\n\nexport const CONFIG_DIR = path.join(os.homedir(), '.hackersbaby');\nexport const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\nexport const QUEUE_FILE = path.join(CONFIG_DIR, 'queue.jsonl');\n\nexport interface PluginConfig {\n token: string;\n refresh_token: string;\n user_id: string;\n server: string;\n preferences: {\n dashboard_port: number;\n batch_interval_ms: number;\n };\n}\n\nexport function ensureConfigDir(): void {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): PluginConfig | null {\n try {\n if (!fs.existsSync(CONFIG_FILE)) return null;\n const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');\n return JSON.parse(raw) as PluginConfig;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: PluginConfig): void {\n ensureConfigDir();\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');\n}\n","import { loadConfig, saveConfig } from './config';\nimport type { EventBatch } from '@hackersbaby/shared';\n\nexport class APIClient {\n private config = loadConfig();\n\n private get headers(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config?.token || ''}`,\n };\n }\n\n async sendBatch(batch: EventBatch): Promise<boolean> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/scores/batch`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify(batch),\n });\n return res.ok;\n } catch {\n return false;\n }\n }\n\n async refreshTokenIfNeeded(): Promise<void> {\n if (!this.config) return;\n try {\n const parts = this.config.token.split('.');\n if (parts.length !== 3) return;\n const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString('utf-8'));\n const expMs = payload.exp * 1000;\n const oneDayMs = 24 * 60 * 60 * 1000;\n if (Date.now() + oneDayMs < expMs) return; // more than 1 day remaining, no refresh needed\n\n const res = await fetch(`${this.config.server}/api/auth/cli-token/refresh`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ refresh_token: this.config.refresh_token }),\n });\n if (res.ok) {\n const data = (await res.json()) as { token?: string; refresh_token?: string };\n if (data.token) {\n this.config.token = data.token;\n if (data.refresh_token) this.config.refresh_token = data.refresh_token;\n saveConfig(this.config);\n }\n }\n } catch {\n // silently ignore refresh errors\n }\n }\n\n async getStatus(): Promise<Record<string, unknown>> {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/users/me`, { headers: this.headers });\n if (!res.ok) throw new Error(`getStatus failed: ${res.status}`);\n return res.json() as Promise<Record<string, unknown>>;\n }\n\n async getRank(): Promise<Record<string, unknown>> {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/users/me/rank`, { headers: this.headers });\n if (!res.ok) throw new Error(`getRank failed: ${res.status}`);\n return res.json() as Promise<Record<string, unknown>>;\n }\n\n async getLeaderboard(): Promise<Record<string, unknown>> {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/leaderboard/global?limit=10`, { headers: this.headers });\n if (!res.ok) throw new Error(`getLeaderboard failed: ${res.status}`);\n return res.json() as Promise<Record<string, unknown>>;\n }\n\n async getPublicStats(): Promise<Record<string, unknown> | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/stats/public`);\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n } catch {\n return null;\n }\n }\n\n async getNotifications(): Promise<{ notifications: Array<{ type: string; message: string }> } | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/users/me/notifications`, { headers: this.headers });\n if (!res.ok) return null;\n return res.json() as Promise<{ notifications: Array<{ type: string; message: string }> }>;\n } catch {\n return null;\n }\n }\n\n async claimReferral(code: string): Promise<Record<string, unknown> | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/referral/claim`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ referral_code: code }),\n });\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n } catch {\n return null;\n }\n }\n\n async getReferralStats(): Promise<Record<string, unknown> | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/referral/stats`, { headers: this.headers });\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n } catch {\n return null;\n }\n }\n}\n","import { APIClient } from '../api-client';\n\nexport async function statusCommand(): Promise<string> {\n const client = new APIClient();\n try {\n const [me, rank] = await Promise.all([client.getStatus(), client.getRank()]);\n return [\n 'hackers.baby Status',\n ` Score: ${(me as any).total_score?.toLocaleString() || 0}`,\n ` Global Rank: #${(rank as any).global || '-'}`,\n ` Streak: ${(me as any).streak_days || 0} days`,\n ` Languages: ${((me as any).languages || []).join(', ') || 'none set'}`,\n ].join('\\n');\n } catch {\n return 'Error fetching status. Run `hackersbaby init` to set up.';\n }\n}\n","import { APIClient } from '../api-client';\n\nexport async function leaderboardCommand(): Promise<string> {\n const client = new APIClient();\n try {\n const data = await client.getLeaderboard();\n const lines = ['Global Leaderboard', ''];\n for (const entry of (data as any).entries || []) {\n const marker = entry.rank <= 3 ? ['', '#1', '#2', '#3'][entry.rank] : `#${entry.rank}`;\n lines.push(` ${marker.padEnd(4)} ${entry.username.padEnd(20)} ${entry.score.toLocaleString()}`);\n }\n return lines.join('\\n');\n } catch {\n return 'Error fetching leaderboard.';\n }\n}\n","import { loadConfig } from '../config';\nimport { execFile } from 'child_process';\n\nexport async function dashboardCommand(): Promise<string> {\n const config = loadConfig();\n const url = `${config?.server || 'https://hackers.baby'}/dashboard`;\n\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';\n const args = process.platform === 'win32' ? ['/c', 'start', url] : [url];\n execFile(cmd, args, () => {});\n\n return `Opening dashboard at ${url}`;\n}\n","import { loadConfig } from '../config';\nimport { APIClient } from '../api-client';\nimport { execFileSync } from 'child_process';\n\nexport async function flexCommand(args: string[]) {\n const config = loadConfig();\n if (!config?.token) {\n console.log('Not logged in. Run: hackersbaby init');\n return;\n }\n\n const client = new APIClient();\n const [status, rankData, stats] = await Promise.all([\n client.getStatus().catch(() => null),\n client.getRank().catch(() => null),\n client.getPublicStats(),\n ]);\n\n if (!status) {\n console.log('Could not fetch your stats. Are you logged in?');\n return;\n }\n\n const username = String(status.github_username ?? 'unknown');\n const score = Number(status.total_score ?? 0).toLocaleString();\n const rank = rankData?.global_rank ?? '—';\n const streak = Number(status.streak_days ?? 0);\n const totalUsers = stats?.total_users ?? '?';\n const season = stats?.current_season ?? 0;\n\n const refCode = `${username}-${(config.user_id ?? '').slice(0, 3)}`;\n const refUrl = `hackers.baby/ref/${refCode}`;\n\n const c = '\\x1b[36m'; // cyan\n const g = '\\x1b[32m'; // green\n const y = '\\x1b[33m'; // yellow\n const b = '\\x1b[1m'; // bold\n const d = '\\x1b[2m'; // dim\n const r = '\\x1b[0m'; // reset\n\n const pad = (s: string, n: number) => s.length >= n ? s.slice(0, n) : s + ' '.repeat(n - s.length);\n\n const card = [\n '',\n `${c}╔══════════════════════════════════════╗${r}`,\n `${c}║${r} ${b}${g}hackers.baby${r} /// ${y}SEASON ${season}${r} ${c}║${r}`,\n `${c}╠══════════════════════════════════════╣${r}`,\n `${c}║${r} ${b}@${pad(username, 24)}${r}${b}RANK #${pad(String(rank), 4)}${r} ${c}║${r}`,\n `${c}║${r} Score: ${g}${pad(score, 14)}${r} pts ${c}║${r}`,\n `${c}║${r} Streak: ${y}${pad(String(streak), 3)}${r} days ${c}║${r}`,\n `${c}║${r} Players: ${pad(String(totalUsers), 26)}${c}║${r}`,\n `${c}╠══════════════════════════════════════╣${r}`,\n `${c}║${r} ${d}npm i -g @hackersbaby/plugin${r} ${c}║${r}`,\n `${c}║${r} ${d}${pad(refUrl, 34)}${r} ${c}║${r}`,\n `${c}╚══════════════════════════════════════╝${r}`,\n '',\n ].join('\\n');\n\n console.log(card);\n\n if (args.includes('--share')) {\n const shareText = [\n `I'm ranked #${rank} on hackers.baby with ${score} points`,\n '',\n `${streak}-day streak | Season ${season}`,\n '',\n 'Think you can beat me?',\n 'npm i -g @hackersbaby/plugin',\n `https://${refUrl}`,\n ].join('\\n');\n\n let copied = false;\n try {\n const platform = process.platform;\n if (platform === 'darwin') {\n execFileSync('pbcopy', { input: shareText });\n copied = true;\n } else if (platform === 'win32') {\n execFileSync('clip', { input: shareText });\n copied = true;\n } else {\n // Linux: try xclip, fall back to xsel\n try {\n execFileSync('xclip', ['-selection', 'clipboard'], { input: shareText });\n copied = true;\n } catch {\n try {\n execFileSync('xsel', ['--clipboard', '--input'], { input: shareText });\n copied = true;\n } catch {\n // no clipboard tool available\n }\n }\n }\n } catch {\n // clipboard failed\n }\n\n if (copied) {\n console.log(`${g}Copied to clipboard! Paste it on X, Discord, or wherever devs hang out.${r}`);\n } else {\n console.log('\\nShare this:\\n');\n console.log(shareText);\n }\n }\n}\n","import { loadConfig, saveConfig, ensureConfigDir } from './config';\nimport { statusCommand } from './commands/status';\nimport { leaderboardCommand } from './commands/leaderboard';\nimport { dashboardCommand } from './commands/dashboard';\nimport { flexCommand } from './commands/flex';\nimport fs from 'fs';\nimport path from 'path';\nimport { execFile } from 'child_process';\nimport readline from 'readline';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nasync function main() {\n switch (command) {\n case 'init': await init(); break;\n case 'status': console.log(await statusCommand()); break;\n case 'leaderboard': console.log(await leaderboardCommand()); break;\n case 'dashboard': console.log(await dashboardCommand()); break;\n case 'flex': await flexCommand(process.argv.slice(3)); break;\n default: console.log('Usage: hackersbaby <init|status|leaderboard|dashboard|flex>'); break;\n }\n}\n\nasync function init() {\n ensureConfigDir();\n const server = process.env.HACKERSBABY_SERVER || 'https://hackers.baby';\n console.log('Opening browser for GitHub authentication...');\n\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';\n const browserArgs = process.platform === 'win32' ? ['/c', 'start', `${server}/cli-setup`] : [`${server}/cli-setup`];\n execFile(cmd, browserArgs, () => {});\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n\n const question = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));\n\n console.log('After authenticating, paste your CLI token:');\n const token = await question('Token: ');\n const refresh_token = await question('Refresh Token: ');\n\n try {\n const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());\n saveConfig({\n token, refresh_token,\n user_id: payload.userId,\n server,\n preferences: { dashboard_port: 3847, batch_interval_ms: 10000 },\n });\n console.log('Configuration saved! hackers.baby is active.');\n registerHooks();\n } catch {\n console.error('Invalid token format');\n }\n rl.close();\n}\n\nfunction registerHooks() {\n const claudeSettingsPath = path.join(process.env.HOME || '', '.claude', 'settings.json');\n let settings: Record<string, any> = {};\n if (fs.existsSync(claudeSettingsPath)) {\n settings = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf-8'));\n }\n if (!settings.hooks) settings.hooks = {};\n\n const distDir = path.resolve(__dirname);\n const hookEntries: Record<string, { command: string; timeout: number; matcher?: string }> = {\n SessionStart: { command: `node ${path.join(distDir, 'hooks', 'session-start.js')}`, timeout: 10 },\n UserPromptSubmit: { command: `node ${path.join(distDir, 'hooks', 'prompt-submit.js')}`, timeout: 5 },\n PostToolUse: { command: `node ${path.join(distDir, 'hooks', 'tool-call.js')}`, timeout: 5 },\n Stop: { command: `node ${path.join(distDir, 'hooks', 'stop.js')}`, timeout: 5 },\n SubagentStart: { command: `node ${path.join(distDir, 'hooks', 'subagent.js')}`, timeout: 5 },\n PreCompact: { command: `node ${path.join(distDir, 'hooks', 'compact.js')}`, timeout: 5 },\n SessionEnd: { command: `node ${path.join(distDir, 'hooks', 'session-end.js')}`, timeout: 30 },\n };\n\n for (const [event, cfg] of Object.entries(hookEntries)) {\n if (!settings.hooks[event]) settings.hooks[event] = [];\n const hookDef = {\n matcher: cfg.matcher || '',\n hooks: [{ type: 'command', command: cfg.command, timeout: cfg.timeout }],\n };\n // Avoid duplicates by checking if command already registered\n const exists = settings.hooks[event].some((entry: any) =>\n entry.hooks?.some((h: any) => h.command === cfg.command)\n );\n if (!exists) settings.hooks[event].push(hookDef);\n }\n\n fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2));\n console.log('Claude Code hooks registered.');\n}\n\nmain().catch(console.error);\n"],"mappings":"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","names":["path","os","fs","args","import_child_process","args","import_fs","import_path","import_child_process","readline","path","fs"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/api-client.ts","../src/cli.ts","../src/commands/status.ts","../src/commands/leaderboard.ts","../src/commands/dashboard.ts","../src/commands/flex.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport os from 'os';\n\nexport const CONFIG_DIR = path.join(os.homedir(), '.hackersbaby');\nexport const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\nexport const QUEUE_FILE = path.join(CONFIG_DIR, 'queue.jsonl');\n\nexport type Source = 'claude' | 'cursor';\n\nexport interface PluginConfig {\n token: string;\n refresh_token: string;\n user_id: string;\n server: string;\n targets?: Source[];\n preferences: {\n dashboard_port: number;\n batch_interval_ms: number;\n };\n}\n\nexport function sessionStateFile(source: Source): string {\n return path.join(CONFIG_DIR, `active-session-${source}.json`);\n}\n\nexport function ensureConfigDir(): void {\n if (!fs.existsSync(CONFIG_DIR)) {\n fs.mkdirSync(CONFIG_DIR, { recursive: true });\n }\n}\n\nexport function loadConfig(): PluginConfig | null {\n try {\n if (!fs.existsSync(CONFIG_FILE)) return null;\n const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');\n return JSON.parse(raw) as PluginConfig;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: PluginConfig): void {\n ensureConfigDir();\n fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');\n}\n","import { loadConfig, saveConfig } from './config';\nimport type { EventBatch } from '@hackersbaby/shared';\n\nexport class APIClient {\n private config = loadConfig();\n\n private get headers(): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.config?.token || ''}`,\n };\n }\n\n async sendBatch(batch: EventBatch): Promise<boolean> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/scores/batch`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify(batch),\n });\n return res.ok;\n } catch {\n return false;\n }\n }\n\n async refreshTokenIfNeeded(): Promise<void> {\n if (!this.config) return;\n try {\n const parts = this.config.token.split('.');\n if (parts.length !== 3) return;\n const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString('utf-8'));\n const expMs = payload.exp * 1000;\n const oneDayMs = 24 * 60 * 60 * 1000;\n if (Date.now() + oneDayMs < expMs) return; // more than 1 day remaining, no refresh needed\n\n const res = await fetch(`${this.config.server}/api/auth/cli-token/refresh`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ refresh_token: this.config.refresh_token }),\n });\n if (res.ok) {\n const data = (await res.json()) as { token?: string; refresh_token?: string };\n if (data.token) {\n this.config.token = data.token;\n if (data.refresh_token) this.config.refresh_token = data.refresh_token;\n saveConfig(this.config);\n }\n }\n } catch {\n // silently ignore refresh errors\n }\n }\n\n async getStatus(): Promise<Record<string, unknown>> {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/users/me`, { headers: this.headers });\n if (!res.ok) throw new Error(`getStatus failed: ${res.status}`);\n return res.json() as Promise<Record<string, unknown>>;\n }\n\n async getRank(): Promise<Record<string, unknown>> {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/users/me/rank`, { headers: this.headers });\n if (!res.ok) throw new Error(`getRank failed: ${res.status}`);\n return res.json() as Promise<Record<string, unknown>>;\n }\n\n async getLeaderboard(): Promise<Record<string, unknown>> {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/leaderboard/global?limit=10`, { headers: this.headers });\n if (!res.ok) throw new Error(`getLeaderboard failed: ${res.status}`);\n return res.json() as Promise<Record<string, unknown>>;\n }\n\n async getPublicStats(): Promise<Record<string, unknown> | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/stats/public`);\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n } catch {\n return null;\n }\n }\n\n async getNotifications(): Promise<{ notifications: Array<{ type: string; message: string }> } | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/users/me/notifications`, { headers: this.headers });\n if (!res.ok) return null;\n return res.json() as Promise<{ notifications: Array<{ type: string; message: string }> }>;\n } catch {\n return null;\n }\n }\n\n async claimReferral(code: string): Promise<Record<string, unknown> | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/referral/claim`, {\n method: 'POST',\n headers: this.headers,\n body: JSON.stringify({ referral_code: code }),\n });\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n } catch {\n return null;\n }\n }\n\n async getReferralStats(): Promise<Record<string, unknown> | null> {\n try {\n const server = this.config?.server || 'https://hackers.baby';\n const res = await fetch(`${server}/api/referral/stats`, { headers: this.headers });\n if (!res.ok) return null;\n return res.json() as Promise<Record<string, unknown>>;\n } catch {\n return null;\n }\n }\n}\n","import { loadConfig, saveConfig, ensureConfigDir } from './config';\nimport type { Source } from './config';\nimport { statusCommand } from './commands/status';\nimport { leaderboardCommand } from './commands/leaderboard';\nimport { dashboardCommand } from './commands/dashboard';\nimport { flexCommand } from './commands/flex';\nimport fs from 'fs';\nimport path from 'path';\nimport { execFile } from 'child_process';\nimport readline from 'readline';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nasync function main() {\n switch (command) {\n case 'init': await init(); break;\n case 'status': console.log(await statusCommand()); break;\n case 'leaderboard': console.log(await leaderboardCommand()); break;\n case 'dashboard': console.log(await dashboardCommand()); break;\n case 'flex': await flexCommand(process.argv.slice(3)); break;\n default: console.log('Usage: hackersbaby <init|status|leaderboard|dashboard|flex>'); break;\n }\n}\n\nasync function init() {\n ensureConfigDir();\n const server = process.env.HACKERSBABY_SERVER || 'https://hackers.baby';\n console.log('Opening browser for GitHub authentication...');\n\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';\n const browserArgs = process.platform === 'win32' ? ['/c', 'start', `${server}/cli-setup`] : [`${server}/cli-setup`];\n execFile(cmd, browserArgs, () => {});\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const question = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));\n\n console.log('After authenticating, paste your CLI token:');\n const token = await question('Token: ');\n const refresh_token = await question('Refresh Token: ');\n\n try {\n const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());\n\n // Ask which tool(s) to integrate with\n console.log('\\nWhich tool do you use?');\n console.log(' 1) Claude Code');\n console.log(' 2) Cursor');\n console.log(' 3) Both');\n const choice = await question('> ');\n\n let targets: Source[];\n switch (choice.trim()) {\n case '2': targets = ['cursor']; break;\n case '3': targets = ['claude', 'cursor']; break;\n default: targets = ['claude']; break;\n }\n\n saveConfig({\n token, refresh_token,\n user_id: payload.userId,\n server,\n targets,\n preferences: { dashboard_port: 3847, batch_interval_ms: 10000 },\n });\n console.log('Configuration saved! hackers.baby is active.');\n\n if (targets.includes('claude')) {\n registerClaudeHooks();\n }\n if (targets.includes('cursor')) {\n registerCursorHooks();\n }\n\n // Auto-claim referral if --ref flag or HACKERSBABY_REF env var is set\n const refFlag = args.find((a) => a.startsWith('--ref='))?.split('=')[1];\n const refCode = refFlag || process.env.HACKERSBABY_REF;\n if (refCode) {\n try {\n const { APIClient } = await import('./api-client');\n const client = new APIClient();\n const result = await client.claimReferral(refCode);\n if (result) {\n console.log(`\\x1b[32m🎁 Referral claimed! 2x multiplier active for 24 hours.\\x1b[0m`);\n }\n } catch {}\n }\n } catch {\n console.error('Invalid token format');\n }\n rl.close();\n}\n\nfunction registerClaudeHooks() {\n const claudeSettingsPath = path.join(process.env.HOME || '', '.claude', 'settings.json');\n let settings: Record<string, any> = {};\n if (fs.existsSync(claudeSettingsPath)) {\n settings = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf-8'));\n }\n if (!settings.hooks) settings.hooks = {};\n\n const distDir = path.resolve(__dirname);\n const hookEntries: Record<string, { command: string; timeout: number; matcher?: string }> = {\n SessionStart: { command: `node ${path.join(distDir, 'hooks', 'session-start.js')}`, timeout: 10 },\n UserPromptSubmit: { command: `node ${path.join(distDir, 'hooks', 'prompt-submit.js')}`, timeout: 5 },\n PostToolUse: { command: `node ${path.join(distDir, 'hooks', 'tool-call.js')}`, timeout: 5 },\n Stop: { command: `node ${path.join(distDir, 'hooks', 'stop.js')}`, timeout: 5 },\n SubagentStart: { command: `node ${path.join(distDir, 'hooks', 'subagent.js')}`, timeout: 5 },\n PreCompact: { command: `node ${path.join(distDir, 'hooks', 'compact.js')}`, timeout: 5 },\n SessionEnd: { command: `node ${path.join(distDir, 'hooks', 'session-end.js')}`, timeout: 30 },\n };\n\n for (const [event, cfg] of Object.entries(hookEntries)) {\n if (!settings.hooks[event]) settings.hooks[event] = [];\n const hookDef = {\n matcher: cfg.matcher || '',\n hooks: [{ type: 'command', command: cfg.command, timeout: cfg.timeout }],\n };\n const exists = settings.hooks[event].some((entry: any) =>\n entry.hooks?.some((h: any) => h.command === cfg.command)\n );\n if (!exists) settings.hooks[event].push(hookDef);\n }\n\n fs.writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2));\n console.log('Claude Code hooks registered.');\n}\n\nfunction registerCursorHooks() {\n const cursorDir = path.join(process.env.HOME || '', '.cursor');\n if (!fs.existsSync(cursorDir)) {\n fs.mkdirSync(cursorDir, { recursive: true });\n }\n\n const cursorHooksPath = path.join(cursorDir, 'hooks.json');\n let hooksConfig: Record<string, any> = {};\n if (fs.existsSync(cursorHooksPath)) {\n hooksConfig = JSON.parse(fs.readFileSync(cursorHooksPath, 'utf-8'));\n }\n if (!hooksConfig.hooks) hooksConfig.hooks = {};\n\n const distDir = path.resolve(__dirname);\n // Cursor uses camelCase hook names and millisecond timeouts\n const hookEntries: Record<string, { command: string; timeout: number }> = {\n sessionStart: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'session-start.js')}`, timeout: 10000 },\n beforeSubmitPrompt: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'prompt-submit.js')}`, timeout: 5000 },\n postToolUse: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'tool-call.js')}`, timeout: 5000 },\n stop: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'stop.js')}`, timeout: 5000 },\n subagentStart: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'subagent.js')}`, timeout: 5000 },\n preCompact: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'compact.js')}`, timeout: 5000 },\n sessionEnd: { command: `node ${path.join(distDir, 'hooks', 'cursor', 'session-end.js')}`, timeout: 30000 },\n };\n\n for (const [event, cfg] of Object.entries(hookEntries)) {\n if (!hooksConfig.hooks[event]) hooksConfig.hooks[event] = [];\n const hookDef = { command: cfg.command, timeout: cfg.timeout };\n // Avoid duplicates\n const exists = hooksConfig.hooks[event].some((entry: any) => entry.command === cfg.command);\n if (!exists) hooksConfig.hooks[event].push(hookDef);\n }\n\n fs.writeFileSync(cursorHooksPath, JSON.stringify(hooksConfig, null, 2));\n console.log('Cursor hooks registered.');\n}\n\nmain().catch(console.error);\n","import { APIClient } from '../api-client';\n\nexport async function statusCommand(): Promise<string> {\n const client = new APIClient();\n try {\n const [me, rank] = await Promise.all([client.getStatus(), client.getRank()]);\n return [\n 'hackers.baby Status',\n ` Score: ${(me as any).total_score?.toLocaleString() || 0}`,\n ` Global Rank: #${(rank as any).global || '-'}`,\n ` Streak: ${(me as any).streak_days || 0} days`,\n ` Languages: ${((me as any).languages || []).join(', ') || 'none set'}`,\n ].join('\\n');\n } catch {\n return 'Error fetching status. Run `hackersbaby init` to set up.';\n }\n}\n","import { APIClient } from '../api-client';\n\nexport async function leaderboardCommand(): Promise<string> {\n const client = new APIClient();\n try {\n const data = await client.getLeaderboard();\n const lines = ['Global Leaderboard', ''];\n for (const entry of (data as any).entries || []) {\n const marker = entry.rank <= 3 ? ['', '#1', '#2', '#3'][entry.rank] : `#${entry.rank}`;\n lines.push(` ${marker.padEnd(4)} ${entry.username.padEnd(20)} ${entry.score.toLocaleString()}`);\n }\n return lines.join('\\n');\n } catch {\n return 'Error fetching leaderboard.';\n }\n}\n","import { loadConfig } from '../config';\nimport { execFile } from 'child_process';\n\nexport async function dashboardCommand(): Promise<string> {\n const config = loadConfig();\n const url = `${config?.server || 'https://hackers.baby'}/dashboard`;\n\n const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';\n const args = process.platform === 'win32' ? ['/c', 'start', url] : [url];\n execFile(cmd, args, () => {});\n\n return `Opening dashboard at ${url}`;\n}\n","import { loadConfig } from '../config';\nimport { APIClient } from '../api-client';\nimport { execFileSync } from 'child_process';\n\nexport async function flexCommand(args: string[]) {\n const config = loadConfig();\n if (!config?.token) {\n console.log('Not logged in. Run: hackersbaby init');\n return;\n }\n\n const client = new APIClient();\n const [status, rankData, stats] = await Promise.all([\n client.getStatus().catch(() => null),\n client.getRank().catch(() => null),\n client.getPublicStats(),\n ]);\n\n if (!status) {\n console.log('Could not fetch your stats. Are you logged in?');\n return;\n }\n\n const username = String(status.github_username ?? 'unknown');\n const score = Number(status.total_score ?? 0).toLocaleString();\n const rank = rankData?.global_rank ?? '—';\n const streak = Number(status.streak_days ?? 0);\n const totalUsers = stats?.total_users ?? '?';\n const season = stats?.current_season ?? 0;\n\n const refCode = `${username}-${(config.user_id ?? '').slice(0, 3)}`;\n const refUrl = `hackers.baby/ref/${refCode}`;\n\n const c = '\\x1b[36m'; // cyan\n const g = '\\x1b[32m'; // green\n const y = '\\x1b[33m'; // yellow\n const b = '\\x1b[1m'; // bold\n const d = '\\x1b[2m'; // dim\n const r = '\\x1b[0m'; // reset\n\n const pad = (s: string, n: number) => s.length >= n ? s.slice(0, n) : s + ' '.repeat(n - s.length);\n\n const card = [\n '',\n `${c}╔══════════════════════════════════════╗${r}`,\n `${c}║${r} ${b}${g}hackers.baby${r} /// ${y}SEASON ${season}${r} ${c}║${r}`,\n `${c}╠══════════════════════════════════════╣${r}`,\n `${c}║${r} ${b}@${pad(username, 24)}${r}${b}RANK #${pad(String(rank), 4)}${r} ${c}║${r}`,\n `${c}║${r} Score: ${g}${pad(score, 14)}${r} pts ${c}║${r}`,\n `${c}║${r} Streak: ${y}${pad(String(streak), 3)}${r} days ${c}║${r}`,\n `${c}║${r} Players: ${pad(String(totalUsers), 26)}${c}║${r}`,\n `${c}╠══════════════════════════════════════╣${r}`,\n `${c}║${r} ${d}npm i -g @hackersbaby/plugin${r} ${c}║${r}`,\n `${c}║${r} ${d}${pad(refUrl, 34)}${r} ${c}║${r}`,\n `${c}╚══════════════════════════════════════╝${r}`,\n '',\n ].join('\\n');\n\n console.log(card);\n\n if (args.includes('--share')) {\n const shareText = [\n `I'm ranked #${rank} on hackers.baby with ${score} points`,\n '',\n `${streak}-day streak | Season ${season}`,\n '',\n 'Think you can beat me?',\n 'npm i -g @hackersbaby/plugin',\n `https://${refUrl}`,\n ].join('\\n');\n\n let copied = false;\n try {\n const platform = process.platform;\n if (platform === 'darwin') {\n execFileSync('pbcopy', { input: shareText });\n copied = true;\n } else if (platform === 'win32') {\n execFileSync('clip', { input: shareText });\n copied = true;\n } else {\n // Linux: try xclip, fall back to xsel\n try {\n execFileSync('xclip', ['-selection', 'clipboard'], { input: shareText });\n copied = true;\n } catch {\n try {\n execFileSync('xsel', ['--clipboard', '--input'], { input: shareText });\n copied = true;\n } catch {\n // no clipboard tool available\n }\n }\n }\n } catch {\n // clipboard failed\n }\n\n if (copied) {\n console.log(`${g}Copied to clipboard! Paste it on X, Discord, or wherever devs hang out.${r}`);\n } else {\n console.log('\\nShare this:\\n');\n console.log(shareText);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BO,SAAS,kBAAwB;AACtC,MAAI,CAAC,UAAAA,QAAG,WAAW,UAAU,GAAG;AAC9B,cAAAA,QAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAAA,EAC9C;AACF;AAEO,SAAS,aAAkC;AAChD,MAAI;AACF,QAAI,CAAC,UAAAA,QAAG,WAAW,WAAW,EAAG,QAAO;AACxC,UAAM,MAAM,UAAAA,QAAG,aAAa,aAAa,OAAO;AAChD,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,WAAW,QAA4B;AACrD,kBAAgB;AAChB,YAAAA,QAAG,cAAc,aAAa,KAAK,UAAU,QAAQ,MAAM,CAAC,GAAG,OAAO;AACxE;AA7CA,eACA,aACA,WAEa,YACA,aACA;AANb;AAAA;AAAA;AAAA,gBAAe;AACf,kBAAiB;AACjB,gBAAe;AAER,IAAM,aAAa,YAAAC,QAAK,KAAK,UAAAC,QAAG,QAAQ,GAAG,cAAc;AACzD,IAAM,cAAc,YAAAD,QAAK,KAAK,YAAY,aAAa;AACvD,IAAM,aAAa,YAAAA,QAAK,KAAK,YAAY,aAAa;AAAA;AAAA;;;ACN7D;AAAA;AAAA;AAAA;AAAA,IAGa;AAHb;AAAA;AAAA;AAAA;AAGO,IAAM,YAAN,MAAgB;AAAA,MACb,SAAS,WAAW;AAAA,MAE5B,IAAY,UAAkC;AAC5C,eAAO;AAAA,UACL,gBAAgB;AAAA,UAChB,eAAe,UAAU,KAAK,QAAQ,SAAS,EAAE;AAAA,QACnD;AAAA,MACF;AAAA,MAEA,MAAM,UAAU,OAAqC;AACnD,YAAI;AACF,gBAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,gBAAM,MAAM,MAAM,MAAM,GAAG,MAAM,qBAAqB;AAAA,YACpD,QAAQ;AAAA,YACR,SAAS,KAAK;AAAA,YACd,MAAM,KAAK,UAAU,KAAK;AAAA,UAC5B,CAAC;AACD,iBAAO,IAAI;AAAA,QACb,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,uBAAsC;AAC1C,YAAI,CAAC,KAAK,OAAQ;AAClB,YAAI;AACF,gBAAM,QAAQ,KAAK,OAAO,MAAM,MAAM,GAAG;AACzC,cAAI,MAAM,WAAW,EAAG;AACxB,gBAAM,UAAU,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC,GAAG,QAAQ,EAAE,SAAS,OAAO,CAAC;AAC5E,gBAAM,QAAQ,QAAQ,MAAM;AAC5B,gBAAM,WAAW,KAAK,KAAK,KAAK;AAChC,cAAI,KAAK,IAAI,IAAI,WAAW,MAAO;AAEnC,gBAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,MAAM,+BAA+B;AAAA,YAC1E,QAAQ;AAAA,YACR,SAAS,KAAK;AAAA,YACd,MAAM,KAAK,UAAU,EAAE,eAAe,KAAK,OAAO,cAAc,CAAC;AAAA,UACnE,CAAC;AACD,cAAI,IAAI,IAAI;AACV,kBAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,gBAAI,KAAK,OAAO;AACd,mBAAK,OAAO,QAAQ,KAAK;AACzB,kBAAI,KAAK,cAAe,MAAK,OAAO,gBAAgB,KAAK;AACzD,yBAAW,KAAK,MAAM;AAAA,YACxB;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,MAEA,MAAM,YAA8C;AAClD,cAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,cAAM,MAAM,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,SAAS,KAAK,QAAQ,CAAC;AAC3E,YAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,qBAAqB,IAAI,MAAM,EAAE;AAC9D,eAAO,IAAI,KAAK;AAAA,MAClB;AAAA,MAEA,MAAM,UAA4C;AAChD,cAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,cAAM,MAAM,MAAM,MAAM,GAAG,MAAM,sBAAsB,EAAE,SAAS,KAAK,QAAQ,CAAC;AAChF,YAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,mBAAmB,IAAI,MAAM,EAAE;AAC5D,eAAO,IAAI,KAAK;AAAA,MAClB;AAAA,MAEA,MAAM,iBAAmD;AACvD,cAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,cAAM,MAAM,MAAM,MAAM,GAAG,MAAM,oCAAoC,EAAE,SAAS,KAAK,QAAQ,CAAC;AAC9F,YAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,EAAE;AACnE,eAAO,IAAI,KAAK;AAAA,MAClB;AAAA,MAEA,MAAM,iBAA0D;AAC9D,YAAI;AACF,gBAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,gBAAM,MAAM,MAAM,MAAM,GAAG,MAAM,mBAAmB;AACpD,cAAI,CAAC,IAAI,GAAI,QAAO;AACpB,iBAAO,IAAI,KAAK;AAAA,QAClB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,mBAAgG;AACpG,YAAI;AACF,gBAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,gBAAM,MAAM,MAAM,MAAM,GAAG,MAAM,+BAA+B,EAAE,SAAS,KAAK,QAAQ,CAAC;AACzF,cAAI,CAAC,IAAI,GAAI,QAAO;AACpB,iBAAO,IAAI,KAAK;AAAA,QAClB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,cAAc,MAAuD;AACzE,YAAI;AACF,gBAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,gBAAM,MAAM,MAAM,MAAM,GAAG,MAAM,uBAAuB;AAAA,YACtD,QAAQ;AAAA,YACR,SAAS,KAAK;AAAA,YACd,MAAM,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC;AAAA,UAC9C,CAAC;AACD,cAAI,CAAC,IAAI,GAAI,QAAO;AACpB,iBAAO,IAAI,KAAK;AAAA,QAClB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,mBAA4D;AAChE,YAAI;AACF,gBAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,gBAAM,MAAM,MAAM,MAAM,GAAG,MAAM,uBAAuB,EAAE,SAAS,KAAK,QAAQ,CAAC;AACjF,cAAI,CAAC,IAAI,GAAI,QAAO;AACpB,iBAAO,IAAI,KAAK;AAAA,QAClB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC3HA;;;ACAA;AAEA,eAAsB,gBAAiC;AACrD,QAAM,SAAS,IAAI,UAAU;AAC7B,MAAI;AACF,UAAM,CAAC,IAAI,IAAI,IAAI,MAAM,QAAQ,IAAI,CAAC,OAAO,UAAU,GAAG,OAAO,QAAQ,CAAC,CAAC;AAC3E,WAAO;AAAA,MACL;AAAA,MACA,aAAc,GAAW,aAAa,eAAe,KAAK,CAAC;AAAA,MAC3D,oBAAqB,KAAa,UAAU,GAAG;AAAA,MAC/C,cAAe,GAAW,eAAe,CAAC;AAAA,MAC1C,kBAAmB,GAAW,aAAa,CAAC,GAAG,KAAK,IAAI,KAAK,UAAU;AAAA,IACzE,EAAE,KAAK,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AChBA;AAEA,eAAsB,qBAAsC;AAC1D,QAAM,SAAS,IAAI,UAAU;AAC7B,MAAI;AACF,UAAM,OAAO,MAAM,OAAO,eAAe;AACzC,UAAM,QAAQ,CAAC,sBAAsB,EAAE;AACvC,eAAW,SAAU,KAAa,WAAW,CAAC,GAAG;AAC/C,YAAM,SAAS,MAAM,QAAQ,IAAI,CAAC,IAAI,MAAM,MAAM,IAAI,EAAE,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI;AACpF,YAAM,KAAK,MAAM,OAAO,OAAO,CAAC,CAAC,IAAI,MAAM,SAAS,OAAO,EAAE,CAAC,IAAI,MAAM,MAAM,eAAe,CAAC,EAAE;AAAA,IAClG;AACA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;ACfA;AACA,2BAAyB;AAEzB,eAAsB,mBAAoC;AACxD,QAAM,SAAS,WAAW;AAC1B,QAAM,MAAM,GAAG,QAAQ,UAAU,sBAAsB;AAEvD,QAAM,MAAM,QAAQ,aAAa,WAAW,SAAS,QAAQ,aAAa,UAAU,QAAQ;AAC5F,QAAME,QAAO,QAAQ,aAAa,UAAU,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG;AACvE,qCAAS,KAAKA,OAAM,MAAM;AAAA,EAAC,CAAC;AAE5B,SAAO,wBAAwB,GAAG;AACpC;;;ACZA;AACA;AACA,IAAAC,wBAA6B;AAE7B,eAAsB,YAAYC,OAAgB;AAChD,QAAM,SAAS,WAAW;AAC1B,MAAI,CAAC,QAAQ,OAAO;AAClB,YAAQ,IAAI,sCAAsC;AAClD;AAAA,EACF;AAEA,QAAM,SAAS,IAAI,UAAU;AAC7B,QAAM,CAAC,QAAQ,UAAU,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IAClD,OAAO,UAAU,EAAE,MAAM,MAAM,IAAI;AAAA,IACnC,OAAO,QAAQ,EAAE,MAAM,MAAM,IAAI;AAAA,IACjC,OAAO,eAAe;AAAA,EACxB,CAAC;AAED,MAAI,CAAC,QAAQ;AACX,YAAQ,IAAI,gDAAgD;AAC5D;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,OAAO,mBAAmB,SAAS;AAC3D,QAAM,QAAQ,OAAO,OAAO,eAAe,CAAC,EAAE,eAAe;AAC7D,QAAM,OAAO,UAAU,eAAe;AACtC,QAAM,SAAS,OAAO,OAAO,eAAe,CAAC;AAC7C,QAAM,aAAa,OAAO,eAAe;AACzC,QAAM,SAAS,OAAO,kBAAkB;AAExC,QAAM,UAAU,GAAG,QAAQ,KAAK,OAAO,WAAW,IAAI,MAAM,GAAG,CAAC,CAAC;AACjE,QAAM,SAAS,oBAAoB,OAAO;AAE1C,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,IAAI;AAEV,QAAM,MAAM,CAAC,GAAW,MAAc,EAAE,UAAU,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,IAAI,IAAI,OAAO,IAAI,EAAE,MAAM;AAEjG,QAAM,OAAO;AAAA,IACX;AAAA,IACA,GAAG,CAAC,mPAA2C,CAAC;AAAA,IAChD,GAAG,CAAC,SAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,UAAU,MAAM,GAAG,CAAC,WAAW,CAAC,SAAI,CAAC;AAAA,IAClF,GAAG,CAAC,mPAA2C,CAAC;AAAA,IAChD,GAAG,CAAC,SAAI,CAAC,KAAK,CAAC,IAAI,IAAI,UAAU,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,IAAI,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAI,CAAC;AAAA,IACvF,GAAG,CAAC,SAAI,CAAC,gBAAgB,CAAC,GAAG,IAAI,OAAO,EAAE,CAAC,GAAG,CAAC,eAAe,CAAC,SAAI,CAAC;AAAA,IACpE,GAAG,CAAC,SAAI,CAAC,gBAAgB,CAAC,GAAG,IAAI,OAAO,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,yBAAyB,CAAC,SAAI,CAAC;AAAA,IACtF,GAAG,CAAC,SAAI,CAAC,gBAAgB,IAAI,OAAO,UAAU,GAAG,EAAE,CAAC,GAAG,CAAC,SAAI,CAAC;AAAA,IAC7D,GAAG,CAAC,mPAA2C,CAAC;AAAA,IAChD,GAAG,CAAC,SAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,UAAU,CAAC,SAAI,CAAC;AAAA,IAC/D,GAAG,CAAC,SAAI,CAAC,KAAK,CAAC,GAAG,IAAI,QAAQ,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAI,CAAC;AAAA,IAC/C,GAAG,CAAC,mPAA2C,CAAC;AAAA,IAChD;AAAA,EACF,EAAE,KAAK,IAAI;AAEX,UAAQ,IAAI,IAAI;AAEhB,MAAIA,MAAK,SAAS,SAAS,GAAG;AAC5B,UAAM,YAAY;AAAA,MAChB,eAAe,IAAI,yBAAyB,KAAK;AAAA,MACjD;AAAA,MACA,GAAG,MAAM,wBAAwB,MAAM;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,MAAM;AAAA,IACnB,EAAE,KAAK,IAAI;AAEX,QAAI,SAAS;AACb,QAAI;AACF,YAAM,WAAW,QAAQ;AACzB,UAAI,aAAa,UAAU;AACzB,gDAAa,UAAU,EAAE,OAAO,UAAU,CAAC;AAC3C,iBAAS;AAAA,MACX,WAAW,aAAa,SAAS;AAC/B,gDAAa,QAAQ,EAAE,OAAO,UAAU,CAAC;AACzC,iBAAS;AAAA,MACX,OAAO;AAEL,YAAI;AACF,kDAAa,SAAS,CAAC,cAAc,WAAW,GAAG,EAAE,OAAO,UAAU,CAAC;AACvE,mBAAS;AAAA,QACX,QAAQ;AACN,cAAI;AACF,oDAAa,QAAQ,CAAC,eAAe,SAAS,GAAG,EAAE,OAAO,UAAU,CAAC;AACrE,qBAAS;AAAA,UACX,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,QAAI,QAAQ;AACV,cAAQ,IAAI,GAAG,CAAC,0EAA0E,CAAC,EAAE;AAAA,IAC/F,OAAO;AACL,cAAQ,IAAI,iBAAiB;AAC7B,cAAQ,IAAI,SAAS;AAAA,IACvB;AAAA,EACF;AACF;;;AJnGA,IAAAC,aAAe;AACf,IAAAC,eAAiB;AACjB,IAAAC,wBAAyB;AACzB,sBAAqB;AAErB,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,eAAe,OAAO;AACpB,UAAQ,SAAS;AAAA,IACf,KAAK;AAAQ,YAAM,KAAK;AAAG;AAAA,IAC3B,KAAK;AAAU,cAAQ,IAAI,MAAM,cAAc,CAAC;AAAG;AAAA,IACnD,KAAK;AAAe,cAAQ,IAAI,MAAM,mBAAmB,CAAC;AAAG;AAAA,IAC7D,KAAK;AAAa,cAAQ,IAAI,MAAM,iBAAiB,CAAC;AAAG;AAAA,IACzD,KAAK;AAAQ,YAAM,YAAY,QAAQ,KAAK,MAAM,CAAC,CAAC;AAAG;AAAA,IACvD;AAAS,cAAQ,IAAI,6DAA6D;AAAG;AAAA,EACvF;AACF;AAEA,eAAe,OAAO;AACpB,kBAAgB;AAChB,QAAM,SAAS,QAAQ,IAAI,sBAAsB;AACjD,UAAQ,IAAI,8CAA8C;AAE1D,QAAM,MAAM,QAAQ,aAAa,WAAW,SAAS,QAAQ,aAAa,UAAU,QAAQ;AAC5F,QAAM,cAAc,QAAQ,aAAa,UAAU,CAAC,MAAM,SAAS,GAAG,MAAM,YAAY,IAAI,CAAC,GAAG,MAAM,YAAY;AAClH,sCAAS,KAAK,aAAa,MAAM;AAAA,EAAC,CAAC;AAEnC,QAAM,KAAK,gBAAAC,QAAS,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AACpF,QAAM,WAAW,CAAC,MAA+B,IAAI,QAAQ,CAAC,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;AAEjG,UAAQ,IAAI,6CAA6C;AACzD,QAAM,QAAQ,MAAM,SAAS,SAAS;AACtC,QAAM,gBAAgB,MAAM,SAAS,iBAAiB;AAEtD,MAAI;AACF,UAAM,UAAU,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,QAAQ,EAAE,SAAS,CAAC;AAGhF,YAAQ,IAAI,0BAA0B;AACtC,YAAQ,IAAI,kBAAkB;AAC9B,YAAQ,IAAI,aAAa;AACzB,YAAQ,IAAI,WAAW;AACvB,UAAM,SAAS,MAAM,SAAS,IAAI;AAElC,QAAI;AACJ,YAAQ,OAAO,KAAK,GAAG;AAAA,MACrB,KAAK;AAAK,kBAAU,CAAC,QAAQ;AAAG;AAAA,MAChC,KAAK;AAAK,kBAAU,CAAC,UAAU,QAAQ;AAAG;AAAA,MAC1C;AAAS,kBAAU,CAAC,QAAQ;AAAG;AAAA,IACjC;AAEA,eAAW;AAAA,MACT;AAAA,MAAO;AAAA,MACP,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,MACA,aAAa,EAAE,gBAAgB,MAAM,mBAAmB,IAAM;AAAA,IAChE,CAAC;AACD,YAAQ,IAAI,8CAA8C;AAE1D,QAAI,QAAQ,SAAS,QAAQ,GAAG;AAC9B,0BAAoB;AAAA,IACtB;AACA,QAAI,QAAQ,SAAS,QAAQ,GAAG;AAC9B,0BAAoB;AAAA,IACtB;AAGA,UAAM,UAAU,KAAK,KAAK,CAAC,MAAM,EAAE,WAAW,QAAQ,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC;AACtE,UAAM,UAAU,WAAW,QAAQ,IAAI;AACvC,QAAI,SAAS;AACX,UAAI;AACF,cAAM,EAAE,WAAAC,WAAU,IAAI,MAAM;AAC5B,cAAM,SAAS,IAAIA,WAAU;AAC7B,cAAM,SAAS,MAAM,OAAO,cAAc,OAAO;AACjD,YAAI,QAAQ;AACV,kBAAQ,IAAI,+EAAwE;AAAA,QACtF;AAAA,MACF,QAAQ;AAAA,MAAC;AAAA,IACX;AAAA,EACF,QAAQ;AACN,YAAQ,MAAM,sBAAsB;AAAA,EACtC;AACA,KAAG,MAAM;AACX;AAEA,SAAS,sBAAsB;AAC7B,QAAM,qBAAqB,aAAAC,QAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,WAAW,eAAe;AACvF,MAAI,WAAgC,CAAC;AACrC,MAAI,WAAAC,QAAG,WAAW,kBAAkB,GAAG;AACrC,eAAW,KAAK,MAAM,WAAAA,QAAG,aAAa,oBAAoB,OAAO,CAAC;AAAA,EACpE;AACA,MAAI,CAAC,SAAS,MAAO,UAAS,QAAQ,CAAC;AAEvC,QAAM,UAAU,aAAAD,QAAK,QAAQ,SAAS;AACtC,QAAM,cAAsF;AAAA,IAC1F,cAAc,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,kBAAkB,CAAC,IAAI,SAAS,GAAG;AAAA,IAChG,kBAAkB,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,kBAAkB,CAAC,IAAI,SAAS,EAAE;AAAA,IACnG,aAAa,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,cAAc,CAAC,IAAI,SAAS,EAAE;AAAA,IAC1F,MAAM,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,SAAS,CAAC,IAAI,SAAS,EAAE;AAAA,IAC9E,eAAe,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,aAAa,CAAC,IAAI,SAAS,EAAE;AAAA,IAC3F,YAAY,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,YAAY,CAAC,IAAI,SAAS,EAAE;AAAA,IACvF,YAAY,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,gBAAgB,CAAC,IAAI,SAAS,GAAG;AAAA,EAC9F;AAEA,aAAW,CAAC,OAAO,GAAG,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,QAAI,CAAC,SAAS,MAAM,KAAK,EAAG,UAAS,MAAM,KAAK,IAAI,CAAC;AACrD,UAAM,UAAU;AAAA,MACd,SAAS,IAAI,WAAW;AAAA,MACxB,OAAO,CAAC,EAAE,MAAM,WAAW,SAAS,IAAI,SAAS,SAAS,IAAI,QAAQ,CAAC;AAAA,IACzE;AACA,UAAM,SAAS,SAAS,MAAM,KAAK,EAAE;AAAA,MAAK,CAAC,UACzC,MAAM,OAAO,KAAK,CAAC,MAAW,EAAE,YAAY,IAAI,OAAO;AAAA,IACzD;AACA,QAAI,CAAC,OAAQ,UAAS,MAAM,KAAK,EAAE,KAAK,OAAO;AAAA,EACjD;AAEA,aAAAC,QAAG,cAAc,oBAAoB,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AACtE,UAAQ,IAAI,+BAA+B;AAC7C;AAEA,SAAS,sBAAsB;AAC7B,QAAM,YAAY,aAAAD,QAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI,SAAS;AAC7D,MAAI,CAAC,WAAAC,QAAG,WAAW,SAAS,GAAG;AAC7B,eAAAA,QAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC7C;AAEA,QAAM,kBAAkB,aAAAD,QAAK,KAAK,WAAW,YAAY;AACzD,MAAI,cAAmC,CAAC;AACxC,MAAI,WAAAC,QAAG,WAAW,eAAe,GAAG;AAClC,kBAAc,KAAK,MAAM,WAAAA,QAAG,aAAa,iBAAiB,OAAO,CAAC;AAAA,EACpE;AACA,MAAI,CAAC,YAAY,MAAO,aAAY,QAAQ,CAAC;AAE7C,QAAM,UAAU,aAAAD,QAAK,QAAQ,SAAS;AAEtC,QAAM,cAAoE;AAAA,IACxE,cAAc,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,kBAAkB,CAAC,IAAI,SAAS,IAAM;AAAA,IAC7G,oBAAoB,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,kBAAkB,CAAC,IAAI,SAAS,IAAK;AAAA,IAClH,aAAa,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,cAAc,CAAC,IAAI,SAAS,IAAK;AAAA,IACvG,MAAM,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,SAAS,CAAC,IAAI,SAAS,IAAK;AAAA,IAC3F,eAAe,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,aAAa,CAAC,IAAI,SAAS,IAAK;AAAA,IACxG,YAAY,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,YAAY,CAAC,IAAI,SAAS,IAAK;AAAA,IACpG,YAAY,EAAE,SAAS,QAAQ,aAAAA,QAAK,KAAK,SAAS,SAAS,UAAU,gBAAgB,CAAC,IAAI,SAAS,IAAM;AAAA,EAC3G;AAEA,aAAW,CAAC,OAAO,GAAG,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,QAAI,CAAC,YAAY,MAAM,KAAK,EAAG,aAAY,MAAM,KAAK,IAAI,CAAC;AAC3D,UAAM,UAAU,EAAE,SAAS,IAAI,SAAS,SAAS,IAAI,QAAQ;AAE7D,UAAM,SAAS,YAAY,MAAM,KAAK,EAAE,KAAK,CAAC,UAAe,MAAM,YAAY,IAAI,OAAO;AAC1F,QAAI,CAAC,OAAQ,aAAY,MAAM,KAAK,EAAE,KAAK,OAAO;AAAA,EACpD;AAEA,aAAAC,QAAG,cAAc,iBAAiB,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AACtE,UAAQ,IAAI,0BAA0B;AACxC;AAEA,KAAK,EAAE,MAAM,QAAQ,KAAK;","names":["fs","path","os","args","import_child_process","args","import_fs","import_path","import_child_process","readline","APIClient","path","fs"]}
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  "use strict";
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
@@ -32,6 +33,9 @@ var import_os = __toESM(require("os"));
32
33
  var CONFIG_DIR = import_path.default.join(import_os.default.homedir(), ".hackersbaby");
33
34
  var CONFIG_FILE = import_path.default.join(CONFIG_DIR, "config.json");
34
35
  var QUEUE_FILE = import_path.default.join(CONFIG_DIR, "queue.jsonl");
36
+ function sessionStateFile(source) {
37
+ return import_path.default.join(CONFIG_DIR, `active-session-${source}.json`);
38
+ }
35
39
  function ensureConfigDir() {
36
40
  if (!import_fs.default.existsSync(CONFIG_DIR)) {
37
41
  import_fs.default.mkdirSync(CONFIG_DIR, { recursive: true });
@@ -210,13 +214,17 @@ var EventCollector = class {
210
214
  buffer = [];
211
215
  flushInterval = null;
212
216
  client;
213
- constructor(sessionId) {
217
+ source;
218
+ constructor(sessionId, source) {
214
219
  this.sessionId = sessionId ?? (0, import_uuid.v4)();
215
220
  this.client = new APIClient();
221
+ this.source = source;
216
222
  }
217
223
  addEvent(event) {
224
+ const metadata = this.source ? { ...event.metadata, source: this.source } : event.metadata;
218
225
  this.buffer.push({
219
226
  ...event,
227
+ metadata,
220
228
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
221
229
  });
222
230
  }
@@ -256,29 +264,41 @@ var EventCollector = class {
256
264
  }
257
265
  };
258
266
 
259
- // src/hooks/compact.ts
267
+ // src/hooks/shared/utils.ts
260
268
  var import_fs3 = __toESM(require("fs"));
261
- var import_path2 = __toESM(require("path"));
262
- var import_os2 = __toESM(require("os"));
263
- var stateFile = import_path2.default.join(import_os2.default.homedir(), ".hackersbaby", "active-session.json");
264
- function loadSessionId() {
269
+ function loadSessionId(source) {
265
270
  try {
266
- if (!import_fs3.default.existsSync(stateFile)) return void 0;
267
- const data = JSON.parse(import_fs3.default.readFileSync(stateFile, "utf-8"));
271
+ const file = sessionStateFile(source);
272
+ if (!import_fs3.default.existsSync(file)) return void 0;
273
+ const data = JSON.parse(import_fs3.default.readFileSync(file, "utf-8"));
268
274
  return data.sessionId;
269
275
  } catch {
270
276
  return void 0;
271
277
  }
272
278
  }
273
- var input = "";
274
- process.stdin.on("data", (chunk) => {
275
- input += chunk;
276
- });
277
- process.stdin.on("end", async () => {
279
+ function readStdin() {
280
+ return new Promise((resolve) => {
281
+ let input = "";
282
+ process.stdin.on("data", (chunk) => {
283
+ input += chunk;
284
+ });
285
+ process.stdin.on("end", () => resolve(input));
286
+ });
287
+ }
288
+ function normalizePayload(source, raw) {
289
+ if (source === "cursor") {
290
+ return { ...raw };
291
+ }
292
+ return raw;
293
+ }
294
+
295
+ // src/hooks/shared/compact.ts
296
+ async function handleCompact(source) {
297
+ const input = await readStdin();
278
298
  try {
279
- const hookData = JSON.parse(input);
280
- const sessionId = hookData.session_id || loadSessionId();
281
- const collector = new EventCollector(sessionId);
299
+ const hookData = normalizePayload(source, JSON.parse(input));
300
+ const sessionId = hookData.session_id || loadSessionId(source);
301
+ const collector = new EventCollector(sessionId, source);
282
302
  collector.addEvent({
283
303
  action_type: "context_compacted",
284
304
  value: 1,
@@ -287,5 +307,8 @@ process.stdin.on("end", async () => {
287
307
  await collector.flush();
288
308
  } catch {
289
309
  }
290
- });
310
+ }
311
+
312
+ // src/hooks/compact.ts
313
+ handleCompact("claude");
291
314
  //# sourceMappingURL=compact.js.map