vibemancer 1.0.1 → 1.0.2

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.
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/auth/oauth-client.ts
4
+ import { createHash, randomBytes } from "crypto";
5
+
6
+ // src/auth/credentials-store.ts
7
+ import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
8
+ import { homedir } from "os";
9
+ import { join } from "path";
10
+ function configDir() {
11
+ return process.env.VIBEMANCER_CONFIG_DIR ?? join(homedir(), ".vibemancer");
12
+ }
13
+ function credentialsPath() {
14
+ return join(configDir(), "credentials.json");
15
+ }
16
+ function loadCredentials() {
17
+ const path = credentialsPath();
18
+ if (!existsSync(path)) return null;
19
+ try {
20
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
21
+ if (typeof parsed === "object" && parsed !== null && "refreshToken" in parsed && typeof parsed.refreshToken === "string" && "accessToken" in parsed && typeof parsed.accessToken === "string" && "expiresAt" in parsed && typeof parsed.expiresAt === "number") {
22
+ return { refreshToken: parsed.refreshToken, accessToken: parsed.accessToken, expiresAt: parsed.expiresAt };
23
+ }
24
+ return null;
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+ function saveCredentials(credentials) {
30
+ mkdirSync(configDir(), { recursive: true });
31
+ const path = credentialsPath();
32
+ writeFileSync(path, JSON.stringify(credentials, null, 2), { mode: 384 });
33
+ try {
34
+ chmodSync(path, 384);
35
+ } catch {
36
+ }
37
+ }
38
+ function clearCredentials() {
39
+ try {
40
+ rmSync(credentialsPath(), { force: true });
41
+ } catch {
42
+ }
43
+ }
44
+
45
+ // src/auth/oauth-client.ts
46
+ var MCP_BASE_URL = process.env.VIBEMANCER_MCP_URL ?? "https://mcp.vibemancer.com";
47
+ var NotLoggedInError = class extends Error {
48
+ constructor() {
49
+ super("Not logged in. Run: vibemancer login");
50
+ this.name = "NotLoggedInError";
51
+ }
52
+ };
53
+ function generatePkce() {
54
+ const verifier = randomBytes(32).toString("base64url");
55
+ const challenge = createHash("sha256").update(verifier).digest("base64url");
56
+ return { verifier, challenge };
57
+ }
58
+ async function registerClient(redirectUri) {
59
+ const res = await fetch(`${MCP_BASE_URL}/register`, {
60
+ method: "POST",
61
+ headers: { "Content-Type": "application/json" },
62
+ body: JSON.stringify({ redirect_uris: [redirectUri], client_name: "vibemancer-cli" })
63
+ });
64
+ if (!res.ok) throw new Error(`Client registration failed (${res.status}).`);
65
+ const json = await res.json();
66
+ const clientId = typeof json === "object" && json !== null && "client_id" in json && typeof json.client_id === "string" ? json.client_id : "";
67
+ if (!clientId) throw new Error("Client registration returned no client_id.");
68
+ return clientId;
69
+ }
70
+ function parseTokenResponse(json, fallbackRefresh) {
71
+ if (typeof json !== "object" || json === null) throw new Error("Invalid token response.");
72
+ const accessToken = "access_token" in json && typeof json.access_token === "string" ? json.access_token : "";
73
+ if (!accessToken) throw new Error("Token response missing access_token.");
74
+ const refreshToken = "refresh_token" in json && typeof json.refresh_token === "string" ? json.refresh_token : fallbackRefresh;
75
+ const expiresIn = "expires_in" in json && typeof json.expires_in === "number" ? json.expires_in : 3600;
76
+ return { accessToken, refreshToken, expiresAt: Date.now() + expiresIn * 1e3 };
77
+ }
78
+ async function exchangeCode(code, codeVerifier) {
79
+ const res = await fetch(`${MCP_BASE_URL}/token`, {
80
+ method: "POST",
81
+ headers: { "Content-Type": "application/json" },
82
+ body: JSON.stringify({ grant_type: "authorization_code", code, code_verifier: codeVerifier })
83
+ });
84
+ if (!res.ok) throw new Error(`Token exchange failed (${res.status}): ${await res.text()}`);
85
+ const creds = parseTokenResponse(await res.json(), "");
86
+ saveCredentials(creds);
87
+ return creds;
88
+ }
89
+ async function refreshCredentials(refreshToken) {
90
+ const res = await fetch(`${MCP_BASE_URL}/token`, {
91
+ method: "POST",
92
+ headers: { "Content-Type": "application/json" },
93
+ body: JSON.stringify({ grant_type: "refresh_token", refresh_token: refreshToken })
94
+ });
95
+ if (!res.ok) throw new NotLoggedInError();
96
+ const creds = parseTokenResponse(await res.json(), refreshToken);
97
+ saveCredentials(creds);
98
+ return creds;
99
+ }
100
+ var REFRESH_SKEW_MS = 6e4;
101
+ async function getAccessToken() {
102
+ const creds = loadCredentials();
103
+ if (!creds) throw new NotLoggedInError();
104
+ if (creds.expiresAt - Date.now() > REFRESH_SKEW_MS) return creds.accessToken;
105
+ const refreshed = await refreshCredentials(creds.refreshToken);
106
+ return refreshed.accessToken;
107
+ }
108
+
109
+ export {
110
+ loadCredentials,
111
+ clearCredentials,
112
+ MCP_BASE_URL,
113
+ NotLoggedInError,
114
+ generatePkce,
115
+ registerClient,
116
+ exchangeCode,
117
+ getAccessToken
118
+ };
119
+ //# sourceMappingURL=chunk-MCU2B4PZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/oauth-client.ts","../src/auth/credentials-store.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/naming-convention -- OAuth 2.0 wire-format field names (grant_type, access_token, …) are snake_case by spec */\n\n/**\n * CLI OAuth client for the Vibemancer MCP gateway.\n *\n * The CLI is a PKCE OAuth client of mcp.vibemancer.com (the same gateway the MCP\n * AI clients use). `vibemancer login` runs the authorization-code flow; the\n * resulting session token carries the canonical Firebase uid. This module owns\n * PKCE, the token exchange/refresh, and handing callers a fresh access token.\n */\n\nimport {createHash, randomBytes} from 'node:crypto';\nimport {loadCredentials, saveCredentials, type Credentials} from './credentials-store.js';\n\n/** Gateway base URL; overridable for emulator/E2E via VIBEMANCER_MCP_URL. */\nexport const MCP_BASE_URL = process.env.VIBEMANCER_MCP_URL ?? 'https://mcp.vibemancer.com';\n\nexport class NotLoggedInError extends Error\n{\n\tconstructor()\n\t{\n\t\tsuper('Not logged in. Run: vibemancer login');\n\t\tthis.name = 'NotLoggedInError';\n\t}\n}\n\nexport interface Pkce\n{\n\tverifier: string;\n\tchallenge: string;\n}\n\nexport function generatePkce(): Pkce\n{\n\tconst verifier = randomBytes(32).toString('base64url');\n\tconst challenge = createHash('sha256').update(verifier).digest('base64url');\n\treturn {verifier, challenge};\n}\n\n/** Dynamic client registration → client_id (localhost/https redirect allowed). */\nexport async function registerClient(redirectUri: string): Promise<string>\n{\n\tconst res = await fetch(`${MCP_BASE_URL}/register`, {\n\t\tmethod: 'POST',\n\t\theaders: {'Content-Type': 'application/json'},\n\t\tbody: JSON.stringify({redirect_uris: [redirectUri], client_name: 'vibemancer-cli'}),\n\t});\n\tif (!res.ok) throw new Error(`Client registration failed (${res.status}).`);\n\tconst json: unknown = await res.json();\n\tconst clientId = typeof json === 'object' && json !== null && 'client_id' in json && typeof json.client_id === 'string'\n\t\t? json.client_id\n\t\t: '';\n\tif (!clientId) throw new Error('Client registration returned no client_id.');\n\treturn clientId;\n}\n\nfunction parseTokenResponse(json: unknown, fallbackRefresh: string): Credentials\n{\n\tif (typeof json !== 'object' || json === null) throw new Error('Invalid token response.');\n\tconst accessToken = 'access_token' in json && typeof json.access_token === 'string' ? json.access_token : '';\n\tif (!accessToken) throw new Error('Token response missing access_token.');\n\tconst refreshToken = 'refresh_token' in json && typeof json.refresh_token === 'string' ? json.refresh_token : fallbackRefresh;\n\tconst expiresIn = 'expires_in' in json && typeof json.expires_in === 'number' ? json.expires_in : 3600;\n\treturn {accessToken, refreshToken, expiresAt: Date.now() + expiresIn * 1000};\n}\n\n/** Exchange an authorization code (PKCE) for tokens, and persist them. */\nexport async function exchangeCode(code: string, codeVerifier: string): Promise<Credentials>\n{\n\tconst res = await fetch(`${MCP_BASE_URL}/token`, {\n\t\tmethod: 'POST',\n\t\theaders: {'Content-Type': 'application/json'},\n\t\tbody: JSON.stringify({grant_type: 'authorization_code', code, code_verifier: codeVerifier}),\n\t});\n\tif (!res.ok) throw new Error(`Token exchange failed (${res.status}): ${await res.text()}`);\n\tconst creds = parseTokenResponse(await res.json(), '');\n\tsaveCredentials(creds);\n\treturn creds;\n}\n\nasync function refreshCredentials(refreshToken: string): Promise<Credentials>\n{\n\tconst res = await fetch(`${MCP_BASE_URL}/token`, {\n\t\tmethod: 'POST',\n\t\theaders: {'Content-Type': 'application/json'},\n\t\tbody: JSON.stringify({grant_type: 'refresh_token', refresh_token: refreshToken}),\n\t});\n\tif (!res.ok) throw new NotLoggedInError();\n\tconst creds = parseTokenResponse(await res.json(), refreshToken);\n\tsaveCredentials(creds);\n\treturn creds;\n}\n\nconst REFRESH_SKEW_MS = 60_000;\n\n/** A valid access token, refreshing silently when within 60s of expiry. */\nexport async function getAccessToken(): Promise<string>\n{\n\tconst creds = loadCredentials();\n\tif (!creds) throw new NotLoggedInError();\n\tif (creds.expiresAt - Date.now() > REFRESH_SKEW_MS) return creds.accessToken;\n\tconst refreshed = await refreshCredentials(creds.refreshToken);\n\treturn refreshed.accessToken;\n}\n","/**\n * Local credential store for the CLI's OAuth session.\n *\n * Persists the refresh + access tokens at ~/.vibemancer/credentials.json so the\n * user stays logged in between commands. The directory is overridable via\n * VIBEMANCER_CONFIG_DIR (tests, or users who relocate their config).\n */\n\nimport {chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync} from 'node:fs';\nimport {homedir} from 'node:os';\nimport {join} from 'node:path';\n\nexport interface Credentials\n{\n\trefreshToken: string;\n\taccessToken: string;\n\t/** Epoch milliseconds at which the access token expires. */\n\texpiresAt: number;\n}\n\nfunction configDir(): string\n{\n\treturn process.env.VIBEMANCER_CONFIG_DIR ?? join(homedir(), '.vibemancer');\n}\n\nfunction credentialsPath(): string\n{\n\treturn join(configDir(), 'credentials.json');\n}\n\nexport function loadCredentials(): Credentials | null\n{\n\tconst path = credentialsPath();\n\tif (!existsSync(path)) return null;\n\ttry\n\t{\n\t\tconst parsed: unknown = JSON.parse(readFileSync(path, 'utf-8'));\n\t\tif (\n\t\t\ttypeof parsed === 'object' && parsed !== null\n\t\t\t&& 'refreshToken' in parsed && typeof parsed.refreshToken === 'string'\n\t\t\t&& 'accessToken' in parsed && typeof parsed.accessToken === 'string'\n\t\t\t&& 'expiresAt' in parsed && typeof parsed.expiresAt === 'number'\n\t\t)\n\t\t{\n\t\t\treturn {refreshToken: parsed.refreshToken, accessToken: parsed.accessToken, expiresAt: parsed.expiresAt};\n\t\t}\n\t\treturn null;\n\t}\n\tcatch\n\t{\n\t\treturn null;\n\t}\n}\n\nexport function saveCredentials(credentials: Credentials): void\n{\n\tmkdirSync(configDir(), {recursive: true});\n\tconst path = credentialsPath();\n\twriteFileSync(path, JSON.stringify(credentials, null, 2), {mode: 0o600});\n\t// Best-effort tighten perms (no-op semantics on Windows).\n\ttry\n\t{\n\t\tchmodSync(path, 0o600);\n\t}\n\tcatch\n\t{\n\t\t// ignore — Windows / restricted FS\n\t}\n}\n\nexport function clearCredentials(): void\n{\n\ttry\n\t{\n\t\trmSync(credentialsPath(), {force: true});\n\t}\n\tcatch\n\t{\n\t\t// ignore\n\t}\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -6,8 +6,15 @@ import {
6
6
  resolveOpponent
7
7
  } from "./chunk-4DUS7IHW.js";
8
8
  import {
9
- FIREBASE_CONFIG
10
- } from "./chunk-AA2UJPPN.js";
9
+ MCP_BASE_URL,
10
+ NotLoggedInError,
11
+ clearCredentials,
12
+ exchangeCode,
13
+ generatePkce,
14
+ getAccessToken,
15
+ loadCredentials,
16
+ registerClient
17
+ } from "./chunk-MCU2B4PZ.js";
11
18
 
12
19
  // src/commands/dev.ts
13
20
  import { execFile } from "child_process";
@@ -352,6 +359,16 @@ import { initializeApp, getApps } from "firebase/app";
352
359
  import { getFirestore, collection, query, where, limit, getDocs, connectFirestoreEmulator } from "firebase/firestore";
353
360
  import { getStorage, ref, getBytes, connectStorageEmulator } from "firebase/storage";
354
361
  import { isBannedBotName } from "@vibemancer/core";
362
+
363
+ // src/firebase-config.ts
364
+ var FIREBASE_CONFIG = {
365
+ apiKey: "AIzaSyDSUJ2jlk5_vlpGOypMtvqKjHhDmbgomIY",
366
+ authDomain: "le-vibemancer.firebaseapp.com",
367
+ projectId: "le-vibemancer",
368
+ storageBucket: "le-vibemancer.firebasestorage.app"
369
+ };
370
+
371
+ // src/remote-opponent.ts
355
372
  function isHandleSelector(opponent) {
356
373
  const trimmed = opponent.trim();
357
374
  const slash = trimmed.indexOf("/");
@@ -994,121 +1011,15 @@ function getStyleDescription(bot) {
994
1011
  // src/commands/upload.ts
995
1012
  import fs4 from "fs";
996
1013
 
997
- // src/auth/oauth-client.ts
998
- import { createHash, randomBytes } from "crypto";
999
-
1000
- // src/auth/credentials-store.ts
1001
- import { chmodSync, existsSync, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
1002
- import { homedir } from "os";
1003
- import { join } from "path";
1004
- function configDir() {
1005
- return process.env.VIBEMANCER_CONFIG_DIR ?? join(homedir(), ".vibemancer");
1006
- }
1007
- function credentialsPath() {
1008
- return join(configDir(), "credentials.json");
1009
- }
1010
- function loadCredentials() {
1011
- const path7 = credentialsPath();
1012
- if (!existsSync(path7)) return null;
1013
- try {
1014
- const parsed = JSON.parse(readFileSync2(path7, "utf-8"));
1015
- if (typeof parsed === "object" && parsed !== null && "refreshToken" in parsed && typeof parsed.refreshToken === "string" && "accessToken" in parsed && typeof parsed.accessToken === "string" && "expiresAt" in parsed && typeof parsed.expiresAt === "number") {
1016
- return { refreshToken: parsed.refreshToken, accessToken: parsed.accessToken, expiresAt: parsed.expiresAt };
1017
- }
1018
- return null;
1019
- } catch {
1020
- return null;
1021
- }
1022
- }
1023
- function saveCredentials(credentials) {
1024
- mkdirSync(configDir(), { recursive: true });
1025
- const path7 = credentialsPath();
1026
- writeFileSync2(path7, JSON.stringify(credentials, null, 2), { mode: 384 });
1027
- try {
1028
- chmodSync(path7, 384);
1029
- } catch {
1030
- }
1031
- }
1032
- function clearCredentials() {
1033
- try {
1034
- rmSync(credentialsPath(), { force: true });
1035
- } catch {
1036
- }
1037
- }
1038
-
1039
- // src/auth/oauth-client.ts
1040
- var MCP_BASE_URL = process.env.VIBEMANCER_MCP_URL ?? "https://mcp.vibemancer.com";
1041
- var NotLoggedInError = class extends Error {
1042
- constructor() {
1043
- super("Not logged in. Run: vibemancer login");
1044
- this.name = "NotLoggedInError";
1045
- }
1046
- };
1047
- function generatePkce() {
1048
- const verifier = randomBytes(32).toString("base64url");
1049
- const challenge = createHash("sha256").update(verifier).digest("base64url");
1050
- return { verifier, challenge };
1051
- }
1052
- async function registerClient(redirectUri) {
1053
- const res = await fetch(`${MCP_BASE_URL}/register`, {
1054
- method: "POST",
1055
- headers: { "Content-Type": "application/json" },
1056
- body: JSON.stringify({ redirect_uris: [redirectUri], client_name: "vibemancer-cli" })
1057
- });
1058
- if (!res.ok) throw new Error(`Client registration failed (${res.status}).`);
1059
- const json = await res.json();
1060
- const clientId = typeof json === "object" && json !== null && "client_id" in json && typeof json.client_id === "string" ? json.client_id : "";
1061
- if (!clientId) throw new Error("Client registration returned no client_id.");
1062
- return clientId;
1063
- }
1064
- function parseTokenResponse(json, fallbackRefresh) {
1065
- if (typeof json !== "object" || json === null) throw new Error("Invalid token response.");
1066
- const accessToken = "access_token" in json && typeof json.access_token === "string" ? json.access_token : "";
1067
- if (!accessToken) throw new Error("Token response missing access_token.");
1068
- const refreshToken = "refresh_token" in json && typeof json.refresh_token === "string" ? json.refresh_token : fallbackRefresh;
1069
- const expiresIn = "expires_in" in json && typeof json.expires_in === "number" ? json.expires_in : 3600;
1070
- return { accessToken, refreshToken, expiresAt: Date.now() + expiresIn * 1e3 };
1071
- }
1072
- async function exchangeCode(code, codeVerifier) {
1073
- const res = await fetch(`${MCP_BASE_URL}/token`, {
1074
- method: "POST",
1075
- headers: { "Content-Type": "application/json" },
1076
- body: JSON.stringify({ grant_type: "authorization_code", code, code_verifier: codeVerifier })
1077
- });
1078
- if (!res.ok) throw new Error(`Token exchange failed (${res.status}): ${await res.text()}`);
1079
- const creds = parseTokenResponse(await res.json(), "");
1080
- saveCredentials(creds);
1081
- return creds;
1082
- }
1083
- async function refreshCredentials(refreshToken) {
1084
- const res = await fetch(`${MCP_BASE_URL}/token`, {
1085
- method: "POST",
1086
- headers: { "Content-Type": "application/json" },
1087
- body: JSON.stringify({ grant_type: "refresh_token", refresh_token: refreshToken })
1088
- });
1089
- if (!res.ok) throw new NotLoggedInError();
1090
- const creds = parseTokenResponse(await res.json(), refreshToken);
1091
- saveCredentials(creds);
1092
- return creds;
1093
- }
1094
- var REFRESH_SKEW_MS = 6e4;
1095
- async function getAccessToken() {
1096
- const creds = loadCredentials();
1097
- if (!creds) throw new NotLoggedInError();
1098
- if (creds.expiresAt - Date.now() > REFRESH_SKEW_MS) return creds.accessToken;
1099
- const refreshed = await refreshCredentials(creds.refreshToken);
1100
- return refreshed.accessToken;
1101
- }
1102
-
1103
1014
  // src/auth/env-headers.ts
1104
1015
  import os from "os";
1105
- import { readFileSync as readFileSync3 } from "fs";
1016
+ import { readFileSync as readFileSync2 } from "fs";
1106
1017
  import path4 from "path";
1107
1018
  import { fileURLToPath } from "url";
1108
1019
  function findCliVersionFrom(here) {
1109
1020
  for (const rel of ["../../package.json", "../package.json", "../../../package.json"]) {
1110
1021
  try {
1111
- const parsed = JSON.parse(readFileSync3(path4.resolve(here, rel), "utf8"));
1022
+ const parsed = JSON.parse(readFileSync2(path4.resolve(here, rel), "utf8"));
1112
1023
  if (typeof parsed !== "object" || parsed === null) continue;
1113
1024
  if (!("name" in parsed) || !("version" in parsed)) continue;
1114
1025
  const { name, version } = parsed;
@@ -1251,7 +1162,7 @@ async function runPull(options) {
1251
1162
 
1252
1163
  // src/commands/login.ts
1253
1164
  import { createServer } from "http";
1254
- import { randomBytes as randomBytes2 } from "crypto";
1165
+ import { randomBytes } from "crypto";
1255
1166
  import { spawn as spawn2 } from "child_process";
1256
1167
  import { createInterface } from "readline/promises";
1257
1168
  function buildAuthorizeUrl(baseUrl, params) {
@@ -1343,7 +1254,7 @@ async function runPasteLogin(challenge, verifier, state) {
1343
1254
  }
1344
1255
  async function runLogin(options) {
1345
1256
  const { verifier, challenge } = generatePkce();
1346
- const state = randomBytes2(16).toString("hex");
1257
+ const state = randomBytes(16).toString("hex");
1347
1258
  if (options.noBrowser) {
1348
1259
  await runPasteLogin(challenge, verifier, state);
1349
1260
  } else {
@@ -1380,22 +1291,49 @@ async function runLogout() {
1380
1291
  }
1381
1292
 
1382
1293
  // src/commands/feedback.ts
1383
- async function runFeedback(options) {
1294
+ async function defaultTokenLookup() {
1295
+ const { getAccessToken: getAccessToken2 } = await import("./oauth-client-AX3HNK6P.js");
1296
+ return await getAccessToken2();
1297
+ }
1298
+ async function runFeedback(options, tokenLookup = defaultTokenLookup) {
1384
1299
  const message = options.message.trim();
1385
1300
  if (!message) {
1386
1301
  console.error(" Error: feedback message cannot be empty.");
1387
1302
  process.exit(1);
1303
+ return;
1388
1304
  }
1389
1305
  console.log("\n Submitting feedback...");
1306
+ let token;
1390
1307
  try {
1391
- const { initializeApp: initializeApp2 } = await import("firebase/app");
1392
- const { getFunctions, httpsCallable } = await import("firebase/functions");
1393
- const { FIREBASE_CONFIG: FIREBASE_CONFIG2 } = await import("./firebase-config-F6COE3NY.js");
1394
- const app = initializeApp2(FIREBASE_CONFIG2);
1395
- const functions = getFunctions(app, "us-central1");
1396
- const submitFn = httpsCallable(functions, "submitFeedback");
1397
- await submitFn({ message });
1398
- console.log(" Sent! Thanks for the feedback.\n");
1308
+ token = await tokenLookup();
1309
+ } catch {
1310
+ token = null;
1311
+ }
1312
+ const headers = { "Content-Type": "application/json", ...envHeaders() };
1313
+ if (token) headers.Authorization = `Bearer ${token}`;
1314
+ try {
1315
+ const res = await fetch(`${MCP_BASE_URL}/feedback`, {
1316
+ method: "POST",
1317
+ headers,
1318
+ body: JSON.stringify({ message }),
1319
+ signal: AbortSignal.timeout(15e3)
1320
+ });
1321
+ if (!res.ok) {
1322
+ const body = await res.text();
1323
+ let detail = body;
1324
+ try {
1325
+ const parsed = JSON.parse(body);
1326
+ if (typeof parsed === "object" && parsed !== null && "error" in parsed) {
1327
+ detail = String(parsed.error);
1328
+ }
1329
+ } catch {
1330
+ }
1331
+ console.error(` Failed to submit: ${detail}
1332
+ `);
1333
+ process.exit(1);
1334
+ return;
1335
+ }
1336
+ console.log(token ? " Sent! Thanks for the feedback.\n" : " Sent! Thanks for the feedback. (Not signed in, so we have no way to reply.)\n");
1399
1337
  } catch (err) {
1400
1338
  const msg = err instanceof Error ? err.message : String(err);
1401
1339
  console.error(` Failed to submit: ${msg}
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/dev.ts","../src/bot-discovery.ts","../src/server.ts","../src/compile-single-bot.ts","../src/commands/test.ts","../src/commands/fight.ts","../src/remote-opponent.ts","../src/commands/trace.ts","../src/commands/tournament.ts","../src/commands/optimize.ts","../src/commands/build.ts","../src/commands/bots.ts","../src/commands/upload.ts","../src/auth/oauth-client.ts","../src/auth/credentials-store.ts","../src/auth/env-headers.ts","../src/auth/gateway-client.ts","../src/commands/pull.ts","../src/commands/login.ts","../src/auth/revoke.ts","../src/commands/logout.ts","../src/commands/feedback.ts","../src/commands/missile-calc.ts","../src/auth/telemetry.ts","../src/cli.ts"],"sourcesContent":["/**\r\n * vibemancer dev\r\n *\r\n * Starts the local development server. Auto-discovers every bot in the\r\n * project's src/ tree and serves them to the hosted web client at\r\n * vibemancer.com via the #botserver= URL hash. Compiles fresh on each\r\n * request so a browser refresh always picks up the latest code. Opens\r\n * the browser automatically.\r\n *\r\n * The --bot flag is accepted for backward compatibility but no longer\r\n * used — multi-bot discovery scans src/ regardless.\r\n */\r\n\r\nimport {execFile} from 'node:child_process';\r\nimport {discoverAllBots} from '../bot-discovery.js';\r\nimport {startServer} from '../server.js';\r\n\r\nexport interface DevOptions\r\n{\r\n\tport: number;\r\n\tbot?: string;\r\n}\r\n\r\nexport async function runDev(options: DevOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\r\n\t// Show what we discovered up front so the user sees it before the\r\n\t// banner lands — purely informational; the server re-scans on every\r\n\t// /local-bots request.\r\n\tconst bots = await discoverAllBots(projectDir);\r\n\tif (bots.length === 0)\r\n\t{\r\n\t\tconsole.log('No bots discovered in src/. Add a .ts file with a PascalCase export, e.g.:');\r\n\t\tconsole.log(' export function MyWizard() { return move(0, 0); }');\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconsole.log(`Discovered ${bots.length} bot${bots.length === 1 ? '' : 's'}: ${bots.map((b) => b.exportName).join(', ')}`);\r\n\t}\r\n\r\n\tconst server = startServer({\r\n\t\tport: options.port,\r\n\t\tprojectDir,\r\n\t});\r\n\r\n\t// Auto-open browser once server is listening\r\n\tserver.once('listening', () =>\r\n\t{\r\n\t\tconst url = `https://vibemancer.com/#botserver=localhost:${options.port}`;\r\n\t\topenBrowser(url);\r\n\t});\r\n}\r\n\r\nfunction openBrowser(url: string): void\r\n{\r\n\tconst platform = process.platform;\r\n\r\n\ttry\r\n\t{\r\n\t\tif (platform === 'darwin')\r\n\t\t{\r\n\t\t\texecFile('open', [url], () => \r\n\t\t\t{});\r\n\t\t}\r\n\t\telse if (platform === 'win32')\r\n\t\t{\r\n\t\t\texecFile('cmd', ['/c', 'start', '', url], () => \r\n\t\t\t{});\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t// Linux / WSL — try xdg-open, fall back to wslview\r\n\t\t\texecFile('xdg-open', [url], (err) =>\r\n\t\t\t{\r\n\t\t\t\tif (err) execFile('wslview', [url], () => \r\n\t\t\t\t{});\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\t// Silently ignore — user can always open manually\r\n\t}\r\n}\r\n","/**\r\n * Bot Discovery\r\n *\r\n * Finds the user's bot source file(s) and export name(s).\r\n *\r\n * Single-bot mode (used by upload, fight, trace, etc.) resolves one bot:\r\n * 1. --bot flag\r\n * 2. vibemancer.json config\r\n * 3. Auto-scan src/ — if exactly one bot found, use it; if multiple,\r\n * error with a list so the user can pick with --bot\r\n *\r\n * Multi-bot mode (used by the dev server) auto-scans src/ for all bots.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\n\r\nexport interface BotInfo\r\n{\r\n\t/** Absolute path to the bot source file. */\r\n\tsourcePath: string;\r\n\t/** Named export of the bot function. */\r\n\texportName: string;\r\n}\r\n\r\ninterface VibemancerConfig\r\n{\r\n\tbot?: string;\r\n\texport?: string;\r\n}\r\n\r\nexport interface DiscoverOptions\r\n{\r\n\t/**\r\n\t * Resolve the bot even when its source file does not exist yet. Only `pull` sets this:\r\n\t * it RESTORES the source onto a machine that has never had it (new laptop, fresh clone,\r\n\t * a bot written in an MCP chat session). vibemancer.json already carries both the path\r\n\t * and the export name, so nothing has to be read off disk. Commands that consume the\r\n\t * source — upload, fight, trace — leave this off and still require a real file.\r\n\t */\r\n\tallowMissingFile?: boolean;\r\n}\r\n\r\nexport async function discoverBot(projectDir: string, overridePath?: string, options: DiscoverOptions = {}): Promise<BotInfo>\r\n{\r\n\tconst absDir = path.resolve(projectDir);\r\n\r\n\t// 1. Explicit --bot flag\r\n\tif (overridePath)\r\n\t{\r\n\t\tconst absPath = path.resolve(absDir, overridePath);\r\n\t\tif (!fs.existsSync(absPath))\r\n\t\t{\r\n\t\t\tthrow new Error(`Bot file not found: ${absPath}`);\r\n\t\t}\r\n\t\tconst exportName = await findExportName(absPath);\r\n\t\treturn {sourcePath: absPath, exportName};\r\n\t}\r\n\r\n\t// 2. vibemancer.json config\r\n\tconst configPath = path.join(absDir, 'vibemancer.json');\r\n\tif (fs.existsSync(configPath))\r\n\t{\r\n\t\tconst raw = fs.readFileSync(configPath, 'utf-8');\r\n\t\tlet config: VibemancerConfig;\r\n\t\ttry\r\n\t\t{\r\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- JSON.parse returns unknown, manual validation follows\r\n\t\t\tconfig = JSON.parse(raw) as VibemancerConfig;\r\n\t\t}\r\n\t\tcatch\r\n\t\t{\r\n\t\t\tthrow new Error(`Invalid JSON in vibemancer.json: ${configPath}`);\r\n\t\t}\r\n\r\n\t\tif (config.bot !== null && config.bot !== undefined && typeof config.bot !== 'string')\r\n\t\t{\r\n\t\t\tthrow new Error(`Invalid \"bot\" field in vibemancer.json: expected string, got ${typeof config.bot}`);\r\n\t\t}\r\n\r\n\t\tif (config.export !== null && config.export !== undefined && typeof config.export !== 'string')\r\n\t\t{\r\n\t\t\tthrow new Error(`Invalid \"export\" field in vibemancer.json: expected string, got ${typeof config.export}`);\r\n\t\t}\r\n\r\n\t\tif (config.bot)\r\n\t\t{\r\n\t\t\tconst botPath = path.resolve(absDir, config.bot);\r\n\t\t\tif (!fs.existsSync(botPath))\r\n\t\t\t{\r\n\t\t\t\tif (!options.allowMissingFile)\r\n\t\t\t\t{\r\n\t\t\t\t\tthrow new Error(`Bot file from vibemancer.json not found: ${botPath}`);\r\n\t\t\t\t}\r\n\t\t\t\t// Restoring a bot that isn't on this machine yet: the export name can't be read\r\n\t\t\t\t// off disk, so vibemancer.json has to name it.\r\n\t\t\t\tif (!config.export)\r\n\t\t\t\t{\r\n\t\t\t\t\tthrow new Error(\r\n\t\t\t\t\t\t`Bot file ${botPath} does not exist yet, and vibemancer.json has no \"export\" field.\\n`\r\n\t\t\t\t\t\t+ 'Add the wizard name so it can be restored, e.g.:\\n'\r\n\t\t\t\t\t\t+ ' {\"bot\": \"src/bot.ts\", \"export\": \"MyWizard\"}',\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t\treturn {sourcePath: botPath, exportName: config.export};\r\n\t\t\t}\r\n\t\t\tconst exportName = config.export || await findExportName(botPath);\r\n\t\t\treturn {sourcePath: botPath, exportName};\r\n\t\t}\r\n\t}\r\n\r\n\t// 3. Auto-discover from src/\r\n\tconst allBots = await discoverAllBots(absDir);\r\n\tif (allBots.length === 1)\r\n\t{\r\n\t\treturn allBots[0]!;\r\n\t}\r\n\tif (allBots.length > 1)\r\n\t{\r\n\t\tconst list = allBots.map((b) => ` --bot ${path.relative(absDir, b.sourcePath).replace(/\\\\/g, '/')} (${b.exportName})`).join('\\n');\r\n\t\tthrow new Error(\r\n\t\t\t`Found ${allBots.length} bots. Pick one with --bot:\\n\\n${list}`,\r\n\t\t);\r\n\t}\r\n\r\n\t// No bots auto-discovered. If src/bot.ts exists, try it directly\r\n\t// so the user gets a specific error (e.g. \"no PascalCase export\").\r\n\tconst defaultPath = path.join(absDir, 'src', 'bot.ts');\r\n\tif (fs.existsSync(defaultPath))\r\n\t{\r\n\t\tconst exportName = await findExportName(defaultPath);\r\n\t\treturn {sourcePath: defaultPath, exportName};\r\n\t}\r\n\r\n\tthrow new Error(\r\n\t\t'Could not find bot source file.\\n'\r\n\t\t+ 'Create a .ts file in src/ with a PascalCase export, e.g.:\\n'\r\n\t\t+ ' export function MyWizard() { ... }',\r\n\t);\r\n}\r\n\r\n/**\r\n * Find the first named export from a TypeScript file.\r\n * Uses a simple regex scan — no full parser needed.\r\n */\r\nasync function findExportName(filePath: string): Promise<string>\r\n{\r\n\tconst content = fs.readFileSync(filePath, 'utf-8');\r\n\r\n\t// Match: export function Foo, export const Foo, export class Foo\r\n\tconst match = content.match(/export\\s+(?:function|const|class)\\s+([A-Z]\\w*)/);\r\n\tif (match?.[1])\r\n\t{\r\n\t\treturn match[1];\r\n\t}\r\n\r\n\t// Match: export { Foo }\r\n\tconst reExport = content.match(/export\\s*\\{\\s*([A-Z]\\w*)/);\r\n\tif (reExport?.[1])\r\n\t{\r\n\t\treturn reExport[1];\r\n\t}\r\n\r\n\tthrow new Error(\r\n\t\t`Could not find a named export in ${filePath}.\\n`\r\n\t\t+ 'Bot export must start with a capital letter (PascalCase).\\n'\r\n\t\t+ 'Example: export function MyWizard() { ... }',\r\n\t);\r\n}\r\n\r\nconst SCAN_SKIP_FILE_PATTERNS = [\r\n\t/\\.d\\.ts$/,\r\n\t/\\.test\\.tsx?$/,\r\n\t/\\.spec\\.tsx?$/,\r\n];\r\nconst SCAN_SKIP_DIR_NAMES = new Set([\r\n\t'node_modules',\r\n\t'dist',\r\n\t'build',\r\n\t'.cache',\r\n\t'.turbo',\r\n\t'__tests__',\r\n]);\r\nconst SCAN_SKIP_FILE_NAMES = new Set([\r\n\t'index.ts', 'index.tsx',\r\n\t'types.ts', 'types.tsx',\r\n\t'helpers.ts', 'helpers.tsx',\r\n]);\r\n\r\nfunction listTsFilesRecursively(rootDir: string): string[]\r\n{\r\n\tconst out: string[] = [];\r\n\tconst stack: string[] = [rootDir];\r\n\twhile (stack.length > 0)\r\n\t{\r\n\t\tconst dir = stack.pop();\r\n\t\tif (dir === undefined) continue;\r\n\t\tlet entries: fs.Dirent[];\r\n\t\ttry\r\n\t\t{\r\n\t\t\tentries = fs.readdirSync(dir, {withFileTypes: true});\r\n\t\t}\r\n\t\tcatch\r\n\t\t{\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tfor (const entry of entries)\r\n\t\t{\r\n\t\t\tconst full = path.join(dir, entry.name);\r\n\t\t\tif (entry.isDirectory())\r\n\t\t\t{\r\n\t\t\t\tif (SCAN_SKIP_DIR_NAMES.has(entry.name)) continue;\r\n\t\t\t\tif (entry.name.startsWith('.')) continue;\r\n\t\t\t\tstack.push(full);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (!entry.isFile()) continue;\r\n\t\t\tif (!entry.name.endsWith('.ts') && !entry.name.endsWith('.tsx')) continue;\r\n\t\t\tif (SCAN_SKIP_FILE_NAMES.has(entry.name)) continue;\r\n\t\t\tif (SCAN_SKIP_FILE_PATTERNS.some((re) => re.test(entry.name))) continue;\r\n\t\t\tout.push(full);\r\n\t\t}\r\n\t}\r\n\treturn out;\r\n}\r\n\r\n/**\r\n * Discover every bot in the project's src/ tree. One file → one bot\r\n * (using its first PascalCase named export). Files without a qualifying\r\n * export are skipped. Returns BotInfo[] sorted alphabetically by export\r\n * name; the array is empty if nothing was found (callers should treat\r\n * that as \"no local bots\", not an error).\r\n *\r\n * Used by the dev server to expose every in-development bot to the web\r\n * client. Single-bot commands (upload, fight, build) still go through\r\n * discoverBot() with its --bot/--export overrides.\r\n */\r\nexport async function discoverAllBots(projectDir: string): Promise<BotInfo[]>\r\n{\r\n\tconst absDir = path.resolve(projectDir);\r\n\tconst srcDir = path.join(absDir, 'src');\r\n\tif (!fs.existsSync(srcDir)) return [];\r\n\r\n\tconst files = listTsFilesRecursively(srcDir);\r\n\tconst bots: BotInfo[] = [];\r\n\tconst seenNames = new Set<string>();\r\n\tfor (const file of files)\r\n\t{\r\n\t\tlet exportName: string;\r\n\t\ttry\r\n\t\t{\r\n\t\t\texportName = await findExportName(file);\r\n\t\t}\r\n\t\tcatch\r\n\t\t{\r\n\t\t\tcontinue; // file has no PascalCase export — not a bot\r\n\t\t}\r\n\t\tif (seenNames.has(exportName)) continue; // duplicate name — keep the first\r\n\t\tseenNames.add(exportName);\r\n\t\tbots.push({sourcePath: file, exportName});\r\n\t}\r\n\tbots.sort((a, b) => a.exportName.localeCompare(b.exportName));\r\n\treturn bots;\r\n}\r\n","/**\n * Dev Server\n *\n * HTTP server with CORS that exposes every locally-developed bot in the\n * project's src/ tree to the VibeMancer web client. Each request compiles\n * the requested bot fresh from source — no caching — so a browser refresh\n * always picks up the latest code.\n *\n * Endpoints:\n * GET /local-bots → {bots: [{name, exportName, sourcePath}]}\n * GET /local-bots/:name/bundle → IIFE bundle setting __injectedBot1\n * GET /health → {status: 'ok'}\n *\n * The web client picks this up via the #botserver=localhost:PORT URL\n * hash and renders the local bots in WizardSourceSelector's \"Local\"\n * tab — usable as either combatant in Arena fights and as the\n * opponent in Manual Play.\n */\n\nimport http from 'node:http';\nimport {discoverAllBots, type BotInfo} from './bot-discovery.js';\nimport {compileSingleBotBundle} from './compile-single-bot.js';\n\nexport interface ServerOptions\n{\n\tport: number;\n\tprojectDir: string;\n}\n\ninterface LocalBotsResponse\n{\n\tbots: {\n\t\tname: string;\n\t\texportName: string;\n\t\tsourcePath: string;\n\t}[];\n}\n\nfunction botInfoToWire(info: BotInfo): LocalBotsResponse['bots'][number]\n{\n\treturn {\n\t\tname: info.exportName,\n\t\texportName: info.exportName,\n\t\tsourcePath: info.sourcePath,\n\t};\n}\n\n/**\n * Start the dev server.\n * Returns the running server instance.\n */\nexport function startServer(options: ServerOptions): http.Server\n{\n\tconst {port, projectDir} = options;\n\n\tasync function loadBots(): Promise<BotInfo[]>\n\t{\n\t\t// Re-scan on every request so newly-added bot files are picked up\n\t\t// without having to restart the server. Discovery is cheap (regex\n\t\t// scan of src/), so this is fine.\n\t\treturn discoverAllBots(projectDir);\n\t}\n\n\tconst server = http.createServer(async(req, res) =>\n\t{\n\t\t// CORS — the hosted viewer at vibemancer.com has to be able to call us\n\t\tres.setHeader('Access-Control-Allow-Origin', '*');\n\t\tres.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n\t\tres.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n\t\tif (req.method === 'OPTIONS')\n\t\t{\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url ?? '/', `http://localhost:${port}`);\n\t\tconst pathname = url.pathname;\n\n\t\ttry\n\t\t{\n\t\t\tif (pathname === '/health')\n\t\t\t{\n\t\t\t\trespond(res, 200, {status: 'ok'});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pathname === '/local-bots')\n\t\t\t{\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst body: LocalBotsResponse = {bots: bots.map(botInfoToWire)};\n\t\t\t\trespond(res, 200, body);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bundleMatch = /^\\/local-bots\\/([A-Za-z_][A-Za-z0-9_]*)\\/bundle$/.exec(pathname);\n\t\t\tif (bundleMatch)\n\t\t\t{\n\t\t\t\tconst requestedName = bundleMatch[1]!;\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst target = bots.find((b) => b.exportName === requestedName);\n\t\t\t\tif (!target)\n\t\t\t\t{\n\t\t\t\t\trespond(res, 404, {error: `No local bot named \"${requestedName}\". Found: ${bots.map((b) => b.exportName).join(', ') || '(none)'}`});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst start = Date.now();\n\t\t\t\tconst bundle = await compileSingleBotBundle(target.sourcePath, target.exportName);\n\t\t\t\tconst elapsed = Date.now() - start;\n\t\t\t\tconsole.log(` Compiled ${target.exportName} (${(bundle.length / 1024).toFixed(1)} KB) in ${elapsed}ms`);\n\n\t\t\t\tres.writeHead(200, {'Content-Type': 'text/javascript'});\n\t\t\t\tres.end(bundle);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trespond(res, 404, {error: `Not found: ${pathname}`});\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(` Error: ${message}`);\n\t\t\trespond(res, 500, {error: message});\n\t\t}\n\t});\n\n\tserver.listen(port, () =>\n\t{\n\t\tconsole.log(`\\nVibemancer dev server running at http://localhost:${port}`);\n\t\tvoid (async(): Promise<void> =>\n\t\t{\n\t\t\tconst bots = await loadBots();\n\t\t\tif (bots.length === 0)\n\t\t\t{\n\t\t\t\tconsole.log(' (no bots discovered in src/ — add a .ts file with a PascalCase export)');\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconsole.log(` Bots: ${bots.map((b) => b.exportName).join(', ')}`);\n\t\t\t}\n\t\t\tconsole.log('');\n\t\t\tconsole.log('Open your browser to play:');\n\t\t\tconsole.log(` https://vibemancer.com/#botserver=localhost:${port}\\n`);\n\t\t\tconsole.log('Endpoints:');\n\t\t\tconsole.log(' GET /local-bots - List of locally-discovered bots');\n\t\t\tconsole.log(' GET /local-bots/<name>/bundle - Compile a single bot to a sandbox-ready bundle');\n\t\t\tconsole.log(' GET /health - Server health check\\n');\n\t\t})();\n\t});\n\n\treturn server;\n}\n\nfunction respond(res: http.ServerResponse, status: number, data: unknown): void\n{\n\tres.writeHead(status, {'Content-Type': 'application/json'});\n\tres.end(JSON.stringify(data));\n}\n","/**\n * Compile a single bot to a self-contained IIFE bundle.\n *\n * The output sets `globalThis.__injectedBot1` to the bot's exported function.\n * This is the canonical \"uploaded wizard\" bundle shape — the same format the\n * Storage-uploaded wizards live in, the same format the fight-runner /\n * BrowserMatchSandbox concatenates with MATCH_TEMPLATE / MANUAL_MATCH_TEMPLATE.\n *\n * Used by:\n * - `vibemancer upload` (CLI) — uploads to Firebase Storage\n * - dev server's /local-bots/:name/bundle endpoint — served to the web\n * client when picking a local bot\n *\n * `@vibemancer/core` is aliased to the package's TypeScript source (mirroring\n * seed-bots.ts) so the bundle is fully self-contained — no runtime shims, no\n * CJS `require()`, just an IIFE that runs anywhere a Web Worker can.\n */\n\nimport {build} from 'esbuild';\nimport {findCoreSourceDir} from './opponent-resolver.js';\n\nexport async function compileSingleBotBundle(\n\tsourcePath: string,\n\texportName: string,\n): Promise<string>\n{\n\tconst coreSourceDir = findCoreSourceDir();\n\n\tconst result = await build({\n\t\tentryPoints: [sourcePath],\n\t\tbundle: true,\n\t\twrite: false,\n\t\tformat: 'iife',\n\t\tglobalName: '__botExport',\n\t\tplatform: 'neutral',\n\t\ttarget: 'es2022',\n\t\tlogLevel: 'error',\n\t\tfooter: {js: `globalThis.__injectedBot1 = __botExport.${exportName};`},\n\t\texternal: [\n\t\t\t'isolated-vm', 'esbuild',\n\t\t\t'node:*',\n\t\t],\n\t\talias: {\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\n\t\t},\n\t});\n\n\tif (!result.outputFiles?.[0])\n\t{\n\t\tthrow new Error('esbuild produced no output');\n\t}\n\n\treturn result.outputFiles[0].text;\n}\n","/**\n * vibemancer test\n *\n * Runs the user's vitest test suite. Scaffolded projects include a\n * tests/ directory with example tests using the testBot() helper.\n */\n\nimport {spawn} from 'node:child_process';\n\nexport interface TestOptions\n{\n\tbot?: string;\n}\n\nexport async function runTest(_options: TestOptions): Promise<void>\n{\n\tconsole.log('\\n Running tests...\\n');\n\n\t// spawn + await, NOT execSync. execSync blocks the entire event loop, and the CLI fires\n\t// a fire-and-forget telemetry request at command start: while the loop is blocked that\n\t// request cannot progress, and its 1s abort then fires the moment the block ends, so it\n\t// is cancelled before ever being sent. `test` was the ONE local command missing from\n\t// the analytics, which is how this was found. Blocking also stops any other timer or\n\t// I/O the CLI may rely on later, so this is not only about telemetry.\n\tconst code = await new Promise<number>((resolve) =>\n\t{\n\t\tconst child = spawn('npx', ['vitest', 'run'], {\n\t\t\tstdio: 'inherit',\n\t\t\tcwd: process.cwd(),\n\t\t\tshell: process.platform === 'win32',\n\t\t});\n\t\tchild.on('error', () => resolve(1));\n\t\tchild.on('close', (status) => resolve(status ?? 1));\n\t});\n\n\tif (code !== 0)\n\t{\n\t\tprocess.exit(code);\n\t}\n}\n","/**\r\n * vibemancer fight\r\n *\r\n * With no args: fights your bot against all 29 built-in bots and shows ranking.\r\n * With --opponent: quick fight against a single opponent.\r\n *\r\n * Results are saved to .vibemancer/history.json for comparison across runs.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {BotBundle, sandboxFight, scoreFight, runBundleFight} from '@vibemancer/core';\r\nimport type {FightWinner, FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface FightOptions\r\n{\r\n\topponent?: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n}\r\n\r\ninterface FightEntry\r\n{\r\n\topponent: string;\r\n\twinner: FightWinner;\r\n\twizard1Wins: number;\r\n\twizard2Wins: number;\r\n\tdraws: number;\r\n\tscore: number;\r\n\telapsedMs: number;\r\n}\r\n\r\ninterface HistoryEntry\r\n{\r\n\ttimestamp: string;\r\n\tbotName: string;\r\n\tresults: FightEntry[];\r\n\tsummary: {wins: number; losses: number; draws: number; score: number; maxScore: number};\r\n}\r\n\r\nexport async function runFight(options: FightOptions): Promise<void>\r\n{\r\n\tif (options.opponent)\r\n\t{\r\n\t\treturn runSingleFight({...options, opponent: options.opponent});\r\n\t}\r\n\treturn runFullFight(options);\r\n}\r\n\r\n// ─── Single opponent fight ───────────────────────────────────────────────────\r\n\r\nasync function runSingleFight(options: FightOptions & {opponent: string}): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\r\n\tconsole.log(` Opponent: ${options.opponent}\\n`);\r\n\r\n\tconst start = Date.now();\r\n\tlet result: FightResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// run locally through the same isolated-vm engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleFight(userBundle, remote.bundle, {seed: options.seed ?? 1});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxFight(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\tconst elapsed = Date.now() - start;\r\n\r\n\tconst {wizard1Wins, wizard2Wins, draws} = result;\r\n\tconst total = wizard1Wins + wizard2Wins + draws;\r\n\tconst outcome = result.winner === 'wizard-1' ? 'WIN'\r\n\t\t: result.winner === 'wizard-2' ? 'LOSS'\r\n\t\t\t: 'DRAW';\r\n\r\n\tconsole.log(` Result: ${outcome}`);\r\n\tconsole.log(` ${botInfo.exportName}: ${wizard1Wins}W | ${options.opponent}: ${wizard2Wins}W | Draws: ${draws}`);\r\n\tconsole.log(` (${total} matches in ${elapsed}ms)\\n`);\r\n\r\n\tif (result.winner === 'wizard-2')\r\n\t{\r\n\t\tprocess.exit(1);\r\n\t}\r\n}\r\n\r\n// ─── Full fight (all built-in bots) ─────────────────────────────────────────\r\n\r\nasync function runFullFight(options: FightOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\tconst opponents = getBuiltinBotNames();\r\n\tconsole.log(`\\n Fighting ${botInfo.exportName} against ${opponents.length} built-in bots...\\n`);\r\n\r\n\tconst entries: FightEntry[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const opponentName of opponents)\r\n\t{\r\n\t\tconst opponentBundle = resolveOpponent(opponentName);\r\n\t\tconst start = Date.now();\r\n\t\tconst result = await sandboxFight(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tconst elapsed = Date.now() - start;\r\n\t\tconst score = scoreFight(result);\r\n\r\n\t\tentries.push({\r\n\t\t\topponent: opponentName,\r\n\t\t\twinner: result.winner,\r\n\t\t\twizard1Wins: result.wizard1Wins,\r\n\t\t\twizard2Wins: result.wizard2Wins,\r\n\t\t\tdraws: result.draws,\r\n\t\t\tscore,\r\n\t\t\telapsedMs: elapsed,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? 'W'\r\n\t\t\t: result.winner === 'wizard-2' ? 'L'\r\n\t\t\t\t: 'D';\r\n\t\tconst pad = opponentName.padEnd(14);\r\n\t\tconsole.log(` ${pad} ${outcome} ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${elapsed}ms)`);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\tconst wins = entries.filter((e) => e.winner === 'wizard-1').length;\r\n\tconst losses = entries.filter((e) => e.winner === 'wizard-2').length;\r\n\tconst drawCount = entries.filter((e) => e.winner === 'draw').length;\r\n\tconst totalScore = entries.reduce((sum, e) => sum + e.score, 0);\r\n\tconst maxScore = opponents.length * 17.5; // 5 matches × 3.5 max per match per opponent\r\n\r\n\tconsole.log(`\\n Summary: ${wins}W ${losses}L ${drawCount}D out of ${opponents.length} opponents`);\r\n\tconsole.log(` Score: ${totalScore.toFixed(1)} / ${maxScore.toFixed(1)} (${((totalScore / maxScore) * 100).toFixed(1)}%)`);\r\n\tconsole.log(` Total time: ${(totalElapsed / 1000).toFixed(1)}s`);\r\n\r\n\t// Load previous results and show diff\r\n\tconst history = loadHistory(projectDir);\r\n\tconst previous = history.length > 0 ? history[history.length - 1]! : null;\r\n\r\n\tif (previous && previous.botName === botInfo.exportName)\r\n\t{\r\n\t\tshowDiff(entries, previous.results);\r\n\t}\r\n\r\n\t// Save current results\r\n\tconst current: HistoryEntry = {\r\n\t\ttimestamp: new Date().toISOString(),\r\n\t\tbotName: botInfo.exportName,\r\n\t\tresults: entries,\r\n\t\tsummary: {wins, losses, draws: drawCount, score: totalScore, maxScore},\r\n\t};\r\n\tsaveHistory(projectDir, history, current);\r\n\tconsole.log('');\r\n}\r\n\r\n// ─── History persistence ─────────────────────────────────────────────────────\r\n\r\nfunction getHistoryPath(projectDir: string): string\r\n{\r\n\treturn path.join(projectDir, '.vibemancer', 'history.json');\r\n}\r\n\r\nfunction loadHistory(projectDir: string): HistoryEntry[]\r\n{\r\n\tconst historyPath = getHistoryPath(projectDir);\r\n\tif (!fs.existsSync(historyPath)) return [];\r\n\ttry\r\n\t{\r\n\t\tconst raw = fs.readFileSync(historyPath, 'utf-8');\r\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- JSON file we wrote\r\n\t\treturn JSON.parse(raw) as HistoryEntry[];\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\treturn [];\r\n\t}\r\n}\r\n\r\nfunction saveHistory(projectDir: string, history: HistoryEntry[], current: HistoryEntry): void\r\n{\r\n\tconst historyPath = getHistoryPath(projectDir);\r\n\tconst dir = path.dirname(historyPath);\r\n\tfs.mkdirSync(dir, {recursive: true});\r\n\r\n\t// Keep last 20 runs\r\n\tconst updated = [...history.slice(-19), current];\r\n\tfs.writeFileSync(historyPath, JSON.stringify(updated, null, '\\t') + '\\n');\r\n}\r\n\r\nfunction showDiff(current: FightEntry[], previous: FightEntry[]): void\r\n{\r\n\tconst prevMap = new Map(previous.map((e) => [e.opponent, e]));\r\n\tconst changes: string[] = [];\r\n\r\n\tfor (const entry of current)\r\n\t{\r\n\t\tconst prev = prevMap.get(entry.opponent);\r\n\t\tif (!prev) continue;\r\n\r\n\t\tconst prevOutcome = prev.winner === 'wizard-1' ? 'W' : prev.winner === 'wizard-2' ? 'L' : 'D';\r\n\t\tconst curOutcome = entry.winner === 'wizard-1' ? 'W' : entry.winner === 'wizard-2' ? 'L' : 'D';\r\n\r\n\t\tif (prevOutcome !== curOutcome)\r\n\t\t{\r\n\t\t\tchanges.push(` ${entry.opponent.padEnd(14)} ${prevOutcome} -> ${curOutcome}`);\r\n\t\t}\r\n\t}\r\n\r\n\tconst prevScore = previous.reduce((sum, e) => sum + e.score, 0);\r\n\tconst curScore = current.reduce((sum, e) => sum + e.score, 0);\r\n\tconst diff = curScore - prevScore;\r\n\r\n\tif (changes.length > 0 || Math.abs(diff) > 0.1)\r\n\t{\r\n\t\tconsole.log('\\n vs last run:');\r\n\t\tif (Math.abs(diff) > 0.1)\r\n\t\t{\r\n\t\t\tconst sign = diff > 0 ? '+' : '';\r\n\t\t\tconsole.log(` Score: ${sign}${diff.toFixed(1)}`);\r\n\t\t}\r\n\t\tfor (const change of changes)\r\n\t\t{\r\n\t\t\tconsole.log(change);\r\n\t\t}\r\n\t}\r\n}\r\n","/**\n * Resolve a `handle/botname` selector to a downloaded, ready-to-run opponent\n * bundle — so the devkit can fight any user's uploaded bot, identically to the\n * MCP fight tool and the live ladder.\n *\n * All reads are PUBLIC (no login): the wizards collection is world-readable and\n * compiled bundles in Storage are public (required for browser spectating), so\n * resolution + download need no auth. The fight then runs locally via core's\n * runBundleFight — the same isolated-vm engine the matchmaker uses.\n */\n\nimport {initializeApp, getApps, type FirebaseApp} from 'firebase/app';\nimport {getFirestore, collection, query, where, limit, getDocs, connectFirestoreEmulator, type Firestore} from 'firebase/firestore';\nimport {getStorage, ref, getBytes, connectStorageEmulator, type FirebaseStorage} from 'firebase/storage';\nimport {isBannedBotName} from '@vibemancer/core';\nimport {FIREBASE_CONFIG} from './firebase-config.js';\n\nexport interface RemoteOpponent\n{\n\tbundle: string;\n\texportName: string;\n\tlabel: string;\n}\n\n/** True when the opponent string is a `handle/botname` selector (vs a built-in name). */\nexport function isHandleSelector(opponent: string): boolean\n{\n\tconst trimmed = opponent.trim();\n\tconst slash = trimmed.indexOf('/');\n\treturn slash > 0 && slash < trimmed.length - 1;\n}\n\nlet cachedDb: Firestore | null = null;\nlet cachedStorage: FirebaseStorage | null = null;\n\nfunction getApp(): FirebaseApp\n{\n\tconst apps = getApps();\n\treturn apps.length > 0 ? apps[0]! : initializeApp(FIREBASE_CONFIG);\n}\n\n/** Talk to the local emulator instead of prod when VIBEMANCER_EMULATOR=1 (E2E tests). */\nfunction getDb(): Firestore\n{\n\tif (!cachedDb)\n\t{\n\t\tcachedDb = getFirestore(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectFirestoreEmulator(cachedDb, '127.0.0.1', 8085);\n\t}\n\treturn cachedDb;\n}\n\nfunction getBucket(): FirebaseStorage\n{\n\tif (!cachedStorage)\n\t{\n\t\tcachedStorage = getStorage(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectStorageEmulator(cachedStorage, '127.0.0.1', 9199);\n\t}\n\treturn cachedStorage;\n}\n\nexport async function resolveRemoteOpponent(selector: string): Promise<RemoteOpponent>\n{\n\tconst slash = selector.indexOf('/');\n\tconst handle = selector.slice(0, slash).trim().toLowerCase();\n\tconst botName = selector.slice(slash + 1).trim();\n\tif (!handle || !botName)\n\t{\n\t\tthrow new Error(`Invalid opponent \"${selector}\" — expected handle/botname (e.g. happy-golden-banana/FireMage).`);\n\t}\n\t// A filtered (banned) name resolves to nothing — same message as not-found.\n\tif (isBannedBotName(botName))\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst db = getDb();\n\tconst snap = await getDocs(query(\n\t\tcollection(db, 'wizards'),\n\t\twhere('ownerHandle', '==', handle),\n\t\twhere('nameLower', '==', botName.toLowerCase()),\n\t\twhere('active', '==', true),\n\t\tlimit(1),\n\t));\n\tif (snap.empty)\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst docSnap = snap.docs[0]!;\n\tconst data = docSnap.data() as {exportName?: unknown; bundlePath?: unknown};\n\tconst exportName = typeof data.exportName === 'string' ? data.exportName : '';\n\tif (!exportName)\n\t{\n\t\tthrow new Error(`Bot \"${handle}/${botName}\" is missing its export name.`);\n\t}\n\tconst bundlePath = typeof data.bundlePath === 'string' ? data.bundlePath : `bundles/${docSnap.id}.js`;\n\n\tconst bytes = await getBytes(ref(getBucket(), bundlePath));\n\tconst bundle = new TextDecoder().decode(bytes);\n\n\treturn {bundle, exportName, label: `${handle}/${botName}`};\n}\n","/**\r\n * vibemancer trace\r\n *\r\n * Runs a single match and prints a full event trace for debugging.\r\n * Shows both bots' actions: state changes, missile launches (with config),\r\n * hits, damage, dodge proximity, movement patterns, and stats.\r\n */\r\n\r\nimport {\r\n\tBotBundle, sandboxSimulate, runBundleSimulate,\r\n\textractTraceEvents, summarizeTrace, formatTraceEvents, formatTraceSummary,\r\n\tdiagnoseTrace, formatDiagnosis,\r\n\textractStats, formatStats,\r\n} from '@vibemancer/core';\r\nimport type {SimulateResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface TraceOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n\tdistance?: number;\r\n\tmaxTicks?: number;\r\n}\r\n\r\nexport async function runTrace(options: TraceOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst distance = options.distance ?? 600;\r\n\tconsole.log(`\\n Trace: ${botInfo.exportName} (W1) vs ${options.opponent} (W2) | distance: ${distance} | seed: ${options.seed ?? 1}\\n`);\r\n\r\n\tlet result: SimulateResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// simulate locally through the same engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleSimulate(userBundle, remote.bundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxSimulate(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\r\n\tconst history = result.history;\r\n\tif (history.length === 0)\r\n\t{\r\n\t\tconsole.log(' No history available.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Extract and print full event trace (including any bot runtime errors)\r\n\tconst events = extractTraceEvents(history, result.errors);\r\n\tconsole.log(formatTraceEvents(events));\r\n\r\n\t// Print summary (both bots)\r\n\tconst summary = summarizeTrace(events, result, botInfo.exportName, options.opponent);\r\n\tconsole.log('\\n' + formatTraceSummary(summary));\r\n\r\n\t// Print detailed stats for the user's bot\r\n\tconst stats = extractStats(result);\r\n\tconsole.log('');\r\n\tconsole.log(formatStats(stats, botInfo.exportName));\r\n\r\n\t// Print auto-diagnosis (tips for common problems)\r\n\tconst tips = diagnoseTrace(events, summary);\r\n\tif (tips.length > 0)\r\n\t{\r\n\t\tconsole.log('');\r\n\t\tconsole.log(formatDiagnosis(tips));\r\n\t}\r\n\tconsole.log('');\r\n}\r\n","/**\r\n * vibemancer tournament\r\n *\r\n * Runs the user's bot in a round-robin tournament against selected opponents.\r\n * Each pairing is a fight (10 matches: 5 spawn distances × 2 sides).\r\n */\r\n\r\nimport {BotBundle, sandboxFight, scoreFight, scoreFightAsWizard2} from '@vibemancer/core';\r\nimport type {FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface TournamentOptions\r\n{\r\n\topponents?: string[];\r\n\tbot?: string;\r\n}\r\n\r\ninterface Pairing\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tbot1Bundle: BotBundle;\r\n\tbot2Bundle: BotBundle;\r\n}\r\n\r\ninterface PairingResult\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tresult: FightResult;\r\n}\r\n\r\nexport async function runTournament(options: TournamentOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\t// Determine opponents\r\n\tconst opponentNames = options.opponents && options.opponents.length > 0\r\n\t\t? options.opponents\r\n\t\t: getBuiltinBotNames();\r\n\r\n\t// Build list of all participants\r\n\tconst participants: {name: string; bundle: BotBundle}[] = [\r\n\t\t{name: botInfo.exportName, bundle: userBundle},\r\n\t];\r\n\r\n\tfor (const name of opponentNames)\r\n\t{\r\n\t\tparticipants.push({name, bundle: resolveOpponent(name)});\r\n\t}\r\n\r\n\tconsole.log(`\\n Tournament: ${participants.length} participants (${participants.length * (participants.length - 1) / 2} pairings)\\n`);\r\n\r\n\t// Generate all pairings\r\n\tconst pairings: Pairing[] = [];\r\n\tfor (let i = 0; i < participants.length; i++)\r\n\t{\r\n\t\tfor (let j = i + 1; j < participants.length; j++)\r\n\t\t{\r\n\t\t\tpairings.push({\r\n\t\t\t\tbot1Name: participants[i]!.name,\r\n\t\t\t\tbot2Name: participants[j]!.name,\r\n\t\t\t\tbot1Bundle: participants[i]!.bundle,\r\n\t\t\t\tbot2Bundle: participants[j]!.bundle,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t// Run all fights\r\n\tconst results: PairingResult[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const pairing of pairings)\r\n\t{\r\n\t\tconst result = await sandboxFight(pairing.bot1Bundle, pairing.bot2Bundle, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tresults.push({\r\n\t\t\tbot1Name: pairing.bot1Name,\r\n\t\t\tbot2Name: pairing.bot2Name,\r\n\t\t\tresult,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? `${pairing.bot1Name} wins`\r\n\t\t\t: result.winner === 'wizard-2' ? `${pairing.bot2Name} wins`\r\n\t\t\t\t: 'Draw';\r\n\t\tconsole.log(` ${pairing.bot1Name} vs ${pairing.bot2Name}: ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${outcome})`);\r\n\t}\r\n\r\n\t// Calculate standings\r\n\tconst points = new Map<string, number>();\r\n\tconst wins = new Map<string, number>();\r\n\r\n\tfor (const p of participants)\r\n\t{\r\n\t\tpoints.set(p.name, 0);\r\n\t\twins.set(p.name, 0);\r\n\t}\r\n\r\n\tfor (const r of results)\r\n\t{\r\n\t\tconst score1 = scoreFight(r.result);\r\n\t\tconst score2 = scoreFightAsWizard2(r.result);\r\n\r\n\t\tpoints.set(r.bot1Name, (points.get(r.bot1Name) ?? 0) + score1);\r\n\t\tpoints.set(r.bot2Name, (points.get(r.bot2Name) ?? 0) + score2);\r\n\t\twins.set(r.bot1Name, (wins.get(r.bot1Name) ?? 0) + r.result.wizard1Wins);\r\n\t\twins.set(r.bot2Name, (wins.get(r.bot2Name) ?? 0) + r.result.wizard2Wins);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\r\n\t// Sort standings by points desc, then wins desc\r\n\tconst standings = [...points.entries()].sort((a, b) =>\r\n\t{\r\n\t\tif (b[1] !== a[1]) return b[1] - a[1];\r\n\t\treturn (wins.get(b[0]) ?? 0) - (wins.get(a[0]) ?? 0);\r\n\t});\r\n\r\n\tconsole.log('\\n Standings:');\r\n\tconsole.log(' ' + '-'.repeat(40));\r\n\tfor (let i = 0; i < standings.length; i++)\r\n\t{\r\n\t\tconst [name, pts] = standings[i]!;\r\n\t\tconst w = wins.get(name) ?? 0;\r\n\t\tconst rank = `#${(i + 1).toString().padStart(2)}`;\r\n\t\tconst isUser = name === botInfo.exportName ? ' *' : '';\r\n\t\tconsole.log(` ${rank} ${name.padEnd(16)} ${pts.toFixed(1)} pts ${w}W${isUser}`);\r\n\t}\r\n\r\n\tconsole.log(`\\n Total time: ${(totalElapsed / 1000).toFixed(1)}s\\n`);\r\n}\r\n","/**\r\n * vibemancer optimize\r\n *\r\n * Runs parameter optimization for the user's bot.\r\n * Scans for useParam() calls, runs coordinate descent against\r\n * all built-in opponents, and rewrites source with optimal values.\r\n */\r\n\r\nimport {readFileSync, writeFileSync} from 'node:fs';\r\nimport {BotBundle, MatchSandbox, scoreFight, generateCandidates, getEffectiveRange} from '@vibemancer/core';\r\nimport type {FightResult, FightWinner, SimulateResult, ParamDeclaration} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface OptimizeOptions\r\n{\r\n\tbot?: string;\r\n\tsteps?: number;\r\n\trounds?: number;\r\n\topponents?: string[];\r\n}\r\n\r\nexport interface ParsedParam\r\n{\r\n\tname: string;\r\n\tdefaultValue: number;\r\n\tmin?: number;\r\n\tmax?: number;\r\n\tstep?: number;\r\n}\r\n\r\n// Parser-style capture: grab everything until the next , or ) instead of matching specific number formats.\r\n// This handles integers, floats, scientific notation (1e-5), negative numbers, etc.\r\nconst USEPAR_RE = /useParam\\(\\s*['\"](\\w+)['\"]\\s*,\\s*([^,)]+?)\\s*(?:,\\s*\\{([^}]*)\\})?\\s*\\)/g;\r\n\r\nfunction parseNumValue(s: string): number\r\n{\r\n\tconst n = parseFloat(s.trim());\r\n\tif (Number.isNaN(n)) throw new Error(`useParam default is not a number: \"${s.trim()}\"`);\r\n\treturn n;\r\n}\r\n\r\nexport function parseParams(source: string): ParsedParam[]\r\n{\r\n\tconst params: ParsedParam[] = [];\r\n\tconst re = new RegExp(USEPAR_RE.source, 'g');\r\n\tlet match: RegExpExecArray | null;\r\n\r\n\twhile ((match = re.exec(source)) !== null)\r\n\t{\r\n\t\tconst name = match[1]!;\r\n\t\tconst defaultValue = parseNumValue(match[2]!);\r\n\t\tconst optsStr = match[3];\r\n\r\n\t\tlet min: number | undefined;\r\n\t\tlet max: number | undefined;\r\n\t\tlet step: number | undefined;\r\n\r\n\t\tif (optsStr)\r\n\t\t{\r\n\t\t\tconst minMatch = optsStr.match(/min\\s*:\\s*([^,}]+)/);\r\n\t\t\tconst maxMatch = optsStr.match(/max\\s*:\\s*([^,}]+)/);\r\n\t\t\tconst stepMatch = optsStr.match(/step\\s*:\\s*([^,}]+)/);\r\n\t\t\tif (minMatch) min = parseNumValue(minMatch[1]!);\r\n\t\t\tif (maxMatch) max = parseNumValue(maxMatch[1]!);\r\n\t\t\tif (stepMatch) step = parseNumValue(stepMatch[1]!);\r\n\t\t}\r\n\r\n\t\tparams.push({name, defaultValue, min, max, step});\r\n\t}\r\n\r\n\treturn params;\r\n}\r\n\r\nfunction toParamDeclaration(p: ParsedParam): ParamDeclaration\r\n{\r\n\treturn {\r\n\t\tname: p.name,\r\n\t\tvalue: p.defaultValue,\r\n\t\tmin: p.min,\r\n\t\tmax: p.max,\r\n\t\tsteps: p.step ?? 5,\r\n\t};\r\n}\r\n\r\n/**\r\n * Run a full fight (10 matches: 5 spawn distances × 2 sides)\r\n * using sandbox.simulate() with param overrides.\r\n */\r\nconst SPAWN_DISTANCES = [200, 300, 400, 500, 600];\r\nconst SEEDS = [42, 137, 256];\r\n\r\nfunction runFightWithParams(\r\n\tsandbox: MatchSandbox,\r\n\tparams1: Record<string, number>,\r\n): FightResult\r\n{\r\n\tlet w1 = 0;\r\n\tlet w2 = 0;\r\n\tlet draws = 0;\r\n\tconst matches: SimulateResult[] = [];\r\n\r\n\tfor (const seed of SEEDS)\r\n\t{\r\n\t\tfor (const dist of SPAWN_DISTANCES)\r\n\t\t{\r\n\t\t\tconst r = sandbox.simulate({\r\n\t\t\t\tseed,\r\n\t\t\t\tspawnDistance: dist,\r\n\t\t\t\tskipHistory: true,\r\n\t\t\t\tparams1,\r\n\t\t\t});\r\n\t\t\tif (r.winner === 'wizard-1') w1++;\r\n\t\t\telse if (r.winner === 'wizard-2') w2++;\r\n\t\t\telse draws++;\r\n\r\n\t\t\tmatches.push(r);\r\n\t\t}\r\n\t}\r\n\r\n\treturn {\r\n\t\twizard1Wins: w1,\r\n\t\twizard2Wins: w2,\r\n\t\tdraws,\r\n\t\twinner: (w1 > w2 ? 'wizard-1' : w2 > w1 ? 'wizard-2' : 'draw') as FightWinner,\r\n\t\tmatches,\r\n\t};\r\n}\r\n\r\nasync function evaluateParams(\r\n\tuserBundle: BotBundle,\r\n\topponentBundles: BotBundle[],\r\n\tparams1: Record<string, number>,\r\n): Promise<number>\r\n{\r\n\tlet totalScore = 0;\r\n\tfor (const opponent of opponentBundles)\r\n\t{\r\n\t\tconst sandbox = await MatchSandbox.create(userBundle, opponent, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\ttry\r\n\t\t{\r\n\t\t\tconst result = runFightWithParams(sandbox, params1);\r\n\t\t\ttotalScore += scoreFight(result);\r\n\t\t}\r\n\t\tfinally\r\n\t\t{\r\n\t\t\tsandbox.dispose();\r\n\t\t}\r\n\t}\r\n\treturn totalScore;\r\n}\r\n\r\n/**\r\n * Resolve the opponent names to use for optimization.\r\n * If opponents are specified, validates them. Otherwise uses all built-in bots.\r\n */\r\nexport function resolveOpponentNames(opponents: string[] | undefined): string[]\r\n{\r\n\tif (!opponents || opponents.length === 0)\r\n\t{\r\n\t\treturn getBuiltinBotNames();\r\n\t}\r\n\r\n\t// Validate all names before starting\r\n\tconst allNames = getBuiltinBotNames();\r\n\tfor (const name of opponents)\r\n\t{\r\n\t\tif (!allNames.includes(name))\r\n\t\t{\r\n\t\t\tthrow new Error(\r\n\t\t\t\t`Unknown opponent: \"${name}\". Available bots:\\n ${allNames.join(', ')}`,\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\treturn opponents;\r\n}\r\n\r\nexport async function runOptimize(options: OptimizeOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst source = readFileSync(botInfo.sourcePath, 'utf-8');\r\n\tconst params = parseParams(source);\r\n\r\n\tif (params.length === 0)\r\n\t{\r\n\t\tconsole.log('\\n No useParam() calls found in your bot.');\r\n\t\tconsole.log(' Add useParam(\"paramName\", defaultValue, {min, max}) to enable optimization.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\r\n\tconsole.log(` Parameters: ${params.length}`);\r\n\tparams.forEach((p) => console.log(` ${p.name} = ${p.defaultValue} [${p.min ?? 'auto'} .. ${p.max ?? 'auto'}]`));\r\n\r\n\tconst steps = options.steps ?? 5;\r\n\tconst maxRounds = options.rounds ?? 3;\r\n\tconst opponentNames = resolveOpponentNames(options.opponents);\r\n\tconst opponentBundles = opponentNames.map((name) => resolveOpponent(name));\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\tconsole.log(` Opponents: ${opponentBundles.length}`);\r\n\tconsole.log(` Steps per param: ${steps}`);\r\n\tconsole.log(` Max rounds: ${maxRounds}\\n`);\r\n\r\n\t// Current best values\r\n\tconst best: Record<string, number> = {};\r\n\tfor (const p of params) best[p.name] = p.defaultValue;\r\n\r\n\t// Baseline score\r\n\tlet bestScore = await evaluateParams(userBundle, opponentBundles, best);\r\n\tconsole.log(` Baseline score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\r\n\r\n\t// Coordinate descent\r\n\tfor (let round = 0; round < maxRounds; round++)\r\n\t{\r\n\t\tlet improved = false;\r\n\t\tconsole.log(` Round ${round + 1}:`);\r\n\r\n\t\tfor (const p of params)\r\n\t\t{\r\n\t\t\tconst decl = toParamDeclaration(p);\r\n\t\t\tconst range = getEffectiveRange(decl);\r\n\t\t\tconst candidates = generateCandidates(range.min, range.max, steps);\r\n\r\n\t\t\tlet paramBest = best[p.name]!;\r\n\t\t\tlet paramBestScore = bestScore;\r\n\r\n\t\t\tfor (const candidate of candidates)\r\n\t\t\t{\r\n\t\t\t\tif (Math.abs(candidate - paramBest) < 0.001) continue;\r\n\r\n\t\t\t\tconst trial = {...best, [p.name]: candidate};\r\n\t\t\t\tconst score = await evaluateParams(userBundle, opponentBundles, trial);\r\n\r\n\t\t\t\tif (score > paramBestScore)\r\n\t\t\t\t{\r\n\t\t\t\t\tparamBest = candidate;\r\n\t\t\t\t\tparamBestScore = score;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (paramBest !== best[p.name])\r\n\t\t\t{\r\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} -> ${paramBest} (+${(paramBestScore - bestScore).toFixed(1)})`);\r\n\t\t\t\tbest[p.name] = paramBest;\r\n\t\t\t\tbestScore = paramBestScore;\r\n\t\t\t\timproved = true;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} (no improvement)`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!improved)\r\n\t\t{\r\n\t\t\tconsole.log(' No improvements found, stopping.\\n');\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tconsole.log(` Round ${round + 1} score: ${bestScore.toFixed(1)}\\n`);\r\n\t}\r\n\r\n\t// Rewrite source\r\n\tlet updated = source;\r\n\tfor (const p of params)\r\n\t{\r\n\t\tconst newVal = best[p.name]!;\r\n\t\tif (newVal !== p.defaultValue)\r\n\t\t{\r\n\t\t\tconst pattern = new RegExp(\r\n\t\t\t\t`(useParam\\\\(\\\\s*['\"]${escapeRegex(p.name)}['\"]\\\\s*,\\\\s*)${escapeRegex(String(p.defaultValue))}`,\r\n\t\t\t);\r\n\t\t\tupdated = updated.replace(pattern, `$1${newVal}`);\r\n\t\t}\r\n\t}\r\n\r\n\tif (updated !== source)\r\n\t{\r\n\t\twriteFileSync(botInfo.sourcePath, updated);\r\n\t\tconsole.log(` Source updated: ${botInfo.sourcePath}`);\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconsole.log(' No parameter changes to write.');\r\n\t}\r\n\r\n\tconsole.log(` Final score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\r\n}\r\n\r\nfunction escapeRegex(s: string): string\r\n{\r\n\treturn s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n","/**\r\n * vibemancer build\r\n *\r\n * Compiles the user's bot against an opponent into a standalone bundle.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {BotBundle, compileMatchBundle} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, findCoreSourceDir} from '../opponent-resolver.js';\r\n\r\nexport interface BuildOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\toutput?: string;\r\n}\r\n\r\nexport async function runBuild(options: BuildOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst coreSourceDir = findCoreSourceDir();\r\n\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\r\n\tconsole.log(`\\n Compiling ${botInfo.exportName} vs ${options.opponent}...`);\r\n\r\n\tconst start = Date.now();\r\n\tconst bundle = await compileMatchBundle(userBundle, opponentBundle, {\r\n\t\talias: {\r\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\r\n\t\t},\r\n\t});\r\n\tconst elapsed = Date.now() - start;\r\n\r\n\tconst outFile = options.output ?? `dist/${botInfo.exportName}-vs-${options.opponent}.js`;\r\n\tconst outDir = path.dirname(path.resolve(outFile));\r\n\tfs.mkdirSync(outDir, {recursive: true});\r\n\tfs.writeFileSync(path.resolve(outFile), bundle);\r\n\r\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\r\n\tconsole.log(` Output: ${outFile} (${sizeKb} KB)`);\r\n\tconsole.log(` Compiled in ${elapsed}ms\\n`);\r\n}\r\n","/**\r\n * vibemancer bots\r\n *\r\n * Lists all built-in bots with descriptions, grouped by archetype.\r\n * With --name: shows detailed info about a specific bot.\r\n */\r\n\r\nimport {BOT_GROUPS, ALL_BOTS} from '@vibemancer/core';\r\nimport type {WizardEntry} from '@vibemancer/core';\r\n\r\nexport interface BotsOptions\r\n{\r\n\tname?: string;\r\n}\r\n\r\nexport function runBots(options: BotsOptions): void\r\n{\r\n\tif (options.name)\r\n\t{\r\n\t\tshowBotDetail(options.name);\r\n\t\treturn;\r\n\t}\r\n\tlistAllBots();\r\n}\r\n\r\nfunction listAllBots(): void\r\n{\r\n\tconsole.log('\\n Built-in Bots (29 total, ranked weakest → strongest)\\n');\r\n\r\n\tfor (const group of BOT_GROUPS)\r\n\t{\r\n\t\tconsole.log(` ${group.label}:`);\r\n\t\tfor (const bot of group.bots)\r\n\t\t{\r\n\t\t\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\t\t\tconst tierLabel = bot.tier ? `T${bot.tier}` : ' ';\r\n\t\t\tconst rankStr = `#${String(rank).padStart(2)}`;\r\n\t\t\tconsole.log(` ${rankStr} ${tierLabel} ${bot.name.padEnd(14)} ${bot.description}`);\r\n\t\t}\r\n\t\tconsole.log('');\r\n\t}\r\n}\r\n\r\nfunction showBotDetail(name: string): void\r\n{\r\n\tconst bot = ALL_BOTS.find((b) => b.name.toLowerCase() === name.toLowerCase());\r\n\tif (!bot)\r\n\t{\r\n\t\tconst available = ALL_BOTS.map((b) => b.name).join(', ');\r\n\t\tconsole.error(`\\n Unknown bot: \"${name}\"\\n Available: ${available}\\n`);\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\r\n\tconsole.log(`\\n ${bot.name}`);\r\n\tconsole.log(` ${'─'.repeat(40)}`);\r\n\tconsole.log(` Rank: #${rank} of ${ALL_BOTS.length}`);\r\n\tconsole.log(` Group: ${bot.group}`);\r\n\tif (bot.tier) console.log(` Tier: ${bot.tier} of 3`);\r\n\tconsole.log(` Description: ${bot.description}`);\r\n\tconsole.log(` Style: ${getStyleDescription(bot)}`);\r\n\r\n\t// Show group progression if tiered\r\n\tif (bot.tier && bot.group !== 'Standalone')\r\n\t{\r\n\t\tconst groupBots = BOT_GROUPS.find((g) => g.label === bot.group)?.bots ?? [];\r\n\t\tif (groupBots.length > 1)\r\n\t\t{\r\n\t\t\tconsole.log(`\\n ${bot.group} progression:`);\r\n\t\t\tfor (const gb of groupBots)\r\n\t\t\t{\r\n\t\t\t\tconst gbRank = ALL_BOTS.indexOf(gb) + 1;\r\n\t\t\t\tconst marker = gb.name === bot.name ? ' ←' : '';\r\n\t\t\t\tconsole.log(` T${gb.tier} ${gb.name.padEnd(14)} #${gbRank} — ${gb.description}${marker}`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconsole.log(`\\n To fight: vibemancer fight --opponent ${bot.name}`);\r\n\tconsole.log(` To trace: vibemancer trace --opponent ${bot.name}\\n`);\r\n}\r\n\r\nfunction getStyleDescription(bot: WizardEntry): string\r\n{\r\n\tswitch (bot.group)\r\n\t{\r\n\t\tcase 'Standalone':\r\n\t\t\tif (bot.name === 'TargetDummy') return 'Does nothing. Use for basic testing.';\r\n\t\t\tif (bot.name === 'Critter') return 'Random actions. Tests handling of unpredictable opponents.';\r\n\t\t\tif (bot.name === 'Rookie') return 'Simple homing missiles. Good first benchmark.';\r\n\t\t\tif (bot.name === 'Hogger') return 'Random but with real damage. Chaos test.';\r\n\t\t\tif (bot.name === 'Doombringer') return 'One huge missile. Tests shield timing.';\r\n\t\t\treturn bot.description;\r\n\t\tcase 'Defensive': return 'Prioritizes shields and survival. Punishes aggression with counter-missiles. Weak to chip damage and shield baiting.';\r\n\t\tcase 'Melee': return 'Blinks in close, fires fast low-range stabs. Weak to kiting and ranged pressure.';\r\n\t\tcase 'Homing': return 'Slow tracking missiles that are hard to dodge. Weak to shields and fast burst.';\r\n\t\tcase 'Caster': return 'Medium-range homing with adaptive missile fitting. Balanced offense and defense.';\r\n\t\tcase 'Sniper': return 'Intercept-predicted straight shots. High accuracy, weak to erratic movement.';\r\n\t\tcase 'Duelist': return 'Close-range fighters with balanced offense/defense. Jack of all trades.';\r\n\t\tcase 'Berserker': return 'Aggressive traders who close distance fast. Weak to kiting and strong defense.';\r\n\t\tcase 'Kiter': return 'Maintains distance while firing homing missiles. Weak to fast closers and blink gap-close.';\r\n\t\tdefault: return bot.description;\r\n\t}\r\n}\r\n","/**\n * vibemancer upload\n *\n * Compiles the user's bot into a standalone bundle and uploads it to Vibemancer\n * via the authed gateway (`POST /api/upload`), owned by the canonical Firebase\n * identity from `vibemancer login`. The server validates + dedupes; if the same\n * code was uploaded before, the old wizard is reactivated (rating/history kept).\n */\n\nimport fs from 'node:fs';\nimport {discoverBot} from '../bot-discovery.js';\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\nimport {uploadBot} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface UploadOptions\n{\n\tbot?: string;\n}\n\nconst MAX_BUNDLE_BYTES = 500 * 1024;\n\nexport async function runUpload(options: UploadOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\n\tconsole.log(`\\n Compiling ${botInfo.exportName}...`);\n\tconst bundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\n\tconsole.log(` Bundle: ${sizeKb} KB`);\n\n\tif (bundle.length > MAX_BUNDLE_BYTES)\n\t{\n\t\tconsole.error(` Error: Bundle too large (${sizeKb} KB). Max ${MAX_BUNDLE_BYTES / 1024} KB.`);\n\t\tprocess.exit(1);\n\t}\n\n\tlet sourceCode = '';\n\ttry\n\t{\n\t\tsourceCode = fs.readFileSync(botInfo.sourcePath, 'utf-8');\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — source storage is optional\n\t}\n\n\tconsole.log(` Wizard: ${botInfo.exportName}`);\n\tconsole.log(' Uploading to Vibemancer...');\n\n\ttry\n\t{\n\t\tconst result = await uploadBot({\n\t\t\tbundle,\n\t\t\tname: botInfo.exportName,\n\t\t\texportName: botInfo.exportName,\n\t\t\tsourceCode,\n\t\t});\n\t\tconsole.log(` ✓ ${result.message}`);\n\t\tif (result.wizardId) console.log(` Wizard ID: ${result.wizardId}`);\n\t\tconsole.log(` Your wizard \"${botInfo.exportName}\" is now competing.\\n`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` ✗ Upload failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/* eslint-disable @typescript-eslint/naming-convention -- OAuth 2.0 wire-format field names (grant_type, access_token, …) are snake_case by spec */\n\n/**\n * CLI OAuth client for the Vibemancer MCP gateway.\n *\n * The CLI is a PKCE OAuth client of mcp.vibemancer.com (the same gateway the MCP\n * AI clients use). `vibemancer login` runs the authorization-code flow; the\n * resulting session token carries the canonical Firebase uid. This module owns\n * PKCE, the token exchange/refresh, and handing callers a fresh access token.\n */\n\nimport {createHash, randomBytes} from 'node:crypto';\nimport {loadCredentials, saveCredentials, type Credentials} from './credentials-store.js';\n\n/** Gateway base URL; overridable for emulator/E2E via VIBEMANCER_MCP_URL. */\nexport const MCP_BASE_URL = process.env.VIBEMANCER_MCP_URL ?? 'https://mcp.vibemancer.com';\n\nexport class NotLoggedInError extends Error\n{\n\tconstructor()\n\t{\n\t\tsuper('Not logged in. Run: vibemancer login');\n\t\tthis.name = 'NotLoggedInError';\n\t}\n}\n\nexport interface Pkce\n{\n\tverifier: string;\n\tchallenge: string;\n}\n\nexport function generatePkce(): Pkce\n{\n\tconst verifier = randomBytes(32).toString('base64url');\n\tconst challenge = createHash('sha256').update(verifier).digest('base64url');\n\treturn {verifier, challenge};\n}\n\n/** Dynamic client registration → client_id (localhost/https redirect allowed). */\nexport async function registerClient(redirectUri: string): Promise<string>\n{\n\tconst res = await fetch(`${MCP_BASE_URL}/register`, {\n\t\tmethod: 'POST',\n\t\theaders: {'Content-Type': 'application/json'},\n\t\tbody: JSON.stringify({redirect_uris: [redirectUri], client_name: 'vibemancer-cli'}),\n\t});\n\tif (!res.ok) throw new Error(`Client registration failed (${res.status}).`);\n\tconst json: unknown = await res.json();\n\tconst clientId = typeof json === 'object' && json !== null && 'client_id' in json && typeof json.client_id === 'string'\n\t\t? json.client_id\n\t\t: '';\n\tif (!clientId) throw new Error('Client registration returned no client_id.');\n\treturn clientId;\n}\n\nfunction parseTokenResponse(json: unknown, fallbackRefresh: string): Credentials\n{\n\tif (typeof json !== 'object' || json === null) throw new Error('Invalid token response.');\n\tconst accessToken = 'access_token' in json && typeof json.access_token === 'string' ? json.access_token : '';\n\tif (!accessToken) throw new Error('Token response missing access_token.');\n\tconst refreshToken = 'refresh_token' in json && typeof json.refresh_token === 'string' ? json.refresh_token : fallbackRefresh;\n\tconst expiresIn = 'expires_in' in json && typeof json.expires_in === 'number' ? json.expires_in : 3600;\n\treturn {accessToken, refreshToken, expiresAt: Date.now() + expiresIn * 1000};\n}\n\n/** Exchange an authorization code (PKCE) for tokens, and persist them. */\nexport async function exchangeCode(code: string, codeVerifier: string): Promise<Credentials>\n{\n\tconst res = await fetch(`${MCP_BASE_URL}/token`, {\n\t\tmethod: 'POST',\n\t\theaders: {'Content-Type': 'application/json'},\n\t\tbody: JSON.stringify({grant_type: 'authorization_code', code, code_verifier: codeVerifier}),\n\t});\n\tif (!res.ok) throw new Error(`Token exchange failed (${res.status}): ${await res.text()}`);\n\tconst creds = parseTokenResponse(await res.json(), '');\n\tsaveCredentials(creds);\n\treturn creds;\n}\n\nasync function refreshCredentials(refreshToken: string): Promise<Credentials>\n{\n\tconst res = await fetch(`${MCP_BASE_URL}/token`, {\n\t\tmethod: 'POST',\n\t\theaders: {'Content-Type': 'application/json'},\n\t\tbody: JSON.stringify({grant_type: 'refresh_token', refresh_token: refreshToken}),\n\t});\n\tif (!res.ok) throw new NotLoggedInError();\n\tconst creds = parseTokenResponse(await res.json(), refreshToken);\n\tsaveCredentials(creds);\n\treturn creds;\n}\n\nconst REFRESH_SKEW_MS = 60_000;\n\n/** A valid access token, refreshing silently when within 60s of expiry. */\nexport async function getAccessToken(): Promise<string>\n{\n\tconst creds = loadCredentials();\n\tif (!creds) throw new NotLoggedInError();\n\tif (creds.expiresAt - Date.now() > REFRESH_SKEW_MS) return creds.accessToken;\n\tconst refreshed = await refreshCredentials(creds.refreshToken);\n\treturn refreshed.accessToken;\n}\n","/**\n * Local credential store for the CLI's OAuth session.\n *\n * Persists the refresh + access tokens at ~/.vibemancer/credentials.json so the\n * user stays logged in between commands. The directory is overridable via\n * VIBEMANCER_CONFIG_DIR (tests, or users who relocate their config).\n */\n\nimport {chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync} from 'node:fs';\nimport {homedir} from 'node:os';\nimport {join} from 'node:path';\n\nexport interface Credentials\n{\n\trefreshToken: string;\n\taccessToken: string;\n\t/** Epoch milliseconds at which the access token expires. */\n\texpiresAt: number;\n}\n\nfunction configDir(): string\n{\n\treturn process.env.VIBEMANCER_CONFIG_DIR ?? join(homedir(), '.vibemancer');\n}\n\nfunction credentialsPath(): string\n{\n\treturn join(configDir(), 'credentials.json');\n}\n\nexport function loadCredentials(): Credentials | null\n{\n\tconst path = credentialsPath();\n\tif (!existsSync(path)) return null;\n\ttry\n\t{\n\t\tconst parsed: unknown = JSON.parse(readFileSync(path, 'utf-8'));\n\t\tif (\n\t\t\ttypeof parsed === 'object' && parsed !== null\n\t\t\t&& 'refreshToken' in parsed && typeof parsed.refreshToken === 'string'\n\t\t\t&& 'accessToken' in parsed && typeof parsed.accessToken === 'string'\n\t\t\t&& 'expiresAt' in parsed && typeof parsed.expiresAt === 'number'\n\t\t)\n\t\t{\n\t\t\treturn {refreshToken: parsed.refreshToken, accessToken: parsed.accessToken, expiresAt: parsed.expiresAt};\n\t\t}\n\t\treturn null;\n\t}\n\tcatch\n\t{\n\t\treturn null;\n\t}\n}\n\nexport function saveCredentials(credentials: Credentials): void\n{\n\tmkdirSync(configDir(), {recursive: true});\n\tconst path = credentialsPath();\n\twriteFileSync(path, JSON.stringify(credentials, null, 2), {mode: 0o600});\n\t// Best-effort tighten perms (no-op semantics on Windows).\n\ttry\n\t{\n\t\tchmodSync(path, 0o600);\n\t}\n\tcatch\n\t{\n\t\t// ignore — Windows / restricted FS\n\t}\n}\n\nexport function clearCredentials(): void\n{\n\ttry\n\t{\n\t\trmSync(credentialsPath(), {force: true});\n\t}\n\tcatch\n\t{\n\t\t// ignore\n\t}\n}\n","/**\n * Environment headers the CLI attaches to requests it ALREADY makes, so the server can\n * answer \"which OS are CLI users on\" and \"MCP vs CLI\" without the CLI issuing a single\n * extra outbound request. See docs/decisions/0001-usage-analytics-bigquery.md.\n *\n * Deliberately narrow: platform, release, arch, node version, CLI version. No username,\n * no hostname, no paths — none of which we need, and all of which would be a liability.\n */\n\nimport os from 'node:os';\nimport {readFileSync} from 'node:fs';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\n/**\n * Walk upwards from `here` looking for this package's own manifest.\n *\n * The try/catch sits INSIDE the loop deliberately. With one try around the whole loop, the\n * first candidate that does not exist aborted the entire search — which is what happens in\n * every built layout (`dist/cli.js` has nothing two levels up) and in every published\n * install. The result was a CLI that reported no version at all, invisible in the tests\n * because the SOURCE layout happens to match the first candidate, and only visible as a\n * column of nulls in the analytics.\n *\n * Exported so the layouts can be exercised directly rather than only the one the tests\n * happen to run in.\n */\nexport function findCliVersionFrom(here: string): string\n{\n\tfor (const rel of ['../../package.json', '../package.json', '../../../package.json'])\n\t{\n\t\ttry\n\t\t{\n\t\t\tconst parsed: unknown = JSON.parse(readFileSync(path.resolve(here, rel), 'utf8'));\n\t\t\tif (typeof parsed !== 'object' || parsed === null) continue;\n\t\t\tif (!('name' in parsed) || !('version' in parsed)) continue;\n\t\t\tconst {name, version} = parsed;\n\t\t\tif (name === 'vibemancer' && typeof version === 'string') return version;\n\t\t}\n\t\tcatch\n\t\t{\n\t\t\t// A candidate that is missing or unreadable is ordinary; try the next one.\n\t\t}\n\t}\n\treturn '';\n}\n\nfunction readCliVersion(): string\n{\n\ttry\n\t{\n\t\treturn findCliVersionFrom(path.dirname(fileURLToPath(import.meta.url)));\n\t}\n\tcatch\n\t{\n\t\t// Version is nice-to-have; never worth failing a command over.\n\t\treturn '';\n\t}\n}\n\n/**\n * Build the telemetry headers. Pure given its inputs so it can be tested without touching\n * the real environment.\n */\nexport function buildEnvHeaders(env: {\n\tplatform: string;\n\trelease: string;\n\tarch: string;\n\tnodeVersion: string;\n\tcliVersion: string;\n}): Record<string, string>\n{\n\tconst headers: Record<string, string> = {};\n\tconst put = (key: string, value: string): void =>\n\t{\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed) headers[key] = trimmed.slice(0, 64);\n\t};\n\tput('x-vibemancer-os', env.platform);\n\tput('x-vibemancer-os-release', env.release);\n\tput('x-vibemancer-arch', env.arch);\n\tput('x-vibemancer-node', env.nodeVersion);\n\tput('x-vibemancer-cli', env.cliVersion);\n\treturn headers;\n}\n\n/** The headers for THIS machine. */\nexport function envHeaders(): Record<string, string>\n{\n\ttry\n\t{\n\t\treturn buildEnvHeaders({\n\t\t\tplatform: os.platform(),\n\t\t\trelease: os.release(),\n\t\t\tarch: os.arch(),\n\t\t\tnodeVersion: process.version,\n\t\t\tcliVersion: readCliVersion(),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\treturn {};\n\t}\n}\n","/**\n * Client for the authed gateway REST endpoints. Attaches the Bearer session\n * token (carrying the canonical Firebase uid) and parses responses. This is the\n * single network path the CLI uses to upload + pull.\n */\n\nimport {getAccessToken, MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\nexport interface UploadPayload\n{\n\tbundle: string;\n\tname: string;\n\texportName: string;\n\tsourceCode: string;\n}\n\nexport interface UploadResult\n{\n\twizardId: string;\n\tmessage: string;\n}\n\nexport async function uploadBot(payload: UploadPayload): Promise<UploadResult>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/upload`, {\n\t\tmethod: 'POST',\n\t\t// Environment headers ride along on a request already being made — no extra call.\n\t\theaders: {'Content-Type': 'application/json', Authorization: `Bearer ${token}`, ...envHeaders()},\n\t\tbody: JSON.stringify(payload),\n\t});\n\tif (!res.ok) throw new Error(`Upload failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst wizardId = typeof data === 'object' && data !== null && 'wizardId' in data && typeof data.wizardId === 'string'\n\t\t? data.wizardId\n\t\t: '';\n\tconst message = typeof data === 'object' && data !== null && 'message' in data && typeof data.message === 'string'\n\t\t? data.message\n\t\t: 'Uploaded.';\n\treturn {wizardId, message};\n}\n\nexport async function pullSource(name: string): Promise<string>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/pull?name=${encodeURIComponent(name)}`, {\n\t\theaders: {Authorization: `Bearer ${token}`, ...envHeaders()},\n\t});\n\tif (!res.ok) throw new Error(`Pull failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst source = typeof data === 'object' && data !== null && 'sourceCode' in data && typeof data.sourceCode === 'string'\n\t\t? data.sourceCode\n\t\t: '';\n\tif (source) return source;\n\tconst error = typeof data === 'object' && data !== null && 'error' in data && typeof data.error === 'string'\n\t\t? data.error\n\t\t: 'No source returned.';\n\tthrow new Error(error);\n}\n","/**\n * vibemancer pull\n *\n * Downloads the latest source of your active wizard (by export name) from the\n * authed gateway (`GET /api/pull`) and writes it to the local bot file. Enables\n * round-tripping between MCP chat sessions and local CLI development.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {discoverBot} from '../bot-discovery.js';\nimport {pullSource} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface PullOptions\n{\n\tbot?: string;\n}\n\nexport async function runPull(options: PullOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\t// pull RESTORES source, so the file legitimately may not exist yet — a new machine, a\n\t// fresh clone, or a bot authored in an MCP chat session. See DiscoverOptions.\n\tconst botInfo = await discoverBot(projectDir, options.bot, {allowMissingFile: true});\n\tconst isNew = !fs.existsSync(botInfo.sourcePath);\n\n\tconsole.log(`\\n Pulling latest source for ${botInfo.exportName}...`);\n\n\ttry\n\t{\n\t\tconst sourceCode = await pullSource(botInfo.exportName);\n\t\t// On a fresh machine the containing directory (src/) may not exist either.\n\t\tfs.mkdirSync(path.dirname(botInfo.sourcePath), {recursive: true});\n\t\tfs.writeFileSync(botInfo.sourcePath, sourceCode);\n\t\tconsole.log(` ✓ ${isNew ? 'Created' : 'Updated'} ${botInfo.sourcePath}`);\n\t\tconsole.log(` ${(sourceCode.length / 1024).toFixed(1)} KB written`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` Pull failed: ${err instanceof Error ? err.message : String(err)}`);\n\t\t\tconsole.error(' Upload first with: vibemancer upload\\n');\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * vibemancer login\n *\n * Authenticates the CLI as an OAuth client of the MCP gateway. The resulting\n * session token carries the canonical Firebase uid (the same identity the web\n * and MCP use), so uploads from the CLI are owned by the same account.\n *\n * Default: browser loopback (a localhost server catches the redirect).\n * `--no-browser`: print the URL + paste the code shown on the gateway page.\n */\n\nimport {createServer, type IncomingMessage, type ServerResponse} from 'node:http';\nimport {randomBytes} from 'node:crypto';\nimport {spawn} from 'node:child_process';\nimport {createInterface} from 'node:readline/promises';\nimport {generatePkce, registerClient, exchangeCode, MCP_BASE_URL} from '../auth/oauth-client.js';\n\nexport interface LoginOptions\n{\n\tnoBrowser?: boolean;\n}\n\nexport function buildAuthorizeUrl(\n\tbaseUrl: string,\n\tparams: {clientId: string; redirectUri: string; challenge: string; state: string},\n): string\n{\n\tconst u = new URL(`${baseUrl}/authorize`);\n\tu.searchParams.set('response_type', 'code');\n\tu.searchParams.set('client_id', params.clientId);\n\tu.searchParams.set('redirect_uri', params.redirectUri);\n\tu.searchParams.set('code_challenge', params.challenge);\n\tu.searchParams.set('code_challenge_method', 'S256');\n\tu.searchParams.set('state', params.state);\n\treturn u.toString();\n}\n\nexport function extractCodeFromCallback(reqUrl: string, expectedState: string): {code: string} | {error: string}\n{\n\tconst u = new URL(reqUrl, 'http://localhost');\n\tconst code = u.searchParams.get('code');\n\tconst state = u.searchParams.get('state');\n\tif (!code) return {error: 'No authorization code in the callback.'};\n\tif (state !== expectedState) return {error: 'State mismatch (possible CSRF) — try again.'};\n\treturn {code};\n}\n\nfunction openBrowser(url: string): void\n{\n\ttry\n\t{\n\t\tconst child = process.platform === 'win32'\n\t\t\t? spawn('cmd', ['/c', 'start', '', url], {stdio: 'ignore', detached: true})\n\t\t\t: spawn(process.platform === 'darwin' ? 'open' : 'xdg-open', [url], {stdio: 'ignore', detached: true});\n\t\tchild.unref();\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — the URL is also printed for manual opening\n\t}\n}\n\ninterface LoopbackServer\n{\n\tport: number;\n\twaitForCode: Promise<string>;\n\tclose: () => void;\n}\n\nfunction startLoopbackServer(expectedState: string): Promise<LoopbackServer>\n{\n\treturn new Promise((resolveServer) =>\n\t{\n\t\tlet resolveCode: (code: string) => void = () => undefined;\n\t\tlet rejectCode: (err: Error) => void = () => undefined;\n\t\tconst waitForCode = new Promise<string>((res, rej) =>\n\t\t{\n\t\t\tresolveCode = res;\n\t\t\trejectCode = rej;\n\t\t});\n\n\t\tconst server = createServer((req: IncomingMessage, res: ServerResponse) =>\n\t\t{\n\t\t\tconst result = extractCodeFromCallback(req.url ?? '', expectedState);\n\t\t\tif ('error' in result)\n\t\t\t{\n\t\t\t\tres.writeHead(400, {'Content-Type': 'text/html'});\n\t\t\t\tres.end('<h2>Login failed</h2><p>You can close this tab and try again.</p>');\n\t\t\t\trejectCode(new Error(result.error));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.writeHead(200, {'Content-Type': 'text/html'});\n\t\t\tres.end('<h2>Vibemancer login complete</h2><p>You can close this tab and return to the terminal.</p>');\n\t\t\tresolveCode(result.code);\n\t\t});\n\n\t\tserver.listen(0, '127.0.0.1', () =>\n\t\t{\n\t\t\tconst addr = server.address();\n\t\t\tconst port = typeof addr === 'object' && addr !== null ? addr.port : 0;\n\t\t\tresolveServer({port, waitForCode, close: () => server.close()});\n\t\t});\n\t});\n}\n\nasync function runBrowserLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst {port, waitForCode, close} = await startLoopbackServer(state);\n\tconst redirectUri = `http://localhost:${port}/callback`;\n\ttry\n\t{\n\t\tconst clientId = await registerClient(redirectUri);\n\t\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\t\tconsole.log('\\n Opening your browser to sign in with Google...');\n\t\tconsole.log(` If it doesn't open, visit:\\n ${authUrl}\\n`);\n\t\topenBrowser(authUrl);\n\t\tconst code = await waitForCode;\n\t\tawait exchangeCode(code, verifier);\n\t\tconsole.log(' ✓ Logged in. You can now run `vibemancer upload`.\\n');\n\t}\n\tfinally\n\t{\n\t\tclose();\n\t}\n}\n\nasync function runPasteLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst redirectUri = `${MCP_BASE_URL}/cli-code`;\n\tconst clientId = await registerClient(redirectUri);\n\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\tconsole.log('\\n Open this URL in a browser, sign in, then paste the code shown:\\n');\n\tconsole.log(` ${authUrl}\\n`);\n\tconst rl = createInterface({input: process.stdin, output: process.stdout});\n\tconst code = (await rl.question(' Paste code: ')).trim();\n\trl.close();\n\tif (!code)\n\t{\n\t\tconsole.error(' No code entered.');\n\t\tprocess.exit(1);\n\t}\n\tawait exchangeCode(code, verifier);\n\tconsole.log(' ✓ Logged in.\\n');\n}\n\nexport async function runLogin(options: LoginOptions): Promise<void>\n{\n\tconst {verifier, challenge} = generatePkce();\n\tconst state = randomBytes(16).toString('hex');\n\tif (options.noBrowser)\n\t{\n\t\tawait runPasteLogin(challenge, verifier, state);\n\t}\n\telse\n\t{\n\t\tawait runBrowserLogin(challenge, verifier, state);\n\t}\n}\n","/**\n * Server-side session revocation for the CLI.\n *\n * `clearCredentials()` only deletes the local file; the refresh token stayed valid on the\n * gateway for the rest of its 30 days, so a copied token survived a logout. This calls\n * the gateway so the session actually ends.\n *\n * Best-effort by design: it reports failure rather than throwing, because the local\n * credentials must still be cleared when the network is down — or when the user is\n * logging out precisely because something has gone wrong.\n */\n\nimport {MCP_BASE_URL} from './oauth-client.js';\n\n/** Revoke the session behind `token`. Returns whether the gateway confirmed it. */\nexport async function revokeSession(token: string): Promise<boolean>\n{\n\tif (!token) return false;\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/revoke`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json'},\n\t\t\tbody: JSON.stringify({token}),\n\t\t});\n\t\treturn res.ok;\n\t}\n\tcatch\n\t{\n\t\treturn false;\n\t}\n}\n","/**\n * vibemancer logout — end the session, then clear the cached OAuth credentials.\n *\n * Clearing the local file alone used to leave the refresh token valid on the gateway for\n * the rest of its 30 days, so a copied credential survived a logout. The revoke call is\n * best-effort: the local credentials are cleared either way, because a user with no\n * network — or one logging out BECAUSE something is wrong — must still be able to get\n * their credentials off the machine.\n */\n\nimport {clearCredentials, loadCredentials} from '../auth/credentials-store.js';\nimport {revokeSession} from '../auth/revoke.js';\n\nexport async function runLogout(): Promise<void>\n{\n\tconst credentials = loadCredentials();\n\tconst revoked = credentials ? await revokeSession(credentials.accessToken) : false;\n\n\tclearCredentials();\n\n\tif (credentials && !revoked)\n\t{\n\t\tconsole.log(' Logged out locally, but the server could not be reached to end the session.');\n\t\tconsole.log(' Run `vibemancer logout` again while online to revoke it.');\n\t\treturn;\n\t}\n\tconsole.log(' Logged out.');\n}\n","export interface FeedbackOptions\n{\n\tmessage: string;\n}\n\nexport async function runFeedback(options: FeedbackOptions): Promise<void>\n{\n\tconst message = options.message.trim();\n\tif (!message)\n\t{\n\t\tconsole.error(' Error: feedback message cannot be empty.');\n\t\tprocess.exit(1);\n\t}\n\n\tconsole.log('\\n Submitting feedback...');\n\n\ttry\n\t{\n\t\tconst {initializeApp} = await import('firebase/app');\n\t\tconst {getFunctions, httpsCallable} = await import('firebase/functions');\n\t\tconst {FIREBASE_CONFIG} = await import('../firebase-config.js');\n\n\t\tconst app = initializeApp(FIREBASE_CONFIG);\n\n\t\tconst functions = getFunctions(app, 'us-central1');\n\t\tconst submitFn = httpsCallable(functions, 'submitFeedback');\n\t\tawait submitFn({message});\n\n\t\tconsole.log(' Sent! Thanks for the feedback.\\n');\n\t}\n\tcatch(err: unknown)\n\t{\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tconsole.error(` Failed to submit: ${msg}\\n`);\n\t\tprocess.exit(1);\n\t}\n}\n","import {calculateMissileCastTime, GCD_DURATION, TICKS_PER_SECOND, calculateMissileRadius} from '@vibemancer/core';\n\nexport interface MissileCalcOptions\n{\n\tdamage: number;\n\tspeed: number;\n\tduration: number;\n\tturnRate: number;\n}\n\nexport function runMissileCalc(options: MissileCalcOptions): void\n{\n\tconst config = {\n\t\tdamage: options.damage,\n\t\tspeed: options.speed,\n\t\tduration: options.duration,\n\t\tturnRate: options.turnRate,\n\t};\n\n\tconst castTimeSec = calculateMissileCastTime(config);\n\tconst castFrames = Math.max(1, Math.round(castTimeSec * TICKS_PER_SECOND));\n\tconst gcdSec = GCD_DURATION / TICKS_PER_SECOND;\n\tconst totalCycleSec = castTimeSec + gcdSec;\n\tconst dps = config.damage / totalCycleSec;\n\tconst range = config.speed * config.duration;\n\tconst radius = calculateMissileRadius(config.damage);\n\n\tconsole.log(`\n Missile Calculator\n ──────────────────\n Config: damage=${config.damage} speed=${config.speed} duration=${config.duration} turnRate=${config.turnRate}\n Cast time: ${castTimeSec.toFixed(3)}s (${castFrames} frames)\n GCD: ${gcdSec}s (${GCD_DURATION} frames)\n Full cycle: ${totalCycleSec.toFixed(3)}s (cast + GCD)\n Eff. DPS: ${dps.toFixed(2)} HP/s\n Range: ${range} units (speed × duration)\n Hitbox: ${radius.toFixed(2)} radius\n`);\n}\n","/**\n * CLI telemetry for LOCAL commands (dev / fight / test / optimize / trace / build).\n *\n * Commands that talk to the gateway are already measured by the headers in\n * env-headers.ts. Local commands are not, and that gap is the important one: without\n * them the only people counted are those who successfully signed in and uploaded, so\n * \"what fraction of installs never upload?\" — the question that decides whether the CLI\n * is worth maintaining — would be computed over survivors only.\n *\n * Three rules this must never break:\n * 1. It must never block. Sent at command START so a long command overlaps the request,\n * with a hard timeout so an unreachable server cannot delay the exit.\n * 2. It must never throw. A telemetry failure is not a CLI failure.\n * 3. It must be refusable, and say so once. Developers are the audience most likely to\n * object to a tool phoning home, and the least likely to forgive doing it silently.\n */\n\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\n/** Milliseconds before an unreachable server is abandoned. */\nconst TIMEOUT_MS = 1000;\n\n/**\n * Is telemetry allowed?\n *\n * Honours our own switch AND `DO_NOT_TRACK`, the cross-tool convention — a developer who\n * has set that globally has already expressed the preference, and ignoring it because it\n * is not our variable would be obtuse.\n */\nexport function isTelemetryEnabled(env: NodeJS.ProcessEnv): boolean\n{\n\tconst off = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '0' || v === 'false' || v === 'off' || v === 'no';\n\t};\n\tconst on = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '1' || v === 'true' || v === 'on' || v === 'yes';\n\t};\n\n\tif (off(env.VIBEMANCER_TELEMETRY)) return false;\n\tif (on(env.DO_NOT_TRACK)) return false;\n\t// CI machines are not people; counting them would inflate every figure.\n\tif (on(env.CI)) return false;\n\treturn true;\n}\n\n/** The one-time notice. Exported so its wording can be asserted rather than drift. */\nexport const TELEMETRY_NOTICE =\n\t' Vibemancer records which commands are run, your OS and version numbers, to decide\\n'\n\t+ ' which platforms to support. No code, file paths or personal files are ever sent.\\n'\n\t+ ' Opt out any time with VIBEMANCER_TELEMETRY=0 (DO_NOT_TRACK is honoured too).\\n';\n\n/** Where the \"already told them\" marker lives. */\nfunction noticePath(): string\n{\n\treturn path.join(os.homedir(), '.vibemancer', 'telemetry-notice-shown');\n}\n\n/**\n * Print the notice the first time only. Returns whether it printed, so tests can assert\n * the once-only behaviour rather than trusting it.\n */\nexport function showNoticeOnce(marker: string = noticePath()): boolean\n{\n\ttry\n\t{\n\t\tif (fs.existsSync(marker)) return false;\n\t\tfs.mkdirSync(path.dirname(marker), {recursive: true});\n\t\tfs.writeFileSync(marker, new Date().toISOString());\n\t\tconsole.log(TELEMETRY_NOTICE);\n\t\treturn true;\n\t}\n\tcatch\n\t{\n\t\t// If the marker cannot be written, stay silent rather than nagging every run.\n\t\treturn false;\n\t}\n}\n\n/**\n * Record that a local command ran. Fire-and-forget by construction: the returned promise\n * is resolved even on failure, so a caller that forgets to await cannot produce an\n * unhandled rejection.\n */\nexport async function recordLocalCommand(command: string, env: NodeJS.ProcessEnv = process.env, marker: string = noticePath()): Promise<void>\n{\n\tif (!isTelemetryEnabled(env)) return;\n\t// `marker` is injectable so the test suite cannot consume the real first-run notice on\n\t// whichever machine runs it — otherwise the one person certain to have run the tests is\n\t// the one person who never sees the notice.\n\tshowNoticeOnce(marker);\n\n\ttry\n\t{\n\t\t// envHeaders() rather than hand-built ones: it resolves the CLI version too, and the\n\t\t// version spread of people who never upload is the half we could not otherwise see.\n\t\tconst headers = envHeaders();\n\t\tawait fetch(`${MCP_BASE_URL}/cli-telemetry`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json', ...headers},\n\t\t\tbody: JSON.stringify({command}),\n\t\t\tsignal: AbortSignal.timeout(TIMEOUT_MS),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\t// Never a CLI failure.\n\t}\n}\n","/**\r\n * Vibemancer CLI\r\n *\r\n * Development tools for building wizard bots.\r\n *\r\n * Usage:\r\n * vibemancer dev [--port 4242] [--bot src/bot.ts]\r\n * vibemancer test\r\n * vibemancer fight [--opponent Battlemage]\r\n * vibemancer trace --opponent Battlemage\r\n * vibemancer tournament [opponents...]\r\n * vibemancer optimize [--opponents Battlemage,Warmage]\r\n * vibemancer build --opponent Battlemage\r\n */\r\n\r\nimport {runDev} from './commands/dev.js';\r\nimport {runTest} from './commands/test.js';\r\nimport {runFight} from './commands/fight.js';\r\nimport {runTrace} from './commands/trace.js';\r\nimport {runTournament} from './commands/tournament.js';\r\nimport {runOptimize} from './commands/optimize.js';\r\nimport {runBuild} from './commands/build.js';\r\nimport {runBots} from './commands/bots.js';\r\nimport {runUpload} from './commands/upload.js';\r\nimport {runPull} from './commands/pull.js';\r\nimport {runLogin} from './commands/login.js';\r\nimport {runLogout} from './commands/logout.js';\r\nimport {runFeedback} from './commands/feedback.js';\r\nimport {runMissileCalc} from './commands/missile-calc.js';\r\nimport {recordLocalCommand} from './auth/telemetry.js';\r\n\r\nconst args = process.argv.slice(2);\r\nconst command = args[0];\r\n\r\nfunction parseFlag(flag: string): string | undefined\r\n{\r\n\tconst idx = args.indexOf(flag);\r\n\tif (idx !== -1 && idx + 1 < args.length)\r\n\t{\r\n\t\treturn args[idx + 1];\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nfunction parseIntFlag(flag: string, fallback: number): number\r\n{\r\n\tconst str = parseFlag(flag);\r\n\tif (str === undefined) return fallback;\r\n\tconst n = parseInt(str, 10);\r\n\tif (Number.isNaN(n))\r\n\t{\r\n\t\tconsole.error(`Error: ${flag} must be a number, got \"${str}\".`);\r\n\t\tprocess.exit(1);\r\n\t}\r\n\treturn n;\r\n}\r\n\r\nfunction printHelp(): void\r\n{\r\n\tconsole.log(`\r\nVibemancer CLI - Development tools for wizard bots\r\n\r\nUsage:\r\n vibemancer <command> [options]\r\n\r\nCommands:\r\n dev Start the development server (auto-opens browser)\r\n test Run your test suite (vitest)\r\n fight Fight against all 29 built-in bots (or a single opponent)\r\n bots List all built-in bots with descriptions\r\n trace Per-tick debug trace of a single match\r\n tournament Round-robin tournament between your bot + selected opponents\r\n optimize Optimize bot parameters via coordinate descent\r\n build Compile bot to a standalone bundle\r\n login Sign in to VibeMancer (required before upload/pull)\r\n logout Sign out\r\n upload Upload bot to VibeMancer for online competition\r\n pull Download latest source code from VibeMancer\r\n feedback Submit a bug report or suggestion\r\n missile-calc Calculate missile cast time and DPS for a config\r\n\r\nCommon options:\r\n --bot <path> Path to bot source file (default: auto-discover)\r\n\r\nDev options:\r\n --port <n> Server port (default: 4242)\r\n\r\nFight options:\r\n --opponent <name> Fight a single opponent: a built-in name OR another\r\n user's uploaded bot as handle/botname\r\n --seed <n> Random seed\r\n\r\nTrace options:\r\n --opponent <name> Opponent: a built-in name OR handle/botname (required)\r\n --seed <n> Random seed (default: 1)\r\n --distance <n> Spawn distance (default: 600)\r\n\r\nBuild options:\r\n --opponent <name> Opponent bot name (required)\r\n --output <path> Output file path (default: dist/<Bot>-vs-<Opponent>.js)\r\n\r\nOptimize options:\r\n --steps <n> Candidates per parameter (default: 5)\r\n --rounds <n> Max optimization rounds (default: 3)\r\n --opponents <list> Comma-separated bot names to optimize against (default: all)\r\n\r\nExamples:\r\n vibemancer dev\r\n vibemancer test\r\n vibemancer fight\r\n vibemancer fight --opponent Battlemage\r\n vibemancer trace --opponent Battlemage\r\n vibemancer trace --opponent Nightblade --distance 300\r\n vibemancer tournament Battlemage Warmage Archmage\r\n vibemancer optimize\r\n vibemancer build --opponent Battlemage\r\n vibemancer feedback \"missiles go through walls sometimes\"\r\n vibemancer missile-calc --damage 15 --speed 7 --duration 200 --turnRate 3\r\n`);\r\n}\r\n\r\nasync function main(): Promise<void>\r\n{\r\n\tif (!command || command === '--help' || command === '-h')\r\n\t{\r\n\t\tprintHelp();\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Local commands are otherwise invisible: only people who successfully sign in and\r\n\t// upload would ever be counted, so \"how many installs never upload?\" would be measured\r\n\t// over survivors only. Fired here, at the START, so the request overlaps the command's\r\n\t// real work instead of delaying its exit. Never awaited, never able to throw.\r\n\tvoid recordLocalCommand(command);\r\n\r\n\tswitch (command)\r\n\t{\r\n\t\tcase 'dev':\r\n\t\t{\r\n\t\t\tconst port = parseIntFlag('--port', 4242);\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runDev({port, bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'test':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runTest({bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'fight':\r\n\t\t{\r\n\t\t\tconst opponent = parseFlag('--opponent');\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst seed = parseFlag('--seed') !== undefined ? parseIntFlag('--seed', 0) : undefined;\r\n\t\t\tawait runFight({opponent, bot, seed});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'trace':\r\n\t\t{\r\n\t\t\tconst opponent = parseFlag('--opponent');\r\n\t\t\tif (!opponent)\r\n\t\t\t{\r\n\t\t\t\tconst {getBuiltinBotNames} = await import('./opponent-resolver.js');\r\n\t\t\t\tconst names = getBuiltinBotNames();\r\n\t\t\t\tconst list = names.map((n) => ` --opponent ${n}`).join('\\n');\r\n\t\t\t\tconsole.error('Error: --opponent is required for trace.\\n');\r\n\t\t\t\tconsole.error(`Available opponents:\\n\\n${list}\\n`);\r\n\t\t\t\tconsole.error('Usage: vibemancer trace --opponent Battlemage');\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst seed = parseFlag('--seed') !== undefined ? parseIntFlag('--seed', 0) : undefined;\r\n\t\t\tconst distance = parseFlag('--distance') !== undefined ? parseIntFlag('--distance', 600) : undefined;\r\n\t\t\tawait runTrace({opponent, bot, seed, distance});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'bots':\r\n\t\t{\r\n\t\t\tconst name = parseFlag('--name') ?? args[1];\r\n\t\t\trunBots({name: name?.startsWith('--') ? undefined : name});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'tournament':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst flagIndices = new Set<number>();\r\n\t\t\tfor (let i = 1; i < args.length; i++)\r\n\t\t\t{\r\n\t\t\t\tif (args[i]!.startsWith('--'))\r\n\t\t\t\t{\r\n\t\t\t\t\tflagIndices.add(i);\r\n\t\t\t\t\tflagIndices.add(i + 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst opponents = args.slice(1).filter((_, i) => !flagIndices.has(i + 1));\r\n\t\t\tawait runTournament({opponents, bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'optimize':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst opponentsStr = parseFlag('--opponents');\r\n\t\t\tconst opponents = opponentsStr ? opponentsStr.split(',').map((s) => s.trim()).filter(Boolean) : undefined;\r\n\t\t\tawait runOptimize({\r\n\t\t\t\tbot,\r\n\t\t\t\tsteps: parseFlag('--steps') !== undefined ? parseIntFlag('--steps', 5) : undefined,\r\n\t\t\t\trounds: parseFlag('--rounds') !== undefined ? parseIntFlag('--rounds', 3) : undefined,\r\n\t\t\t\topponents,\r\n\t\t\t});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'build':\r\n\t\t{\r\n\t\t\tconst opponent = parseFlag('--opponent');\r\n\t\t\tif (!opponent)\r\n\t\t\t{\r\n\t\t\t\tconsole.error('Error: --opponent is required for build command.');\r\n\t\t\t\tconsole.error('Usage: vibemancer build --opponent Battlemage');\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst output = parseFlag('--output');\r\n\t\t\tawait runBuild({opponent, bot, output});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'upload':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runUpload({bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'pull':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runPull({bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'login':\r\n\t\t{\r\n\t\t\tawait runLogin({noBrowser: args.includes('--no-browser')});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'logout':\r\n\t\t{\r\n\t\t\tawait runLogout();\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'feedback':\r\n\t\t{\r\n\t\t\tconst message = args.slice(1).join(' ');\r\n\t\t\tawait runFeedback({message});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'missile-calc':\r\n\t\t{\r\n\t\t\trunMissileCalc({\r\n\t\t\t\tdamage: parseIntFlag('--damage', 15),\r\n\t\t\t\tspeed: parseIntFlag('--speed', 7),\r\n\t\t\t\tduration: parseIntFlag('--duration', 200),\r\n\t\t\t\tturnRate: parseIntFlag('--turnRate', 0),\r\n\t\t\t});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tdefault:\r\n\t\t\tconsole.error(`Unknown command: ${command}`);\r\n\t\t\tprintHelp();\r\n\t\t\tprocess.exit(1);\r\n\t}\r\n}\r\n\r\nmain().catch((error) =>\r\n{\r\n\tconsole.error('Error:', error instanceof Error ? error.message : error);\r\n\tprocess.exit(1);\r\n});\r\n"],"mappings":"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","names":["fs","path","path","fs","BotBundle","BotBundle","BotBundle","sandboxFight","scoreFight","BotBundle","sandboxFight","scoreFight","BotBundle","scoreFight","scoreFight","BotBundle","fs","path","BotBundle","BotBundle","path","fs","fs","readFileSync","writeFileSync","path","readFileSync","path","fs","fs","path","fs","path","randomBytes","spawn","openBrowser","spawn","randomBytes","initializeApp","FIREBASE_CONFIG","os","fs","path","path","os","fs","command","getBuiltinBotNames"]}
1
+ {"version":3,"sources":["../src/commands/dev.ts","../src/bot-discovery.ts","../src/server.ts","../src/compile-single-bot.ts","../src/commands/test.ts","../src/commands/fight.ts","../src/remote-opponent.ts","../src/firebase-config.ts","../src/commands/trace.ts","../src/commands/tournament.ts","../src/commands/optimize.ts","../src/commands/build.ts","../src/commands/bots.ts","../src/commands/upload.ts","../src/auth/env-headers.ts","../src/auth/gateway-client.ts","../src/commands/pull.ts","../src/commands/login.ts","../src/auth/revoke.ts","../src/commands/logout.ts","../src/commands/feedback.ts","../src/commands/missile-calc.ts","../src/auth/telemetry.ts","../src/cli.ts"],"sourcesContent":["/**\r\n * vibemancer dev\r\n *\r\n * Starts the local development server. Auto-discovers every bot in the\r\n * project's src/ tree and serves them to the hosted web client at\r\n * vibemancer.com via the #botserver= URL hash. Compiles fresh on each\r\n * request so a browser refresh always picks up the latest code. Opens\r\n * the browser automatically.\r\n *\r\n * The --bot flag is accepted for backward compatibility but no longer\r\n * used — multi-bot discovery scans src/ regardless.\r\n */\r\n\r\nimport {execFile} from 'node:child_process';\r\nimport {discoverAllBots} from '../bot-discovery.js';\r\nimport {startServer} from '../server.js';\r\n\r\nexport interface DevOptions\r\n{\r\n\tport: number;\r\n\tbot?: string;\r\n}\r\n\r\nexport async function runDev(options: DevOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\r\n\t// Show what we discovered up front so the user sees it before the\r\n\t// banner lands — purely informational; the server re-scans on every\r\n\t// /local-bots request.\r\n\tconst bots = await discoverAllBots(projectDir);\r\n\tif (bots.length === 0)\r\n\t{\r\n\t\tconsole.log('No bots discovered in src/. Add a .ts file with a PascalCase export, e.g.:');\r\n\t\tconsole.log(' export function MyWizard() { return move(0, 0); }');\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconsole.log(`Discovered ${bots.length} bot${bots.length === 1 ? '' : 's'}: ${bots.map((b) => b.exportName).join(', ')}`);\r\n\t}\r\n\r\n\tconst server = startServer({\r\n\t\tport: options.port,\r\n\t\tprojectDir,\r\n\t});\r\n\r\n\t// Auto-open browser once server is listening\r\n\tserver.once('listening', () =>\r\n\t{\r\n\t\tconst url = `https://vibemancer.com/#botserver=localhost:${options.port}`;\r\n\t\topenBrowser(url);\r\n\t});\r\n}\r\n\r\nfunction openBrowser(url: string): void\r\n{\r\n\tconst platform = process.platform;\r\n\r\n\ttry\r\n\t{\r\n\t\tif (platform === 'darwin')\r\n\t\t{\r\n\t\t\texecFile('open', [url], () => \r\n\t\t\t{});\r\n\t\t}\r\n\t\telse if (platform === 'win32')\r\n\t\t{\r\n\t\t\texecFile('cmd', ['/c', 'start', '', url], () => \r\n\t\t\t{});\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\t// Linux / WSL — try xdg-open, fall back to wslview\r\n\t\t\texecFile('xdg-open', [url], (err) =>\r\n\t\t\t{\r\n\t\t\t\tif (err) execFile('wslview', [url], () => \r\n\t\t\t\t{});\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\t// Silently ignore — user can always open manually\r\n\t}\r\n}\r\n","/**\r\n * Bot Discovery\r\n *\r\n * Finds the user's bot source file(s) and export name(s).\r\n *\r\n * Single-bot mode (used by upload, fight, trace, etc.) resolves one bot:\r\n * 1. --bot flag\r\n * 2. vibemancer.json config\r\n * 3. Auto-scan src/ — if exactly one bot found, use it; if multiple,\r\n * error with a list so the user can pick with --bot\r\n *\r\n * Multi-bot mode (used by the dev server) auto-scans src/ for all bots.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\n\r\nexport interface BotInfo\r\n{\r\n\t/** Absolute path to the bot source file. */\r\n\tsourcePath: string;\r\n\t/** Named export of the bot function. */\r\n\texportName: string;\r\n}\r\n\r\ninterface VibemancerConfig\r\n{\r\n\tbot?: string;\r\n\texport?: string;\r\n}\r\n\r\nexport interface DiscoverOptions\r\n{\r\n\t/**\r\n\t * Resolve the bot even when its source file does not exist yet. Only `pull` sets this:\r\n\t * it RESTORES the source onto a machine that has never had it (new laptop, fresh clone,\r\n\t * a bot written in an MCP chat session). vibemancer.json already carries both the path\r\n\t * and the export name, so nothing has to be read off disk. Commands that consume the\r\n\t * source — upload, fight, trace — leave this off and still require a real file.\r\n\t */\r\n\tallowMissingFile?: boolean;\r\n}\r\n\r\nexport async function discoverBot(projectDir: string, overridePath?: string, options: DiscoverOptions = {}): Promise<BotInfo>\r\n{\r\n\tconst absDir = path.resolve(projectDir);\r\n\r\n\t// 1. Explicit --bot flag\r\n\tif (overridePath)\r\n\t{\r\n\t\tconst absPath = path.resolve(absDir, overridePath);\r\n\t\tif (!fs.existsSync(absPath))\r\n\t\t{\r\n\t\t\tthrow new Error(`Bot file not found: ${absPath}`);\r\n\t\t}\r\n\t\tconst exportName = await findExportName(absPath);\r\n\t\treturn {sourcePath: absPath, exportName};\r\n\t}\r\n\r\n\t// 2. vibemancer.json config\r\n\tconst configPath = path.join(absDir, 'vibemancer.json');\r\n\tif (fs.existsSync(configPath))\r\n\t{\r\n\t\tconst raw = fs.readFileSync(configPath, 'utf-8');\r\n\t\tlet config: VibemancerConfig;\r\n\t\ttry\r\n\t\t{\r\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- JSON.parse returns unknown, manual validation follows\r\n\t\t\tconfig = JSON.parse(raw) as VibemancerConfig;\r\n\t\t}\r\n\t\tcatch\r\n\t\t{\r\n\t\t\tthrow new Error(`Invalid JSON in vibemancer.json: ${configPath}`);\r\n\t\t}\r\n\r\n\t\tif (config.bot !== null && config.bot !== undefined && typeof config.bot !== 'string')\r\n\t\t{\r\n\t\t\tthrow new Error(`Invalid \"bot\" field in vibemancer.json: expected string, got ${typeof config.bot}`);\r\n\t\t}\r\n\r\n\t\tif (config.export !== null && config.export !== undefined && typeof config.export !== 'string')\r\n\t\t{\r\n\t\t\tthrow new Error(`Invalid \"export\" field in vibemancer.json: expected string, got ${typeof config.export}`);\r\n\t\t}\r\n\r\n\t\tif (config.bot)\r\n\t\t{\r\n\t\t\tconst botPath = path.resolve(absDir, config.bot);\r\n\t\t\tif (!fs.existsSync(botPath))\r\n\t\t\t{\r\n\t\t\t\tif (!options.allowMissingFile)\r\n\t\t\t\t{\r\n\t\t\t\t\tthrow new Error(`Bot file from vibemancer.json not found: ${botPath}`);\r\n\t\t\t\t}\r\n\t\t\t\t// Restoring a bot that isn't on this machine yet: the export name can't be read\r\n\t\t\t\t// off disk, so vibemancer.json has to name it.\r\n\t\t\t\tif (!config.export)\r\n\t\t\t\t{\r\n\t\t\t\t\tthrow new Error(\r\n\t\t\t\t\t\t`Bot file ${botPath} does not exist yet, and vibemancer.json has no \"export\" field.\\n`\r\n\t\t\t\t\t\t+ 'Add the wizard name so it can be restored, e.g.:\\n'\r\n\t\t\t\t\t\t+ ' {\"bot\": \"src/bot.ts\", \"export\": \"MyWizard\"}',\r\n\t\t\t\t\t);\r\n\t\t\t\t}\r\n\t\t\t\treturn {sourcePath: botPath, exportName: config.export};\r\n\t\t\t}\r\n\t\t\tconst exportName = config.export || await findExportName(botPath);\r\n\t\t\treturn {sourcePath: botPath, exportName};\r\n\t\t}\r\n\t}\r\n\r\n\t// 3. Auto-discover from src/\r\n\tconst allBots = await discoverAllBots(absDir);\r\n\tif (allBots.length === 1)\r\n\t{\r\n\t\treturn allBots[0]!;\r\n\t}\r\n\tif (allBots.length > 1)\r\n\t{\r\n\t\tconst list = allBots.map((b) => ` --bot ${path.relative(absDir, b.sourcePath).replace(/\\\\/g, '/')} (${b.exportName})`).join('\\n');\r\n\t\tthrow new Error(\r\n\t\t\t`Found ${allBots.length} bots. Pick one with --bot:\\n\\n${list}`,\r\n\t\t);\r\n\t}\r\n\r\n\t// No bots auto-discovered. If src/bot.ts exists, try it directly\r\n\t// so the user gets a specific error (e.g. \"no PascalCase export\").\r\n\tconst defaultPath = path.join(absDir, 'src', 'bot.ts');\r\n\tif (fs.existsSync(defaultPath))\r\n\t{\r\n\t\tconst exportName = await findExportName(defaultPath);\r\n\t\treturn {sourcePath: defaultPath, exportName};\r\n\t}\r\n\r\n\tthrow new Error(\r\n\t\t'Could not find bot source file.\\n'\r\n\t\t+ 'Create a .ts file in src/ with a PascalCase export, e.g.:\\n'\r\n\t\t+ ' export function MyWizard() { ... }',\r\n\t);\r\n}\r\n\r\n/**\r\n * Find the first named export from a TypeScript file.\r\n * Uses a simple regex scan — no full parser needed.\r\n */\r\nasync function findExportName(filePath: string): Promise<string>\r\n{\r\n\tconst content = fs.readFileSync(filePath, 'utf-8');\r\n\r\n\t// Match: export function Foo, export const Foo, export class Foo\r\n\tconst match = content.match(/export\\s+(?:function|const|class)\\s+([A-Z]\\w*)/);\r\n\tif (match?.[1])\r\n\t{\r\n\t\treturn match[1];\r\n\t}\r\n\r\n\t// Match: export { Foo }\r\n\tconst reExport = content.match(/export\\s*\\{\\s*([A-Z]\\w*)/);\r\n\tif (reExport?.[1])\r\n\t{\r\n\t\treturn reExport[1];\r\n\t}\r\n\r\n\tthrow new Error(\r\n\t\t`Could not find a named export in ${filePath}.\\n`\r\n\t\t+ 'Bot export must start with a capital letter (PascalCase).\\n'\r\n\t\t+ 'Example: export function MyWizard() { ... }',\r\n\t);\r\n}\r\n\r\nconst SCAN_SKIP_FILE_PATTERNS = [\r\n\t/\\.d\\.ts$/,\r\n\t/\\.test\\.tsx?$/,\r\n\t/\\.spec\\.tsx?$/,\r\n];\r\nconst SCAN_SKIP_DIR_NAMES = new Set([\r\n\t'node_modules',\r\n\t'dist',\r\n\t'build',\r\n\t'.cache',\r\n\t'.turbo',\r\n\t'__tests__',\r\n]);\r\nconst SCAN_SKIP_FILE_NAMES = new Set([\r\n\t'index.ts', 'index.tsx',\r\n\t'types.ts', 'types.tsx',\r\n\t'helpers.ts', 'helpers.tsx',\r\n]);\r\n\r\nfunction listTsFilesRecursively(rootDir: string): string[]\r\n{\r\n\tconst out: string[] = [];\r\n\tconst stack: string[] = [rootDir];\r\n\twhile (stack.length > 0)\r\n\t{\r\n\t\tconst dir = stack.pop();\r\n\t\tif (dir === undefined) continue;\r\n\t\tlet entries: fs.Dirent[];\r\n\t\ttry\r\n\t\t{\r\n\t\t\tentries = fs.readdirSync(dir, {withFileTypes: true});\r\n\t\t}\r\n\t\tcatch\r\n\t\t{\r\n\t\t\tcontinue;\r\n\t\t}\r\n\t\tfor (const entry of entries)\r\n\t\t{\r\n\t\t\tconst full = path.join(dir, entry.name);\r\n\t\t\tif (entry.isDirectory())\r\n\t\t\t{\r\n\t\t\t\tif (SCAN_SKIP_DIR_NAMES.has(entry.name)) continue;\r\n\t\t\t\tif (entry.name.startsWith('.')) continue;\r\n\t\t\t\tstack.push(full);\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\tif (!entry.isFile()) continue;\r\n\t\t\tif (!entry.name.endsWith('.ts') && !entry.name.endsWith('.tsx')) continue;\r\n\t\t\tif (SCAN_SKIP_FILE_NAMES.has(entry.name)) continue;\r\n\t\t\tif (SCAN_SKIP_FILE_PATTERNS.some((re) => re.test(entry.name))) continue;\r\n\t\t\tout.push(full);\r\n\t\t}\r\n\t}\r\n\treturn out;\r\n}\r\n\r\n/**\r\n * Discover every bot in the project's src/ tree. One file → one bot\r\n * (using its first PascalCase named export). Files without a qualifying\r\n * export are skipped. Returns BotInfo[] sorted alphabetically by export\r\n * name; the array is empty if nothing was found (callers should treat\r\n * that as \"no local bots\", not an error).\r\n *\r\n * Used by the dev server to expose every in-development bot to the web\r\n * client. Single-bot commands (upload, fight, build) still go through\r\n * discoverBot() with its --bot/--export overrides.\r\n */\r\nexport async function discoverAllBots(projectDir: string): Promise<BotInfo[]>\r\n{\r\n\tconst absDir = path.resolve(projectDir);\r\n\tconst srcDir = path.join(absDir, 'src');\r\n\tif (!fs.existsSync(srcDir)) return [];\r\n\r\n\tconst files = listTsFilesRecursively(srcDir);\r\n\tconst bots: BotInfo[] = [];\r\n\tconst seenNames = new Set<string>();\r\n\tfor (const file of files)\r\n\t{\r\n\t\tlet exportName: string;\r\n\t\ttry\r\n\t\t{\r\n\t\t\texportName = await findExportName(file);\r\n\t\t}\r\n\t\tcatch\r\n\t\t{\r\n\t\t\tcontinue; // file has no PascalCase export — not a bot\r\n\t\t}\r\n\t\tif (seenNames.has(exportName)) continue; // duplicate name — keep the first\r\n\t\tseenNames.add(exportName);\r\n\t\tbots.push({sourcePath: file, exportName});\r\n\t}\r\n\tbots.sort((a, b) => a.exportName.localeCompare(b.exportName));\r\n\treturn bots;\r\n}\r\n","/**\n * Dev Server\n *\n * HTTP server with CORS that exposes every locally-developed bot in the\n * project's src/ tree to the VibeMancer web client. Each request compiles\n * the requested bot fresh from source — no caching — so a browser refresh\n * always picks up the latest code.\n *\n * Endpoints:\n * GET /local-bots → {bots: [{name, exportName, sourcePath}]}\n * GET /local-bots/:name/bundle → IIFE bundle setting __injectedBot1\n * GET /health → {status: 'ok'}\n *\n * The web client picks this up via the #botserver=localhost:PORT URL\n * hash and renders the local bots in WizardSourceSelector's \"Local\"\n * tab — usable as either combatant in Arena fights and as the\n * opponent in Manual Play.\n */\n\nimport http from 'node:http';\nimport {discoverAllBots, type BotInfo} from './bot-discovery.js';\nimport {compileSingleBotBundle} from './compile-single-bot.js';\n\nexport interface ServerOptions\n{\n\tport: number;\n\tprojectDir: string;\n}\n\ninterface LocalBotsResponse\n{\n\tbots: {\n\t\tname: string;\n\t\texportName: string;\n\t\tsourcePath: string;\n\t}[];\n}\n\nfunction botInfoToWire(info: BotInfo): LocalBotsResponse['bots'][number]\n{\n\treturn {\n\t\tname: info.exportName,\n\t\texportName: info.exportName,\n\t\tsourcePath: info.sourcePath,\n\t};\n}\n\n/**\n * Start the dev server.\n * Returns the running server instance.\n */\nexport function startServer(options: ServerOptions): http.Server\n{\n\tconst {port, projectDir} = options;\n\n\tasync function loadBots(): Promise<BotInfo[]>\n\t{\n\t\t// Re-scan on every request so newly-added bot files are picked up\n\t\t// without having to restart the server. Discovery is cheap (regex\n\t\t// scan of src/), so this is fine.\n\t\treturn discoverAllBots(projectDir);\n\t}\n\n\tconst server = http.createServer(async(req, res) =>\n\t{\n\t\t// CORS — the hosted viewer at vibemancer.com has to be able to call us\n\t\tres.setHeader('Access-Control-Allow-Origin', '*');\n\t\tres.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');\n\t\tres.setHeader('Access-Control-Allow-Headers', 'Content-Type');\n\n\t\tif (req.method === 'OPTIONS')\n\t\t{\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url ?? '/', `http://localhost:${port}`);\n\t\tconst pathname = url.pathname;\n\n\t\ttry\n\t\t{\n\t\t\tif (pathname === '/health')\n\t\t\t{\n\t\t\t\trespond(res, 200, {status: 'ok'});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pathname === '/local-bots')\n\t\t\t{\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst body: LocalBotsResponse = {bots: bots.map(botInfoToWire)};\n\t\t\t\trespond(res, 200, body);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bundleMatch = /^\\/local-bots\\/([A-Za-z_][A-Za-z0-9_]*)\\/bundle$/.exec(pathname);\n\t\t\tif (bundleMatch)\n\t\t\t{\n\t\t\t\tconst requestedName = bundleMatch[1]!;\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst target = bots.find((b) => b.exportName === requestedName);\n\t\t\t\tif (!target)\n\t\t\t\t{\n\t\t\t\t\trespond(res, 404, {error: `No local bot named \"${requestedName}\". Found: ${bots.map((b) => b.exportName).join(', ') || '(none)'}`});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst start = Date.now();\n\t\t\t\tconst bundle = await compileSingleBotBundle(target.sourcePath, target.exportName);\n\t\t\t\tconst elapsed = Date.now() - start;\n\t\t\t\tconsole.log(` Compiled ${target.exportName} (${(bundle.length / 1024).toFixed(1)} KB) in ${elapsed}ms`);\n\n\t\t\t\tres.writeHead(200, {'Content-Type': 'text/javascript'});\n\t\t\t\tres.end(bundle);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trespond(res, 404, {error: `Not found: ${pathname}`});\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(` Error: ${message}`);\n\t\t\trespond(res, 500, {error: message});\n\t\t}\n\t});\n\n\tserver.listen(port, () =>\n\t{\n\t\tconsole.log(`\\nVibemancer dev server running at http://localhost:${port}`);\n\t\tvoid (async(): Promise<void> =>\n\t\t{\n\t\t\tconst bots = await loadBots();\n\t\t\tif (bots.length === 0)\n\t\t\t{\n\t\t\t\tconsole.log(' (no bots discovered in src/ — add a .ts file with a PascalCase export)');\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconsole.log(` Bots: ${bots.map((b) => b.exportName).join(', ')}`);\n\t\t\t}\n\t\t\tconsole.log('');\n\t\t\tconsole.log('Open your browser to play:');\n\t\t\tconsole.log(` https://vibemancer.com/#botserver=localhost:${port}\\n`);\n\t\t\tconsole.log('Endpoints:');\n\t\t\tconsole.log(' GET /local-bots - List of locally-discovered bots');\n\t\t\tconsole.log(' GET /local-bots/<name>/bundle - Compile a single bot to a sandbox-ready bundle');\n\t\t\tconsole.log(' GET /health - Server health check\\n');\n\t\t})();\n\t});\n\n\treturn server;\n}\n\nfunction respond(res: http.ServerResponse, status: number, data: unknown): void\n{\n\tres.writeHead(status, {'Content-Type': 'application/json'});\n\tres.end(JSON.stringify(data));\n}\n","/**\n * Compile a single bot to a self-contained IIFE bundle.\n *\n * The output sets `globalThis.__injectedBot1` to the bot's exported function.\n * This is the canonical \"uploaded wizard\" bundle shape — the same format the\n * Storage-uploaded wizards live in, the same format the fight-runner /\n * BrowserMatchSandbox concatenates with MATCH_TEMPLATE / MANUAL_MATCH_TEMPLATE.\n *\n * Used by:\n * - `vibemancer upload` (CLI) — uploads to Firebase Storage\n * - dev server's /local-bots/:name/bundle endpoint — served to the web\n * client when picking a local bot\n *\n * `@vibemancer/core` is aliased to the package's TypeScript source (mirroring\n * seed-bots.ts) so the bundle is fully self-contained — no runtime shims, no\n * CJS `require()`, just an IIFE that runs anywhere a Web Worker can.\n */\n\nimport {build} from 'esbuild';\nimport {findCoreSourceDir} from './opponent-resolver.js';\n\nexport async function compileSingleBotBundle(\n\tsourcePath: string,\n\texportName: string,\n): Promise<string>\n{\n\tconst coreSourceDir = findCoreSourceDir();\n\n\tconst result = await build({\n\t\tentryPoints: [sourcePath],\n\t\tbundle: true,\n\t\twrite: false,\n\t\tformat: 'iife',\n\t\tglobalName: '__botExport',\n\t\tplatform: 'neutral',\n\t\ttarget: 'es2022',\n\t\tlogLevel: 'error',\n\t\tfooter: {js: `globalThis.__injectedBot1 = __botExport.${exportName};`},\n\t\texternal: [\n\t\t\t'isolated-vm', 'esbuild',\n\t\t\t'node:*',\n\t\t],\n\t\talias: {\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\n\t\t},\n\t});\n\n\tif (!result.outputFiles?.[0])\n\t{\n\t\tthrow new Error('esbuild produced no output');\n\t}\n\n\treturn result.outputFiles[0].text;\n}\n","/**\n * vibemancer test\n *\n * Runs the user's vitest test suite. Scaffolded projects include a\n * tests/ directory with example tests using the testBot() helper.\n */\n\nimport {spawn} from 'node:child_process';\n\nexport interface TestOptions\n{\n\tbot?: string;\n}\n\nexport async function runTest(_options: TestOptions): Promise<void>\n{\n\tconsole.log('\\n Running tests...\\n');\n\n\t// spawn + await, NOT execSync. execSync blocks the entire event loop, and the CLI fires\n\t// a fire-and-forget telemetry request at command start: while the loop is blocked that\n\t// request cannot progress, and its 1s abort then fires the moment the block ends, so it\n\t// is cancelled before ever being sent. `test` was the ONE local command missing from\n\t// the analytics, which is how this was found. Blocking also stops any other timer or\n\t// I/O the CLI may rely on later, so this is not only about telemetry.\n\tconst code = await new Promise<number>((resolve) =>\n\t{\n\t\tconst child = spawn('npx', ['vitest', 'run'], {\n\t\t\tstdio: 'inherit',\n\t\t\tcwd: process.cwd(),\n\t\t\tshell: process.platform === 'win32',\n\t\t});\n\t\tchild.on('error', () => resolve(1));\n\t\tchild.on('close', (status) => resolve(status ?? 1));\n\t});\n\n\tif (code !== 0)\n\t{\n\t\tprocess.exit(code);\n\t}\n}\n","/**\r\n * vibemancer fight\r\n *\r\n * With no args: fights your bot against all 29 built-in bots and shows ranking.\r\n * With --opponent: quick fight against a single opponent.\r\n *\r\n * Results are saved to .vibemancer/history.json for comparison across runs.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {BotBundle, sandboxFight, scoreFight, runBundleFight} from '@vibemancer/core';\r\nimport type {FightWinner, FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface FightOptions\r\n{\r\n\topponent?: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n}\r\n\r\ninterface FightEntry\r\n{\r\n\topponent: string;\r\n\twinner: FightWinner;\r\n\twizard1Wins: number;\r\n\twizard2Wins: number;\r\n\tdraws: number;\r\n\tscore: number;\r\n\telapsedMs: number;\r\n}\r\n\r\ninterface HistoryEntry\r\n{\r\n\ttimestamp: string;\r\n\tbotName: string;\r\n\tresults: FightEntry[];\r\n\tsummary: {wins: number; losses: number; draws: number; score: number; maxScore: number};\r\n}\r\n\r\nexport async function runFight(options: FightOptions): Promise<void>\r\n{\r\n\tif (options.opponent)\r\n\t{\r\n\t\treturn runSingleFight({...options, opponent: options.opponent});\r\n\t}\r\n\treturn runFullFight(options);\r\n}\r\n\r\n// ─── Single opponent fight ───────────────────────────────────────────────────\r\n\r\nasync function runSingleFight(options: FightOptions & {opponent: string}): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\r\n\tconsole.log(` Opponent: ${options.opponent}\\n`);\r\n\r\n\tconst start = Date.now();\r\n\tlet result: FightResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// run locally through the same isolated-vm engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleFight(userBundle, remote.bundle, {seed: options.seed ?? 1});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxFight(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\tconst elapsed = Date.now() - start;\r\n\r\n\tconst {wizard1Wins, wizard2Wins, draws} = result;\r\n\tconst total = wizard1Wins + wizard2Wins + draws;\r\n\tconst outcome = result.winner === 'wizard-1' ? 'WIN'\r\n\t\t: result.winner === 'wizard-2' ? 'LOSS'\r\n\t\t\t: 'DRAW';\r\n\r\n\tconsole.log(` Result: ${outcome}`);\r\n\tconsole.log(` ${botInfo.exportName}: ${wizard1Wins}W | ${options.opponent}: ${wizard2Wins}W | Draws: ${draws}`);\r\n\tconsole.log(` (${total} matches in ${elapsed}ms)\\n`);\r\n\r\n\tif (result.winner === 'wizard-2')\r\n\t{\r\n\t\tprocess.exit(1);\r\n\t}\r\n}\r\n\r\n// ─── Full fight (all built-in bots) ─────────────────────────────────────────\r\n\r\nasync function runFullFight(options: FightOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\tconst opponents = getBuiltinBotNames();\r\n\tconsole.log(`\\n Fighting ${botInfo.exportName} against ${opponents.length} built-in bots...\\n`);\r\n\r\n\tconst entries: FightEntry[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const opponentName of opponents)\r\n\t{\r\n\t\tconst opponentBundle = resolveOpponent(opponentName);\r\n\t\tconst start = Date.now();\r\n\t\tconst result = await sandboxFight(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tconst elapsed = Date.now() - start;\r\n\t\tconst score = scoreFight(result);\r\n\r\n\t\tentries.push({\r\n\t\t\topponent: opponentName,\r\n\t\t\twinner: result.winner,\r\n\t\t\twizard1Wins: result.wizard1Wins,\r\n\t\t\twizard2Wins: result.wizard2Wins,\r\n\t\t\tdraws: result.draws,\r\n\t\t\tscore,\r\n\t\t\telapsedMs: elapsed,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? 'W'\r\n\t\t\t: result.winner === 'wizard-2' ? 'L'\r\n\t\t\t\t: 'D';\r\n\t\tconst pad = opponentName.padEnd(14);\r\n\t\tconsole.log(` ${pad} ${outcome} ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${elapsed}ms)`);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\tconst wins = entries.filter((e) => e.winner === 'wizard-1').length;\r\n\tconst losses = entries.filter((e) => e.winner === 'wizard-2').length;\r\n\tconst drawCount = entries.filter((e) => e.winner === 'draw').length;\r\n\tconst totalScore = entries.reduce((sum, e) => sum + e.score, 0);\r\n\tconst maxScore = opponents.length * 17.5; // 5 matches × 3.5 max per match per opponent\r\n\r\n\tconsole.log(`\\n Summary: ${wins}W ${losses}L ${drawCount}D out of ${opponents.length} opponents`);\r\n\tconsole.log(` Score: ${totalScore.toFixed(1)} / ${maxScore.toFixed(1)} (${((totalScore / maxScore) * 100).toFixed(1)}%)`);\r\n\tconsole.log(` Total time: ${(totalElapsed / 1000).toFixed(1)}s`);\r\n\r\n\t// Load previous results and show diff\r\n\tconst history = loadHistory(projectDir);\r\n\tconst previous = history.length > 0 ? history[history.length - 1]! : null;\r\n\r\n\tif (previous && previous.botName === botInfo.exportName)\r\n\t{\r\n\t\tshowDiff(entries, previous.results);\r\n\t}\r\n\r\n\t// Save current results\r\n\tconst current: HistoryEntry = {\r\n\t\ttimestamp: new Date().toISOString(),\r\n\t\tbotName: botInfo.exportName,\r\n\t\tresults: entries,\r\n\t\tsummary: {wins, losses, draws: drawCount, score: totalScore, maxScore},\r\n\t};\r\n\tsaveHistory(projectDir, history, current);\r\n\tconsole.log('');\r\n}\r\n\r\n// ─── History persistence ─────────────────────────────────────────────────────\r\n\r\nfunction getHistoryPath(projectDir: string): string\r\n{\r\n\treturn path.join(projectDir, '.vibemancer', 'history.json');\r\n}\r\n\r\nfunction loadHistory(projectDir: string): HistoryEntry[]\r\n{\r\n\tconst historyPath = getHistoryPath(projectDir);\r\n\tif (!fs.existsSync(historyPath)) return [];\r\n\ttry\r\n\t{\r\n\t\tconst raw = fs.readFileSync(historyPath, 'utf-8');\r\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- JSON file we wrote\r\n\t\treturn JSON.parse(raw) as HistoryEntry[];\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\treturn [];\r\n\t}\r\n}\r\n\r\nfunction saveHistory(projectDir: string, history: HistoryEntry[], current: HistoryEntry): void\r\n{\r\n\tconst historyPath = getHistoryPath(projectDir);\r\n\tconst dir = path.dirname(historyPath);\r\n\tfs.mkdirSync(dir, {recursive: true});\r\n\r\n\t// Keep last 20 runs\r\n\tconst updated = [...history.slice(-19), current];\r\n\tfs.writeFileSync(historyPath, JSON.stringify(updated, null, '\\t') + '\\n');\r\n}\r\n\r\nfunction showDiff(current: FightEntry[], previous: FightEntry[]): void\r\n{\r\n\tconst prevMap = new Map(previous.map((e) => [e.opponent, e]));\r\n\tconst changes: string[] = [];\r\n\r\n\tfor (const entry of current)\r\n\t{\r\n\t\tconst prev = prevMap.get(entry.opponent);\r\n\t\tif (!prev) continue;\r\n\r\n\t\tconst prevOutcome = prev.winner === 'wizard-1' ? 'W' : prev.winner === 'wizard-2' ? 'L' : 'D';\r\n\t\tconst curOutcome = entry.winner === 'wizard-1' ? 'W' : entry.winner === 'wizard-2' ? 'L' : 'D';\r\n\r\n\t\tif (prevOutcome !== curOutcome)\r\n\t\t{\r\n\t\t\tchanges.push(` ${entry.opponent.padEnd(14)} ${prevOutcome} -> ${curOutcome}`);\r\n\t\t}\r\n\t}\r\n\r\n\tconst prevScore = previous.reduce((sum, e) => sum + e.score, 0);\r\n\tconst curScore = current.reduce((sum, e) => sum + e.score, 0);\r\n\tconst diff = curScore - prevScore;\r\n\r\n\tif (changes.length > 0 || Math.abs(diff) > 0.1)\r\n\t{\r\n\t\tconsole.log('\\n vs last run:');\r\n\t\tif (Math.abs(diff) > 0.1)\r\n\t\t{\r\n\t\t\tconst sign = diff > 0 ? '+' : '';\r\n\t\t\tconsole.log(` Score: ${sign}${diff.toFixed(1)}`);\r\n\t\t}\r\n\t\tfor (const change of changes)\r\n\t\t{\r\n\t\t\tconsole.log(change);\r\n\t\t}\r\n\t}\r\n}\r\n","/**\n * Resolve a `handle/botname` selector to a downloaded, ready-to-run opponent\n * bundle — so the devkit can fight any user's uploaded bot, identically to the\n * MCP fight tool and the live ladder.\n *\n * All reads are PUBLIC (no login): the wizards collection is world-readable and\n * compiled bundles in Storage are public (required for browser spectating), so\n * resolution + download need no auth. The fight then runs locally via core's\n * runBundleFight — the same isolated-vm engine the matchmaker uses.\n */\n\nimport {initializeApp, getApps, type FirebaseApp} from 'firebase/app';\nimport {getFirestore, collection, query, where, limit, getDocs, connectFirestoreEmulator, type Firestore} from 'firebase/firestore';\nimport {getStorage, ref, getBytes, connectStorageEmulator, type FirebaseStorage} from 'firebase/storage';\nimport {isBannedBotName} from '@vibemancer/core';\nimport {FIREBASE_CONFIG} from './firebase-config.js';\n\nexport interface RemoteOpponent\n{\n\tbundle: string;\n\texportName: string;\n\tlabel: string;\n}\n\n/** True when the opponent string is a `handle/botname` selector (vs a built-in name). */\nexport function isHandleSelector(opponent: string): boolean\n{\n\tconst trimmed = opponent.trim();\n\tconst slash = trimmed.indexOf('/');\n\treturn slash > 0 && slash < trimmed.length - 1;\n}\n\nlet cachedDb: Firestore | null = null;\nlet cachedStorage: FirebaseStorage | null = null;\n\nfunction getApp(): FirebaseApp\n{\n\tconst apps = getApps();\n\treturn apps.length > 0 ? apps[0]! : initializeApp(FIREBASE_CONFIG);\n}\n\n/** Talk to the local emulator instead of prod when VIBEMANCER_EMULATOR=1 (E2E tests). */\nfunction getDb(): Firestore\n{\n\tif (!cachedDb)\n\t{\n\t\tcachedDb = getFirestore(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectFirestoreEmulator(cachedDb, '127.0.0.1', 8085);\n\t}\n\treturn cachedDb;\n}\n\nfunction getBucket(): FirebaseStorage\n{\n\tif (!cachedStorage)\n\t{\n\t\tcachedStorage = getStorage(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectStorageEmulator(cachedStorage, '127.0.0.1', 9199);\n\t}\n\treturn cachedStorage;\n}\n\nexport async function resolveRemoteOpponent(selector: string): Promise<RemoteOpponent>\n{\n\tconst slash = selector.indexOf('/');\n\tconst handle = selector.slice(0, slash).trim().toLowerCase();\n\tconst botName = selector.slice(slash + 1).trim();\n\tif (!handle || !botName)\n\t{\n\t\tthrow new Error(`Invalid opponent \"${selector}\" — expected handle/botname (e.g. happy-golden-banana/FireMage).`);\n\t}\n\t// A filtered (banned) name resolves to nothing — same message as not-found.\n\tif (isBannedBotName(botName))\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst db = getDb();\n\tconst snap = await getDocs(query(\n\t\tcollection(db, 'wizards'),\n\t\twhere('ownerHandle', '==', handle),\n\t\twhere('nameLower', '==', botName.toLowerCase()),\n\t\twhere('active', '==', true),\n\t\tlimit(1),\n\t));\n\tif (snap.empty)\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst docSnap = snap.docs[0]!;\n\tconst data = docSnap.data() as {exportName?: unknown; bundlePath?: unknown};\n\tconst exportName = typeof data.exportName === 'string' ? data.exportName : '';\n\tif (!exportName)\n\t{\n\t\tthrow new Error(`Bot \"${handle}/${botName}\" is missing its export name.`);\n\t}\n\tconst bundlePath = typeof data.bundlePath === 'string' ? data.bundlePath : `bundles/${docSnap.id}.js`;\n\n\tconst bytes = await getBytes(ref(getBucket(), bundlePath));\n\tconst bundle = new TextDecoder().decode(bytes);\n\n\treturn {bundle, exportName, label: `${handle}/${botName}`};\n}\n","export const FIREBASE_CONFIG = {\n\tapiKey: 'AIzaSyDSUJ2jlk5_vlpGOypMtvqKjHhDmbgomIY',\n\tauthDomain: 'le-vibemancer.firebaseapp.com',\n\tprojectId: 'le-vibemancer',\n\tstorageBucket: 'le-vibemancer.firebasestorage.app',\n} as const;\n","/**\r\n * vibemancer trace\r\n *\r\n * Runs a single match and prints a full event trace for debugging.\r\n * Shows both bots' actions: state changes, missile launches (with config),\r\n * hits, damage, dodge proximity, movement patterns, and stats.\r\n */\r\n\r\nimport {\r\n\tBotBundle, sandboxSimulate, runBundleSimulate,\r\n\textractTraceEvents, summarizeTrace, formatTraceEvents, formatTraceSummary,\r\n\tdiagnoseTrace, formatDiagnosis,\r\n\textractStats, formatStats,\r\n} from '@vibemancer/core';\r\nimport type {SimulateResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface TraceOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n\tdistance?: number;\r\n\tmaxTicks?: number;\r\n}\r\n\r\nexport async function runTrace(options: TraceOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst distance = options.distance ?? 600;\r\n\tconsole.log(`\\n Trace: ${botInfo.exportName} (W1) vs ${options.opponent} (W2) | distance: ${distance} | seed: ${options.seed ?? 1}\\n`);\r\n\r\n\tlet result: SimulateResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// simulate locally through the same engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleSimulate(userBundle, remote.bundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxSimulate(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\r\n\tconst history = result.history;\r\n\tif (history.length === 0)\r\n\t{\r\n\t\tconsole.log(' No history available.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Extract and print full event trace (including any bot runtime errors)\r\n\tconst events = extractTraceEvents(history, result.errors);\r\n\tconsole.log(formatTraceEvents(events));\r\n\r\n\t// Print summary (both bots)\r\n\tconst summary = summarizeTrace(events, result, botInfo.exportName, options.opponent);\r\n\tconsole.log('\\n' + formatTraceSummary(summary));\r\n\r\n\t// Print detailed stats for the user's bot\r\n\tconst stats = extractStats(result);\r\n\tconsole.log('');\r\n\tconsole.log(formatStats(stats, botInfo.exportName));\r\n\r\n\t// Print auto-diagnosis (tips for common problems)\r\n\tconst tips = diagnoseTrace(events, summary);\r\n\tif (tips.length > 0)\r\n\t{\r\n\t\tconsole.log('');\r\n\t\tconsole.log(formatDiagnosis(tips));\r\n\t}\r\n\tconsole.log('');\r\n}\r\n","/**\r\n * vibemancer tournament\r\n *\r\n * Runs the user's bot in a round-robin tournament against selected opponents.\r\n * Each pairing is a fight (10 matches: 5 spawn distances × 2 sides).\r\n */\r\n\r\nimport {BotBundle, sandboxFight, scoreFight, scoreFightAsWizard2} from '@vibemancer/core';\r\nimport type {FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface TournamentOptions\r\n{\r\n\topponents?: string[];\r\n\tbot?: string;\r\n}\r\n\r\ninterface Pairing\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tbot1Bundle: BotBundle;\r\n\tbot2Bundle: BotBundle;\r\n}\r\n\r\ninterface PairingResult\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tresult: FightResult;\r\n}\r\n\r\nexport async function runTournament(options: TournamentOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\t// Determine opponents\r\n\tconst opponentNames = options.opponents && options.opponents.length > 0\r\n\t\t? options.opponents\r\n\t\t: getBuiltinBotNames();\r\n\r\n\t// Build list of all participants\r\n\tconst participants: {name: string; bundle: BotBundle}[] = [\r\n\t\t{name: botInfo.exportName, bundle: userBundle},\r\n\t];\r\n\r\n\tfor (const name of opponentNames)\r\n\t{\r\n\t\tparticipants.push({name, bundle: resolveOpponent(name)});\r\n\t}\r\n\r\n\tconsole.log(`\\n Tournament: ${participants.length} participants (${participants.length * (participants.length - 1) / 2} pairings)\\n`);\r\n\r\n\t// Generate all pairings\r\n\tconst pairings: Pairing[] = [];\r\n\tfor (let i = 0; i < participants.length; i++)\r\n\t{\r\n\t\tfor (let j = i + 1; j < participants.length; j++)\r\n\t\t{\r\n\t\t\tpairings.push({\r\n\t\t\t\tbot1Name: participants[i]!.name,\r\n\t\t\t\tbot2Name: participants[j]!.name,\r\n\t\t\t\tbot1Bundle: participants[i]!.bundle,\r\n\t\t\t\tbot2Bundle: participants[j]!.bundle,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t// Run all fights\r\n\tconst results: PairingResult[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const pairing of pairings)\r\n\t{\r\n\t\tconst result = await sandboxFight(pairing.bot1Bundle, pairing.bot2Bundle, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tresults.push({\r\n\t\t\tbot1Name: pairing.bot1Name,\r\n\t\t\tbot2Name: pairing.bot2Name,\r\n\t\t\tresult,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? `${pairing.bot1Name} wins`\r\n\t\t\t: result.winner === 'wizard-2' ? `${pairing.bot2Name} wins`\r\n\t\t\t\t: 'Draw';\r\n\t\tconsole.log(` ${pairing.bot1Name} vs ${pairing.bot2Name}: ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${outcome})`);\r\n\t}\r\n\r\n\t// Calculate standings\r\n\tconst points = new Map<string, number>();\r\n\tconst wins = new Map<string, number>();\r\n\r\n\tfor (const p of participants)\r\n\t{\r\n\t\tpoints.set(p.name, 0);\r\n\t\twins.set(p.name, 0);\r\n\t}\r\n\r\n\tfor (const r of results)\r\n\t{\r\n\t\tconst score1 = scoreFight(r.result);\r\n\t\tconst score2 = scoreFightAsWizard2(r.result);\r\n\r\n\t\tpoints.set(r.bot1Name, (points.get(r.bot1Name) ?? 0) + score1);\r\n\t\tpoints.set(r.bot2Name, (points.get(r.bot2Name) ?? 0) + score2);\r\n\t\twins.set(r.bot1Name, (wins.get(r.bot1Name) ?? 0) + r.result.wizard1Wins);\r\n\t\twins.set(r.bot2Name, (wins.get(r.bot2Name) ?? 0) + r.result.wizard2Wins);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\r\n\t// Sort standings by points desc, then wins desc\r\n\tconst standings = [...points.entries()].sort((a, b) =>\r\n\t{\r\n\t\tif (b[1] !== a[1]) return b[1] - a[1];\r\n\t\treturn (wins.get(b[0]) ?? 0) - (wins.get(a[0]) ?? 0);\r\n\t});\r\n\r\n\tconsole.log('\\n Standings:');\r\n\tconsole.log(' ' + '-'.repeat(40));\r\n\tfor (let i = 0; i < standings.length; i++)\r\n\t{\r\n\t\tconst [name, pts] = standings[i]!;\r\n\t\tconst w = wins.get(name) ?? 0;\r\n\t\tconst rank = `#${(i + 1).toString().padStart(2)}`;\r\n\t\tconst isUser = name === botInfo.exportName ? ' *' : '';\r\n\t\tconsole.log(` ${rank} ${name.padEnd(16)} ${pts.toFixed(1)} pts ${w}W${isUser}`);\r\n\t}\r\n\r\n\tconsole.log(`\\n Total time: ${(totalElapsed / 1000).toFixed(1)}s\\n`);\r\n}\r\n","/**\r\n * vibemancer optimize\r\n *\r\n * Runs parameter optimization for the user's bot.\r\n * Scans for useParam() calls, runs coordinate descent against\r\n * all built-in opponents, and rewrites source with optimal values.\r\n */\r\n\r\nimport {readFileSync, writeFileSync} from 'node:fs';\r\nimport {BotBundle, MatchSandbox, scoreFight, generateCandidates, getEffectiveRange} from '@vibemancer/core';\r\nimport type {FightResult, FightWinner, SimulateResult, ParamDeclaration} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface OptimizeOptions\r\n{\r\n\tbot?: string;\r\n\tsteps?: number;\r\n\trounds?: number;\r\n\topponents?: string[];\r\n}\r\n\r\nexport interface ParsedParam\r\n{\r\n\tname: string;\r\n\tdefaultValue: number;\r\n\tmin?: number;\r\n\tmax?: number;\r\n\tstep?: number;\r\n}\r\n\r\n// Parser-style capture: grab everything until the next , or ) instead of matching specific number formats.\r\n// This handles integers, floats, scientific notation (1e-5), negative numbers, etc.\r\nconst USEPAR_RE = /useParam\\(\\s*['\"](\\w+)['\"]\\s*,\\s*([^,)]+?)\\s*(?:,\\s*\\{([^}]*)\\})?\\s*\\)/g;\r\n\r\nfunction parseNumValue(s: string): number\r\n{\r\n\tconst n = parseFloat(s.trim());\r\n\tif (Number.isNaN(n)) throw new Error(`useParam default is not a number: \"${s.trim()}\"`);\r\n\treturn n;\r\n}\r\n\r\nexport function parseParams(source: string): ParsedParam[]\r\n{\r\n\tconst params: ParsedParam[] = [];\r\n\tconst re = new RegExp(USEPAR_RE.source, 'g');\r\n\tlet match: RegExpExecArray | null;\r\n\r\n\twhile ((match = re.exec(source)) !== null)\r\n\t{\r\n\t\tconst name = match[1]!;\r\n\t\tconst defaultValue = parseNumValue(match[2]!);\r\n\t\tconst optsStr = match[3];\r\n\r\n\t\tlet min: number | undefined;\r\n\t\tlet max: number | undefined;\r\n\t\tlet step: number | undefined;\r\n\r\n\t\tif (optsStr)\r\n\t\t{\r\n\t\t\tconst minMatch = optsStr.match(/min\\s*:\\s*([^,}]+)/);\r\n\t\t\tconst maxMatch = optsStr.match(/max\\s*:\\s*([^,}]+)/);\r\n\t\t\tconst stepMatch = optsStr.match(/step\\s*:\\s*([^,}]+)/);\r\n\t\t\tif (minMatch) min = parseNumValue(minMatch[1]!);\r\n\t\t\tif (maxMatch) max = parseNumValue(maxMatch[1]!);\r\n\t\t\tif (stepMatch) step = parseNumValue(stepMatch[1]!);\r\n\t\t}\r\n\r\n\t\tparams.push({name, defaultValue, min, max, step});\r\n\t}\r\n\r\n\treturn params;\r\n}\r\n\r\nfunction toParamDeclaration(p: ParsedParam): ParamDeclaration\r\n{\r\n\treturn {\r\n\t\tname: p.name,\r\n\t\tvalue: p.defaultValue,\r\n\t\tmin: p.min,\r\n\t\tmax: p.max,\r\n\t\tsteps: p.step ?? 5,\r\n\t};\r\n}\r\n\r\n/**\r\n * Run a full fight (10 matches: 5 spawn distances × 2 sides)\r\n * using sandbox.simulate() with param overrides.\r\n */\r\nconst SPAWN_DISTANCES = [200, 300, 400, 500, 600];\r\nconst SEEDS = [42, 137, 256];\r\n\r\nfunction runFightWithParams(\r\n\tsandbox: MatchSandbox,\r\n\tparams1: Record<string, number>,\r\n): FightResult\r\n{\r\n\tlet w1 = 0;\r\n\tlet w2 = 0;\r\n\tlet draws = 0;\r\n\tconst matches: SimulateResult[] = [];\r\n\r\n\tfor (const seed of SEEDS)\r\n\t{\r\n\t\tfor (const dist of SPAWN_DISTANCES)\r\n\t\t{\r\n\t\t\tconst r = sandbox.simulate({\r\n\t\t\t\tseed,\r\n\t\t\t\tspawnDistance: dist,\r\n\t\t\t\tskipHistory: true,\r\n\t\t\t\tparams1,\r\n\t\t\t});\r\n\t\t\tif (r.winner === 'wizard-1') w1++;\r\n\t\t\telse if (r.winner === 'wizard-2') w2++;\r\n\t\t\telse draws++;\r\n\r\n\t\t\tmatches.push(r);\r\n\t\t}\r\n\t}\r\n\r\n\treturn {\r\n\t\twizard1Wins: w1,\r\n\t\twizard2Wins: w2,\r\n\t\tdraws,\r\n\t\twinner: (w1 > w2 ? 'wizard-1' : w2 > w1 ? 'wizard-2' : 'draw') as FightWinner,\r\n\t\tmatches,\r\n\t};\r\n}\r\n\r\nasync function evaluateParams(\r\n\tuserBundle: BotBundle,\r\n\topponentBundles: BotBundle[],\r\n\tparams1: Record<string, number>,\r\n): Promise<number>\r\n{\r\n\tlet totalScore = 0;\r\n\tfor (const opponent of opponentBundles)\r\n\t{\r\n\t\tconst sandbox = await MatchSandbox.create(userBundle, opponent, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\ttry\r\n\t\t{\r\n\t\t\tconst result = runFightWithParams(sandbox, params1);\r\n\t\t\ttotalScore += scoreFight(result);\r\n\t\t}\r\n\t\tfinally\r\n\t\t{\r\n\t\t\tsandbox.dispose();\r\n\t\t}\r\n\t}\r\n\treturn totalScore;\r\n}\r\n\r\n/**\r\n * Resolve the opponent names to use for optimization.\r\n * If opponents are specified, validates them. Otherwise uses all built-in bots.\r\n */\r\nexport function resolveOpponentNames(opponents: string[] | undefined): string[]\r\n{\r\n\tif (!opponents || opponents.length === 0)\r\n\t{\r\n\t\treturn getBuiltinBotNames();\r\n\t}\r\n\r\n\t// Validate all names before starting\r\n\tconst allNames = getBuiltinBotNames();\r\n\tfor (const name of opponents)\r\n\t{\r\n\t\tif (!allNames.includes(name))\r\n\t\t{\r\n\t\t\tthrow new Error(\r\n\t\t\t\t`Unknown opponent: \"${name}\". Available bots:\\n ${allNames.join(', ')}`,\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\treturn opponents;\r\n}\r\n\r\nexport async function runOptimize(options: OptimizeOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst source = readFileSync(botInfo.sourcePath, 'utf-8');\r\n\tconst params = parseParams(source);\r\n\r\n\tif (params.length === 0)\r\n\t{\r\n\t\tconsole.log('\\n No useParam() calls found in your bot.');\r\n\t\tconsole.log(' Add useParam(\"paramName\", defaultValue, {min, max}) to enable optimization.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\r\n\tconsole.log(` Parameters: ${params.length}`);\r\n\tparams.forEach((p) => console.log(` ${p.name} = ${p.defaultValue} [${p.min ?? 'auto'} .. ${p.max ?? 'auto'}]`));\r\n\r\n\tconst steps = options.steps ?? 5;\r\n\tconst maxRounds = options.rounds ?? 3;\r\n\tconst opponentNames = resolveOpponentNames(options.opponents);\r\n\tconst opponentBundles = opponentNames.map((name) => resolveOpponent(name));\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\tconsole.log(` Opponents: ${opponentBundles.length}`);\r\n\tconsole.log(` Steps per param: ${steps}`);\r\n\tconsole.log(` Max rounds: ${maxRounds}\\n`);\r\n\r\n\t// Current best values\r\n\tconst best: Record<string, number> = {};\r\n\tfor (const p of params) best[p.name] = p.defaultValue;\r\n\r\n\t// Baseline score\r\n\tlet bestScore = await evaluateParams(userBundle, opponentBundles, best);\r\n\tconsole.log(` Baseline score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\r\n\r\n\t// Coordinate descent\r\n\tfor (let round = 0; round < maxRounds; round++)\r\n\t{\r\n\t\tlet improved = false;\r\n\t\tconsole.log(` Round ${round + 1}:`);\r\n\r\n\t\tfor (const p of params)\r\n\t\t{\r\n\t\t\tconst decl = toParamDeclaration(p);\r\n\t\t\tconst range = getEffectiveRange(decl);\r\n\t\t\tconst candidates = generateCandidates(range.min, range.max, steps);\r\n\r\n\t\t\tlet paramBest = best[p.name]!;\r\n\t\t\tlet paramBestScore = bestScore;\r\n\r\n\t\t\tfor (const candidate of candidates)\r\n\t\t\t{\r\n\t\t\t\tif (Math.abs(candidate - paramBest) < 0.001) continue;\r\n\r\n\t\t\t\tconst trial = {...best, [p.name]: candidate};\r\n\t\t\t\tconst score = await evaluateParams(userBundle, opponentBundles, trial);\r\n\r\n\t\t\t\tif (score > paramBestScore)\r\n\t\t\t\t{\r\n\t\t\t\t\tparamBest = candidate;\r\n\t\t\t\t\tparamBestScore = score;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (paramBest !== best[p.name])\r\n\t\t\t{\r\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} -> ${paramBest} (+${(paramBestScore - bestScore).toFixed(1)})`);\r\n\t\t\t\tbest[p.name] = paramBest;\r\n\t\t\t\tbestScore = paramBestScore;\r\n\t\t\t\timproved = true;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} (no improvement)`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!improved)\r\n\t\t{\r\n\t\t\tconsole.log(' No improvements found, stopping.\\n');\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tconsole.log(` Round ${round + 1} score: ${bestScore.toFixed(1)}\\n`);\r\n\t}\r\n\r\n\t// Rewrite source\r\n\tlet updated = source;\r\n\tfor (const p of params)\r\n\t{\r\n\t\tconst newVal = best[p.name]!;\r\n\t\tif (newVal !== p.defaultValue)\r\n\t\t{\r\n\t\t\tconst pattern = new RegExp(\r\n\t\t\t\t`(useParam\\\\(\\\\s*['\"]${escapeRegex(p.name)}['\"]\\\\s*,\\\\s*)${escapeRegex(String(p.defaultValue))}`,\r\n\t\t\t);\r\n\t\t\tupdated = updated.replace(pattern, `$1${newVal}`);\r\n\t\t}\r\n\t}\r\n\r\n\tif (updated !== source)\r\n\t{\r\n\t\twriteFileSync(botInfo.sourcePath, updated);\r\n\t\tconsole.log(` Source updated: ${botInfo.sourcePath}`);\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconsole.log(' No parameter changes to write.');\r\n\t}\r\n\r\n\tconsole.log(` Final score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\r\n}\r\n\r\nfunction escapeRegex(s: string): string\r\n{\r\n\treturn s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n","/**\r\n * vibemancer build\r\n *\r\n * Compiles the user's bot against an opponent into a standalone bundle.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {BotBundle, compileMatchBundle} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, findCoreSourceDir} from '../opponent-resolver.js';\r\n\r\nexport interface BuildOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\toutput?: string;\r\n}\r\n\r\nexport async function runBuild(options: BuildOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst coreSourceDir = findCoreSourceDir();\r\n\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\r\n\tconsole.log(`\\n Compiling ${botInfo.exportName} vs ${options.opponent}...`);\r\n\r\n\tconst start = Date.now();\r\n\tconst bundle = await compileMatchBundle(userBundle, opponentBundle, {\r\n\t\talias: {\r\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\r\n\t\t},\r\n\t});\r\n\tconst elapsed = Date.now() - start;\r\n\r\n\tconst outFile = options.output ?? `dist/${botInfo.exportName}-vs-${options.opponent}.js`;\r\n\tconst outDir = path.dirname(path.resolve(outFile));\r\n\tfs.mkdirSync(outDir, {recursive: true});\r\n\tfs.writeFileSync(path.resolve(outFile), bundle);\r\n\r\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\r\n\tconsole.log(` Output: ${outFile} (${sizeKb} KB)`);\r\n\tconsole.log(` Compiled in ${elapsed}ms\\n`);\r\n}\r\n","/**\r\n * vibemancer bots\r\n *\r\n * Lists all built-in bots with descriptions, grouped by archetype.\r\n * With --name: shows detailed info about a specific bot.\r\n */\r\n\r\nimport {BOT_GROUPS, ALL_BOTS} from '@vibemancer/core';\r\nimport type {WizardEntry} from '@vibemancer/core';\r\n\r\nexport interface BotsOptions\r\n{\r\n\tname?: string;\r\n}\r\n\r\nexport function runBots(options: BotsOptions): void\r\n{\r\n\tif (options.name)\r\n\t{\r\n\t\tshowBotDetail(options.name);\r\n\t\treturn;\r\n\t}\r\n\tlistAllBots();\r\n}\r\n\r\nfunction listAllBots(): void\r\n{\r\n\tconsole.log('\\n Built-in Bots (29 total, ranked weakest → strongest)\\n');\r\n\r\n\tfor (const group of BOT_GROUPS)\r\n\t{\r\n\t\tconsole.log(` ${group.label}:`);\r\n\t\tfor (const bot of group.bots)\r\n\t\t{\r\n\t\t\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\t\t\tconst tierLabel = bot.tier ? `T${bot.tier}` : ' ';\r\n\t\t\tconst rankStr = `#${String(rank).padStart(2)}`;\r\n\t\t\tconsole.log(` ${rankStr} ${tierLabel} ${bot.name.padEnd(14)} ${bot.description}`);\r\n\t\t}\r\n\t\tconsole.log('');\r\n\t}\r\n}\r\n\r\nfunction showBotDetail(name: string): void\r\n{\r\n\tconst bot = ALL_BOTS.find((b) => b.name.toLowerCase() === name.toLowerCase());\r\n\tif (!bot)\r\n\t{\r\n\t\tconst available = ALL_BOTS.map((b) => b.name).join(', ');\r\n\t\tconsole.error(`\\n Unknown bot: \"${name}\"\\n Available: ${available}\\n`);\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\r\n\tconsole.log(`\\n ${bot.name}`);\r\n\tconsole.log(` ${'─'.repeat(40)}`);\r\n\tconsole.log(` Rank: #${rank} of ${ALL_BOTS.length}`);\r\n\tconsole.log(` Group: ${bot.group}`);\r\n\tif (bot.tier) console.log(` Tier: ${bot.tier} of 3`);\r\n\tconsole.log(` Description: ${bot.description}`);\r\n\tconsole.log(` Style: ${getStyleDescription(bot)}`);\r\n\r\n\t// Show group progression if tiered\r\n\tif (bot.tier && bot.group !== 'Standalone')\r\n\t{\r\n\t\tconst groupBots = BOT_GROUPS.find((g) => g.label === bot.group)?.bots ?? [];\r\n\t\tif (groupBots.length > 1)\r\n\t\t{\r\n\t\t\tconsole.log(`\\n ${bot.group} progression:`);\r\n\t\t\tfor (const gb of groupBots)\r\n\t\t\t{\r\n\t\t\t\tconst gbRank = ALL_BOTS.indexOf(gb) + 1;\r\n\t\t\t\tconst marker = gb.name === bot.name ? ' ←' : '';\r\n\t\t\t\tconsole.log(` T${gb.tier} ${gb.name.padEnd(14)} #${gbRank} — ${gb.description}${marker}`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconsole.log(`\\n To fight: vibemancer fight --opponent ${bot.name}`);\r\n\tconsole.log(` To trace: vibemancer trace --opponent ${bot.name}\\n`);\r\n}\r\n\r\nfunction getStyleDescription(bot: WizardEntry): string\r\n{\r\n\tswitch (bot.group)\r\n\t{\r\n\t\tcase 'Standalone':\r\n\t\t\tif (bot.name === 'TargetDummy') return 'Does nothing. Use for basic testing.';\r\n\t\t\tif (bot.name === 'Critter') return 'Random actions. Tests handling of unpredictable opponents.';\r\n\t\t\tif (bot.name === 'Rookie') return 'Simple homing missiles. Good first benchmark.';\r\n\t\t\tif (bot.name === 'Hogger') return 'Random but with real damage. Chaos test.';\r\n\t\t\tif (bot.name === 'Doombringer') return 'One huge missile. Tests shield timing.';\r\n\t\t\treturn bot.description;\r\n\t\tcase 'Defensive': return 'Prioritizes shields and survival. Punishes aggression with counter-missiles. Weak to chip damage and shield baiting.';\r\n\t\tcase 'Melee': return 'Blinks in close, fires fast low-range stabs. Weak to kiting and ranged pressure.';\r\n\t\tcase 'Homing': return 'Slow tracking missiles that are hard to dodge. Weak to shields and fast burst.';\r\n\t\tcase 'Caster': return 'Medium-range homing with adaptive missile fitting. Balanced offense and defense.';\r\n\t\tcase 'Sniper': return 'Intercept-predicted straight shots. High accuracy, weak to erratic movement.';\r\n\t\tcase 'Duelist': return 'Close-range fighters with balanced offense/defense. Jack of all trades.';\r\n\t\tcase 'Berserker': return 'Aggressive traders who close distance fast. Weak to kiting and strong defense.';\r\n\t\tcase 'Kiter': return 'Maintains distance while firing homing missiles. Weak to fast closers and blink gap-close.';\r\n\t\tdefault: return bot.description;\r\n\t}\r\n}\r\n","/**\n * vibemancer upload\n *\n * Compiles the user's bot into a standalone bundle and uploads it to Vibemancer\n * via the authed gateway (`POST /api/upload`), owned by the canonical Firebase\n * identity from `vibemancer login`. The server validates + dedupes; if the same\n * code was uploaded before, the old wizard is reactivated (rating/history kept).\n */\n\nimport fs from 'node:fs';\nimport {discoverBot} from '../bot-discovery.js';\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\nimport {uploadBot} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface UploadOptions\n{\n\tbot?: string;\n}\n\nconst MAX_BUNDLE_BYTES = 500 * 1024;\n\nexport async function runUpload(options: UploadOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\n\tconsole.log(`\\n Compiling ${botInfo.exportName}...`);\n\tconst bundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\n\tconsole.log(` Bundle: ${sizeKb} KB`);\n\n\tif (bundle.length > MAX_BUNDLE_BYTES)\n\t{\n\t\tconsole.error(` Error: Bundle too large (${sizeKb} KB). Max ${MAX_BUNDLE_BYTES / 1024} KB.`);\n\t\tprocess.exit(1);\n\t}\n\n\tlet sourceCode = '';\n\ttry\n\t{\n\t\tsourceCode = fs.readFileSync(botInfo.sourcePath, 'utf-8');\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — source storage is optional\n\t}\n\n\tconsole.log(` Wizard: ${botInfo.exportName}`);\n\tconsole.log(' Uploading to Vibemancer...');\n\n\ttry\n\t{\n\t\tconst result = await uploadBot({\n\t\t\tbundle,\n\t\t\tname: botInfo.exportName,\n\t\t\texportName: botInfo.exportName,\n\t\t\tsourceCode,\n\t\t});\n\t\tconsole.log(` ✓ ${result.message}`);\n\t\tif (result.wizardId) console.log(` Wizard ID: ${result.wizardId}`);\n\t\tconsole.log(` Your wizard \"${botInfo.exportName}\" is now competing.\\n`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` ✗ Upload failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * Environment headers the CLI attaches to requests it ALREADY makes, so the server can\n * answer \"which OS are CLI users on\" and \"MCP vs CLI\" without the CLI issuing a single\n * extra outbound request. See docs/decisions/0001-usage-analytics-bigquery.md.\n *\n * Deliberately narrow: platform, release, arch, node version, CLI version. No username,\n * no hostname, no paths — none of which we need, and all of which would be a liability.\n */\n\nimport os from 'node:os';\nimport {readFileSync} from 'node:fs';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\n/**\n * Walk upwards from `here` looking for this package's own manifest.\n *\n * The try/catch sits INSIDE the loop deliberately. With one try around the whole loop, the\n * first candidate that does not exist aborted the entire search — which is what happens in\n * every built layout (`dist/cli.js` has nothing two levels up) and in every published\n * install. The result was a CLI that reported no version at all, invisible in the tests\n * because the SOURCE layout happens to match the first candidate, and only visible as a\n * column of nulls in the analytics.\n *\n * Exported so the layouts can be exercised directly rather than only the one the tests\n * happen to run in.\n */\nexport function findCliVersionFrom(here: string): string\n{\n\tfor (const rel of ['../../package.json', '../package.json', '../../../package.json'])\n\t{\n\t\ttry\n\t\t{\n\t\t\tconst parsed: unknown = JSON.parse(readFileSync(path.resolve(here, rel), 'utf8'));\n\t\t\tif (typeof parsed !== 'object' || parsed === null) continue;\n\t\t\tif (!('name' in parsed) || !('version' in parsed)) continue;\n\t\t\tconst {name, version} = parsed;\n\t\t\tif (name === 'vibemancer' && typeof version === 'string') return version;\n\t\t}\n\t\tcatch\n\t\t{\n\t\t\t// A candidate that is missing or unreadable is ordinary; try the next one.\n\t\t}\n\t}\n\treturn '';\n}\n\nfunction readCliVersion(): string\n{\n\ttry\n\t{\n\t\treturn findCliVersionFrom(path.dirname(fileURLToPath(import.meta.url)));\n\t}\n\tcatch\n\t{\n\t\t// Version is nice-to-have; never worth failing a command over.\n\t\treturn '';\n\t}\n}\n\n/**\n * Build the telemetry headers. Pure given its inputs so it can be tested without touching\n * the real environment.\n */\nexport function buildEnvHeaders(env: {\n\tplatform: string;\n\trelease: string;\n\tarch: string;\n\tnodeVersion: string;\n\tcliVersion: string;\n}): Record<string, string>\n{\n\tconst headers: Record<string, string> = {};\n\tconst put = (key: string, value: string): void =>\n\t{\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed) headers[key] = trimmed.slice(0, 64);\n\t};\n\tput('x-vibemancer-os', env.platform);\n\tput('x-vibemancer-os-release', env.release);\n\tput('x-vibemancer-arch', env.arch);\n\tput('x-vibemancer-node', env.nodeVersion);\n\tput('x-vibemancer-cli', env.cliVersion);\n\treturn headers;\n}\n\n/** The headers for THIS machine. */\nexport function envHeaders(): Record<string, string>\n{\n\ttry\n\t{\n\t\treturn buildEnvHeaders({\n\t\t\tplatform: os.platform(),\n\t\t\trelease: os.release(),\n\t\t\tarch: os.arch(),\n\t\t\tnodeVersion: process.version,\n\t\t\tcliVersion: readCliVersion(),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\treturn {};\n\t}\n}\n","/**\n * Client for the authed gateway REST endpoints. Attaches the Bearer session\n * token (carrying the canonical Firebase uid) and parses responses. This is the\n * single network path the CLI uses to upload + pull.\n */\n\nimport {getAccessToken, MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\nexport interface UploadPayload\n{\n\tbundle: string;\n\tname: string;\n\texportName: string;\n\tsourceCode: string;\n}\n\nexport interface UploadResult\n{\n\twizardId: string;\n\tmessage: string;\n}\n\nexport async function uploadBot(payload: UploadPayload): Promise<UploadResult>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/upload`, {\n\t\tmethod: 'POST',\n\t\t// Environment headers ride along on a request already being made — no extra call.\n\t\theaders: {'Content-Type': 'application/json', Authorization: `Bearer ${token}`, ...envHeaders()},\n\t\tbody: JSON.stringify(payload),\n\t});\n\tif (!res.ok) throw new Error(`Upload failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst wizardId = typeof data === 'object' && data !== null && 'wizardId' in data && typeof data.wizardId === 'string'\n\t\t? data.wizardId\n\t\t: '';\n\tconst message = typeof data === 'object' && data !== null && 'message' in data && typeof data.message === 'string'\n\t\t? data.message\n\t\t: 'Uploaded.';\n\treturn {wizardId, message};\n}\n\nexport async function pullSource(name: string): Promise<string>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/pull?name=${encodeURIComponent(name)}`, {\n\t\theaders: {Authorization: `Bearer ${token}`, ...envHeaders()},\n\t});\n\tif (!res.ok) throw new Error(`Pull failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst source = typeof data === 'object' && data !== null && 'sourceCode' in data && typeof data.sourceCode === 'string'\n\t\t? data.sourceCode\n\t\t: '';\n\tif (source) return source;\n\tconst error = typeof data === 'object' && data !== null && 'error' in data && typeof data.error === 'string'\n\t\t? data.error\n\t\t: 'No source returned.';\n\tthrow new Error(error);\n}\n","/**\n * vibemancer pull\n *\n * Downloads the latest source of your active wizard (by export name) from the\n * authed gateway (`GET /api/pull`) and writes it to the local bot file. Enables\n * round-tripping between MCP chat sessions and local CLI development.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {discoverBot} from '../bot-discovery.js';\nimport {pullSource} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface PullOptions\n{\n\tbot?: string;\n}\n\nexport async function runPull(options: PullOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\t// pull RESTORES source, so the file legitimately may not exist yet — a new machine, a\n\t// fresh clone, or a bot authored in an MCP chat session. See DiscoverOptions.\n\tconst botInfo = await discoverBot(projectDir, options.bot, {allowMissingFile: true});\n\tconst isNew = !fs.existsSync(botInfo.sourcePath);\n\n\tconsole.log(`\\n Pulling latest source for ${botInfo.exportName}...`);\n\n\ttry\n\t{\n\t\tconst sourceCode = await pullSource(botInfo.exportName);\n\t\t// On a fresh machine the containing directory (src/) may not exist either.\n\t\tfs.mkdirSync(path.dirname(botInfo.sourcePath), {recursive: true});\n\t\tfs.writeFileSync(botInfo.sourcePath, sourceCode);\n\t\tconsole.log(` ✓ ${isNew ? 'Created' : 'Updated'} ${botInfo.sourcePath}`);\n\t\tconsole.log(` ${(sourceCode.length / 1024).toFixed(1)} KB written`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` Pull failed: ${err instanceof Error ? err.message : String(err)}`);\n\t\t\tconsole.error(' Upload first with: vibemancer upload\\n');\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * vibemancer login\n *\n * Authenticates the CLI as an OAuth client of the MCP gateway. The resulting\n * session token carries the canonical Firebase uid (the same identity the web\n * and MCP use), so uploads from the CLI are owned by the same account.\n *\n * Default: browser loopback (a localhost server catches the redirect).\n * `--no-browser`: print the URL + paste the code shown on the gateway page.\n */\n\nimport {createServer, type IncomingMessage, type ServerResponse} from 'node:http';\nimport {randomBytes} from 'node:crypto';\nimport {spawn} from 'node:child_process';\nimport {createInterface} from 'node:readline/promises';\nimport {generatePkce, registerClient, exchangeCode, MCP_BASE_URL} from '../auth/oauth-client.js';\n\nexport interface LoginOptions\n{\n\tnoBrowser?: boolean;\n}\n\nexport function buildAuthorizeUrl(\n\tbaseUrl: string,\n\tparams: {clientId: string; redirectUri: string; challenge: string; state: string},\n): string\n{\n\tconst u = new URL(`${baseUrl}/authorize`);\n\tu.searchParams.set('response_type', 'code');\n\tu.searchParams.set('client_id', params.clientId);\n\tu.searchParams.set('redirect_uri', params.redirectUri);\n\tu.searchParams.set('code_challenge', params.challenge);\n\tu.searchParams.set('code_challenge_method', 'S256');\n\tu.searchParams.set('state', params.state);\n\treturn u.toString();\n}\n\nexport function extractCodeFromCallback(reqUrl: string, expectedState: string): {code: string} | {error: string}\n{\n\tconst u = new URL(reqUrl, 'http://localhost');\n\tconst code = u.searchParams.get('code');\n\tconst state = u.searchParams.get('state');\n\tif (!code) return {error: 'No authorization code in the callback.'};\n\tif (state !== expectedState) return {error: 'State mismatch (possible CSRF) — try again.'};\n\treturn {code};\n}\n\nfunction openBrowser(url: string): void\n{\n\ttry\n\t{\n\t\tconst child = process.platform === 'win32'\n\t\t\t? spawn('cmd', ['/c', 'start', '', url], {stdio: 'ignore', detached: true})\n\t\t\t: spawn(process.platform === 'darwin' ? 'open' : 'xdg-open', [url], {stdio: 'ignore', detached: true});\n\t\tchild.unref();\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — the URL is also printed for manual opening\n\t}\n}\n\ninterface LoopbackServer\n{\n\tport: number;\n\twaitForCode: Promise<string>;\n\tclose: () => void;\n}\n\nfunction startLoopbackServer(expectedState: string): Promise<LoopbackServer>\n{\n\treturn new Promise((resolveServer) =>\n\t{\n\t\tlet resolveCode: (code: string) => void = () => undefined;\n\t\tlet rejectCode: (err: Error) => void = () => undefined;\n\t\tconst waitForCode = new Promise<string>((res, rej) =>\n\t\t{\n\t\t\tresolveCode = res;\n\t\t\trejectCode = rej;\n\t\t});\n\n\t\tconst server = createServer((req: IncomingMessage, res: ServerResponse) =>\n\t\t{\n\t\t\tconst result = extractCodeFromCallback(req.url ?? '', expectedState);\n\t\t\tif ('error' in result)\n\t\t\t{\n\t\t\t\tres.writeHead(400, {'Content-Type': 'text/html'});\n\t\t\t\tres.end('<h2>Login failed</h2><p>You can close this tab and try again.</p>');\n\t\t\t\trejectCode(new Error(result.error));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.writeHead(200, {'Content-Type': 'text/html'});\n\t\t\tres.end('<h2>Vibemancer login complete</h2><p>You can close this tab and return to the terminal.</p>');\n\t\t\tresolveCode(result.code);\n\t\t});\n\n\t\tserver.listen(0, '127.0.0.1', () =>\n\t\t{\n\t\t\tconst addr = server.address();\n\t\t\tconst port = typeof addr === 'object' && addr !== null ? addr.port : 0;\n\t\t\tresolveServer({port, waitForCode, close: () => server.close()});\n\t\t});\n\t});\n}\n\nasync function runBrowserLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst {port, waitForCode, close} = await startLoopbackServer(state);\n\tconst redirectUri = `http://localhost:${port}/callback`;\n\ttry\n\t{\n\t\tconst clientId = await registerClient(redirectUri);\n\t\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\t\tconsole.log('\\n Opening your browser to sign in with Google...');\n\t\tconsole.log(` If it doesn't open, visit:\\n ${authUrl}\\n`);\n\t\topenBrowser(authUrl);\n\t\tconst code = await waitForCode;\n\t\tawait exchangeCode(code, verifier);\n\t\tconsole.log(' ✓ Logged in. You can now run `vibemancer upload`.\\n');\n\t}\n\tfinally\n\t{\n\t\tclose();\n\t}\n}\n\nasync function runPasteLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst redirectUri = `${MCP_BASE_URL}/cli-code`;\n\tconst clientId = await registerClient(redirectUri);\n\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\tconsole.log('\\n Open this URL in a browser, sign in, then paste the code shown:\\n');\n\tconsole.log(` ${authUrl}\\n`);\n\tconst rl = createInterface({input: process.stdin, output: process.stdout});\n\tconst code = (await rl.question(' Paste code: ')).trim();\n\trl.close();\n\tif (!code)\n\t{\n\t\tconsole.error(' No code entered.');\n\t\tprocess.exit(1);\n\t}\n\tawait exchangeCode(code, verifier);\n\tconsole.log(' ✓ Logged in.\\n');\n}\n\nexport async function runLogin(options: LoginOptions): Promise<void>\n{\n\tconst {verifier, challenge} = generatePkce();\n\tconst state = randomBytes(16).toString('hex');\n\tif (options.noBrowser)\n\t{\n\t\tawait runPasteLogin(challenge, verifier, state);\n\t}\n\telse\n\t{\n\t\tawait runBrowserLogin(challenge, verifier, state);\n\t}\n}\n","/**\n * Server-side session revocation for the CLI.\n *\n * `clearCredentials()` only deletes the local file; the refresh token stayed valid on the\n * gateway for the rest of its 30 days, so a copied token survived a logout. This calls\n * the gateway so the session actually ends.\n *\n * Best-effort by design: it reports failure rather than throwing, because the local\n * credentials must still be cleared when the network is down — or when the user is\n * logging out precisely because something has gone wrong.\n */\n\nimport {MCP_BASE_URL} from './oauth-client.js';\n\n/** Revoke the session behind `token`. Returns whether the gateway confirmed it. */\nexport async function revokeSession(token: string): Promise<boolean>\n{\n\tif (!token) return false;\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/revoke`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json'},\n\t\t\tbody: JSON.stringify({token}),\n\t\t});\n\t\treturn res.ok;\n\t}\n\tcatch\n\t{\n\t\treturn false;\n\t}\n}\n","/**\n * vibemancer logout — end the session, then clear the cached OAuth credentials.\n *\n * Clearing the local file alone used to leave the refresh token valid on the gateway for\n * the rest of its 30 days, so a copied credential survived a logout. The revoke call is\n * best-effort: the local credentials are cleared either way, because a user with no\n * network — or one logging out BECAUSE something is wrong — must still be able to get\n * their credentials off the machine.\n */\n\nimport {clearCredentials, loadCredentials} from '../auth/credentials-store.js';\nimport {revokeSession} from '../auth/revoke.js';\n\nexport async function runLogout(): Promise<void>\n{\n\tconst credentials = loadCredentials();\n\tconst revoked = credentials ? await revokeSession(credentials.accessToken) : false;\n\n\tclearCredentials();\n\n\tif (credentials && !revoked)\n\t{\n\t\tconsole.log(' Logged out locally, but the server could not be reached to end the session.');\n\t\tconsole.log(' Run `vibemancer logout` again while online to revoke it.');\n\t\treturn;\n\t}\n\tconsole.log(' Logged out.');\n}\n","/**\n * vibemancer feedback \"what went wrong\"\n *\n * Posts to the PUBLIC `/feedback` endpoint — the same one the web page documents, which\n * needs no account at all.\n *\n * It used to call the `submitFeedback` Firebase callable from a bare `initializeApp`, with\n * no credential attached: no Firebase Auth session, and not the gateway JWT that `login`\n * caches. The callable requires `request.auth`, so the command answered \"Sign in to submit\n * feedback\" to everyone — including users who were signed in. It could not succeed for\n * anybody, and had been that way since CLI auth moved to the MCP gateway.\n *\n * A cached token is attached when there is one, so a signed-in report stays attributable.\n * Its absence never blocks the report: the endpoint exists precisely so that someone whose\n * sign-in is broken can tell us that, and requiring a token here would rebuild the dead end.\n */\n\nimport {MCP_BASE_URL} from '../auth/oauth-client.js';\nimport {envHeaders} from '../auth/env-headers.js';\n\nexport interface FeedbackOptions\n{\n\tmessage: string;\n}\n\n/** Resolve the cached access token, or null when not signed in. Injected for testing. */\nexport type TokenLookup = () => Promise<string | null>;\n\nasync function defaultTokenLookup(): Promise<string | null>\n{\n\tconst {getAccessToken} = await import('../auth/oauth-client.js');\n\treturn await getAccessToken();\n}\n\nexport async function runFeedback(options: FeedbackOptions, tokenLookup: TokenLookup = defaultTokenLookup): Promise<void>\n{\n\tconst message = options.message.trim();\n\tif (!message)\n\t{\n\t\tconsole.error(' Error: feedback message cannot be empty.');\n\t\tprocess.exit(1);\n\t\treturn;\n\t}\n\n\tconsole.log('\\n Submitting feedback...');\n\n\t// Best effort. Not being signed in is the NORMAL case for a bug report about signing in.\n\tlet token: string | null;\n\ttry\n\t{\n\t\ttoken = await tokenLookup();\n\t}\n\tcatch\n\t{\n\t\t// No cached credential, or a refresh that failed. Neither is a reason to drop a\n\t\t// bug report — especially one that might be about signing in.\n\t\ttoken = null;\n\t}\n\n\tconst headers: Record<string, string> = {'Content-Type': 'application/json', ...envHeaders()};\n\tif (token) headers.Authorization = `Bearer ${token}`;\n\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/feedback`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({message}),\n\t\t\tsignal: AbortSignal.timeout(15_000),\n\t\t});\n\n\t\tif (!res.ok)\n\t\t{\n\t\t\tconst body = await res.text();\n\t\t\tlet detail = body;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst parsed: unknown = JSON.parse(body);\n\t\t\t\tif (typeof parsed === 'object' && parsed !== null && 'error' in parsed)\n\t\t\t\t{\n\t\t\t\t\tdetail = String((parsed as {error: unknown}).error);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch\n\t\t\t{\n\t\t\t\t// Keep the raw body; a non-JSON error is still worth showing.\n\t\t\t}\n\t\t\tconsole.error(` Failed to submit: ${detail}\\n`);\n\t\t\tprocess.exit(1);\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.log(token\n\t\t\t? ' Sent! Thanks for the feedback.\\n'\n\t\t\t: ' Sent! Thanks for the feedback. (Not signed in, so we have no way to reply.)\\n');\n\t}\n\tcatch(err: unknown)\n\t{\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tconsole.error(` Failed to submit: ${msg}\\n`);\n\t\tprocess.exit(1);\n\t}\n}\n","import {calculateMissileCastTime, GCD_DURATION, TICKS_PER_SECOND, calculateMissileRadius} from '@vibemancer/core';\n\nexport interface MissileCalcOptions\n{\n\tdamage: number;\n\tspeed: number;\n\tduration: number;\n\tturnRate: number;\n}\n\nexport function runMissileCalc(options: MissileCalcOptions): void\n{\n\tconst config = {\n\t\tdamage: options.damage,\n\t\tspeed: options.speed,\n\t\tduration: options.duration,\n\t\tturnRate: options.turnRate,\n\t};\n\n\tconst castTimeSec = calculateMissileCastTime(config);\n\tconst castFrames = Math.max(1, Math.round(castTimeSec * TICKS_PER_SECOND));\n\tconst gcdSec = GCD_DURATION / TICKS_PER_SECOND;\n\tconst totalCycleSec = castTimeSec + gcdSec;\n\tconst dps = config.damage / totalCycleSec;\n\tconst range = config.speed * config.duration;\n\tconst radius = calculateMissileRadius(config.damage);\n\n\tconsole.log(`\n Missile Calculator\n ──────────────────\n Config: damage=${config.damage} speed=${config.speed} duration=${config.duration} turnRate=${config.turnRate}\n Cast time: ${castTimeSec.toFixed(3)}s (${castFrames} frames)\n GCD: ${gcdSec}s (${GCD_DURATION} frames)\n Full cycle: ${totalCycleSec.toFixed(3)}s (cast + GCD)\n Eff. DPS: ${dps.toFixed(2)} HP/s\n Range: ${range} units (speed × duration)\n Hitbox: ${radius.toFixed(2)} radius\n`);\n}\n","/**\n * CLI telemetry for LOCAL commands (dev / fight / test / optimize / trace / build).\n *\n * Commands that talk to the gateway are already measured by the headers in\n * env-headers.ts. Local commands are not, and that gap is the important one: without\n * them the only people counted are those who successfully signed in and uploaded, so\n * \"what fraction of installs never upload?\" — the question that decides whether the CLI\n * is worth maintaining — would be computed over survivors only.\n *\n * Three rules this must never break:\n * 1. It must never block. Sent at command START so a long command overlaps the request,\n * with a hard timeout so an unreachable server cannot delay the exit.\n * 2. It must never throw. A telemetry failure is not a CLI failure.\n * 3. It must be refusable, and say so once. Developers are the audience most likely to\n * object to a tool phoning home, and the least likely to forgive doing it silently.\n */\n\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\n/** Milliseconds before an unreachable server is abandoned. */\nconst TIMEOUT_MS = 1000;\n\n/**\n * Is telemetry allowed?\n *\n * Honours our own switch AND `DO_NOT_TRACK`, the cross-tool convention — a developer who\n * has set that globally has already expressed the preference, and ignoring it because it\n * is not our variable would be obtuse.\n */\nexport function isTelemetryEnabled(env: NodeJS.ProcessEnv): boolean\n{\n\tconst off = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '0' || v === 'false' || v === 'off' || v === 'no';\n\t};\n\tconst on = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '1' || v === 'true' || v === 'on' || v === 'yes';\n\t};\n\n\tif (off(env.VIBEMANCER_TELEMETRY)) return false;\n\tif (on(env.DO_NOT_TRACK)) return false;\n\t// CI machines are not people; counting them would inflate every figure.\n\tif (on(env.CI)) return false;\n\treturn true;\n}\n\n/** The one-time notice. Exported so its wording can be asserted rather than drift. */\nexport const TELEMETRY_NOTICE =\n\t' Vibemancer records which commands are run, your OS and version numbers, to decide\\n'\n\t+ ' which platforms to support. No code, file paths or personal files are ever sent.\\n'\n\t+ ' Opt out any time with VIBEMANCER_TELEMETRY=0 (DO_NOT_TRACK is honoured too).\\n';\n\n/** Where the \"already told them\" marker lives. */\nfunction noticePath(): string\n{\n\treturn path.join(os.homedir(), '.vibemancer', 'telemetry-notice-shown');\n}\n\n/**\n * Print the notice the first time only. Returns whether it printed, so tests can assert\n * the once-only behaviour rather than trusting it.\n */\nexport function showNoticeOnce(marker: string = noticePath()): boolean\n{\n\ttry\n\t{\n\t\tif (fs.existsSync(marker)) return false;\n\t\tfs.mkdirSync(path.dirname(marker), {recursive: true});\n\t\tfs.writeFileSync(marker, new Date().toISOString());\n\t\tconsole.log(TELEMETRY_NOTICE);\n\t\treturn true;\n\t}\n\tcatch\n\t{\n\t\t// If the marker cannot be written, stay silent rather than nagging every run.\n\t\treturn false;\n\t}\n}\n\n/**\n * Record that a local command ran. Fire-and-forget by construction: the returned promise\n * is resolved even on failure, so a caller that forgets to await cannot produce an\n * unhandled rejection.\n */\nexport async function recordLocalCommand(command: string, env: NodeJS.ProcessEnv = process.env, marker: string = noticePath()): Promise<void>\n{\n\tif (!isTelemetryEnabled(env)) return;\n\t// `marker` is injectable so the test suite cannot consume the real first-run notice on\n\t// whichever machine runs it — otherwise the one person certain to have run the tests is\n\t// the one person who never sees the notice.\n\tshowNoticeOnce(marker);\n\n\ttry\n\t{\n\t\t// envHeaders() rather than hand-built ones: it resolves the CLI version too, and the\n\t\t// version spread of people who never upload is the half we could not otherwise see.\n\t\tconst headers = envHeaders();\n\t\tawait fetch(`${MCP_BASE_URL}/cli-telemetry`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json', ...headers},\n\t\t\tbody: JSON.stringify({command}),\n\t\t\tsignal: AbortSignal.timeout(TIMEOUT_MS),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\t// Never a CLI failure.\n\t}\n}\n","/**\r\n * Vibemancer CLI\r\n *\r\n * Development tools for building wizard bots.\r\n *\r\n * Usage:\r\n * vibemancer dev [--port 4242] [--bot src/bot.ts]\r\n * vibemancer test\r\n * vibemancer fight [--opponent Battlemage]\r\n * vibemancer trace --opponent Battlemage\r\n * vibemancer tournament [opponents...]\r\n * vibemancer optimize [--opponents Battlemage,Warmage]\r\n * vibemancer build --opponent Battlemage\r\n */\r\n\r\nimport {runDev} from './commands/dev.js';\r\nimport {runTest} from './commands/test.js';\r\nimport {runFight} from './commands/fight.js';\r\nimport {runTrace} from './commands/trace.js';\r\nimport {runTournament} from './commands/tournament.js';\r\nimport {runOptimize} from './commands/optimize.js';\r\nimport {runBuild} from './commands/build.js';\r\nimport {runBots} from './commands/bots.js';\r\nimport {runUpload} from './commands/upload.js';\r\nimport {runPull} from './commands/pull.js';\r\nimport {runLogin} from './commands/login.js';\r\nimport {runLogout} from './commands/logout.js';\r\nimport {runFeedback} from './commands/feedback.js';\r\nimport {runMissileCalc} from './commands/missile-calc.js';\r\nimport {recordLocalCommand} from './auth/telemetry.js';\r\n\r\nconst args = process.argv.slice(2);\r\nconst command = args[0];\r\n\r\nfunction parseFlag(flag: string): string | undefined\r\n{\r\n\tconst idx = args.indexOf(flag);\r\n\tif (idx !== -1 && idx + 1 < args.length)\r\n\t{\r\n\t\treturn args[idx + 1];\r\n\t}\r\n\treturn undefined;\r\n}\r\n\r\nfunction parseIntFlag(flag: string, fallback: number): number\r\n{\r\n\tconst str = parseFlag(flag);\r\n\tif (str === undefined) return fallback;\r\n\tconst n = parseInt(str, 10);\r\n\tif (Number.isNaN(n))\r\n\t{\r\n\t\tconsole.error(`Error: ${flag} must be a number, got \"${str}\".`);\r\n\t\tprocess.exit(1);\r\n\t}\r\n\treturn n;\r\n}\r\n\r\nfunction printHelp(): void\r\n{\r\n\tconsole.log(`\r\nVibemancer CLI - Development tools for wizard bots\r\n\r\nUsage:\r\n vibemancer <command> [options]\r\n\r\nCommands:\r\n dev Start the development server (auto-opens browser)\r\n test Run your test suite (vitest)\r\n fight Fight against all 29 built-in bots (or a single opponent)\r\n bots List all built-in bots with descriptions\r\n trace Per-tick debug trace of a single match\r\n tournament Round-robin tournament between your bot + selected opponents\r\n optimize Optimize bot parameters via coordinate descent\r\n build Compile bot to a standalone bundle\r\n login Sign in to VibeMancer (required before upload/pull)\r\n logout Sign out\r\n upload Upload bot to VibeMancer for online competition\r\n pull Download latest source code from VibeMancer\r\n feedback Submit a bug report or suggestion\r\n missile-calc Calculate missile cast time and DPS for a config\r\n\r\nCommon options:\r\n --bot <path> Path to bot source file (default: auto-discover)\r\n\r\nDev options:\r\n --port <n> Server port (default: 4242)\r\n\r\nFight options:\r\n --opponent <name> Fight a single opponent: a built-in name OR another\r\n user's uploaded bot as handle/botname\r\n --seed <n> Random seed\r\n\r\nTrace options:\r\n --opponent <name> Opponent: a built-in name OR handle/botname (required)\r\n --seed <n> Random seed (default: 1)\r\n --distance <n> Spawn distance (default: 600)\r\n\r\nBuild options:\r\n --opponent <name> Opponent bot name (required)\r\n --output <path> Output file path (default: dist/<Bot>-vs-<Opponent>.js)\r\n\r\nOptimize options:\r\n --steps <n> Candidates per parameter (default: 5)\r\n --rounds <n> Max optimization rounds (default: 3)\r\n --opponents <list> Comma-separated bot names to optimize against (default: all)\r\n\r\nExamples:\r\n vibemancer dev\r\n vibemancer test\r\n vibemancer fight\r\n vibemancer fight --opponent Battlemage\r\n vibemancer trace --opponent Battlemage\r\n vibemancer trace --opponent Nightblade --distance 300\r\n vibemancer tournament Battlemage Warmage Archmage\r\n vibemancer optimize\r\n vibemancer build --opponent Battlemage\r\n vibemancer feedback \"missiles go through walls sometimes\"\r\n vibemancer missile-calc --damage 15 --speed 7 --duration 200 --turnRate 3\r\n`);\r\n}\r\n\r\nasync function main(): Promise<void>\r\n{\r\n\tif (!command || command === '--help' || command === '-h')\r\n\t{\r\n\t\tprintHelp();\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Local commands are otherwise invisible: only people who successfully sign in and\r\n\t// upload would ever be counted, so \"how many installs never upload?\" would be measured\r\n\t// over survivors only. Fired here, at the START, so the request overlaps the command's\r\n\t// real work instead of delaying its exit. Never awaited, never able to throw.\r\n\tvoid recordLocalCommand(command);\r\n\r\n\tswitch (command)\r\n\t{\r\n\t\tcase 'dev':\r\n\t\t{\r\n\t\t\tconst port = parseIntFlag('--port', 4242);\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runDev({port, bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'test':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runTest({bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'fight':\r\n\t\t{\r\n\t\t\tconst opponent = parseFlag('--opponent');\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst seed = parseFlag('--seed') !== undefined ? parseIntFlag('--seed', 0) : undefined;\r\n\t\t\tawait runFight({opponent, bot, seed});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'trace':\r\n\t\t{\r\n\t\t\tconst opponent = parseFlag('--opponent');\r\n\t\t\tif (!opponent)\r\n\t\t\t{\r\n\t\t\t\tconst {getBuiltinBotNames} = await import('./opponent-resolver.js');\r\n\t\t\t\tconst names = getBuiltinBotNames();\r\n\t\t\t\tconst list = names.map((n) => ` --opponent ${n}`).join('\\n');\r\n\t\t\t\tconsole.error('Error: --opponent is required for trace.\\n');\r\n\t\t\t\tconsole.error(`Available opponents:\\n\\n${list}\\n`);\r\n\t\t\t\tconsole.error('Usage: vibemancer trace --opponent Battlemage');\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst seed = parseFlag('--seed') !== undefined ? parseIntFlag('--seed', 0) : undefined;\r\n\t\t\tconst distance = parseFlag('--distance') !== undefined ? parseIntFlag('--distance', 600) : undefined;\r\n\t\t\tawait runTrace({opponent, bot, seed, distance});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'bots':\r\n\t\t{\r\n\t\t\tconst name = parseFlag('--name') ?? args[1];\r\n\t\t\trunBots({name: name?.startsWith('--') ? undefined : name});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'tournament':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst flagIndices = new Set<number>();\r\n\t\t\tfor (let i = 1; i < args.length; i++)\r\n\t\t\t{\r\n\t\t\t\tif (args[i]!.startsWith('--'))\r\n\t\t\t\t{\r\n\t\t\t\t\tflagIndices.add(i);\r\n\t\t\t\t\tflagIndices.add(i + 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst opponents = args.slice(1).filter((_, i) => !flagIndices.has(i + 1));\r\n\t\t\tawait runTournament({opponents, bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'optimize':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst opponentsStr = parseFlag('--opponents');\r\n\t\t\tconst opponents = opponentsStr ? opponentsStr.split(',').map((s) => s.trim()).filter(Boolean) : undefined;\r\n\t\t\tawait runOptimize({\r\n\t\t\t\tbot,\r\n\t\t\t\tsteps: parseFlag('--steps') !== undefined ? parseIntFlag('--steps', 5) : undefined,\r\n\t\t\t\trounds: parseFlag('--rounds') !== undefined ? parseIntFlag('--rounds', 3) : undefined,\r\n\t\t\t\topponents,\r\n\t\t\t});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'build':\r\n\t\t{\r\n\t\t\tconst opponent = parseFlag('--opponent');\r\n\t\t\tif (!opponent)\r\n\t\t\t{\r\n\t\t\t\tconsole.error('Error: --opponent is required for build command.');\r\n\t\t\t\tconsole.error('Usage: vibemancer build --opponent Battlemage');\r\n\t\t\t\tprocess.exit(1);\r\n\t\t\t}\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tconst output = parseFlag('--output');\r\n\t\t\tawait runBuild({opponent, bot, output});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'upload':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runUpload({bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'pull':\r\n\t\t{\r\n\t\t\tconst bot = parseFlag('--bot');\r\n\t\t\tawait runPull({bot});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'login':\r\n\t\t{\r\n\t\t\tawait runLogin({noBrowser: args.includes('--no-browser')});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'logout':\r\n\t\t{\r\n\t\t\tawait runLogout();\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'feedback':\r\n\t\t{\r\n\t\t\tconst message = args.slice(1).join(' ');\r\n\t\t\tawait runFeedback({message});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tcase 'missile-calc':\r\n\t\t{\r\n\t\t\trunMissileCalc({\r\n\t\t\t\tdamage: parseIntFlag('--damage', 15),\r\n\t\t\t\tspeed: parseIntFlag('--speed', 7),\r\n\t\t\t\tduration: parseIntFlag('--duration', 200),\r\n\t\t\t\tturnRate: parseIntFlag('--turnRate', 0),\r\n\t\t\t});\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tdefault:\r\n\t\t\tconsole.error(`Unknown command: ${command}`);\r\n\t\t\tprintHelp();\r\n\t\t\tprocess.exit(1);\r\n\t}\r\n}\r\n\r\nmain().catch((error) =>\r\n{\r\n\tconsole.error('Error:', error instanceof Error ? error.message : error);\r\n\tprocess.exit(1);\r\n});\r\n"],"mappings":"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","names":["fs","path","path","fs","BotBundle","BotBundle","BotBundle","sandboxFight","scoreFight","BotBundle","sandboxFight","scoreFight","BotBundle","scoreFight","scoreFight","BotBundle","fs","path","BotBundle","BotBundle","path","fs","fs","readFileSync","path","fs","fs","path","fs","path","spawn","openBrowser","spawn","getAccessToken","os","fs","path","path","os","fs","command","getBuiltinBotNames"]}
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ MCP_BASE_URL,
4
+ NotLoggedInError,
5
+ exchangeCode,
6
+ generatePkce,
7
+ getAccessToken,
8
+ registerClient
9
+ } from "./chunk-MCU2B4PZ.js";
10
+ export {
11
+ MCP_BASE_URL,
12
+ NotLoggedInError,
13
+ exchangeCode,
14
+ generatePkce,
15
+ getAccessToken,
16
+ registerClient
17
+ };
18
+ //# sourceMappingURL=oauth-client-AX3HNK6P.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibemancer",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Vibemancer devkit - dev server, testing, and tournament tools for wizard bots",
5
5
  "type": "module",
6
6
  "author": "Low Entry",
@@ -29,7 +29,7 @@
29
29
  "test:mutate": "stryker run"
30
30
  },
31
31
  "dependencies": {
32
- "@vibemancer/core": "~1.0.1",
32
+ "@vibemancer/core": "~1.0.2",
33
33
  "firebase": "^12.12.1"
34
34
  },
35
35
  "devDependencies": {
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/firebase-config.ts
4
- var FIREBASE_CONFIG = {
5
- apiKey: "AIzaSyDSUJ2jlk5_vlpGOypMtvqKjHhDmbgomIY",
6
- authDomain: "le-vibemancer.firebaseapp.com",
7
- projectId: "le-vibemancer",
8
- storageBucket: "le-vibemancer.firebasestorage.app"
9
- };
10
-
11
- export {
12
- FIREBASE_CONFIG
13
- };
14
- //# sourceMappingURL=chunk-AA2UJPPN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/firebase-config.ts"],"sourcesContent":["export const FIREBASE_CONFIG = {\n\tapiKey: 'AIzaSyDSUJ2jlk5_vlpGOypMtvqKjHhDmbgomIY',\n\tauthDomain: 'le-vibemancer.firebaseapp.com',\n\tprojectId: 'le-vibemancer',\n\tstorageBucket: 'le-vibemancer.firebasestorage.app',\n} as const;\n"],"mappings":";;;AAAO,IAAM,kBAAkB;AAAA,EAC9B,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,eAAe;AAChB;","names":[]}
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- FIREBASE_CONFIG
4
- } from "./chunk-AA2UJPPN.js";
5
- export {
6
- FIREBASE_CONFIG
7
- };
8
- //# sourceMappingURL=firebase-config-F6COE3NY.js.map