@suncreation/modu-arena 0.2.5 → 0.3.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/index.js CHANGED
@@ -8,15 +8,15 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
8
8
 
9
9
  // src/commands.ts
10
10
  import { createInterface } from "readline";
11
- import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync as unlinkSync2 } from "fs";
11
+ import { existsSync as existsSync5, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, unlinkSync as unlinkSync2 } from "fs";
12
12
  import { homedir as homedir5 } from "os";
13
13
  import { basename, dirname as dirname2, join as join5 } from "path";
14
14
  import { fileURLToPath } from "url";
15
15
  import { createHash as createHash3 } from "crypto";
16
- import { execSync as execSync2 } from "child_process";
16
+ import { execSync as execSync3 } from "child_process";
17
17
 
18
18
  // src/adapters.ts
19
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
19
+ import { existsSync, writeFileSync, mkdirSync } from "fs";
20
20
  import { homedir } from "os";
21
21
  import { join } from "path";
22
22
 
@@ -32,7 +32,7 @@ var TOOL_DISPLAY_NAMES = {
32
32
  };
33
33
  var CONFIG_FILE_NAME = ".modu-arena.json";
34
34
  var DAEMON_STATE_FILE = ".modu-arena-daemon.json";
35
- var DAEMON_SYNC_INTERVAL_SEC = 300;
35
+ var DAEMON_SYNC_INTERVAL_SEC = 120;
36
36
 
37
37
  // src/adapters.ts
38
38
  var IS_WIN = process.platform === "win32";
@@ -134,44 +134,31 @@ var ClaudeCodeAdapter = class {
134
134
  );
135
135
  }
136
136
  };
137
- var OpenCodeAdapter = class _OpenCodeAdapter {
137
+ var OpenCodeAdapter = class {
138
138
  slug = "opencode";
139
139
  displayName = "OpenCode";
140
- static PLUGIN_NAME = "opencode-modu-arena";
141
- // OpenCode uses ~/.config/opencode on ALL platforms (including Windows)
142
- // It uses xdg-basedir which respects XDG_CONFIG_HOME on all platforms
143
140
  get configDir() {
144
141
  return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "opencode");
145
142
  }
146
- get configFile() {
147
- return join(this.configDir, "opencode.json");
143
+ get hooksDir() {
144
+ return join(this.configDir, "hooks");
148
145
  }
149
146
  getHookPath() {
150
- return this.configFile;
147
+ return join(this.hooksDir, hookEntryName());
151
148
  }
152
149
  detect() {
153
150
  return existsSync(this.configDir);
154
151
  }
155
- // OpenCode uses a JS plugin system, not shell hooks — registers plugin in opencode.json
156
- install(_apiKey) {
157
- try {
158
- let config = {};
159
- if (existsSync(this.configFile)) {
160
- const raw = readFileSync(this.configFile, "utf-8");
161
- config = JSON.parse(raw);
162
- }
163
- const plugins = Array.isArray(config.plugin) ? config.plugin : [];
164
- if (plugins.some((p) => p === _OpenCodeAdapter.PLUGIN_NAME || p.startsWith(`${_OpenCodeAdapter.PLUGIN_NAME}@`))) {
165
- return { success: true, message: `${this.displayName} plugin already registered`, hookPath: this.configFile };
166
- }
167
- plugins.push(_OpenCodeAdapter.PLUGIN_NAME);
168
- config.plugin = plugins;
169
- if (!existsSync(this.configDir)) mkdirSync(this.configDir, { recursive: true });
170
- writeFileSync(this.configFile, JSON.stringify(config, null, 4) + "\n");
171
- return { success: true, message: `${this.displayName} plugin registered in ${this.configFile}`, hookPath: this.configFile };
172
- } catch (err) {
173
- return { success: false, message: `Failed to register ${this.displayName} plugin: ${err}` };
174
- }
152
+ install(apiKey) {
153
+ return installHook(
154
+ this.displayName,
155
+ this.hooksDir,
156
+ this.getHookPath(),
157
+ apiKey,
158
+ "opencode",
159
+ "OPENCODE",
160
+ baseFields("OPENCODE")
161
+ );
175
162
  }
176
163
  };
177
164
  var SimpleAdapter = class {
@@ -293,7 +280,7 @@ async function submitEvaluation(payload, opts) {
293
280
  }
294
281
 
295
282
  // src/config.ts
296
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
283
+ import { readFileSync, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
297
284
  import { homedir as homedir2 } from "os";
298
285
  import { join as join2, dirname } from "path";
299
286
  function getConfigPath() {
@@ -303,7 +290,7 @@ function loadConfig() {
303
290
  const configPath = getConfigPath();
304
291
  if (!existsSync2(configPath)) return null;
305
292
  try {
306
- const raw = readFileSync2(configPath, "utf-8");
293
+ const raw = readFileSync(configPath, "utf-8");
307
294
  return JSON.parse(raw);
308
295
  } catch {
309
296
  return null;
@@ -453,10 +440,11 @@ function getDaemonStatus() {
453
440
  }
454
441
 
455
442
  // src/claude-desktop.ts
456
- import { readdirSync, readFileSync as readFileSync3, existsSync as existsSync4, writeFileSync as writeFileSync4 } from "fs";
443
+ import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync4, writeFileSync as writeFileSync4 } from "fs";
457
444
  import { homedir as homedir4 } from "os";
458
445
  import { join as join4 } from "path";
459
446
  import { createHash as createHash2 } from "crypto";
447
+ import { execSync as execSync2 } from "child_process";
460
448
  var IS_WIN3 = process.platform === "win32";
461
449
  function getClaudeDesktopDataDir() {
462
450
  if (IS_WIN3) {
@@ -493,7 +481,7 @@ function findJsonlFiles(baseDir) {
493
481
  return files;
494
482
  }
495
483
  function parseJsonlFile(filePath) {
496
- const content = readFileSync3(filePath, "utf-8");
484
+ const content = readFileSync2(filePath, "utf-8");
497
485
  const lines = content.trim().split("\n");
498
486
  let sessionId = "";
499
487
  let inputTokens = 0;
@@ -535,6 +523,7 @@ function parseJsonlFile(filePath) {
535
523
  if (!sessionId || messageCount === 0) return null;
536
524
  return {
537
525
  sessionId,
526
+ toolType: "claude-desktop",
538
527
  inputTokens,
539
528
  outputTokens,
540
529
  cacheCreationTokens,
@@ -554,7 +543,7 @@ function loadDaemonState() {
554
543
  return { lastSync: (/* @__PURE__ */ new Date(0)).toISOString(), syncedSessions: [] };
555
544
  }
556
545
  try {
557
- return JSON.parse(readFileSync3(path, "utf-8"));
546
+ return JSON.parse(readFileSync2(path, "utf-8"));
558
547
  } catch {
559
548
  return { lastSync: (/* @__PURE__ */ new Date(0)).toISOString(), syncedSessions: [] };
560
549
  }
@@ -564,73 +553,135 @@ function saveDaemonState(state) {
564
553
  writeFileSync4(path, JSON.stringify(state, null, 2));
565
554
  }
566
555
  function computeSessionHash(session) {
567
- const data = `${session.sessionId}:${session.inputTokens}:${session.outputTokens}:${session.endedAt}`;
556
+ const data = `${session.toolType}:${session.sessionId}:${session.inputTokens}:${session.outputTokens}:${session.endedAt}`;
568
557
  return createHash2("sha256").update(data).digest("hex").substring(0, 16);
569
558
  }
570
- async function syncClaudeDesktop(apiKey) {
571
- const state = loadDaemonState();
572
- const errors = [];
559
+ async function submitSessions(sessions, apiKey, state) {
573
560
  let synced = 0;
574
561
  let skipped = 0;
575
- const sessionDirs = getSessionDirs();
576
- for (const orgDir of sessionDirs) {
577
- const jsonlFiles = findJsonlFiles(orgDir);
578
- for (const file of jsonlFiles) {
579
- const session = parseJsonlFile(file);
580
- if (!session) continue;
581
- const hash = computeSessionHash(session);
582
- if (state.syncedSessions.includes(hash)) {
583
- skipped++;
584
- continue;
585
- }
586
- if (session.inputTokens === 0 && session.outputTokens === 0) {
587
- skipped++;
588
- continue;
589
- }
590
- try {
591
- const body = JSON.stringify({
592
- toolType: "claude-desktop",
593
- endedAt: session.endedAt,
594
- startedAt: session.startedAt,
595
- inputTokens: session.inputTokens,
596
- outputTokens: session.outputTokens,
597
- cacheCreationTokens: session.cacheCreationTokens,
598
- cacheReadTokens: session.cacheReadTokens,
599
- modelName: session.model
600
- });
601
- const ts = Math.floor(Date.now() / 1e3).toString();
602
- const sig = computeHmacSignature(apiKey, ts, body);
603
- const res = await fetch(`${API_BASE_URL}/api/v1/sessions`, {
604
- method: "POST",
605
- headers: {
606
- "Content-Type": "application/json",
607
- "X-API-Key": apiKey,
608
- "X-Timestamp": ts,
609
- "X-Signature": sig
610
- },
611
- body
612
- });
613
- if (res.ok) {
614
- state.syncedSessions.push(hash);
615
- synced++;
616
- } else {
617
- const err = await res.text();
618
- errors.push(`${session.sessionId}: ${err}`);
619
- }
620
- } catch (e) {
621
- errors.push(`${session.sessionId}: ${e}`);
562
+ const errors = [];
563
+ for (const session of sessions) {
564
+ const hash = computeSessionHash(session);
565
+ if (state.syncedSessions.includes(hash)) {
566
+ skipped++;
567
+ continue;
568
+ }
569
+ if (session.inputTokens === 0 && session.outputTokens === 0) {
570
+ skipped++;
571
+ continue;
572
+ }
573
+ try {
574
+ const body = JSON.stringify({
575
+ toolType: session.toolType,
576
+ endedAt: session.endedAt,
577
+ startedAt: session.startedAt,
578
+ inputTokens: session.inputTokens,
579
+ outputTokens: session.outputTokens,
580
+ cacheCreationTokens: session.cacheCreationTokens,
581
+ cacheReadTokens: session.cacheReadTokens,
582
+ modelName: session.model
583
+ });
584
+ const ts = Math.floor(Date.now() / 1e3).toString();
585
+ const sig = computeHmacSignature(apiKey, ts, body);
586
+ const res = await fetch(`${API_BASE_URL}/api/v1/sessions`, {
587
+ method: "POST",
588
+ headers: {
589
+ "Content-Type": "application/json",
590
+ "X-API-Key": apiKey,
591
+ "X-Timestamp": ts,
592
+ "X-Signature": sig
593
+ },
594
+ body
595
+ });
596
+ if (res.ok) {
597
+ state.syncedSessions.push(hash);
598
+ synced++;
599
+ } else {
600
+ const err = await res.text();
601
+ errors.push(`[${session.toolType}] ${session.sessionId}: ${err}`);
622
602
  }
603
+ } catch (e) {
604
+ errors.push(`[${session.toolType}] ${session.sessionId}: ${e}`);
623
605
  }
624
606
  }
607
+ return { synced, skipped, errors };
608
+ }
609
+ function getOpenCodeDbPath() {
610
+ if (IS_WIN3) {
611
+ return join4(process.env.LOCALAPPDATA || join4(homedir4(), "AppData", "Local"), "opencode", "opencode.db");
612
+ }
613
+ return join4(homedir4(), ".local", "share", "opencode", "opencode.db");
614
+ }
615
+ function hasOpenCodeDb() {
616
+ return existsSync4(getOpenCodeDbPath());
617
+ }
618
+ function collectOpenCodeSessions() {
619
+ const dbPath = getOpenCodeDbPath();
620
+ if (!existsSync4(dbPath)) return [];
621
+ const query = `
622
+ SELECT s.id, s.time_created, s.time_updated,
623
+ COALESCE(SUM(json_extract(m.data, '$.tokens.input')), 0) as input_tokens,
624
+ COALESCE(SUM(json_extract(m.data, '$.tokens.output')), 0) as output_tokens,
625
+ COALESCE(SUM(json_extract(m.data, '$.tokens.cache.read')), 0) as cache_read,
626
+ COALESCE(SUM(json_extract(m.data, '$.tokens.cache.write')), 0) as cache_write,
627
+ MAX(json_extract(m.data, '$.modelID')) as model,
628
+ COUNT(m.id) as msg_count
629
+ FROM session s
630
+ LEFT JOIN message m ON m.session_id = s.id AND json_extract(m.data, '$.role') = 'assistant'
631
+ GROUP BY s.id
632
+ HAVING input_tokens > 0 OR output_tokens > 0`;
633
+ try {
634
+ const raw = execSync2(`sqlite3 -json "${dbPath}" "${query.replace(/\n/g, " ")}"`, {
635
+ encoding: "utf-8",
636
+ timeout: 1e4
637
+ }).trim();
638
+ if (!raw || raw === "[]") return [];
639
+ const rows = JSON.parse(raw);
640
+ return rows.map((r) => ({
641
+ sessionId: r.id,
642
+ toolType: "opencode",
643
+ inputTokens: r.input_tokens,
644
+ outputTokens: r.output_tokens,
645
+ cacheCreationTokens: r.cache_write,
646
+ cacheReadTokens: r.cache_read,
647
+ model: r.model || "unknown",
648
+ startedAt: r.time_created,
649
+ endedAt: r.time_updated,
650
+ messageCount: r.msg_count
651
+ }));
652
+ } catch {
653
+ return [];
654
+ }
655
+ }
656
+ function collectClaudeDesktopSessions() {
657
+ const sessions = [];
658
+ for (const orgDir of getSessionDirs()) {
659
+ for (const file of findJsonlFiles(orgDir)) {
660
+ const session = parseJsonlFile(file);
661
+ if (session) sessions.push(session);
662
+ }
663
+ }
664
+ return sessions;
665
+ }
666
+ async function syncAllTools(apiKey) {
667
+ const state = loadDaemonState();
668
+ const allSessions = [
669
+ ...collectClaudeDesktopSessions(),
670
+ ...collectOpenCodeSessions()
671
+ ];
672
+ const result = await submitSessions(allSessions, apiKey, state);
625
673
  state.lastSync = (/* @__PURE__ */ new Date()).toISOString();
626
674
  saveDaemonState(state);
627
- return { synced, skipped, errors };
675
+ return result;
628
676
  }
629
677
  function hasClaudeDesktopData() {
630
678
  const dataDir = getClaudeDesktopDataDir();
631
679
  const sessionsDir = join4(dataDir, "local-agent-mode-sessions");
632
680
  return existsSync4(sessionsDir);
633
681
  }
682
+ function hasAnyToolData() {
683
+ return hasClaudeDesktopData() || hasOpenCodeDb();
684
+ }
634
685
 
635
686
  // src/commands.ts
636
687
  function prompt(question) {
@@ -800,6 +851,12 @@ async function installCommand(apiKey) {
800
851
  "No AI coding tools detected. Install one of the supported tools:\n \u2022 Claude Code (https://docs.anthropic.com/s/claude-code)\n \u2022 OpenCode (https://opencode.ai)\n \u2022 Gemini CLI (https://github.com/google-gemini/gemini-cli)\n \u2022 Codex CLI (https://github.com/openai/codex)\n \u2022 Crush (https://charm.sh/crush)\n"
801
852
  );
802
853
  }
854
+ const daemonResult = installDaemon();
855
+ if (daemonResult.success) {
856
+ console.log(`\u2713 Sync daemon installed. ${daemonResult.message}`);
857
+ } else {
858
+ console.log(`\u26A0 Daemon install skipped: ${daemonResult.message}`);
859
+ }
803
860
  installSlashCommands();
804
861
  }
805
862
  async function rankCommand() {
@@ -906,7 +963,7 @@ async function submitCommand() {
906
963
  console.error(" Please create a README.md describing your project.\n");
907
964
  process.exit(1);
908
965
  }
909
- const descriptionRaw = readFileSync4(readmePath, "utf-8");
966
+ const descriptionRaw = readFileSync3(readmePath, "utf-8");
910
967
  if (descriptionRaw.trim().length === 0) {
911
968
  console.error("Error: README.md is empty.\n");
912
969
  process.exit(1);
@@ -920,7 +977,7 @@ async function submitCommand() {
920
977
  console.log(" Running local validation (README: ## Local Validation)...");
921
978
  try {
922
979
  const start = Date.now();
923
- execSync2(localValidationTest, {
980
+ execSync3(localValidationTest, {
924
981
  cwd,
925
982
  stdio: "ignore",
926
983
  timeout: 12e4,
@@ -988,7 +1045,7 @@ function copyCommandsFrom(srcDir, cwd) {
988
1045
  const routerSrc = join5(srcDir, "modu.md");
989
1046
  if (existsSync5(routerSrc)) {
990
1047
  mkdirSync5(targetBase, { recursive: true });
991
- writeFileSync5(join5(targetBase, "modu.md"), readFileSync4(routerSrc));
1048
+ writeFileSync5(join5(targetBase, "modu.md"), readFileSync3(routerSrc));
992
1049
  }
993
1050
  const subDir = join5(srcDir, "modu");
994
1051
  if (!existsSync5(subDir)) return;
@@ -997,7 +1054,7 @@ function copyCommandsFrom(srcDir, cwd) {
997
1054
  let count = 0;
998
1055
  for (const file of readdirSync2(subDir)) {
999
1056
  if (!file.endsWith(".md")) continue;
1000
- writeFileSync5(join5(targetSub, file), readFileSync4(join5(subDir, file)));
1057
+ writeFileSync5(join5(targetSub, file), readFileSync3(join5(subDir, file)));
1001
1058
  count++;
1002
1059
  }
1003
1060
  console.log(`
@@ -1021,16 +1078,16 @@ function extractLocalValidationTestCommand(readme) {
1021
1078
  return cmd.length > 0 ? cmd : null;
1022
1079
  }
1023
1080
  function daemonInstallCommand() {
1024
- console.log("\n\u{1F504} Modu-Arena \u2014 Claude Desktop Daemon\n");
1025
- if (!hasClaudeDesktopData()) {
1026
- console.log(" \u2717 Claude Desktop data not found.");
1027
- console.log(" Make sure Claude Desktop is installed and has been used.\n");
1081
+ console.log("\n\u{1F504} Modu-Arena \u2014 Sync Daemon\n");
1082
+ if (!hasAnyToolData()) {
1083
+ console.log(" \u2717 No tool data found (Claude Desktop, OpenCode).");
1084
+ console.log(" Make sure at least one supported tool is installed and has been used.\n");
1028
1085
  process.exit(1);
1029
1086
  }
1030
1087
  const result = installDaemon();
1031
1088
  if (result.success) {
1032
1089
  console.log(` \u2713 ${result.message}`);
1033
- console.log(" \u2713 Daemon will sync Claude Desktop usage automatically.\n");
1090
+ console.log(" \u2713 Daemon will sync all tool usage automatically.\n");
1034
1091
  } else {
1035
1092
  console.error(` \u2717 ${result.message}
1036
1093
  `);
@@ -1038,7 +1095,7 @@ function daemonInstallCommand() {
1038
1095
  }
1039
1096
  }
1040
1097
  function daemonUninstallCommand() {
1041
- console.log("\n\u{1F504} Modu-Arena \u2014 Claude Desktop Daemon\n");
1098
+ console.log("\n\u{1F504} Modu-Arena \u2014 Sync Daemon\n");
1042
1099
  const result = uninstallDaemon();
1043
1100
  if (result.success) {
1044
1101
  console.log(` \u2713 ${result.message}
@@ -1050,28 +1107,25 @@ function daemonUninstallCommand() {
1050
1107
  }
1051
1108
  }
1052
1109
  function daemonStatusCommand() {
1053
- console.log("\n\u{1F504} Modu-Arena \u2014 Claude Desktop Daemon\n");
1110
+ console.log("\n\u{1F504} Modu-Arena \u2014 Sync Daemon\n");
1054
1111
  const status = getDaemonStatus();
1055
1112
  console.log(` Platform: ${status.platform}`);
1056
1113
  console.log(` Installed: ${status.installed ? "Yes" : "No"}`);
1057
1114
  if (status.installed) {
1058
1115
  console.log(` Sync Interval: ${Math.floor(status.interval / 60)} minutes`);
1059
1116
  }
1060
- if (hasClaudeDesktopData()) {
1061
- console.log(" Claude Desktop Data: Found");
1062
- } else {
1063
- console.log(" Claude Desktop Data: Not found");
1064
- }
1117
+ console.log(` Claude Desktop Data: ${hasClaudeDesktopData() ? "Found" : "Not found"}`);
1118
+ console.log(` Any Tool Data: ${hasAnyToolData() ? "Found" : "Not found"}`);
1065
1119
  console.log("");
1066
1120
  }
1067
1121
  async function daemonSyncCommand() {
1068
1122
  const config = requireConfig();
1069
- if (!hasClaudeDesktopData()) {
1070
- console.log("Claude Desktop data not found. Nothing to sync.\n");
1123
+ if (!hasAnyToolData()) {
1124
+ console.log("No tool data found. Nothing to sync.\n");
1071
1125
  return;
1072
1126
  }
1073
- console.log("Syncing Claude Desktop usage...");
1074
- const result = await syncClaudeDesktop(config.apiKey);
1127
+ console.log("Syncing all tool usage...");
1128
+ const result = await syncAllTools(config.apiKey);
1075
1129
  console.log(` Synced: ${result.synced} sessions`);
1076
1130
  console.log(` Skipped: ${result.skipped} sessions (already synced)`);
1077
1131
  if (result.errors.length > 0) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands.ts","../src/adapters.ts","../src/constants.ts","../src/crypto.ts","../src/api.ts","../src/config.ts","../src/daemon.ts","../src/claude-desktop.ts","../src/index.ts"],"sourcesContent":["/**\n * CLI Commands — install, rank, status, uninstall\n */\n\nimport { createInterface } from 'node:readline';\nimport { existsSync, readFileSync, readdirSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { basename, dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createHash } from 'node:crypto';\nimport { execSync } from 'node:child_process';\nimport { getAllAdapters, type InstallResult } from './adapters.js';\nimport { getRank, registerUser, loginUser, submitEvaluation } from './api.js';\nimport { loadConfig, saveConfig, requireConfig } from './config.js';\nimport { API_BASE_URL, TOOL_DISPLAY_NAMES, type ToolType } from './constants.js';\nimport { installDaemon, uninstallDaemon, getDaemonStatus } from './daemon.js';\nimport { syncClaudeDesktop, hasClaudeDesktopData } from './claude-desktop.js';\n\nfunction prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nfunction promptPassword(question: string): Promise<string> {\n return new Promise((resolve) => {\n process.stdout.write(question);\n const chars: string[] = [];\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding('utf8');\n\n const onData = (ch: string) => {\n const c = ch.toString();\n if (c === '\\n' || c === '\\r' || c === '\\u0004') {\n // Enter or Ctrl+D\n stdin.setRawMode(wasRaw ?? false);\n stdin.pause();\n stdin.removeListener('data', onData);\n process.stdout.write('\\n');\n resolve(chars.join('').trim());\n } else if (c === '\\u0003') {\n // Ctrl+C\n process.stdout.write('\\n');\n process.exit(0);\n } else if (c === '\\u007f' || c === '\\b') {\n // Backspace\n if (chars.length > 0) {\n chars.pop();\n process.stdout.write('\\b \\b');\n }\n } else {\n chars.push(c);\n process.stdout.write('*');\n }\n };\n\n stdin.on('data', onData);\n });\n}\n\n// ─── register ──────────────────────────────────────────────────────────────\n\nexport async function registerCommand(): Promise<void> {\n console.log('\\n📝 Modu-Arena — Register\\n');\n\n const username = await prompt(' Username (3-50 chars): ');\n if (!username || username.length < 3 || username.length > 50) {\n console.error('Error: Username must be between 3 and 50 characters.\\n');\n process.exit(1);\n }\n\n const password = await promptPassword(' Password (min 8 chars): ');\n if (!password || password.length < 8) {\n console.error('Error: Password must be at least 8 characters.\\n');\n process.exit(1);\n }\n\n const displayName = await prompt(' Display name (optional, press Enter to skip): ');\n\n console.log('\\n Registering...');\n\n const existing = loadConfig();\n const result = await registerUser(\n { username, password, displayName: displayName || undefined },\n existing?.serverUrl,\n );\n\n if (result.error) {\n console.error(`\\n Error: ${result.error}\\n`);\n process.exit(1);\n }\n\n if (!result.apiKey) {\n console.error('\\n Error: No API key returned from server.\\n');\n process.exit(1);\n }\n\n saveConfig({ apiKey: result.apiKey, serverUrl: existing?.serverUrl });\n console.log('\\n ✓ Registration successful!');\n console.log(` ✓ API key saved to ~/.modu-arena.json`);\n console.log(`\\n Username: ${result.user?.username}`);\n console.log(` API Key: ${result.apiKey.slice(0, 20)}...${result.apiKey.slice(-4)}`);\n console.log('\\n ⚠ Save your API key — it will not be shown again.\\n');\n\n console.log(' Installing hooks for detected AI coding tools...\\n');\n await installCommand(result.apiKey);\n}\n\n// ─── login ─────────────────────────────────────────────────────────────────\n\nexport async function loginCommand(): Promise<void> {\n console.log('\\n🔑 Modu-Arena — Login\\n');\n\n const username = await prompt(' Username: ');\n if (!username) {\n console.error('Error: Username is required.\\n');\n process.exit(1);\n }\n\n const password = await promptPassword(' Password: ');\n if (!password) {\n console.error('Error: Password is required.\\n');\n process.exit(1);\n }\n\n console.log('\\n Logging in...');\n\n const existing = loadConfig();\n const result = await loginUser({ username, password }, existing?.serverUrl);\n\n if (result.error) {\n console.error(`\\n Error: ${result.error}\\n`);\n process.exit(1);\n }\n\n if (!result.apiKey) {\n console.error('\\n Error: No API key returned from server.\\n');\n process.exit(1);\n }\n\n saveConfig({ apiKey: result.apiKey, serverUrl: existing?.serverUrl });\n console.log('\\n ✓ Login successful!');\n console.log(` ✓ API key saved to ~/.modu-arena.json`);\n console.log(`\\n Username: ${result.user?.username}`);\n console.log(` API Key: ${result.apiKey.slice(0, 20)}...${result.apiKey.slice(-4)}`);\n console.log('\\n ⚠ A new API key was generated. Previous key is now invalid.\\n');\n\n console.log(' Reinstalling hooks with new API key...\\n');\n await installCommand(result.apiKey);\n}\n\n// ─── install ───────────────────────────────────────────────────────────────\n\nexport async function installCommand(apiKey?: string): Promise<void> {\n console.log('\\n🔧 Modu-Arena — AI Coding Tool Usage Tracker\\n');\n\n // Check if already configured\n const existing = loadConfig();\n if (existing?.apiKey && !apiKey) {\n console.log('✓ Already configured.');\n console.log(' Use --api-key <key> to update your API key.\\n');\n apiKey = existing.apiKey;\n }\n\n if (!apiKey) {\n console.error(\n 'Error: API key required.\\n' +\n ' Get your API key from the Modu-Arena dashboard.\\n' +\n ' Usage: npx @suncreation/modu-arena install --api-key <your-api-key>\\n',\n );\n process.exit(1);\n }\n\n // Validate API key format\n if (!apiKey.startsWith('modu_arena_')) {\n console.error(\n 'Error: Invalid API key format. Key must start with \"modu_arena_\".\\n',\n );\n process.exit(1);\n }\n\n // Save config\n saveConfig({ apiKey });\n console.log('✓ API key saved to ~/.modu-arena.json\\n');\n\n // Detect and install hooks for each tool\n const adapters = getAllAdapters();\n const results: { tool: string; result: InstallResult }[] = [];\n\n console.log('Detecting AI coding tools...\\n');\n\n for (const adapter of adapters) {\n const detected = adapter.detect();\n if (detected) {\n console.log(` ✓ ${adapter.displayName} detected`);\n const result = adapter.install(apiKey);\n results.push({ tool: adapter.displayName, result });\n if (result.success) {\n console.log(` → Hook installed: ${result.hookPath}`);\n } else {\n console.log(` ✗ ${result.message}`);\n }\n } else {\n console.log(` - ${adapter.displayName} not found`);\n }\n }\n\n const installed = results.filter((r) => r.result.success);\n console.log(\n `\\n✓ Setup complete. ${installed.length} tool(s) configured.\\n`,\n );\n\n if (installed.length === 0) {\n console.log(\n 'No AI coding tools detected. Install one of the supported tools:\\n' +\n ' • Claude Code (https://docs.anthropic.com/s/claude-code)\\n' +\n ' • OpenCode (https://opencode.ai)\\n' +\n ' • Gemini CLI (https://github.com/google-gemini/gemini-cli)\\n' +\n ' • Codex CLI (https://github.com/openai/codex)\\n' +\n ' • Crush (https://charm.sh/crush)\\n',\n );\n }\n\n installSlashCommands();\n}\n\n// ─── rank ──────────────────────────────────────────────────────────────────\n\nexport async function rankCommand(): Promise<void> {\n const config = requireConfig();\n console.log('\\n📊 Modu-Arena — Your Stats\\n');\n\n const result = await getRank({ apiKey: config.apiKey, serverUrl: config.serverUrl });\n\n if (!result.success) {\n console.error(`Error: ${'error' in result ? result.error : 'Unknown error'}\\n`);\n process.exit(1);\n }\n\n if (!('data' in result) || !result.data) {\n console.error('Error: Unexpected response format.\\n');\n process.exit(1);\n }\n\n const { username, usage, overview } = result.data;\n\n console.log(` User: ${username}`);\n console.log(` Tokens: ${formatNumber(usage.totalTokens)}`);\n console.log(` Sessions: ${usage.totalSessions}`);\n console.log(` Projects: ${overview.successfulProjectsCount}`);\n console.log('');\n\n // Tool breakdown\n if (usage.toolBreakdown.length > 0) {\n console.log(' Tool Breakdown:');\n for (const entry of usage.toolBreakdown) {\n const name = TOOL_DISPLAY_NAMES[entry.tool as ToolType] || entry.tool;\n console.log(\n ` ${name}: ${formatNumber(entry.tokens)} tokens`,\n );\n }\n console.log('');\n }\n\n // Period stats (aggregate from daily arrays)\n const sum7 = usage.last7Days.reduce(\n (acc, d) => ({ tokens: acc.tokens + d.inputTokens + d.outputTokens, sessions: acc.sessions + d.sessions }),\n { tokens: 0, sessions: 0 },\n );\n const sum30 = usage.last30Days.reduce(\n (acc, d) => ({ tokens: acc.tokens + d.inputTokens + d.outputTokens, sessions: acc.sessions + d.sessions }),\n { tokens: 0, sessions: 0 },\n );\n console.log(\n ` Last 7 days: ${formatNumber(sum7.tokens)} tokens, ${sum7.sessions} sessions`,\n );\n console.log(\n ` Last 30 days: ${formatNumber(sum30.tokens)} tokens, ${sum30.sessions} sessions`,\n );\n console.log('');\n}\n\n// ─── status ────────────────────────────────────────────────────────────────\n\nexport function statusCommand(): void {\n const config = loadConfig();\n console.log('\\n🔍 Modu-Arena — Status\\n');\n\n if (!config?.apiKey) {\n console.log(' Status: Not configured');\n console.log(\n ' Run `npx @suncreation/modu-arena install --api-key <key>` to set up.\\n',\n );\n return;\n }\n\n const maskedKey =\n config.apiKey.slice(0, 15) + '...' + config.apiKey.slice(-4);\n console.log(` API Key: ${maskedKey}`);\n console.log(` Server: ${config.serverUrl || API_BASE_URL}`);\n console.log('');\n\n // Check installed hooks\n const adapters = getAllAdapters();\n console.log(' Installed Hooks:');\n let hookCount = 0;\n for (const adapter of adapters) {\n const detected = adapter.detect();\n if (detected) {\n const hookExists = existsSync(adapter.getHookPath());\n const status = hookExists ? '✓ Active' : '✗ Not installed';\n console.log(` ${adapter.displayName}: ${status}`);\n if (hookExists) hookCount++;\n }\n }\n if (hookCount === 0) {\n console.log(' (none)');\n }\n console.log('');\n}\n\n// ─── uninstall ─────────────────────────────────────────────────────────────\n\nexport function uninstallCommand(): void {\n console.log('\\n🗑️ Modu-Arena — Uninstall\\n');\n\n // Remove hooks\n const adapters = getAllAdapters();\n for (const adapter of adapters) {\n const hookPath = adapter.getHookPath();\n if (existsSync(hookPath)) {\n unlinkSync(hookPath);\n console.log(` ✓ Removed ${adapter.displayName} hook`);\n }\n }\n\n // Remove config\n const configPath = join(homedir(), '.modu-arena.json');\n if (existsSync(configPath)) {\n unlinkSync(configPath);\n console.log(' ✓ Removed ~/.modu-arena.json');\n }\n\n console.log('\\n✓ Modu-Arena uninstalled.\\n');\n}\n\n// ─── submit ─────────────────────────────────────────────────────────────────\n\nexport async function submitCommand(): Promise<void> {\n const config = requireConfig();\n console.log('\\n🚀 Modu-Arena — Project Submit\\n');\n\n const cwd = process.cwd();\n const projectName = basename(cwd);\n\n const readmePath = join(cwd, 'README.md');\n if (!existsSync(readmePath)) {\n console.error('Error: README.md not found in the current directory.');\n console.error(' Please create a README.md describing your project.\\n');\n process.exit(1);\n }\n\n const descriptionRaw = readFileSync(readmePath, 'utf-8');\n if (descriptionRaw.trim().length === 0) {\n console.error('Error: README.md is empty.\\n');\n process.exit(1);\n }\n const description = descriptionRaw.length > 5000 \n ? descriptionRaw.slice(0, 5000) + '\\n... (truncated)'\n : descriptionRaw;\n\n const projectPathHash = sha256Hex(cwd);\n const localValidationTest = extractLocalValidationTestCommand(descriptionRaw);\n let localScore = 0;\n let localEvaluationSummary: string | undefined;\n if (localValidationTest) {\n console.log(' Running local validation (README: ## Local Validation)...');\n try {\n const start = Date.now();\n execSync(localValidationTest, {\n cwd,\n stdio: 'ignore',\n timeout: 120000,\n windowsHide: true,\n });\n localScore = 5;\n localEvaluationSummary = `Ran README Local Validation test: PASS (localScore=5) in ${Date.now() - start}ms.`;\n console.log(' ✓ Local validation passed');\n } catch {\n localScore = 0;\n localEvaluationSummary = 'Ran README Local Validation test: FAIL (localScore=0).';\n console.log(' ✗ Local validation failed');\n }\n console.log('');\n } else {\n localEvaluationSummary = 'No README Local Validation test block found (localScore=0).';\n }\n\n console.log(` Project: ${projectName}`);\n console.log(` README: ${readmePath}`);\n console.log('');\n console.log(' Submitting for evaluation...\\n');\n\n const result = await submitEvaluation(\n { projectName, description, projectPathHash, localScore, localEvaluationSummary },\n { apiKey: config.apiKey, serverUrl: config.serverUrl },\n );\n\n if (!result.success) {\n console.error(`Error: ${'error' in result ? result.error : 'Unknown error'}\\n`);\n process.exit(1);\n }\n\n const { evaluation } = result;\n const statusIcon = evaluation.passed ? '✅' : '❌';\n const statusText = evaluation.passed ? 'PASSED' : 'FAILED';\n\n console.log(` Result: ${statusIcon} ${statusText}`);\n console.log(` Final Score: ${evaluation.finalScore}/10`);\n console.log(` Cumulative: ${evaluation.cumulativeScoreAfter}`);\n console.log('');\n console.log(' Score Breakdown:');\n console.log(` localScore: ${evaluation.localScore}/5`);\n console.log(` backendScore: ${evaluation.backendScore}/5`);\n console.log(` penaltyScore: ${evaluation.penaltyScore}`);\n console.log('');\n\n if (evaluation.feedback) {\n console.log(' Feedback:');\n const lines = evaluation.feedback.split('\\n');\n for (const line of lines) {\n console.log(` ${line}`);\n }\n console.log('');\n }\n}\n\n// ─── slash commands ────────────────────────────────────────────────────────\n\nfunction installSlashCommands(): void {\n const cwd = process.cwd();\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const srcDir = join(thisDir, '..', 'commands');\n\n if (!existsSync(srcDir)) {\n const altDir = join(thisDir, 'commands');\n if (!existsSync(altDir)) return;\n return copyCommandsFrom(altDir, cwd);\n }\n copyCommandsFrom(srcDir, cwd);\n}\n\nfunction copyCommandsFrom(srcDir: string, cwd: string): void {\n const targetBase = join(cwd, '.claude', 'commands');\n\n const routerSrc = join(srcDir, 'modu.md');\n if (existsSync(routerSrc)) {\n mkdirSync(targetBase, { recursive: true });\n writeFileSync(join(targetBase, 'modu.md'), readFileSync(routerSrc));\n }\n\n const subDir = join(srcDir, 'modu');\n if (!existsSync(subDir)) return;\n\n const targetSub = join(targetBase, 'modu');\n mkdirSync(targetSub, { recursive: true });\n\n let count = 0;\n for (const file of readdirSync(subDir)) {\n if (!file.endsWith('.md')) continue;\n writeFileSync(join(targetSub, file), readFileSync(join(subDir, file)));\n count++;\n }\n\n console.log(`\\n✓ Slash commands installed to ${targetBase} (${count} commands)`);\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction formatNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toString();\n}\n\nfunction sha256Hex(input: string): string {\n return createHash('sha256').update(input).digest('hex');\n}\n\nfunction extractLocalValidationTestCommand(readme: string): string | null {\n const idx = readme.toLowerCase().indexOf('## local validation');\n if (idx < 0) return null;\n const section = readme.slice(idx);\n const m = section.match(/```bash[^\\n]*title\\s*=\\s*['\"]test['\"][^\\n]*\\n([\\s\\S]*?)\\n```/i);\n if (!m) return null;\n const cmd = (m[1] || '').trim();\n return cmd.length > 0 ? cmd : null;\n}\n\n// ─── daemon install ────────────────────────────────────────────────────────\n\nexport function daemonInstallCommand(): void {\n console.log('\\n🔄 Modu-Arena — Claude Desktop Daemon\\n');\n \n if (!hasClaudeDesktopData()) {\n console.log(' ✗ Claude Desktop data not found.');\n console.log(' Make sure Claude Desktop is installed and has been used.\\n');\n process.exit(1);\n }\n \n const result = installDaemon();\n \n if (result.success) {\n console.log(` ✓ ${result.message}`);\n console.log(' ✓ Daemon will sync Claude Desktop usage automatically.\\n');\n } else {\n console.error(` ✗ ${result.message}\\n`);\n process.exit(1);\n }\n}\n\n// ─── daemon uninstall ──────────────────────────────────────────────────────\n\nexport function daemonUninstallCommand(): void {\n console.log('\\n🔄 Modu-Arena — Claude Desktop Daemon\\n');\n \n const result = uninstallDaemon();\n \n if (result.success) {\n console.log(` ✓ ${result.message}\\n`);\n } else {\n console.error(` ✗ ${result.message}\\n`);\n process.exit(1);\n }\n}\n\n// ─── daemon status ─────────────────────────────────────────────────────────\n\nexport function daemonStatusCommand(): void {\n console.log('\\n🔄 Modu-Arena — Claude Desktop Daemon\\n');\n \n const status = getDaemonStatus();\n \n console.log(` Platform: ${status.platform}`);\n console.log(` Installed: ${status.installed ? 'Yes' : 'No'}`);\n if (status.installed) {\n console.log(` Sync Interval: ${Math.floor(status.interval / 60)} minutes`);\n }\n \n if (hasClaudeDesktopData()) {\n console.log(' Claude Desktop Data: Found');\n } else {\n console.log(' Claude Desktop Data: Not found');\n }\n console.log('');\n}\n\n// ─── daemon sync ───────────────────────────────────────────────────────────\n\nexport async function daemonSyncCommand(): Promise<void> {\n const config = requireConfig();\n \n if (!hasClaudeDesktopData()) {\n console.log('Claude Desktop data not found. Nothing to sync.\\n');\n return;\n }\n \n console.log('Syncing Claude Desktop usage...');\n \n const result = await syncClaudeDesktop(config.apiKey);\n \n console.log(` Synced: ${result.synced} sessions`);\n console.log(` Skipped: ${result.skipped} sessions (already synced)`);\n \n if (result.errors.length > 0) {\n console.log(` Errors: ${result.errors.length}`);\n for (const err of result.errors.slice(0, 3)) {\n console.log(` - ${err}`);\n }\n if (result.errors.length > 3) {\n console.log(` ... and ${result.errors.length - 3} more`);\n }\n }\n console.log('');\n}\n","/**\n * Tool Adapters — Cross-platform hook installation for AI coding tools.\n *\n * Generates Node.js hook scripts (works on all platforms) with\n * thin shell wrappers (.sh on Unix, .cmd on Windows).\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { API_BASE_URL, type ToolType } from './constants.js';\n\n// ─── Platform ──────────────────────────────────────────────────────────────\n\nconst IS_WIN = process.platform === 'win32';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\nexport interface ToolAdapter {\n slug: ToolType;\n displayName: string;\n detect(): boolean;\n install(apiKey: string): InstallResult;\n getHookPath(): string;\n}\n\nexport interface InstallResult {\n success: boolean;\n message: string;\n hookPath?: string;\n}\n\ninterface EnvField {\n key: string;\n env: string;\n parse: 'string' | 'int';\n fallback: string;\n}\n\n// ─── Hook Script Generation ────────────────────────────────────────────────\n\nconst HOOK_JS = '_modu-hook.js';\n\nfunction baseFields(prefix: string): EnvField[] {\n return [\n { key: 'sessionId', env: `${prefix}_SESSION_ID`, parse: 'string', fallback: '' },\n { key: 'startedAt', env: `${prefix}_SESSION_STARTED_AT`, parse: 'string', fallback: '' },\n { key: 'inputTokens', env: `${prefix}_INPUT_TOKENS`, parse: 'int', fallback: '0' },\n { key: 'outputTokens', env: `${prefix}_OUTPUT_TOKENS`, parse: 'int', fallback: '0' },\n { key: 'modelName', env: `${prefix}_MODEL`, parse: 'string', fallback: 'unknown' },\n ];\n}\n\nfunction generateHookJs(apiKey: string, toolType: string, prefix: string, fields: EnvField[]): string {\n const lines = fields.map((f) =>\n f.parse === 'int'\n ? ` ${f.key}: parseInt(process.env[\"${f.env}\"] || \"${f.fallback}\", 10)`\n : ` ${f.key}: process.env[\"${f.env}\"] || \"${f.fallback}\"`\n );\n\n return `#!/usr/bin/env node\n\"use strict\";\nvar crypto = require(\"crypto\");\n\nvar API_KEY = ${JSON.stringify(apiKey)};\nvar SERVER = ${JSON.stringify(API_BASE_URL)};\n\nif (!process.env[\"${prefix}_SESSION_ID\"]) process.exit(0);\n\nvar body = JSON.stringify({\n toolType: ${JSON.stringify(toolType)},\n endedAt: new Date().toISOString(),\n${lines.join(\",\\n\")}\n});\n\nvar ts = Math.floor(Date.now() / 1000).toString();\nvar sig = crypto.createHmac(\"sha256\", API_KEY).update(ts + \":\" + body).digest(\"hex\");\n\nfetch(SERVER + \"/api/v1/sessions\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-API-Key\": API_KEY, \"X-Timestamp\": ts, \"X-Signature\": sig },\n body: body\n}).then(function(r) {\n if (!r.ok) r.text().then(function(t) { process.stderr.write(\"[modu-arena] \" + r.status + \" \" + t + \"\\\\n\"); });\n}).catch(function(e) { process.stderr.write(\"[modu-arena] hook error: \" + e.message + \"\\\\n\"); });\n`;\n}\n\nfunction shellWrapper(): string {\n return `#!/bin/bash\nexec node \"$(dirname \"$0\")/${HOOK_JS}\"\n`;\n}\n\nfunction cmdWrapper(): string {\n return `@node \"%~dp0${HOOK_JS}\" 2>nul\\r\\n`;\n}\n\n// ─── Shared Install Logic ──────────────────────────────────────────────────\n\nfunction installHook(\n displayName: string,\n hooksDir: string,\n entryPath: string,\n apiKey: string,\n toolType: string,\n prefix: string,\n fields: EnvField[],\n): InstallResult {\n try {\n if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true });\n\n writeFileSync(join(hooksDir, HOOK_JS), generateHookJs(apiKey, toolType, prefix, fields), { mode: 0o755 });\n\n if (IS_WIN) {\n writeFileSync(entryPath, cmdWrapper());\n } else {\n writeFileSync(entryPath, shellWrapper(), { mode: 0o755 });\n }\n\n return { success: true, message: `${displayName} hook installed at ${entryPath}`, hookPath: entryPath };\n } catch (err) {\n return { success: false, message: `Failed to install ${displayName} hook: ${err}` };\n }\n}\n\nfunction hookEntryName(): string {\n return IS_WIN ? 'session-end.cmd' : 'session-end.sh';\n}\n\n// ─── Adapters ──────────────────────────────────────────────────────────────\n\nclass ClaudeCodeAdapter implements ToolAdapter {\n slug = 'claude-code' as const;\n displayName = 'Claude Code';\n\n private get configDir() { return join(homedir(), '.claude'); }\n private get hooksDir() { return join(this.configDir, 'hooks'); }\n\n getHookPath() { return join(this.hooksDir, hookEntryName()); }\n detect() { return existsSync(this.configDir); }\n\n install(apiKey: string) {\n return installHook(this.displayName, this.hooksDir, this.getHookPath(), apiKey, 'claude-code', 'CLAUDE',\n [\n ...baseFields('CLAUDE'),\n { key: 'cacheCreationTokens', env: 'CLAUDE_CACHE_CREATION_TOKENS', parse: 'int', fallback: '0' },\n { key: 'cacheReadTokens', env: 'CLAUDE_CACHE_READ_TOKENS', parse: 'int', fallback: '0' },\n ],\n );\n }\n}\n\nclass OpenCodeAdapter implements ToolAdapter {\n slug = 'opencode' as const;\n displayName = 'OpenCode';\n\n private static readonly PLUGIN_NAME = 'opencode-modu-arena';\n\n // OpenCode uses ~/.config/opencode on ALL platforms (including Windows)\n // It uses xdg-basedir which respects XDG_CONFIG_HOME on all platforms\n private get configDir() {\n return join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'opencode');\n }\n private get configFile() { return join(this.configDir, 'opencode.json'); }\n\n getHookPath() { return this.configFile; }\n detect() { return existsSync(this.configDir); }\n\n // OpenCode uses a JS plugin system, not shell hooks — registers plugin in opencode.json\n install(_apiKey: string) {\n try {\n let config: Record<string, unknown> = {};\n if (existsSync(this.configFile)) {\n const raw = readFileSync(this.configFile, 'utf-8');\n config = JSON.parse(raw) as Record<string, unknown>;\n }\n\n const plugins = (Array.isArray(config.plugin) ? config.plugin : []) as string[];\n\n if (plugins.some((p) => p === OpenCodeAdapter.PLUGIN_NAME || p.startsWith(`${OpenCodeAdapter.PLUGIN_NAME}@`))) {\n return { success: true, message: `${this.displayName} plugin already registered`, hookPath: this.configFile };\n }\n\n plugins.push(OpenCodeAdapter.PLUGIN_NAME);\n config.plugin = plugins;\n\n if (!existsSync(this.configDir)) mkdirSync(this.configDir, { recursive: true });\n writeFileSync(this.configFile, JSON.stringify(config, null, 4) + '\\n');\n\n return { success: true, message: `${this.displayName} plugin registered in ${this.configFile}`, hookPath: this.configFile };\n } catch (err) {\n return { success: false, message: `Failed to register ${this.displayName} plugin: ${err}` };\n }\n }\n}\n\nclass SimpleAdapter implements ToolAdapter {\n constructor(\n public slug: ToolType,\n public displayName: string,\n private dirName: string,\n private envPrefix: string,\n ) {}\n\n private get configDir() { return join(homedir(), this.dirName); }\n private get hooksDir() { return join(this.configDir, 'hooks'); }\n\n getHookPath() { return join(this.hooksDir, hookEntryName()); }\n detect() { return existsSync(this.configDir); }\n\n install(apiKey: string) {\n return installHook(this.displayName, this.hooksDir, this.getHookPath(), apiKey, this.slug, this.envPrefix,\n baseFields(this.envPrefix),\n );\n }\n}\n\n// ─── Registry ──────────────────────────────────────────────────────────────\n\nexport function getAllAdapters(): ToolAdapter[] {\n return [\n new ClaudeCodeAdapter(),\n new OpenCodeAdapter(),\n new SimpleAdapter('gemini', 'Gemini CLI', '.gemini', 'GEMINI'),\n new SimpleAdapter('codex', 'Codex CLI', '.codex', 'CODEX'),\n new SimpleAdapter('crush', 'Crush', '.crush', 'CRUSH'),\n ];\n}\n\nexport function getAdapter(slug: string): ToolAdapter | undefined {\n return getAllAdapters().find((a) => a.slug === slug);\n}\n","/** Base URL for the Modu-Arena API server */\nexport const API_BASE_URL =\n process.env.MODU_ARENA_API_URL ?? 'http://backend.vibemakers.kr:23010';\n\n/** API key prefix used for all keys */\nexport const API_KEY_PREFIX = 'modu_arena_';\n\n/** Supported AI coding tools */\nexport const TOOL_TYPES = [\n 'claude-code',\n 'claude-desktop',\n 'opencode',\n 'gemini',\n 'codex',\n 'crush',\n] as const;\n\nexport type ToolType = (typeof TOOL_TYPES)[number];\n\n/** Display names for each tool */\nexport const TOOL_DISPLAY_NAMES: Record<ToolType, string> = {\n 'claude-code': 'Claude Code',\n 'claude-desktop': 'Claude Desktop',\n opencode: 'OpenCode',\n gemini: 'Gemini CLI',\n codex: 'Codex CLI',\n crush: 'Crush',\n};\n\n/** Config file name stored in user home directory */\nexport const CONFIG_FILE_NAME = '.modu-arena.json';\n\n/** Daemon state file for tracking synced sessions */\nexport const DAEMON_STATE_FILE = '.modu-arena-daemon.json';\n\n/** Minimum interval between sessions (seconds) */\nexport const MIN_SESSION_INTERVAL_SEC = 60;\n\n/** HMAC timestamp tolerance (seconds) */\nexport const HMAC_TIMESTAMP_TOLERANCE_SEC = 300;\n\n/** Daemon sync interval in seconds */\nexport const DAEMON_SYNC_INTERVAL_SEC = 300; // 5 minutes\n","import { createHmac, createHash } from 'node:crypto';\n\n/**\n * Compute HMAC-SHA256 signature for API authentication.\n *\n * message = \"{timestamp}:{bodyJsonString}\"\n * signature = HMAC-SHA256(apiKey, message).hex()\n */\nexport function computeHmacSignature(\n apiKey: string,\n timestamp: string,\n body: string,\n): string {\n const message = `${timestamp}:${body}`;\n return createHmac('sha256', apiKey).update(message).digest('hex');\n}\n\n/**\n * Compute SHA-256 session hash for integrity verification.\n *\n * data = \"{userId}:{userSalt}:{inputTokens}:{outputTokens}:{cacheCreationTokens}:{cacheReadTokens}:{modelName}:{endedAt}\"\n * hash = SHA-256(data).hex()\n */\nexport function computeSessionHash(\n userId: string,\n userSalt: string,\n inputTokens: number,\n outputTokens: number,\n cacheCreationTokens: number,\n cacheReadTokens: number,\n modelName: string,\n endedAt: string,\n): string {\n const data = `${userId}:${userSalt}:${inputTokens}:${outputTokens}:${cacheCreationTokens}:${cacheReadTokens}:${modelName}:${endedAt}`;\n return createHash('sha256').update(data).digest('hex');\n}\n","import { computeHmacSignature } from './crypto.js';\nimport { API_BASE_URL } from './constants.js';\n\nexport interface SessionPayload {\n toolType: string;\n sessionId: string;\n startedAt: string;\n endedAt: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens?: number;\n cacheReadTokens?: number;\n modelName?: string;\n codeMetrics?: Record<string, unknown> | null;\n}\n\nexport interface BatchPayload {\n sessions: SessionPayload[];\n}\n\nexport interface RankResponse {\n success: boolean;\n data: {\n username: string;\n usage: {\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheTokens: number;\n totalTokens: number;\n totalSessions: number;\n toolBreakdown: Array<{ tool: string; tokens: number }>;\n last7Days: Array<{ date: string; inputTokens: number; outputTokens: number; sessions: number }>;\n last30Days: Array<{ date: string; inputTokens: number; outputTokens: number; sessions: number }>;\n };\n overview: {\n successfulProjectsCount: number;\n };\n lastUpdated: string;\n };\n}\n\nexport interface ApiError {\n error?: string | { code?: string; message?: string };\n}\n\ninterface RequestOptions {\n apiKey: string;\n serverUrl?: string;\n}\n\nfunction baseUrl(opts: RequestOptions): string {\n return opts.serverUrl || API_BASE_URL;\n}\n\nfunction makeAuthHeaders(\n apiKey: string,\n body?: string,\n): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n };\n\n if (body !== undefined) {\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const signature = computeHmacSignature(apiKey, timestamp, body);\n headers['X-Timestamp'] = timestamp;\n headers['X-Signature'] = signature;\n }\n\n return headers;\n}\n\nexport async function submitSession(\n session: SessionPayload,\n opts: RequestOptions,\n): Promise<{ success: boolean; session?: unknown; error?: string }> {\n const body = JSON.stringify(session);\n const url = `${baseUrl(opts)}/api/v1/sessions`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: makeAuthHeaders(opts.apiKey, body),\n body,\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as { success: boolean; session: unknown };\n}\n\nexport async function submitBatch(\n sessions: SessionPayload[],\n opts: RequestOptions,\n): Promise<{\n success: boolean;\n processed?: number;\n duplicatesSkipped?: number;\n error?: string;\n}> {\n const body = JSON.stringify({ sessions });\n const url = `${baseUrl(opts)}/api/v1/sessions/batch`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: makeAuthHeaders(opts.apiKey, body),\n body,\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as { success: boolean; processed: number; duplicatesSkipped: number };\n}\n\nexport async function getRank(\n opts: RequestOptions,\n): Promise<RankResponse | { success: false; error: string }> {\n const url = `${baseUrl(opts)}/api/v1/rank`;\n\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n 'X-API-Key': opts.apiKey,\n },\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as RankResponse;\n}\n\n// ─── Auth ─────────────────────────────────────────────────────────────────\n\nexport interface AuthResponse {\n success: boolean;\n apiKey?: string;\n user?: { id: string; username: string; displayName?: string };\n error?: string;\n}\n\nexport async function registerUser(\n payload: { username: string; password: string; displayName?: string },\n serverUrl?: string,\n): Promise<AuthResponse> {\n const body = JSON.stringify(payload);\n const url = `${serverUrl || API_BASE_URL}/api/auth/register`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n });\n\n return (await res.json()) as AuthResponse;\n}\n\nexport async function loginUser(\n payload: { username: string; password: string },\n serverUrl?: string,\n): Promise<AuthResponse> {\n const body = JSON.stringify({ ...payload, source: 'cli' });\n const url = `${serverUrl || API_BASE_URL}/api/auth/login`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n });\n\n return (await res.json()) as AuthResponse;\n}\n\n// ─── Evaluate ─────────────────────────────────────────────────────────────\n\nexport interface EvaluatePayload {\n projectName: string;\n description: string;\n fileStructure?: Record<string, string[]>;\n projectPathHash?: string;\n localScore?: number;\n localEvaluationSummary?: string;\n}\n\nexport interface EvaluationResult {\n passed: boolean;\n projectName: string;\n projectPathHash: string;\n localScore: number;\n backendScore: number;\n penaltyScore: number;\n finalScore: number;\n cumulativeScoreAfter: number;\n feedback: string;\n evaluatedAt: string;\n}\n\nexport interface EvaluateResponse {\n success: true;\n evaluation: EvaluationResult;\n}\n\nexport async function submitEvaluation(\n payload: EvaluatePayload,\n opts: RequestOptions,\n): Promise<EvaluateResponse | { success: false; error: string }> {\n const body = JSON.stringify(payload);\n const url = `${baseUrl(opts)}/api/v1/evaluate`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: makeAuthHeaders(opts.apiKey, body),\n body,\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as EvaluateResponse;\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport { CONFIG_FILE_NAME } from './constants.js';\n\nexport interface Config {\n apiKey: string;\n serverUrl?: string;\n tools?: string[];\n}\n\nfunction getConfigPath(): string {\n return join(homedir(), CONFIG_FILE_NAME);\n}\n\nexport function loadConfig(): Config | null {\n const configPath = getConfigPath();\n if (!existsSync(configPath)) return null;\n\n try {\n const raw = readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as Config;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: Config): void {\n const configPath = getConfigPath();\n const dir = dirname(configPath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function requireConfig(): Config {\n const config = loadConfig();\n if (!config?.apiKey) {\n console.error(\n 'Error: Not configured. Run `npx @suncreation/modu-arena install` first.',\n );\n process.exit(1);\n }\n return config;\n}\n","/**\n * Platform-specific daemon installation for Claude Desktop sync.\n * macOS: launchd (LaunchAgent)\n * Windows: Scheduled Task\n */\nimport { writeFileSync, existsSync, unlinkSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { DAEMON_SYNC_INTERVAL_SEC } from './constants.js';\n\nconst IS_WIN = process.platform === 'win32';\nconst DAEMON_NAME = 'com.modu-arena.sync';\n\nfunction getDaemonLogDir(): string {\n const dir = join(homedir(), '.modu-arena', 'logs');\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nfunction getNodePath(): string {\n try {\n return execSync('which node', { encoding: 'utf-8' }).trim();\n } catch {\n return 'node';\n }\n}\n\nfunction getCliPath(): string {\n return require.resolve('./index.js').replace(/index\\.js$/, 'index.js');\n}\n\nexport function installDaemon(): { success: boolean; message: string } {\n if (IS_WIN) {\n return installWindowsDaemon();\n }\n return installMacosDaemon();\n}\n\nexport function uninstallDaemon(): { success: boolean; message: string } {\n if (IS_WIN) {\n return uninstallWindowsDaemon();\n }\n return uninstallMacosDaemon();\n}\n\nexport function isDaemonInstalled(): boolean {\n if (IS_WIN) {\n try {\n execSync(`schtasks /Query /TN \"${DAEMON_NAME}\"`, { encoding: 'utf-8' });\n return true;\n } catch {\n return false;\n }\n }\n const plistPath = join(homedir(), 'Library', 'LaunchAgents', `${DAEMON_NAME}.plist`);\n return existsSync(plistPath);\n}\n\nfunction installMacosDaemon(): { success: boolean; message: string } {\n const launchAgentsDir = join(homedir(), 'Library', 'LaunchAgents');\n const plistPath = join(launchAgentsDir, `${DAEMON_NAME}.plist`);\n const logDir = getDaemonLogDir();\n const nodePath = getNodePath();\n const cliPath = getCliPath();\n \n const intervalMinutes = Math.floor(DAEMON_SYNC_INTERVAL_SEC / 60);\n \n const plist = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${DAEMON_NAME}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${nodePath}</string>\n <string>${cliPath}</string>\n <string>daemon-sync</string>\n </array>\n <key>StartInterval</key>\n <integer>${DAEMON_SYNC_INTERVAL_SEC}</integer>\n <key>StandardOutPath</key>\n <string>${logDir}/daemon.log</string>\n <key>StandardErrorPath</key>\n <string>${logDir}/daemon-error.log</string>\n <key>RunAtLoad</key>\n <true/>\n</dict>\n</plist>`;\n\n try {\n if (!existsSync(launchAgentsDir)) {\n mkdirSync(launchAgentsDir, { recursive: true });\n }\n writeFileSync(plistPath, plist);\n execSync(`launchctl load ${plistPath}`, { encoding: 'utf-8' });\n return { success: true, message: `Daemon installed. Syncs every ${intervalMinutes} minutes.` };\n } catch (e) {\n return { success: false, message: `Failed to install daemon: ${e}` };\n }\n}\n\nfunction uninstallMacosDaemon(): { success: boolean; message: string } {\n const plistPath = join(homedir(), 'Library', 'LaunchAgents', `${DAEMON_NAME}.plist`);\n \n try {\n if (existsSync(plistPath)) {\n execSync(`launchctl unload ${plistPath}`, { encoding: 'utf-8' });\n unlinkSync(plistPath);\n }\n return { success: true, message: 'Daemon uninstalled.' };\n } catch (e) {\n return { success: false, message: `Failed to uninstall daemon: ${e}` };\n }\n}\n\nfunction installWindowsDaemon(): { success: boolean; message: string } {\n const nodePath = getNodePath();\n const cliPath = getCliPath();\n const intervalMinutes = Math.floor(DAEMON_SYNC_INTERVAL_SEC / 60);\n \n try {\n const cmd = `schtasks /Create /TN \"${DAEMON_NAME}\" /TR \"\\\\\"${nodePath}\\\\\" \\\\\"${cliPath}\\\\\" daemon-sync\" /SC MINUTE /MO ${intervalMinutes} /F`;\n execSync(cmd, { encoding: 'utf-8' });\n return { success: true, message: `Daemon installed. Syncs every ${intervalMinutes} minutes.` };\n } catch (e) {\n return { success: false, message: `Failed to install daemon: ${e}` };\n }\n}\n\nfunction uninstallWindowsDaemon(): { success: boolean; message: string } {\n try {\n execSync(`schtasks /Delete /TN \"${DAEMON_NAME}\" /F`, { encoding: 'utf-8' });\n return { success: true, message: 'Daemon uninstalled.' };\n } catch (e) {\n return { success: false, message: `Failed to uninstall daemon: ${e}` };\n }\n}\n\nexport function getDaemonStatus(): { installed: boolean; platform: string; interval: number } {\n return {\n installed: isDaemonInstalled(),\n platform: IS_WIN ? 'windows' : 'macos',\n interval: DAEMON_SYNC_INTERVAL_SEC,\n };\n}\n","/**\n * Claude Desktop session parser and sync logic.\n * \n * Reads JSONL files from ~/Library/Application Support/Claude/local-agent-mode-sessions/\n * on macOS and %APPDATA%\\Claude\\local-agent-mode-sessions\\ on Windows.\n */\nimport { readdirSync, readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { API_BASE_URL, DAEMON_STATE_FILE } from './constants.js';\nimport { computeHmacSignature } from './crypto.js';\n\nconst IS_WIN = process.platform === 'win32';\n\ninterface UsageData {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n}\n\ninterface JsonlMessage {\n type: string;\n sessionId?: string;\n timestamp?: string;\n message?: {\n model?: string;\n usage?: UsageData;\n };\n}\n\ninterface SessionAggregate {\n sessionId: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n model: string;\n startedAt: string;\n endedAt: string;\n messageCount: number;\n}\n\ninterface DaemonState {\n lastSync: string;\n syncedSessions: string[];\n}\n\nfunction getClaudeDesktopDataDir(): string {\n if (IS_WIN) {\n return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'Claude');\n }\n return join(homedir(), 'Library', 'Application Support', 'Claude');\n}\n\nfunction getSessionDirs(): string[] {\n const dataDir = getClaudeDesktopDataDir();\n const sessionsDir = join(dataDir, 'local-agent-mode-sessions');\n if (!existsSync(sessionsDir)) return [];\n \n const orgDirs: string[] = [];\n for (const entry of readdirSync(sessionsDir, { withFileTypes: true })) {\n if (entry.isDirectory() && entry.name !== 'skills-plugin') {\n orgDirs.push(join(sessionsDir, entry.name));\n }\n }\n return orgDirs;\n}\n\nfunction findJsonlFiles(baseDir: string): string[] {\n const files: string[] = [];\n \n function walk(dir: string) {\n if (!existsSync(dir)) return;\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(full);\n } else if (entry.name.endsWith('.jsonl') && !entry.name.includes('audit')) {\n files.push(full);\n }\n }\n }\n \n walk(baseDir);\n return files;\n}\n\nfunction parseJsonlFile(filePath: string): SessionAggregate | null {\n const content = readFileSync(filePath, 'utf-8');\n const lines = content.trim().split('\\n');\n \n let sessionId = '';\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheCreationTokens = 0;\n let cacheReadTokens = 0;\n let model = 'unknown';\n let startedAt = '';\n let endedAt = '';\n let messageCount = 0;\n \n for (const line of lines) {\n try {\n const msg: JsonlMessage = JSON.parse(line);\n \n if (msg.sessionId && !sessionId) {\n sessionId = msg.sessionId;\n }\n \n if (msg.timestamp) {\n if (!startedAt || msg.timestamp < startedAt) {\n startedAt = msg.timestamp;\n }\n if (!endedAt || msg.timestamp > endedAt) {\n endedAt = msg.timestamp;\n }\n }\n \n if (msg.message?.usage) {\n const usage = msg.message.usage;\n inputTokens += usage.input_tokens || 0;\n outputTokens += usage.output_tokens || 0;\n cacheCreationTokens += usage.cache_creation_input_tokens || 0;\n cacheReadTokens += usage.cache_read_input_tokens || 0;\n messageCount++;\n \n if (msg.message.model) {\n model = msg.message.model;\n }\n }\n } catch {\n }\n }\n \n if (!sessionId || messageCount === 0) return null;\n \n return {\n sessionId,\n inputTokens,\n outputTokens,\n cacheCreationTokens,\n cacheReadTokens,\n model,\n startedAt,\n endedAt,\n messageCount,\n };\n}\n\nfunction getDaemonStatePath(): string {\n return join(homedir(), DAEMON_STATE_FILE);\n}\n\nfunction loadDaemonState(): DaemonState {\n const path = getDaemonStatePath();\n if (!existsSync(path)) {\n return { lastSync: new Date(0).toISOString(), syncedSessions: [] };\n }\n try {\n return JSON.parse(readFileSync(path, 'utf-8'));\n } catch {\n return { lastSync: new Date(0).toISOString(), syncedSessions: [] };\n }\n}\n\nfunction saveDaemonState(state: DaemonState): void {\n const path = getDaemonStatePath();\n writeFileSync(path, JSON.stringify(state, null, 2));\n}\n\nfunction computeSessionHash(session: SessionAggregate): string {\n const data = `${session.sessionId}:${session.inputTokens}:${session.outputTokens}:${session.endedAt}`;\n return createHash('sha256').update(data).digest('hex').substring(0, 16);\n}\n\nexport async function syncClaudeDesktop(apiKey: string): Promise<{ synced: number; skipped: number; errors: string[] }> {\n const state = loadDaemonState();\n const errors: string[] = [];\n let synced = 0;\n let skipped = 0;\n \n const sessionDirs = getSessionDirs();\n \n for (const orgDir of sessionDirs) {\n const jsonlFiles = findJsonlFiles(orgDir);\n \n for (const file of jsonlFiles) {\n const session = parseJsonlFile(file);\n if (!session) continue;\n \n const hash = computeSessionHash(session);\n if (state.syncedSessions.includes(hash)) {\n skipped++;\n continue;\n }\n \n if (session.inputTokens === 0 && session.outputTokens === 0) {\n skipped++;\n continue;\n }\n \n try {\n const body = JSON.stringify({\n toolType: 'claude-desktop',\n endedAt: session.endedAt,\n startedAt: session.startedAt,\n inputTokens: session.inputTokens,\n outputTokens: session.outputTokens,\n cacheCreationTokens: session.cacheCreationTokens,\n cacheReadTokens: session.cacheReadTokens,\n modelName: session.model,\n });\n \n const ts = Math.floor(Date.now() / 1000).toString();\n const sig = computeHmacSignature(apiKey, ts, body);\n \n const res = await fetch(`${API_BASE_URL}/api/v1/sessions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n 'X-Timestamp': ts,\n 'X-Signature': sig,\n },\n body,\n });\n \n if (res.ok) {\n state.syncedSessions.push(hash);\n synced++;\n } else {\n const err = await res.text();\n errors.push(`${session.sessionId}: ${err}`);\n }\n } catch (e) {\n errors.push(`${session.sessionId}: ${e}`);\n }\n }\n }\n \n state.lastSync = new Date().toISOString();\n saveDaemonState(state);\n \n return { synced, skipped, errors };\n}\n\nexport function hasClaudeDesktopData(): boolean {\n const dataDir = getClaudeDesktopDataDir();\n const sessionsDir = join(dataDir, 'local-agent-mode-sessions');\n return existsSync(sessionsDir);\n}\n\nexport function getClaudeDesktopDataPath(): string {\n return getClaudeDesktopDataDir();\n}\n","/**\n * @suncreation/modu-arena CLI\n *\n * Track and rank your AI coding tool usage.\n *\n * Usage:\n * npx @suncreation/modu-arena install --api-key <key>\n * npx @suncreation/modu-arena rank\n * npx @suncreation/modu-arena status\n * npx @suncreation/modu-arena uninstall\n */\n\nimport {\n installCommand,\n loginCommand,\n rankCommand,\n registerCommand,\n statusCommand,\n submitCommand,\n uninstallCommand,\n daemonInstallCommand,\n daemonUninstallCommand,\n daemonStatusCommand,\n daemonSyncCommand,\n} from './commands.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction printHelp(): void {\n console.log(`\nModu-Arena — AI Coding Tool Usage Tracker\n\nUsage:\n npx @suncreation/modu-arena <command> [options]\n\nCommands:\n register Create a new account (interactive)\n login Log in to an existing account (interactive)\n install Set up hooks for detected AI coding tools\n rank View your current stats and ranking\n status Check configuration and installed hooks\n submit Submit current project for evaluation\n uninstall Remove all hooks and configuration\n daemon-install Install Claude Desktop sync daemon\n daemon-status Check daemon status\n daemon-sync Manually sync Claude Desktop data\n daemon-remove Remove the daemon\n\nOptions:\n --api-key <key> Your Modu-Arena API key (for install)\n --help, -h Show this help message\n --version, -v Show version\n\nExamples:\n npx @suncreation/modu-arena register\n npx @suncreation/modu-arena login\n npx @suncreation/modu-arena install --api-key modu_arena_AbCdEfGh_xxx...\n npx @suncreation/modu-arena rank\n npx @suncreation/modu-arena daemon-install\n`);\n}\n\nasync function main(): Promise<void> {\n if (!command || command === '--help' || command === '-h') {\n printHelp();\n process.exit(0);\n }\n\n if (command === '--version' || command === '-v') {\n console.log('0.1.0');\n process.exit(0);\n }\n\n switch (command) {\n case 'register':\n await registerCommand();\n break;\n case 'login':\n await loginCommand();\n break;\n case 'install': {\n const keyIndex = args.indexOf('--api-key');\n const apiKey = keyIndex >= 0 ? args[keyIndex + 1] : undefined;\n await installCommand(apiKey);\n break;\n }\n case 'rank':\n await rankCommand();\n break;\n case 'status':\n statusCommand();\n break;\n case 'submit':\n await submitCommand();\n break;\n case 'uninstall':\n uninstallCommand();\n break;\n case 'daemon-install':\n daemonInstallCommand();\n break;\n case 'daemon-uninstall':\n case 'daemon-remove':\n daemonUninstallCommand();\n break;\n case 'daemon-status':\n daemonStatusCommand();\n break;\n case 'daemon-sync':\n await daemonSyncCommand();\n break;\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n"],"mappings":"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","names":["existsSync","readFileSync","readdirSync","writeFileSync","mkdirSync","unlinkSync","homedir","dirname","join","createHash","execSync","readFileSync","writeFileSync","existsSync","mkdirSync","homedir","join","join","homedir","existsSync","readFileSync","mkdirSync","writeFileSync","writeFileSync","existsSync","mkdirSync","homedir","join","IS_WIN","join","homedir","existsSync","mkdirSync","writeFileSync","readFileSync","existsSync","writeFileSync","homedir","join","createHash","IS_WIN","join","homedir","existsSync","readFileSync","writeFileSync","createHash","existsSync","unlinkSync","join","homedir","readFileSync","execSync","dirname","mkdirSync","writeFileSync","readdirSync","createHash"]}
1
+ {"version":3,"sources":["../src/commands.ts","../src/adapters.ts","../src/constants.ts","../src/crypto.ts","../src/api.ts","../src/config.ts","../src/daemon.ts","../src/claude-desktop.ts","../src/index.ts"],"sourcesContent":["/**\n * CLI Commands — install, rank, status, uninstall\n */\n\nimport { createInterface } from 'node:readline';\nimport { existsSync, readFileSync, readdirSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { basename, dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createHash } from 'node:crypto';\nimport { execSync } from 'node:child_process';\nimport { getAllAdapters, type InstallResult } from './adapters.js';\nimport { getRank, registerUser, loginUser, submitEvaluation } from './api.js';\nimport { loadConfig, saveConfig, requireConfig } from './config.js';\nimport { API_BASE_URL, TOOL_DISPLAY_NAMES, type ToolType } from './constants.js';\nimport { installDaemon, uninstallDaemon, getDaemonStatus } from './daemon.js';\nimport { syncAllTools, hasAnyToolData, hasClaudeDesktopData } from './claude-desktop.js';\n\nfunction prompt(question: string): Promise<string> {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nfunction promptPassword(question: string): Promise<string> {\n return new Promise((resolve) => {\n process.stdout.write(question);\n const chars: string[] = [];\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n stdin.setRawMode(true);\n stdin.resume();\n stdin.setEncoding('utf8');\n\n const onData = (ch: string) => {\n const c = ch.toString();\n if (c === '\\n' || c === '\\r' || c === '\\u0004') {\n // Enter or Ctrl+D\n stdin.setRawMode(wasRaw ?? false);\n stdin.pause();\n stdin.removeListener('data', onData);\n process.stdout.write('\\n');\n resolve(chars.join('').trim());\n } else if (c === '\\u0003') {\n // Ctrl+C\n process.stdout.write('\\n');\n process.exit(0);\n } else if (c === '\\u007f' || c === '\\b') {\n // Backspace\n if (chars.length > 0) {\n chars.pop();\n process.stdout.write('\\b \\b');\n }\n } else {\n chars.push(c);\n process.stdout.write('*');\n }\n };\n\n stdin.on('data', onData);\n });\n}\n\n// ─── register ──────────────────────────────────────────────────────────────\n\nexport async function registerCommand(): Promise<void> {\n console.log('\\n📝 Modu-Arena — Register\\n');\n\n const username = await prompt(' Username (3-50 chars): ');\n if (!username || username.length < 3 || username.length > 50) {\n console.error('Error: Username must be between 3 and 50 characters.\\n');\n process.exit(1);\n }\n\n const password = await promptPassword(' Password (min 8 chars): ');\n if (!password || password.length < 8) {\n console.error('Error: Password must be at least 8 characters.\\n');\n process.exit(1);\n }\n\n const displayName = await prompt(' Display name (optional, press Enter to skip): ');\n\n console.log('\\n Registering...');\n\n const existing = loadConfig();\n const result = await registerUser(\n { username, password, displayName: displayName || undefined },\n existing?.serverUrl,\n );\n\n if (result.error) {\n console.error(`\\n Error: ${result.error}\\n`);\n process.exit(1);\n }\n\n if (!result.apiKey) {\n console.error('\\n Error: No API key returned from server.\\n');\n process.exit(1);\n }\n\n saveConfig({ apiKey: result.apiKey, serverUrl: existing?.serverUrl });\n console.log('\\n ✓ Registration successful!');\n console.log(` ✓ API key saved to ~/.modu-arena.json`);\n console.log(`\\n Username: ${result.user?.username}`);\n console.log(` API Key: ${result.apiKey.slice(0, 20)}...${result.apiKey.slice(-4)}`);\n console.log('\\n ⚠ Save your API key — it will not be shown again.\\n');\n\n console.log(' Installing hooks for detected AI coding tools...\\n');\n await installCommand(result.apiKey);\n}\n\n// ─── login ─────────────────────────────────────────────────────────────────\n\nexport async function loginCommand(): Promise<void> {\n console.log('\\n🔑 Modu-Arena — Login\\n');\n\n const username = await prompt(' Username: ');\n if (!username) {\n console.error('Error: Username is required.\\n');\n process.exit(1);\n }\n\n const password = await promptPassword(' Password: ');\n if (!password) {\n console.error('Error: Password is required.\\n');\n process.exit(1);\n }\n\n console.log('\\n Logging in...');\n\n const existing = loadConfig();\n const result = await loginUser({ username, password }, existing?.serverUrl);\n\n if (result.error) {\n console.error(`\\n Error: ${result.error}\\n`);\n process.exit(1);\n }\n\n if (!result.apiKey) {\n console.error('\\n Error: No API key returned from server.\\n');\n process.exit(1);\n }\n\n saveConfig({ apiKey: result.apiKey, serverUrl: existing?.serverUrl });\n console.log('\\n ✓ Login successful!');\n console.log(` ✓ API key saved to ~/.modu-arena.json`);\n console.log(`\\n Username: ${result.user?.username}`);\n console.log(` API Key: ${result.apiKey.slice(0, 20)}...${result.apiKey.slice(-4)}`);\n console.log('\\n ⚠ A new API key was generated. Previous key is now invalid.\\n');\n\n console.log(' Reinstalling hooks with new API key...\\n');\n await installCommand(result.apiKey);\n}\n\n// ─── install ───────────────────────────────────────────────────────────────\n\nexport async function installCommand(apiKey?: string): Promise<void> {\n console.log('\\n🔧 Modu-Arena — AI Coding Tool Usage Tracker\\n');\n\n // Check if already configured\n const existing = loadConfig();\n if (existing?.apiKey && !apiKey) {\n console.log('✓ Already configured.');\n console.log(' Use --api-key <key> to update your API key.\\n');\n apiKey = existing.apiKey;\n }\n\n if (!apiKey) {\n console.error(\n 'Error: API key required.\\n' +\n ' Get your API key from the Modu-Arena dashboard.\\n' +\n ' Usage: npx @suncreation/modu-arena install --api-key <your-api-key>\\n',\n );\n process.exit(1);\n }\n\n // Validate API key format\n if (!apiKey.startsWith('modu_arena_')) {\n console.error(\n 'Error: Invalid API key format. Key must start with \"modu_arena_\".\\n',\n );\n process.exit(1);\n }\n\n // Save config\n saveConfig({ apiKey });\n console.log('✓ API key saved to ~/.modu-arena.json\\n');\n\n // Detect and install hooks for each tool\n const adapters = getAllAdapters();\n const results: { tool: string; result: InstallResult }[] = [];\n\n console.log('Detecting AI coding tools...\\n');\n\n for (const adapter of adapters) {\n const detected = adapter.detect();\n if (detected) {\n console.log(` ✓ ${adapter.displayName} detected`);\n const result = adapter.install(apiKey);\n results.push({ tool: adapter.displayName, result });\n if (result.success) {\n console.log(` → Hook installed: ${result.hookPath}`);\n } else {\n console.log(` ✗ ${result.message}`);\n }\n } else {\n console.log(` - ${adapter.displayName} not found`);\n }\n }\n\n const installed = results.filter((r) => r.result.success);\n console.log(\n `\\n✓ Setup complete. ${installed.length} tool(s) configured.\\n`,\n );\n\n if (installed.length === 0) {\n console.log(\n 'No AI coding tools detected. Install one of the supported tools:\\n' +\n ' • Claude Code (https://docs.anthropic.com/s/claude-code)\\n' +\n ' • OpenCode (https://opencode.ai)\\n' +\n ' • Gemini CLI (https://github.com/google-gemini/gemini-cli)\\n' +\n ' • Codex CLI (https://github.com/openai/codex)\\n' +\n ' • Crush (https://charm.sh/crush)\\n',\n );\n }\n\n const daemonResult = installDaemon();\n if (daemonResult.success) {\n console.log(`✓ Sync daemon installed. ${daemonResult.message}`);\n } else {\n console.log(`⚠ Daemon install skipped: ${daemonResult.message}`);\n }\n\n installSlashCommands();\n}\n\n// ─── rank ──────────────────────────────────────────────────────────────────\n\nexport async function rankCommand(): Promise<void> {\n const config = requireConfig();\n console.log('\\n📊 Modu-Arena — Your Stats\\n');\n\n const result = await getRank({ apiKey: config.apiKey, serverUrl: config.serverUrl });\n\n if (!result.success) {\n console.error(`Error: ${'error' in result ? result.error : 'Unknown error'}\\n`);\n process.exit(1);\n }\n\n if (!('data' in result) || !result.data) {\n console.error('Error: Unexpected response format.\\n');\n process.exit(1);\n }\n\n const { username, usage, overview } = result.data;\n\n console.log(` User: ${username}`);\n console.log(` Tokens: ${formatNumber(usage.totalTokens)}`);\n console.log(` Sessions: ${usage.totalSessions}`);\n console.log(` Projects: ${overview.successfulProjectsCount}`);\n console.log('');\n\n // Tool breakdown\n if (usage.toolBreakdown.length > 0) {\n console.log(' Tool Breakdown:');\n for (const entry of usage.toolBreakdown) {\n const name = TOOL_DISPLAY_NAMES[entry.tool as ToolType] || entry.tool;\n console.log(\n ` ${name}: ${formatNumber(entry.tokens)} tokens`,\n );\n }\n console.log('');\n }\n\n // Period stats (aggregate from daily arrays)\n const sum7 = usage.last7Days.reduce(\n (acc, d) => ({ tokens: acc.tokens + d.inputTokens + d.outputTokens, sessions: acc.sessions + d.sessions }),\n { tokens: 0, sessions: 0 },\n );\n const sum30 = usage.last30Days.reduce(\n (acc, d) => ({ tokens: acc.tokens + d.inputTokens + d.outputTokens, sessions: acc.sessions + d.sessions }),\n { tokens: 0, sessions: 0 },\n );\n console.log(\n ` Last 7 days: ${formatNumber(sum7.tokens)} tokens, ${sum7.sessions} sessions`,\n );\n console.log(\n ` Last 30 days: ${formatNumber(sum30.tokens)} tokens, ${sum30.sessions} sessions`,\n );\n console.log('');\n}\n\n// ─── status ────────────────────────────────────────────────────────────────\n\nexport function statusCommand(): void {\n const config = loadConfig();\n console.log('\\n🔍 Modu-Arena — Status\\n');\n\n if (!config?.apiKey) {\n console.log(' Status: Not configured');\n console.log(\n ' Run `npx @suncreation/modu-arena install --api-key <key>` to set up.\\n',\n );\n return;\n }\n\n const maskedKey =\n config.apiKey.slice(0, 15) + '...' + config.apiKey.slice(-4);\n console.log(` API Key: ${maskedKey}`);\n console.log(` Server: ${config.serverUrl || API_BASE_URL}`);\n console.log('');\n\n // Check installed hooks\n const adapters = getAllAdapters();\n console.log(' Installed Hooks:');\n let hookCount = 0;\n for (const adapter of adapters) {\n const detected = adapter.detect();\n if (detected) {\n const hookExists = existsSync(adapter.getHookPath());\n const status = hookExists ? '✓ Active' : '✗ Not installed';\n console.log(` ${adapter.displayName}: ${status}`);\n if (hookExists) hookCount++;\n }\n }\n if (hookCount === 0) {\n console.log(' (none)');\n }\n console.log('');\n}\n\n// ─── uninstall ─────────────────────────────────────────────────────────────\n\nexport function uninstallCommand(): void {\n console.log('\\n🗑️ Modu-Arena — Uninstall\\n');\n\n // Remove hooks\n const adapters = getAllAdapters();\n for (const adapter of adapters) {\n const hookPath = adapter.getHookPath();\n if (existsSync(hookPath)) {\n unlinkSync(hookPath);\n console.log(` ✓ Removed ${adapter.displayName} hook`);\n }\n }\n\n // Remove config\n const configPath = join(homedir(), '.modu-arena.json');\n if (existsSync(configPath)) {\n unlinkSync(configPath);\n console.log(' ✓ Removed ~/.modu-arena.json');\n }\n\n console.log('\\n✓ Modu-Arena uninstalled.\\n');\n}\n\n// ─── submit ─────────────────────────────────────────────────────────────────\n\nexport async function submitCommand(): Promise<void> {\n const config = requireConfig();\n console.log('\\n🚀 Modu-Arena — Project Submit\\n');\n\n const cwd = process.cwd();\n const projectName = basename(cwd);\n\n const readmePath = join(cwd, 'README.md');\n if (!existsSync(readmePath)) {\n console.error('Error: README.md not found in the current directory.');\n console.error(' Please create a README.md describing your project.\\n');\n process.exit(1);\n }\n\n const descriptionRaw = readFileSync(readmePath, 'utf-8');\n if (descriptionRaw.trim().length === 0) {\n console.error('Error: README.md is empty.\\n');\n process.exit(1);\n }\n const description = descriptionRaw.length > 5000 \n ? descriptionRaw.slice(0, 5000) + '\\n... (truncated)'\n : descriptionRaw;\n\n const projectPathHash = sha256Hex(cwd);\n const localValidationTest = extractLocalValidationTestCommand(descriptionRaw);\n let localScore = 0;\n let localEvaluationSummary: string | undefined;\n if (localValidationTest) {\n console.log(' Running local validation (README: ## Local Validation)...');\n try {\n const start = Date.now();\n execSync(localValidationTest, {\n cwd,\n stdio: 'ignore',\n timeout: 120000,\n windowsHide: true,\n });\n localScore = 5;\n localEvaluationSummary = `Ran README Local Validation test: PASS (localScore=5) in ${Date.now() - start}ms.`;\n console.log(' ✓ Local validation passed');\n } catch {\n localScore = 0;\n localEvaluationSummary = 'Ran README Local Validation test: FAIL (localScore=0).';\n console.log(' ✗ Local validation failed');\n }\n console.log('');\n } else {\n localEvaluationSummary = 'No README Local Validation test block found (localScore=0).';\n }\n\n console.log(` Project: ${projectName}`);\n console.log(` README: ${readmePath}`);\n console.log('');\n console.log(' Submitting for evaluation...\\n');\n\n const result = await submitEvaluation(\n { projectName, description, projectPathHash, localScore, localEvaluationSummary },\n { apiKey: config.apiKey, serverUrl: config.serverUrl },\n );\n\n if (!result.success) {\n console.error(`Error: ${'error' in result ? result.error : 'Unknown error'}\\n`);\n process.exit(1);\n }\n\n const { evaluation } = result;\n const statusIcon = evaluation.passed ? '✅' : '❌';\n const statusText = evaluation.passed ? 'PASSED' : 'FAILED';\n\n console.log(` Result: ${statusIcon} ${statusText}`);\n console.log(` Final Score: ${evaluation.finalScore}/10`);\n console.log(` Cumulative: ${evaluation.cumulativeScoreAfter}`);\n console.log('');\n console.log(' Score Breakdown:');\n console.log(` localScore: ${evaluation.localScore}/5`);\n console.log(` backendScore: ${evaluation.backendScore}/5`);\n console.log(` penaltyScore: ${evaluation.penaltyScore}`);\n console.log('');\n\n if (evaluation.feedback) {\n console.log(' Feedback:');\n const lines = evaluation.feedback.split('\\n');\n for (const line of lines) {\n console.log(` ${line}`);\n }\n console.log('');\n }\n}\n\n// ─── slash commands ────────────────────────────────────────────────────────\n\nfunction installSlashCommands(): void {\n const cwd = process.cwd();\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const srcDir = join(thisDir, '..', 'commands');\n\n if (!existsSync(srcDir)) {\n const altDir = join(thisDir, 'commands');\n if (!existsSync(altDir)) return;\n return copyCommandsFrom(altDir, cwd);\n }\n copyCommandsFrom(srcDir, cwd);\n}\n\nfunction copyCommandsFrom(srcDir: string, cwd: string): void {\n const targetBase = join(cwd, '.claude', 'commands');\n\n const routerSrc = join(srcDir, 'modu.md');\n if (existsSync(routerSrc)) {\n mkdirSync(targetBase, { recursive: true });\n writeFileSync(join(targetBase, 'modu.md'), readFileSync(routerSrc));\n }\n\n const subDir = join(srcDir, 'modu');\n if (!existsSync(subDir)) return;\n\n const targetSub = join(targetBase, 'modu');\n mkdirSync(targetSub, { recursive: true });\n\n let count = 0;\n for (const file of readdirSync(subDir)) {\n if (!file.endsWith('.md')) continue;\n writeFileSync(join(targetSub, file), readFileSync(join(subDir, file)));\n count++;\n }\n\n console.log(`\\n✓ Slash commands installed to ${targetBase} (${count} commands)`);\n}\n\n// ─── Helpers ───────────────────────────────────────────────────────────────\n\nfunction formatNumber(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return n.toString();\n}\n\nfunction sha256Hex(input: string): string {\n return createHash('sha256').update(input).digest('hex');\n}\n\nfunction extractLocalValidationTestCommand(readme: string): string | null {\n const idx = readme.toLowerCase().indexOf('## local validation');\n if (idx < 0) return null;\n const section = readme.slice(idx);\n const m = section.match(/```bash[^\\n]*title\\s*=\\s*['\"]test['\"][^\\n]*\\n([\\s\\S]*?)\\n```/i);\n if (!m) return null;\n const cmd = (m[1] || '').trim();\n return cmd.length > 0 ? cmd : null;\n}\n\n// ─── daemon install ────────────────────────────────────────────────────────\n\nexport function daemonInstallCommand(): void {\n console.log('\\n🔄 Modu-Arena — Sync Daemon\\n');\n \n if (!hasAnyToolData()) {\n console.log(' ✗ No tool data found (Claude Desktop, OpenCode).');\n console.log(' Make sure at least one supported tool is installed and has been used.\\n');\n process.exit(1);\n }\n \n const result = installDaemon();\n \n if (result.success) {\n console.log(` ✓ ${result.message}`);\n console.log(' ✓ Daemon will sync all tool usage automatically.\\n');\n } else {\n console.error(` ✗ ${result.message}\\n`);\n process.exit(1);\n }\n}\n\n// ─── daemon uninstall ──────────────────────────────────────────────────────\n\nexport function daemonUninstallCommand(): void {\n console.log('\\n🔄 Modu-Arena — Sync Daemon\\n');\n \n const result = uninstallDaemon();\n \n if (result.success) {\n console.log(` ✓ ${result.message}\\n`);\n } else {\n console.error(` ✗ ${result.message}\\n`);\n process.exit(1);\n }\n}\n\n// ─── daemon status ─────────────────────────────────────────────────────────\n\nexport function daemonStatusCommand(): void {\n console.log('\\n🔄 Modu-Arena — Sync Daemon\\n');\n \n const status = getDaemonStatus();\n \n console.log(` Platform: ${status.platform}`);\n console.log(` Installed: ${status.installed ? 'Yes' : 'No'}`);\n if (status.installed) {\n console.log(` Sync Interval: ${Math.floor(status.interval / 60)} minutes`);\n }\n \n console.log(` Claude Desktop Data: ${hasClaudeDesktopData() ? 'Found' : 'Not found'}`);\n console.log(` Any Tool Data: ${hasAnyToolData() ? 'Found' : 'Not found'}`);\n console.log('');\n}\n\n// ─── daemon sync ───────────────────────────────────────────────────────────\n\nexport async function daemonSyncCommand(): Promise<void> {\n const config = requireConfig();\n \n if (!hasAnyToolData()) {\n console.log('No tool data found. Nothing to sync.\\n');\n return;\n }\n \n console.log('Syncing all tool usage...');\n \n const result = await syncAllTools(config.apiKey);\n \n console.log(` Synced: ${result.synced} sessions`);\n console.log(` Skipped: ${result.skipped} sessions (already synced)`);\n \n if (result.errors.length > 0) {\n console.log(` Errors: ${result.errors.length}`);\n for (const err of result.errors.slice(0, 3)) {\n console.log(` - ${err}`);\n }\n if (result.errors.length > 3) {\n console.log(` ... and ${result.errors.length - 3} more`);\n }\n }\n console.log('');\n}\n","/**\n * Tool Adapters — Cross-platform hook installation for AI coding tools.\n *\n * Generates Node.js hook scripts (works on all platforms) with\n * thin shell wrappers (.sh on Unix, .cmd on Windows).\n */\n\nimport { existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { API_BASE_URL, type ToolType } from './constants.js';\n\n// ─── Platform ──────────────────────────────────────────────────────────────\n\nconst IS_WIN = process.platform === 'win32';\n\n// ─── Types ─────────────────────────────────────────────────────────────────\n\nexport interface ToolAdapter {\n slug: ToolType;\n displayName: string;\n detect(): boolean;\n install(apiKey: string): InstallResult;\n getHookPath(): string;\n}\n\nexport interface InstallResult {\n success: boolean;\n message: string;\n hookPath?: string;\n}\n\ninterface EnvField {\n key: string;\n env: string;\n parse: 'string' | 'int';\n fallback: string;\n}\n\n// ─── Hook Script Generation ────────────────────────────────────────────────\n\nconst HOOK_JS = '_modu-hook.js';\n\nfunction baseFields(prefix: string): EnvField[] {\n return [\n { key: 'sessionId', env: `${prefix}_SESSION_ID`, parse: 'string', fallback: '' },\n { key: 'startedAt', env: `${prefix}_SESSION_STARTED_AT`, parse: 'string', fallback: '' },\n { key: 'inputTokens', env: `${prefix}_INPUT_TOKENS`, parse: 'int', fallback: '0' },\n { key: 'outputTokens', env: `${prefix}_OUTPUT_TOKENS`, parse: 'int', fallback: '0' },\n { key: 'modelName', env: `${prefix}_MODEL`, parse: 'string', fallback: 'unknown' },\n ];\n}\n\nfunction generateHookJs(apiKey: string, toolType: string, prefix: string, fields: EnvField[]): string {\n const lines = fields.map((f) =>\n f.parse === 'int'\n ? ` ${f.key}: parseInt(process.env[\"${f.env}\"] || \"${f.fallback}\", 10)`\n : ` ${f.key}: process.env[\"${f.env}\"] || \"${f.fallback}\"`\n );\n\n return `#!/usr/bin/env node\n\"use strict\";\nvar crypto = require(\"crypto\");\n\nvar API_KEY = ${JSON.stringify(apiKey)};\nvar SERVER = ${JSON.stringify(API_BASE_URL)};\n\nif (!process.env[\"${prefix}_SESSION_ID\"]) process.exit(0);\n\nvar body = JSON.stringify({\n toolType: ${JSON.stringify(toolType)},\n endedAt: new Date().toISOString(),\n${lines.join(\",\\n\")}\n});\n\nvar ts = Math.floor(Date.now() / 1000).toString();\nvar sig = crypto.createHmac(\"sha256\", API_KEY).update(ts + \":\" + body).digest(\"hex\");\n\nfetch(SERVER + \"/api/v1/sessions\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-API-Key\": API_KEY, \"X-Timestamp\": ts, \"X-Signature\": sig },\n body: body\n}).then(function(r) {\n if (!r.ok) r.text().then(function(t) { process.stderr.write(\"[modu-arena] \" + r.status + \" \" + t + \"\\\\n\"); });\n}).catch(function(e) { process.stderr.write(\"[modu-arena] hook error: \" + e.message + \"\\\\n\"); });\n`;\n}\n\nfunction shellWrapper(): string {\n return `#!/bin/bash\nexec node \"$(dirname \"$0\")/${HOOK_JS}\"\n`;\n}\n\nfunction cmdWrapper(): string {\n return `@node \"%~dp0${HOOK_JS}\" 2>nul\\r\\n`;\n}\n\n// ─── Shared Install Logic ──────────────────────────────────────────────────\n\nfunction installHook(\n displayName: string,\n hooksDir: string,\n entryPath: string,\n apiKey: string,\n toolType: string,\n prefix: string,\n fields: EnvField[],\n): InstallResult {\n try {\n if (!existsSync(hooksDir)) mkdirSync(hooksDir, { recursive: true });\n\n writeFileSync(join(hooksDir, HOOK_JS), generateHookJs(apiKey, toolType, prefix, fields), { mode: 0o755 });\n\n if (IS_WIN) {\n writeFileSync(entryPath, cmdWrapper());\n } else {\n writeFileSync(entryPath, shellWrapper(), { mode: 0o755 });\n }\n\n return { success: true, message: `${displayName} hook installed at ${entryPath}`, hookPath: entryPath };\n } catch (err) {\n return { success: false, message: `Failed to install ${displayName} hook: ${err}` };\n }\n}\n\nfunction hookEntryName(): string {\n return IS_WIN ? 'session-end.cmd' : 'session-end.sh';\n}\n\n// ─── Adapters ──────────────────────────────────────────────────────────────\n\nclass ClaudeCodeAdapter implements ToolAdapter {\n slug = 'claude-code' as const;\n displayName = 'Claude Code';\n\n private get configDir() { return join(homedir(), '.claude'); }\n private get hooksDir() { return join(this.configDir, 'hooks'); }\n\n getHookPath() { return join(this.hooksDir, hookEntryName()); }\n detect() { return existsSync(this.configDir); }\n\n install(apiKey: string) {\n return installHook(this.displayName, this.hooksDir, this.getHookPath(), apiKey, 'claude-code', 'CLAUDE',\n [\n ...baseFields('CLAUDE'),\n { key: 'cacheCreationTokens', env: 'CLAUDE_CACHE_CREATION_TOKENS', parse: 'int', fallback: '0' },\n { key: 'cacheReadTokens', env: 'CLAUDE_CACHE_READ_TOKENS', parse: 'int', fallback: '0' },\n ],\n );\n }\n}\n\nclass OpenCodeAdapter implements ToolAdapter {\n slug = 'opencode' as const;\n displayName = 'OpenCode';\n\n private get configDir() {\n return join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'opencode');\n }\n private get hooksDir() { return join(this.configDir, 'hooks'); }\n\n getHookPath() { return join(this.hooksDir, hookEntryName()); }\n detect() { return existsSync(this.configDir); }\n\n install(apiKey: string) {\n return installHook(this.displayName, this.hooksDir, this.getHookPath(), apiKey, 'opencode', 'OPENCODE',\n baseFields('OPENCODE'),\n );\n }\n}\n\nclass SimpleAdapter implements ToolAdapter {\n constructor(\n public slug: ToolType,\n public displayName: string,\n private dirName: string,\n private envPrefix: string,\n ) {}\n\n private get configDir() { return join(homedir(), this.dirName); }\n private get hooksDir() { return join(this.configDir, 'hooks'); }\n\n getHookPath() { return join(this.hooksDir, hookEntryName()); }\n detect() { return existsSync(this.configDir); }\n\n install(apiKey: string) {\n return installHook(this.displayName, this.hooksDir, this.getHookPath(), apiKey, this.slug, this.envPrefix,\n baseFields(this.envPrefix),\n );\n }\n}\n\n// ─── Registry ──────────────────────────────────────────────────────────────\n\nexport function getAllAdapters(): ToolAdapter[] {\n return [\n new ClaudeCodeAdapter(),\n new OpenCodeAdapter(),\n new SimpleAdapter('gemini', 'Gemini CLI', '.gemini', 'GEMINI'),\n new SimpleAdapter('codex', 'Codex CLI', '.codex', 'CODEX'),\n new SimpleAdapter('crush', 'Crush', '.crush', 'CRUSH'),\n ];\n}\n\nexport function getAdapter(slug: string): ToolAdapter | undefined {\n return getAllAdapters().find((a) => a.slug === slug);\n}\n","/** Base URL for the Modu-Arena API server */\nexport const API_BASE_URL =\n process.env.MODU_ARENA_API_URL ?? 'http://backend.vibemakers.kr:23010';\n\n/** API key prefix used for all keys */\nexport const API_KEY_PREFIX = 'modu_arena_';\n\n/** Supported AI coding tools */\nexport const TOOL_TYPES = [\n 'claude-code',\n 'claude-desktop',\n 'opencode',\n 'gemini',\n 'codex',\n 'crush',\n] as const;\n\nexport type ToolType = (typeof TOOL_TYPES)[number];\n\n/** Display names for each tool */\nexport const TOOL_DISPLAY_NAMES: Record<ToolType, string> = {\n 'claude-code': 'Claude Code',\n 'claude-desktop': 'Claude Desktop',\n opencode: 'OpenCode',\n gemini: 'Gemini CLI',\n codex: 'Codex CLI',\n crush: 'Crush',\n};\n\n/** Config file name stored in user home directory */\nexport const CONFIG_FILE_NAME = '.modu-arena.json';\n\n/** Daemon state file for tracking synced sessions */\nexport const DAEMON_STATE_FILE = '.modu-arena-daemon.json';\n\n/** Minimum interval between sessions (seconds) */\nexport const MIN_SESSION_INTERVAL_SEC = 60;\n\n/** HMAC timestamp tolerance (seconds) */\nexport const HMAC_TIMESTAMP_TOLERANCE_SEC = 300;\n\n/** Daemon sync interval in seconds */\nexport const DAEMON_SYNC_INTERVAL_SEC = 120; // 2 minutes\n","import { createHmac, createHash } from 'node:crypto';\n\n/**\n * Compute HMAC-SHA256 signature for API authentication.\n *\n * message = \"{timestamp}:{bodyJsonString}\"\n * signature = HMAC-SHA256(apiKey, message).hex()\n */\nexport function computeHmacSignature(\n apiKey: string,\n timestamp: string,\n body: string,\n): string {\n const message = `${timestamp}:${body}`;\n return createHmac('sha256', apiKey).update(message).digest('hex');\n}\n\n/**\n * Compute SHA-256 session hash for integrity verification.\n *\n * data = \"{userId}:{userSalt}:{inputTokens}:{outputTokens}:{cacheCreationTokens}:{cacheReadTokens}:{modelName}:{endedAt}\"\n * hash = SHA-256(data).hex()\n */\nexport function computeSessionHash(\n userId: string,\n userSalt: string,\n inputTokens: number,\n outputTokens: number,\n cacheCreationTokens: number,\n cacheReadTokens: number,\n modelName: string,\n endedAt: string,\n): string {\n const data = `${userId}:${userSalt}:${inputTokens}:${outputTokens}:${cacheCreationTokens}:${cacheReadTokens}:${modelName}:${endedAt}`;\n return createHash('sha256').update(data).digest('hex');\n}\n","import { computeHmacSignature } from './crypto.js';\nimport { API_BASE_URL } from './constants.js';\n\nexport interface SessionPayload {\n toolType: string;\n sessionId: string;\n startedAt: string;\n endedAt: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens?: number;\n cacheReadTokens?: number;\n modelName?: string;\n codeMetrics?: Record<string, unknown> | null;\n}\n\nexport interface BatchPayload {\n sessions: SessionPayload[];\n}\n\nexport interface RankResponse {\n success: boolean;\n data: {\n username: string;\n usage: {\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheTokens: number;\n totalTokens: number;\n totalSessions: number;\n toolBreakdown: Array<{ tool: string; tokens: number }>;\n last7Days: Array<{ date: string; inputTokens: number; outputTokens: number; sessions: number }>;\n last30Days: Array<{ date: string; inputTokens: number; outputTokens: number; sessions: number }>;\n };\n overview: {\n successfulProjectsCount: number;\n };\n lastUpdated: string;\n };\n}\n\nexport interface ApiError {\n error?: string | { code?: string; message?: string };\n}\n\ninterface RequestOptions {\n apiKey: string;\n serverUrl?: string;\n}\n\nfunction baseUrl(opts: RequestOptions): string {\n return opts.serverUrl || API_BASE_URL;\n}\n\nfunction makeAuthHeaders(\n apiKey: string,\n body?: string,\n): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n };\n\n if (body !== undefined) {\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const signature = computeHmacSignature(apiKey, timestamp, body);\n headers['X-Timestamp'] = timestamp;\n headers['X-Signature'] = signature;\n }\n\n return headers;\n}\n\nexport async function submitSession(\n session: SessionPayload,\n opts: RequestOptions,\n): Promise<{ success: boolean; session?: unknown; error?: string }> {\n const body = JSON.stringify(session);\n const url = `${baseUrl(opts)}/api/v1/sessions`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: makeAuthHeaders(opts.apiKey, body),\n body,\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as { success: boolean; session: unknown };\n}\n\nexport async function submitBatch(\n sessions: SessionPayload[],\n opts: RequestOptions,\n): Promise<{\n success: boolean;\n processed?: number;\n duplicatesSkipped?: number;\n error?: string;\n}> {\n const body = JSON.stringify({ sessions });\n const url = `${baseUrl(opts)}/api/v1/sessions/batch`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: makeAuthHeaders(opts.apiKey, body),\n body,\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as { success: boolean; processed: number; duplicatesSkipped: number };\n}\n\nexport async function getRank(\n opts: RequestOptions,\n): Promise<RankResponse | { success: false; error: string }> {\n const url = `${baseUrl(opts)}/api/v1/rank`;\n\n const res = await fetch(url, {\n method: 'GET',\n headers: {\n 'X-API-Key': opts.apiKey,\n },\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as RankResponse;\n}\n\n// ─── Auth ─────────────────────────────────────────────────────────────────\n\nexport interface AuthResponse {\n success: boolean;\n apiKey?: string;\n user?: { id: string; username: string; displayName?: string };\n error?: string;\n}\n\nexport async function registerUser(\n payload: { username: string; password: string; displayName?: string },\n serverUrl?: string,\n): Promise<AuthResponse> {\n const body = JSON.stringify(payload);\n const url = `${serverUrl || API_BASE_URL}/api/auth/register`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n });\n\n return (await res.json()) as AuthResponse;\n}\n\nexport async function loginUser(\n payload: { username: string; password: string },\n serverUrl?: string,\n): Promise<AuthResponse> {\n const body = JSON.stringify({ ...payload, source: 'cli' });\n const url = `${serverUrl || API_BASE_URL}/api/auth/login`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body,\n });\n\n return (await res.json()) as AuthResponse;\n}\n\n// ─── Evaluate ─────────────────────────────────────────────────────────────\n\nexport interface EvaluatePayload {\n projectName: string;\n description: string;\n fileStructure?: Record<string, string[]>;\n projectPathHash?: string;\n localScore?: number;\n localEvaluationSummary?: string;\n}\n\nexport interface EvaluationResult {\n passed: boolean;\n projectName: string;\n projectPathHash: string;\n localScore: number;\n backendScore: number;\n penaltyScore: number;\n finalScore: number;\n cumulativeScoreAfter: number;\n feedback: string;\n evaluatedAt: string;\n}\n\nexport interface EvaluateResponse {\n success: true;\n evaluation: EvaluationResult;\n}\n\nexport async function submitEvaluation(\n payload: EvaluatePayload,\n opts: RequestOptions,\n): Promise<EvaluateResponse | { success: false; error: string }> {\n const body = JSON.stringify(payload);\n const url = `${baseUrl(opts)}/api/v1/evaluate`;\n\n const res = await fetch(url, {\n method: 'POST',\n headers: makeAuthHeaders(opts.apiKey, body),\n body,\n });\n\n const data = await res.json();\n if (!res.ok) {\n const err = (data as ApiError).error;\n const errMsg = typeof err === 'string' ? err : (err?.message || `HTTP ${res.status}`);\n return { success: false, error: errMsg };\n }\n return data as EvaluateResponse;\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join, dirname } from 'node:path';\nimport { CONFIG_FILE_NAME } from './constants.js';\n\nexport interface Config {\n apiKey: string;\n serverUrl?: string;\n tools?: string[];\n}\n\nfunction getConfigPath(): string {\n return join(homedir(), CONFIG_FILE_NAME);\n}\n\nexport function loadConfig(): Config | null {\n const configPath = getConfigPath();\n if (!existsSync(configPath)) return null;\n\n try {\n const raw = readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as Config;\n } catch {\n return null;\n }\n}\n\nexport function saveConfig(config: Config): void {\n const configPath = getConfigPath();\n const dir = dirname(configPath);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function requireConfig(): Config {\n const config = loadConfig();\n if (!config?.apiKey) {\n console.error(\n 'Error: Not configured. Run `npx @suncreation/modu-arena install` first.',\n );\n process.exit(1);\n }\n return config;\n}\n","/**\n * Platform-specific daemon installation for periodic tool data sync.\n * macOS: launchd (LaunchAgent)\n * Windows: Scheduled Task\n */\nimport { writeFileSync, existsSync, unlinkSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { DAEMON_SYNC_INTERVAL_SEC } from './constants.js';\n\nconst IS_WIN = process.platform === 'win32';\nconst DAEMON_NAME = 'com.modu-arena.sync';\n\nfunction getDaemonLogDir(): string {\n const dir = join(homedir(), '.modu-arena', 'logs');\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n return dir;\n}\n\nfunction getNodePath(): string {\n try {\n return execSync('which node', { encoding: 'utf-8' }).trim();\n } catch {\n return 'node';\n }\n}\n\nfunction getCliPath(): string {\n return require.resolve('./index.js').replace(/index\\.js$/, 'index.js');\n}\n\nexport function installDaemon(): { success: boolean; message: string } {\n if (IS_WIN) {\n return installWindowsDaemon();\n }\n return installMacosDaemon();\n}\n\nexport function uninstallDaemon(): { success: boolean; message: string } {\n if (IS_WIN) {\n return uninstallWindowsDaemon();\n }\n return uninstallMacosDaemon();\n}\n\nexport function isDaemonInstalled(): boolean {\n if (IS_WIN) {\n try {\n execSync(`schtasks /Query /TN \"${DAEMON_NAME}\"`, { encoding: 'utf-8' });\n return true;\n } catch {\n return false;\n }\n }\n const plistPath = join(homedir(), 'Library', 'LaunchAgents', `${DAEMON_NAME}.plist`);\n return existsSync(plistPath);\n}\n\nfunction installMacosDaemon(): { success: boolean; message: string } {\n const launchAgentsDir = join(homedir(), 'Library', 'LaunchAgents');\n const plistPath = join(launchAgentsDir, `${DAEMON_NAME}.plist`);\n const logDir = getDaemonLogDir();\n const nodePath = getNodePath();\n const cliPath = getCliPath();\n \n const intervalMinutes = Math.floor(DAEMON_SYNC_INTERVAL_SEC / 60);\n \n const plist = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${DAEMON_NAME}</string>\n <key>ProgramArguments</key>\n <array>\n <string>${nodePath}</string>\n <string>${cliPath}</string>\n <string>daemon-sync</string>\n </array>\n <key>StartInterval</key>\n <integer>${DAEMON_SYNC_INTERVAL_SEC}</integer>\n <key>StandardOutPath</key>\n <string>${logDir}/daemon.log</string>\n <key>StandardErrorPath</key>\n <string>${logDir}/daemon-error.log</string>\n <key>RunAtLoad</key>\n <true/>\n</dict>\n</plist>`;\n\n try {\n if (!existsSync(launchAgentsDir)) {\n mkdirSync(launchAgentsDir, { recursive: true });\n }\n writeFileSync(plistPath, plist);\n execSync(`launchctl load ${plistPath}`, { encoding: 'utf-8' });\n return { success: true, message: `Daemon installed. Syncs every ${intervalMinutes} minutes.` };\n } catch (e) {\n return { success: false, message: `Failed to install daemon: ${e}` };\n }\n}\n\nfunction uninstallMacosDaemon(): { success: boolean; message: string } {\n const plistPath = join(homedir(), 'Library', 'LaunchAgents', `${DAEMON_NAME}.plist`);\n \n try {\n if (existsSync(plistPath)) {\n execSync(`launchctl unload ${plistPath}`, { encoding: 'utf-8' });\n unlinkSync(plistPath);\n }\n return { success: true, message: 'Daemon uninstalled.' };\n } catch (e) {\n return { success: false, message: `Failed to uninstall daemon: ${e}` };\n }\n}\n\nfunction installWindowsDaemon(): { success: boolean; message: string } {\n const nodePath = getNodePath();\n const cliPath = getCliPath();\n const intervalMinutes = Math.floor(DAEMON_SYNC_INTERVAL_SEC / 60);\n \n try {\n const cmd = `schtasks /Create /TN \"${DAEMON_NAME}\" /TR \"\\\\\"${nodePath}\\\\\" \\\\\"${cliPath}\\\\\" daemon-sync\" /SC MINUTE /MO ${intervalMinutes} /F`;\n execSync(cmd, { encoding: 'utf-8' });\n return { success: true, message: `Daemon installed. Syncs every ${intervalMinutes} minutes.` };\n } catch (e) {\n return { success: false, message: `Failed to install daemon: ${e}` };\n }\n}\n\nfunction uninstallWindowsDaemon(): { success: boolean; message: string } {\n try {\n execSync(`schtasks /Delete /TN \"${DAEMON_NAME}\" /F`, { encoding: 'utf-8' });\n return { success: true, message: 'Daemon uninstalled.' };\n } catch (e) {\n return { success: false, message: `Failed to uninstall daemon: ${e}` };\n }\n}\n\nexport function getDaemonStatus(): { installed: boolean; platform: string; interval: number } {\n return {\n installed: isDaemonInstalled(),\n platform: IS_WIN ? 'windows' : 'macos',\n interval: DAEMON_SYNC_INTERVAL_SEC,\n };\n}\n","/**\n * Multi-tool session parser and sync logic.\n * \n * Supports:\n * - Claude Desktop: JSONL files from ~/Library/Application Support/Claude/local-agent-mode-sessions/\n * - OpenCode: SQLite DB at ~/.local/share/opencode/opencode.db\n */\nimport { readdirSync, readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { execSync } from 'node:child_process';\nimport { API_BASE_URL, DAEMON_STATE_FILE } from './constants.js';\nimport { computeHmacSignature } from './crypto.js';\n\nconst IS_WIN = process.platform === 'win32';\n\ninterface UsageData {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens?: number;\n cache_read_input_tokens?: number;\n}\n\ninterface JsonlMessage {\n type: string;\n sessionId?: string;\n timestamp?: string;\n message?: {\n model?: string;\n usage?: UsageData;\n };\n}\n\ninterface SessionAggregate {\n sessionId: string;\n toolType: string;\n inputTokens: number;\n outputTokens: number;\n cacheCreationTokens: number;\n cacheReadTokens: number;\n model: string;\n startedAt: string;\n endedAt: string;\n messageCount: number;\n}\n\ninterface DaemonState {\n lastSync: string;\n syncedSessions: string[];\n}\n\nfunction getClaudeDesktopDataDir(): string {\n if (IS_WIN) {\n return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'Claude');\n }\n return join(homedir(), 'Library', 'Application Support', 'Claude');\n}\n\nfunction getSessionDirs(): string[] {\n const dataDir = getClaudeDesktopDataDir();\n const sessionsDir = join(dataDir, 'local-agent-mode-sessions');\n if (!existsSync(sessionsDir)) return [];\n \n const orgDirs: string[] = [];\n for (const entry of readdirSync(sessionsDir, { withFileTypes: true })) {\n if (entry.isDirectory() && entry.name !== 'skills-plugin') {\n orgDirs.push(join(sessionsDir, entry.name));\n }\n }\n return orgDirs;\n}\n\nfunction findJsonlFiles(baseDir: string): string[] {\n const files: string[] = [];\n \n function walk(dir: string) {\n if (!existsSync(dir)) return;\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(full);\n } else if (entry.name.endsWith('.jsonl') && !entry.name.includes('audit')) {\n files.push(full);\n }\n }\n }\n \n walk(baseDir);\n return files;\n}\n\nfunction parseJsonlFile(filePath: string): SessionAggregate | null {\n const content = readFileSync(filePath, 'utf-8');\n const lines = content.trim().split('\\n');\n \n let sessionId = '';\n let inputTokens = 0;\n let outputTokens = 0;\n let cacheCreationTokens = 0;\n let cacheReadTokens = 0;\n let model = 'unknown';\n let startedAt = '';\n let endedAt = '';\n let messageCount = 0;\n \n for (const line of lines) {\n try {\n const msg: JsonlMessage = JSON.parse(line);\n \n if (msg.sessionId && !sessionId) {\n sessionId = msg.sessionId;\n }\n \n if (msg.timestamp) {\n if (!startedAt || msg.timestamp < startedAt) {\n startedAt = msg.timestamp;\n }\n if (!endedAt || msg.timestamp > endedAt) {\n endedAt = msg.timestamp;\n }\n }\n \n if (msg.message?.usage) {\n const usage = msg.message.usage;\n inputTokens += usage.input_tokens || 0;\n outputTokens += usage.output_tokens || 0;\n cacheCreationTokens += usage.cache_creation_input_tokens || 0;\n cacheReadTokens += usage.cache_read_input_tokens || 0;\n messageCount++;\n \n if (msg.message.model) {\n model = msg.message.model;\n }\n }\n } catch {\n }\n }\n \n if (!sessionId || messageCount === 0) return null;\n \n return {\n sessionId,\n toolType: 'claude-desktop',\n inputTokens,\n outputTokens,\n cacheCreationTokens,\n cacheReadTokens,\n model,\n startedAt,\n endedAt,\n messageCount,\n };\n}\n\nfunction getDaemonStatePath(): string {\n return join(homedir(), DAEMON_STATE_FILE);\n}\n\nfunction loadDaemonState(): DaemonState {\n const path = getDaemonStatePath();\n if (!existsSync(path)) {\n return { lastSync: new Date(0).toISOString(), syncedSessions: [] };\n }\n try {\n return JSON.parse(readFileSync(path, 'utf-8'));\n } catch {\n return { lastSync: new Date(0).toISOString(), syncedSessions: [] };\n }\n}\n\nfunction saveDaemonState(state: DaemonState): void {\n const path = getDaemonStatePath();\n writeFileSync(path, JSON.stringify(state, null, 2));\n}\n\nfunction computeSessionHash(session: SessionAggregate): string {\n const data = `${session.toolType}:${session.sessionId}:${session.inputTokens}:${session.outputTokens}:${session.endedAt}`;\n return createHash('sha256').update(data).digest('hex').substring(0, 16);\n}\n\nasync function submitSessions(\n sessions: SessionAggregate[],\n apiKey: string,\n state: DaemonState,\n): Promise<{ synced: number; skipped: number; errors: string[] }> {\n let synced = 0;\n let skipped = 0;\n const errors: string[] = [];\n\n for (const session of sessions) {\n const hash = computeSessionHash(session);\n if (state.syncedSessions.includes(hash)) {\n skipped++;\n continue;\n }\n\n if (session.inputTokens === 0 && session.outputTokens === 0) {\n skipped++;\n continue;\n }\n\n try {\n const body = JSON.stringify({\n toolType: session.toolType,\n endedAt: session.endedAt,\n startedAt: session.startedAt,\n inputTokens: session.inputTokens,\n outputTokens: session.outputTokens,\n cacheCreationTokens: session.cacheCreationTokens,\n cacheReadTokens: session.cacheReadTokens,\n modelName: session.model,\n });\n\n const ts = Math.floor(Date.now() / 1000).toString();\n const sig = computeHmacSignature(apiKey, ts, body);\n\n const res = await fetch(`${API_BASE_URL}/api/v1/sessions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-API-Key': apiKey,\n 'X-Timestamp': ts,\n 'X-Signature': sig,\n },\n body,\n });\n\n if (res.ok) {\n state.syncedSessions.push(hash);\n synced++;\n } else {\n const err = await res.text();\n errors.push(`[${session.toolType}] ${session.sessionId}: ${err}`);\n }\n } catch (e) {\n errors.push(`[${session.toolType}] ${session.sessionId}: ${e}`);\n }\n }\n\n return { synced, skipped, errors };\n}\n\n// ─── OpenCode SQLite support ───────────────────────────────────────────────\n\nfunction getOpenCodeDbPath(): string {\n if (IS_WIN) {\n return join(process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local'), 'opencode', 'opencode.db');\n }\n return join(homedir(), '.local', 'share', 'opencode', 'opencode.db');\n}\n\nfunction hasOpenCodeDb(): boolean {\n return existsSync(getOpenCodeDbPath());\n}\n\nfunction collectOpenCodeSessions(): SessionAggregate[] {\n const dbPath = getOpenCodeDbPath();\n if (!existsSync(dbPath)) return [];\n\n const query = `\nSELECT s.id, s.time_created, s.time_updated,\n COALESCE(SUM(json_extract(m.data, '$.tokens.input')), 0) as input_tokens,\n COALESCE(SUM(json_extract(m.data, '$.tokens.output')), 0) as output_tokens,\n COALESCE(SUM(json_extract(m.data, '$.tokens.cache.read')), 0) as cache_read,\n COALESCE(SUM(json_extract(m.data, '$.tokens.cache.write')), 0) as cache_write,\n MAX(json_extract(m.data, '$.modelID')) as model,\n COUNT(m.id) as msg_count\nFROM session s\nLEFT JOIN message m ON m.session_id = s.id AND json_extract(m.data, '$.role') = 'assistant'\nGROUP BY s.id\nHAVING input_tokens > 0 OR output_tokens > 0`;\n\n try {\n const raw = execSync(`sqlite3 -json \"${dbPath}\" \"${query.replace(/\\n/g, ' ')}\"`, {\n encoding: 'utf-8',\n timeout: 10000,\n }).trim();\n\n if (!raw || raw === '[]') return [];\n const rows = JSON.parse(raw) as Array<{\n id: string;\n time_created: string;\n time_updated: string;\n input_tokens: number;\n output_tokens: number;\n cache_read: number;\n cache_write: number;\n model: string | null;\n msg_count: number;\n }>;\n\n return rows.map((r) => ({\n sessionId: r.id,\n toolType: 'opencode',\n inputTokens: r.input_tokens,\n outputTokens: r.output_tokens,\n cacheCreationTokens: r.cache_write,\n cacheReadTokens: r.cache_read,\n model: r.model || 'unknown',\n startedAt: r.time_created,\n endedAt: r.time_updated,\n messageCount: r.msg_count,\n }));\n } catch {\n return [];\n }\n}\n\n// ─── Claude Desktop JSONL collection ───────────────────────────────────────\n\nfunction collectClaudeDesktopSessions(): SessionAggregate[] {\n const sessions: SessionAggregate[] = [];\n for (const orgDir of getSessionDirs()) {\n for (const file of findJsonlFiles(orgDir)) {\n const session = parseJsonlFile(file);\n if (session) sessions.push(session);\n }\n }\n return sessions;\n}\n\n// ─── Public API ────────────────────────────────────────────────────────────\n\nexport async function syncAllTools(apiKey: string): Promise<{ synced: number; skipped: number; errors: string[] }> {\n const state = loadDaemonState();\n const allSessions: SessionAggregate[] = [\n ...collectClaudeDesktopSessions(),\n ...collectOpenCodeSessions(),\n ];\n\n const result = await submitSessions(allSessions, apiKey, state);\n\n state.lastSync = new Date().toISOString();\n saveDaemonState(state);\n\n return result;\n}\n\nexport async function syncClaudeDesktop(apiKey: string): Promise<{ synced: number; skipped: number; errors: string[] }> {\n return syncAllTools(apiKey);\n}\n\nexport function hasClaudeDesktopData(): boolean {\n const dataDir = getClaudeDesktopDataDir();\n const sessionsDir = join(dataDir, 'local-agent-mode-sessions');\n return existsSync(sessionsDir);\n}\n\nexport function hasAnyToolData(): boolean {\n return hasClaudeDesktopData() || hasOpenCodeDb();\n}\n\nexport function getClaudeDesktopDataPath(): string {\n return getClaudeDesktopDataDir();\n}\n","/**\n * @suncreation/modu-arena CLI\n *\n * Track and rank your AI coding tool usage.\n *\n * Usage:\n * npx @suncreation/modu-arena install --api-key <key>\n * npx @suncreation/modu-arena rank\n * npx @suncreation/modu-arena status\n * npx @suncreation/modu-arena uninstall\n */\n\nimport {\n installCommand,\n loginCommand,\n rankCommand,\n registerCommand,\n statusCommand,\n submitCommand,\n uninstallCommand,\n daemonInstallCommand,\n daemonUninstallCommand,\n daemonStatusCommand,\n daemonSyncCommand,\n} from './commands.js';\n\nconst args = process.argv.slice(2);\nconst command = args[0];\n\nfunction printHelp(): void {\n console.log(`\nModu-Arena — AI Coding Tool Usage Tracker\n\nUsage:\n npx @suncreation/modu-arena <command> [options]\n\nCommands:\n register Create a new account (interactive)\n login Log in to an existing account (interactive)\n install Set up hooks for detected AI coding tools\n rank View your current stats and ranking\n status Check configuration and installed hooks\n submit Submit current project for evaluation\n uninstall Remove all hooks and configuration\n daemon-install Install Claude Desktop sync daemon\n daemon-status Check daemon status\n daemon-sync Manually sync Claude Desktop data\n daemon-remove Remove the daemon\n\nOptions:\n --api-key <key> Your Modu-Arena API key (for install)\n --help, -h Show this help message\n --version, -v Show version\n\nExamples:\n npx @suncreation/modu-arena register\n npx @suncreation/modu-arena login\n npx @suncreation/modu-arena install --api-key modu_arena_AbCdEfGh_xxx...\n npx @suncreation/modu-arena rank\n npx @suncreation/modu-arena daemon-install\n`);\n}\n\nasync function main(): Promise<void> {\n if (!command || command === '--help' || command === '-h') {\n printHelp();\n process.exit(0);\n }\n\n if (command === '--version' || command === '-v') {\n console.log('0.1.0');\n process.exit(0);\n }\n\n switch (command) {\n case 'register':\n await registerCommand();\n break;\n case 'login':\n await loginCommand();\n break;\n case 'install': {\n const keyIndex = args.indexOf('--api-key');\n const apiKey = keyIndex >= 0 ? args[keyIndex + 1] : undefined;\n await installCommand(apiKey);\n break;\n }\n case 'rank':\n await rankCommand();\n break;\n case 'status':\n statusCommand();\n break;\n case 'submit':\n await submitCommand();\n break;\n case 'uninstall':\n uninstallCommand();\n break;\n case 'daemon-install':\n daemonInstallCommand();\n break;\n case 'daemon-uninstall':\n case 'daemon-remove':\n daemonUninstallCommand();\n break;\n case 'daemon-status':\n daemonStatusCommand();\n break;\n case 'daemon-sync':\n await daemonSyncCommand();\n break;\n default:\n console.error(`Unknown command: ${command}`);\n printHelp();\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error('Fatal error:', err);\n process.exit(1);\n});\n"],"mappings":"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","names":["existsSync","readFileSync","readdirSync","writeFileSync","mkdirSync","unlinkSync","homedir","dirname","join","createHash","execSync","writeFileSync","existsSync","mkdirSync","homedir","join","join","homedir","existsSync","mkdirSync","writeFileSync","writeFileSync","existsSync","mkdirSync","homedir","join","IS_WIN","join","homedir","existsSync","mkdirSync","writeFileSync","readFileSync","existsSync","writeFileSync","homedir","join","createHash","execSync","IS_WIN","join","homedir","existsSync","readFileSync","writeFileSync","createHash","execSync","join","existsSync","existsSync","unlinkSync","join","homedir","readFileSync","execSync","dirname","mkdirSync","writeFileSync","readdirSync","createHash"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suncreation/modu-arena",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Track and rank your AI coding tool usage across Claude Code, Claude Desktop, OpenCode, Gemini CLI, Codex CLI, and Crush",
6
6
  "bin": {