vibemancer 0.2.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1004,10 +1004,10 @@ function credentialsPath() {
1004
1004
  return join(configDir(), "credentials.json");
1005
1005
  }
1006
1006
  function loadCredentials() {
1007
- const path5 = credentialsPath();
1008
- if (!existsSync(path5)) return null;
1007
+ const path7 = credentialsPath();
1008
+ if (!existsSync(path7)) return null;
1009
1009
  try {
1010
- const parsed = JSON.parse(readFileSync2(path5, "utf-8"));
1010
+ const parsed = JSON.parse(readFileSync2(path7, "utf-8"));
1011
1011
  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") {
1012
1012
  return { refreshToken: parsed.refreshToken, accessToken: parsed.accessToken, expiresAt: parsed.expiresAt };
1013
1013
  }
@@ -1018,10 +1018,10 @@ function loadCredentials() {
1018
1018
  }
1019
1019
  function saveCredentials(credentials) {
1020
1020
  mkdirSync(configDir(), { recursive: true });
1021
- const path5 = credentialsPath();
1022
- writeFileSync2(path5, JSON.stringify(credentials, null, 2), { mode: 384 });
1021
+ const path7 = credentialsPath();
1022
+ writeFileSync2(path7, JSON.stringify(credentials, null, 2), { mode: 384 });
1023
1023
  try {
1024
- chmodSync(path5, 384);
1024
+ chmodSync(path7, 384);
1025
1025
  } catch {
1026
1026
  }
1027
1027
  }
@@ -1096,12 +1096,65 @@ async function getAccessToken() {
1096
1096
  return refreshed.accessToken;
1097
1097
  }
1098
1098
 
1099
+ // src/auth/env-headers.ts
1100
+ import os from "os";
1101
+ import { readFileSync as readFileSync3 } from "fs";
1102
+ import path4 from "path";
1103
+ import { fileURLToPath } from "url";
1104
+ function findCliVersionFrom(here) {
1105
+ for (const rel of ["../../package.json", "../package.json", "../../../package.json"]) {
1106
+ try {
1107
+ const parsed = JSON.parse(readFileSync3(path4.resolve(here, rel), "utf8"));
1108
+ if (typeof parsed !== "object" || parsed === null) continue;
1109
+ if (!("name" in parsed) || !("version" in parsed)) continue;
1110
+ const { name, version } = parsed;
1111
+ if (name === "vibemancer" && typeof version === "string") return version;
1112
+ } catch {
1113
+ }
1114
+ }
1115
+ return "";
1116
+ }
1117
+ function readCliVersion() {
1118
+ try {
1119
+ return findCliVersionFrom(path4.dirname(fileURLToPath(import.meta.url)));
1120
+ } catch {
1121
+ return "";
1122
+ }
1123
+ }
1124
+ function buildEnvHeaders(env) {
1125
+ const headers = {};
1126
+ const put = (key, value) => {
1127
+ const trimmed = value.trim();
1128
+ if (trimmed) headers[key] = trimmed.slice(0, 64);
1129
+ };
1130
+ put("x-vibemancer-os", env.platform);
1131
+ put("x-vibemancer-os-release", env.release);
1132
+ put("x-vibemancer-arch", env.arch);
1133
+ put("x-vibemancer-node", env.nodeVersion);
1134
+ put("x-vibemancer-cli", env.cliVersion);
1135
+ return headers;
1136
+ }
1137
+ function envHeaders() {
1138
+ try {
1139
+ return buildEnvHeaders({
1140
+ platform: os.platform(),
1141
+ release: os.release(),
1142
+ arch: os.arch(),
1143
+ nodeVersion: process.version,
1144
+ cliVersion: readCliVersion()
1145
+ });
1146
+ } catch {
1147
+ return {};
1148
+ }
1149
+ }
1150
+
1099
1151
  // src/auth/gateway-client.ts
1100
1152
  async function uploadBot(payload) {
1101
1153
  const token = await getAccessToken();
1102
1154
  const res = await fetch(`${MCP_BASE_URL}/api/upload`, {
1103
1155
  method: "POST",
1104
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
1156
+ // Environment headers ride along on a request already being made — no extra call.
1157
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, ...envHeaders() },
1105
1158
  body: JSON.stringify(payload)
1106
1159
  });
1107
1160
  if (!res.ok) throw new Error(`Upload failed (${res.status}): ${await res.text()}`);
@@ -1113,7 +1166,7 @@ async function uploadBot(payload) {
1113
1166
  async function pullSource(name) {
1114
1167
  const token = await getAccessToken();
1115
1168
  const res = await fetch(`${MCP_BASE_URL}/api/pull?name=${encodeURIComponent(name)}`, {
1116
- headers: { Authorization: `Bearer ${token}` }
1169
+ headers: { Authorization: `Bearer ${token}`, ...envHeaders() }
1117
1170
  });
1118
1171
  if (!res.ok) throw new Error(`Pull failed (${res.status}): ${await res.text()}`);
1119
1172
  const data = await res.json();
@@ -1168,7 +1221,7 @@ async function runUpload(options) {
1168
1221
 
1169
1222
  // src/commands/pull.ts
1170
1223
  import fs5 from "fs";
1171
- import path4 from "path";
1224
+ import path5 from "path";
1172
1225
  async function runPull(options) {
1173
1226
  const projectDir = process.cwd();
1174
1227
  const botInfo = await discoverBot(projectDir, options.bot, { allowMissingFile: true });
@@ -1177,7 +1230,7 @@ async function runPull(options) {
1177
1230
  Pulling latest source for ${botInfo.exportName}...`);
1178
1231
  try {
1179
1232
  const sourceCode = await pullSource(botInfo.exportName);
1180
- fs5.mkdirSync(path4.dirname(botInfo.sourcePath), { recursive: true });
1233
+ fs5.mkdirSync(path5.dirname(botInfo.sourcePath), { recursive: true });
1181
1234
  fs5.writeFileSync(botInfo.sourcePath, sourceCode);
1182
1235
  console.log(` \u2713 ${isNew ? "Created" : "Updated"} ${botInfo.sourcePath}`);
1183
1236
  console.log(` ${(sourceCode.length / 1024).toFixed(1)} KB written`);
@@ -1294,9 +1347,31 @@ async function runLogin(options) {
1294
1347
  }
1295
1348
  }
1296
1349
 
1350
+ // src/auth/revoke.ts
1351
+ async function revokeSession(token) {
1352
+ if (!token) return false;
1353
+ try {
1354
+ const res = await fetch(`${MCP_BASE_URL}/revoke`, {
1355
+ method: "POST",
1356
+ headers: { "Content-Type": "application/json" },
1357
+ body: JSON.stringify({ token })
1358
+ });
1359
+ return res.ok;
1360
+ } catch {
1361
+ return false;
1362
+ }
1363
+ }
1364
+
1297
1365
  // src/commands/logout.ts
1298
- function runLogout() {
1366
+ async function runLogout() {
1367
+ const credentials = loadCredentials();
1368
+ const revoked = credentials ? await revokeSession(credentials.accessToken) : false;
1299
1369
  clearCredentials();
1370
+ if (credentials && !revoked) {
1371
+ console.log(" Logged out locally, but the server could not be reached to end the session.");
1372
+ console.log(" Run `vibemancer logout` again while online to revoke it.");
1373
+ return;
1374
+ }
1300
1375
  console.log(" Logged out.");
1301
1376
  }
1302
1377
 
@@ -1354,6 +1429,57 @@ function runMissileCalc(options) {
1354
1429
  `);
1355
1430
  }
1356
1431
 
1432
+ // src/auth/telemetry.ts
1433
+ import os2 from "os";
1434
+ import fs6 from "fs";
1435
+ import path6 from "path";
1436
+ var TIMEOUT_MS = 1e3;
1437
+ function isTelemetryEnabled(env) {
1438
+ const off = (value) => {
1439
+ if (value === void 0) return false;
1440
+ const v = value.trim().toLowerCase();
1441
+ return v === "0" || v === "false" || v === "off" || v === "no";
1442
+ };
1443
+ const on = (value) => {
1444
+ if (value === void 0) return false;
1445
+ const v = value.trim().toLowerCase();
1446
+ return v === "1" || v === "true" || v === "on" || v === "yes";
1447
+ };
1448
+ if (off(env.VIBEMANCER_TELEMETRY)) return false;
1449
+ if (on(env.DO_NOT_TRACK)) return false;
1450
+ if (on(env.CI)) return false;
1451
+ return true;
1452
+ }
1453
+ var TELEMETRY_NOTICE = " Vibemancer records which commands are run, your OS and version numbers, to decide\n which platforms to support. No code, file paths or personal files are ever sent.\n Opt out any time with VIBEMANCER_TELEMETRY=0 (DO_NOT_TRACK is honoured too).\n";
1454
+ function noticePath() {
1455
+ return path6.join(os2.homedir(), ".vibemancer", "telemetry-notice-shown");
1456
+ }
1457
+ function showNoticeOnce(marker = noticePath()) {
1458
+ try {
1459
+ if (fs6.existsSync(marker)) return false;
1460
+ fs6.mkdirSync(path6.dirname(marker), { recursive: true });
1461
+ fs6.writeFileSync(marker, (/* @__PURE__ */ new Date()).toISOString());
1462
+ console.log(TELEMETRY_NOTICE);
1463
+ return true;
1464
+ } catch {
1465
+ return false;
1466
+ }
1467
+ }
1468
+ async function recordLocalCommand(command2, env = process.env, marker = noticePath()) {
1469
+ if (!isTelemetryEnabled(env)) return;
1470
+ showNoticeOnce(marker);
1471
+ try {
1472
+ const headers = envHeaders();
1473
+ await fetch(`${MCP_BASE_URL}/cli-telemetry`, {
1474
+ method: "POST",
1475
+ headers: { "Content-Type": "application/json", ...headers },
1476
+ body: JSON.stringify({ command: command2 }),
1477
+ signal: AbortSignal.timeout(TIMEOUT_MS)
1478
+ });
1479
+ } catch {
1480
+ }
1481
+ }
1482
+
1357
1483
  // src/cli.ts
1358
1484
  var args = process.argv.slice(2);
1359
1485
  var command = args[0];
@@ -1441,6 +1567,7 @@ async function main() {
1441
1567
  printHelp();
1442
1568
  return;
1443
1569
  }
1570
+ void recordLocalCommand(command);
1444
1571
  switch (command) {
1445
1572
  case "dev": {
1446
1573
  const port = parseIntFlag("--port", 4242);
@@ -1537,7 +1664,7 @@ ${list}
1537
1664
  break;
1538
1665
  }
1539
1666
  case "logout": {
1540
- runLogout();
1667
+ await runLogout();
1541
1668
  break;
1542
1669
  }
1543
1670
  case "feedback": {
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/gateway-client.ts","../src/commands/pull.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/feedback.ts","../src/commands/missile-calc.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","/**\r\n * vibemancer test\r\n *\r\n * Runs the user's vitest test suite. Scaffolded projects include a\r\n * tests/ directory with example tests using the testBot() helper.\r\n */\r\n\r\nimport {execSync} from 'node:child_process';\r\n\r\nexport interface TestOptions\r\n{\r\n\tbot?: string;\r\n}\r\n\r\nexport async function runTest(_options: TestOptions): Promise<void>\r\n{\r\n\tconsole.log('\\n Running tests...\\n');\r\n\r\n\ttry\r\n\t{\r\n\t\texecSync('npx vitest run', {\r\n\t\t\tstdio: 'inherit',\r\n\t\t\tcwd: process.cwd(),\r\n\t\t});\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\tprocess.exit(1);\r\n\t}\r\n}\r\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 * 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';\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\theaders: {'Content-Type': 'application/json', Authorization: `Bearer ${token}`},\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}`},\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 * vibemancer logout — clear the cached OAuth credentials.\n */\n\nimport {clearCredentials} from '../auth/credentials-store.js';\n\nexport function runLogout(): void\n{\n\tclearCredentials();\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","/**\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\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\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\trunLogout();\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","fs","fs","path","fs","path","randomBytes","openBrowser","randomBytes","initializeApp","FIREBASE_CONFIG","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/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","/**\r\n * vibemancer test\r\n *\r\n * Runs the user's vitest test suite. Scaffolded projects include a\r\n * tests/ directory with example tests using the testBot() helper.\r\n */\r\n\r\nimport {execSync} from 'node:child_process';\r\n\r\nexport interface TestOptions\r\n{\r\n\tbot?: string;\r\n}\r\n\r\nexport async function runTest(_options: TestOptions): Promise<void>\r\n{\r\n\tconsole.log('\\n Running tests...\\n');\r\n\r\n\ttry\r\n\t{\r\n\t\texecSync('npx vitest run', {\r\n\t\t\tstdio: 'inherit',\r\n\t\t\tcwd: process.cwd(),\r\n\t\t});\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\tprocess.exit(1);\r\n\t}\r\n}\r\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":";;;;;;;;;;;;AAaA,SAAQ,gBAAe;;;ACCvB,OAAO,QAAQ;AACf,OAAO,UAAU;AA4BjB,eAAsB,YAAY,YAAoB,cAAuB,UAA2B,CAAC,GACzG;AACC,QAAM,SAAS,KAAK,QAAQ,UAAU;AAGtC,MAAI,cACJ;AACC,UAAM,UAAU,KAAK,QAAQ,QAAQ,YAAY;AACjD,QAAI,CAAC,GAAG,WAAW,OAAO,GAC1B;AACC,YAAM,IAAI,MAAM,uBAAuB,OAAO,EAAE;AAAA,IACjD;AACA,UAAM,aAAa,MAAM,eAAe,OAAO;AAC/C,WAAO,EAAC,YAAY,SAAS,WAAU;AAAA,EACxC;AAGA,QAAM,aAAa,KAAK,KAAK,QAAQ,iBAAiB;AACtD,MAAI,GAAG,WAAW,UAAU,GAC5B;AACC,UAAM,MAAM,GAAG,aAAa,YAAY,OAAO;AAC/C,QAAI;AACJ,QACA;AAEC,eAAS,KAAK,MAAM,GAAG;AAAA,IACxB,QAEA;AACC,YAAM,IAAI,MAAM,oCAAoC,UAAU,EAAE;AAAA,IACjE;AAEA,QAAI,OAAO,QAAQ,QAAQ,OAAO,QAAQ,UAAa,OAAO,OAAO,QAAQ,UAC7E;AACC,YAAM,IAAI,MAAM,gEAAgE,OAAO,OAAO,GAAG,EAAE;AAAA,IACpG;AAEA,QAAI,OAAO,WAAW,QAAQ,OAAO,WAAW,UAAa,OAAO,OAAO,WAAW,UACtF;AACC,YAAM,IAAI,MAAM,mEAAmE,OAAO,OAAO,MAAM,EAAE;AAAA,IAC1G;AAEA,QAAI,OAAO,KACX;AACC,YAAM,UAAU,KAAK,QAAQ,QAAQ,OAAO,GAAG;AAC/C,UAAI,CAAC,GAAG,WAAW,OAAO,GAC1B;AACC,YAAI,CAAC,QAAQ,kBACb;AACC,gBAAM,IAAI,MAAM,4CAA4C,OAAO,EAAE;AAAA,QACtE;AAGA,YAAI,CAAC,OAAO,QACZ;AACC,gBAAM,IAAI;AAAA,YACT,YAAY,OAAO;AAAA;AAAA;AAAA,UAGpB;AAAA,QACD;AACA,eAAO,EAAC,YAAY,SAAS,YAAY,OAAO,OAAM;AAAA,MACvD;AACA,YAAM,aAAa,OAAO,UAAU,MAAM,eAAe,OAAO;AAChE,aAAO,EAAC,YAAY,SAAS,WAAU;AAAA,IACxC;AAAA,EACD;AAGA,QAAM,UAAU,MAAM,gBAAgB,MAAM;AAC5C,MAAI,QAAQ,WAAW,GACvB;AACC,WAAO,QAAQ,CAAC;AAAA,EACjB;AACA,MAAI,QAAQ,SAAS,GACrB;AACC,UAAM,OAAO,QAAQ,IAAI,CAAC,MAAM,WAAW,KAAK,SAAS,QAAQ,EAAE,UAAU,EAAE,QAAQ,OAAO,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,EAAE,KAAK,IAAI;AAClI,UAAM,IAAI;AAAA,MACT,SAAS,QAAQ,MAAM;AAAA;AAAA,EAAkC,IAAI;AAAA,IAC9D;AAAA,EACD;AAIA,QAAM,cAAc,KAAK,KAAK,QAAQ,OAAO,QAAQ;AACrD,MAAI,GAAG,WAAW,WAAW,GAC7B;AACC,UAAM,aAAa,MAAM,eAAe,WAAW;AACnD,WAAO,EAAC,YAAY,aAAa,WAAU;AAAA,EAC5C;AAEA,QAAM,IAAI;AAAA,IACT;AAAA,EAGD;AACD;AAMA,eAAe,eAAe,UAC9B;AACC,QAAM,UAAU,GAAG,aAAa,UAAU,OAAO;AAGjD,QAAM,QAAQ,QAAQ,MAAM,gDAAgD;AAC5E,MAAI,QAAQ,CAAC,GACb;AACC,WAAO,MAAM,CAAC;AAAA,EACf;AAGA,QAAM,WAAW,QAAQ,MAAM,0BAA0B;AACzD,MAAI,WAAW,CAAC,GAChB;AACC,WAAO,SAAS,CAAC;AAAA,EAClB;AAEA,QAAM,IAAI;AAAA,IACT,oCAAoC,QAAQ;AAAA;AAAA;AAAA,EAG7C;AACD;AAEA,IAAM,0BAA0B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACD;AACA,IAAM,sBAAsB,oBAAI,IAAI;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AACD,IAAM,uBAAuB,oBAAI,IAAI;AAAA,EACpC;AAAA,EAAY;AAAA,EACZ;AAAA,EAAY;AAAA,EACZ;AAAA,EAAc;AACf,CAAC;AAED,SAAS,uBAAuB,SAChC;AACC,QAAM,MAAgB,CAAC;AACvB,QAAM,QAAkB,CAAC,OAAO;AAChC,SAAO,MAAM,SAAS,GACtB;AACC,UAAM,MAAM,MAAM,IAAI;AACtB,QAAI,QAAQ,OAAW;AACvB,QAAI;AACJ,QACA;AACC,gBAAU,GAAG,YAAY,KAAK,EAAC,eAAe,KAAI,CAAC;AAAA,IACpD,QAEA;AACC;AAAA,IACD;AACA,eAAW,SAAS,SACpB;AACC,YAAM,OAAO,KAAK,KAAK,KAAK,MAAM,IAAI;AACtC,UAAI,MAAM,YAAY,GACtB;AACC,YAAI,oBAAoB,IAAI,MAAM,IAAI,EAAG;AACzC,YAAI,MAAM,KAAK,WAAW,GAAG,EAAG;AAChC,cAAM,KAAK,IAAI;AACf;AAAA,MACD;AACA,UAAI,CAAC,MAAM,OAAO,EAAG;AACrB,UAAI,CAAC,MAAM,KAAK,SAAS,KAAK,KAAK,CAAC,MAAM,KAAK,SAAS,MAAM,EAAG;AACjE,UAAI,qBAAqB,IAAI,MAAM,IAAI,EAAG;AAC1C,UAAI,wBAAwB,KAAK,CAAC,OAAO,GAAG,KAAK,MAAM,IAAI,CAAC,EAAG;AAC/D,UAAI,KAAK,IAAI;AAAA,IACd;AAAA,EACD;AACA,SAAO;AACR;AAaA,eAAsB,gBAAgB,YACtC;AACC,QAAM,SAAS,KAAK,QAAQ,UAAU;AACtC,QAAM,SAAS,KAAK,KAAK,QAAQ,KAAK;AACtC,MAAI,CAAC,GAAG,WAAW,MAAM,EAAG,QAAO,CAAC;AAEpC,QAAM,QAAQ,uBAAuB,MAAM;AAC3C,QAAM,OAAkB,CAAC;AACzB,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,QAAQ,OACnB;AACC,QAAI;AACJ,QACA;AACC,mBAAa,MAAM,eAAe,IAAI;AAAA,IACvC,QAEA;AACC;AAAA,IACD;AACA,QAAI,UAAU,IAAI,UAAU,EAAG;AAC/B,cAAU,IAAI,UAAU;AACxB,SAAK,KAAK,EAAC,YAAY,MAAM,WAAU,CAAC;AAAA,EACzC;AACA,OAAK,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,cAAc,EAAE,UAAU,CAAC;AAC5D,SAAO;AACR;;;ACpPA,OAAO,UAAU;;;ACDjB,SAAQ,aAAY;AAGpB,eAAsB,uBACrB,YACA,YAED;AACC,QAAM,gBAAgB,kBAAkB;AAExC,QAAM,SAAS,MAAM,MAAM;AAAA,IAC1B,aAAa,CAAC,UAAU;AAAA,IACxB,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,QAAQ,EAAC,IAAI,2CAA2C,UAAU,IAAG;AAAA,IACrE,UAAU;AAAA,MACT;AAAA,MAAe;AAAA,MACf;AAAA,IACD;AAAA,IACA,OAAO;AAAA,MACN,oBAAoB,gBAAgB;AAAA,IACrC;AAAA,EACD,CAAC;AAED,MAAI,CAAC,OAAO,cAAc,CAAC,GAC3B;AACC,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC7C;AAEA,SAAO,OAAO,YAAY,CAAC,EAAE;AAC9B;;;ADfA,SAAS,cAAc,MACvB;AACC,SAAO;AAAA,IACN,MAAM,KAAK;AAAA,IACX,YAAY,KAAK;AAAA,IACjB,YAAY,KAAK;AAAA,EAClB;AACD;AAMO,SAAS,YAAY,SAC5B;AACC,QAAM,EAAC,MAAM,WAAU,IAAI;AAE3B,iBAAe,WACf;AAIC,WAAO,gBAAgB,UAAU;AAAA,EAClC;AAEA,QAAM,SAAS,KAAK,aAAa,OAAM,KAAK,QAC5C;AAEC,QAAI,UAAU,+BAA+B,GAAG;AAChD,QAAI,UAAU,gCAAgC,cAAc;AAC5D,QAAI,UAAU,gCAAgC,cAAc;AAE5D,QAAI,IAAI,WAAW,WACnB;AACC,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI;AACR;AAAA,IACD;AAEA,UAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,oBAAoB,IAAI,EAAE;AAC9D,UAAM,WAAW,IAAI;AAErB,QACA;AACC,UAAI,aAAa,WACjB;AACC,gBAAQ,KAAK,KAAK,EAAC,QAAQ,KAAI,CAAC;AAChC;AAAA,MACD;AAEA,UAAI,aAAa,eACjB;AACC,cAAM,OAAO,MAAM,SAAS;AAC5B,cAAM,OAA0B,EAAC,MAAM,KAAK,IAAI,aAAa,EAAC;AAC9D,gBAAQ,KAAK,KAAK,IAAI;AACtB;AAAA,MACD;AAEA,YAAM,cAAc,mDAAmD,KAAK,QAAQ;AACpF,UAAI,aACJ;AACC,cAAM,gBAAgB,YAAY,CAAC;AACnC,cAAM,OAAO,MAAM,SAAS;AAC5B,cAAM,SAAS,KAAK,KAAK,CAAC,MAAM,EAAE,eAAe,aAAa;AAC9D,YAAI,CAAC,QACL;AACC,kBAAQ,KAAK,KAAK,EAAC,OAAO,uBAAuB,aAAa,aAAa,KAAK,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,IAAI,KAAK,QAAQ,GAAE,CAAC;AAClI;AAAA,QACD;AAEA,cAAM,QAAQ,KAAK,IAAI;AACvB,cAAM,SAAS,MAAM,uBAAuB,OAAO,YAAY,OAAO,UAAU;AAChF,cAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,gBAAQ,IAAI,cAAc,OAAO,UAAU,MAAM,OAAO,SAAS,MAAM,QAAQ,CAAC,CAAC,WAAW,OAAO,IAAI;AAEvG,YAAI,UAAU,KAAK,EAAC,gBAAgB,kBAAiB,CAAC;AACtD,YAAI,IAAI,MAAM;AACd;AAAA,MACD;AAEA,cAAQ,KAAK,KAAK,EAAC,OAAO,cAAc,QAAQ,GAAE,CAAC;AAAA,IACpD,SACM,OACN;AACC,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,MAAM,YAAY,OAAO,EAAE;AACnC,cAAQ,KAAK,KAAK,EAAC,OAAO,QAAO,CAAC;AAAA,IACnC;AAAA,EACD,CAAC;AAED,SAAO,OAAO,MAAM,MACpB;AACC,YAAQ,IAAI;AAAA,oDAAuD,IAAI,EAAE;AACzE,UAAM,YACN;AACC,YAAM,OAAO,MAAM,SAAS;AAC5B,UAAI,KAAK,WAAW,GACpB;AACC,gBAAQ,IAAI,+EAA0E;AAAA,MACvF,OAEA;AACC,gBAAQ,IAAI,WAAW,KAAK,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,MAClE;AACA,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,4BAA4B;AACxC,cAAQ,IAAI,iDAAiD,IAAI;AAAA,CAAI;AACrE,cAAQ,IAAI,YAAY;AACxB,cAAQ,IAAI,yEAAyE;AACrF,cAAQ,IAAI,wFAAwF;AACpG,cAAQ,IAAI,+DAA+D;AAAA,IAC5E,GAAG;AAAA,EACJ,CAAC;AAED,SAAO;AACR;AAEA,SAAS,QAAQ,KAA0B,QAAgB,MAC3D;AACC,MAAI,UAAU,QAAQ,EAAC,gBAAgB,mBAAkB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC7B;;;AFxIA,eAAsB,OAAO,SAC7B;AACC,QAAM,aAAa,QAAQ,IAAI;AAK/B,QAAM,OAAO,MAAM,gBAAgB,UAAU;AAC7C,MAAI,KAAK,WAAW,GACpB;AACC,YAAQ,IAAI,4EAA4E;AACxF,YAAQ,IAAI,qDAAqD;AAAA,EAClE,OAEA;AACC,YAAQ,IAAI,cAAc,KAAK,MAAM,OAAO,KAAK,WAAW,IAAI,KAAK,GAAG,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EACxH;AAEA,QAAM,SAAS,YAAY;AAAA,IAC1B,MAAM,QAAQ;AAAA,IACd;AAAA,EACD,CAAC;AAGD,SAAO,KAAK,aAAa,MACzB;AACC,UAAM,MAAM,+CAA+C,QAAQ,IAAI;AACvE,gBAAY,GAAG;AAAA,EAChB,CAAC;AACF;AAEA,SAAS,YAAY,KACrB;AACC,QAAM,WAAW,QAAQ;AAEzB,MACA;AACC,QAAI,aAAa,UACjB;AACC,eAAS,QAAQ,CAAC,GAAG,GAAG,MACxB;AAAA,MAAC,CAAC;AAAA,IACH,WACS,aAAa,SACtB;AACC,eAAS,OAAO,CAAC,MAAM,SAAS,IAAI,GAAG,GAAG,MAC1C;AAAA,MAAC,CAAC;AAAA,IACH,OAEA;AAEC,eAAS,YAAY,CAAC,GAAG,GAAG,CAAC,QAC7B;AACC,YAAI,IAAK,UAAS,WAAW,CAAC,GAAG,GAAG,MACpC;AAAA,QAAC,CAAC;AAAA,MACH,CAAC;AAAA,IACF;AAAA,EACD,QAEA;AAAA,EAEA;AACD;;;AI7EA,SAAQ,gBAAe;AAOvB,eAAsB,QAAQ,UAC9B;AACC,UAAQ,IAAI,wBAAwB;AAEpC,MACA;AACC,aAAS,kBAAkB;AAAA,MAC1B,OAAO;AAAA,MACP,KAAK,QAAQ,IAAI;AAAA,IAClB,CAAC;AAAA,EACF,QAEA;AACC,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;;;ACpBA,OAAOA,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAQ,WAAW,cAAc,YAAY,sBAAqB;;;ACAlE,SAAQ,eAAe,eAAgC;AACvD,SAAQ,cAAc,YAAY,OAAO,OAAO,OAAO,SAAS,gCAA+C;AAC/G,SAAQ,YAAY,KAAK,UAAU,8BAAmD;AACtF,SAAQ,uBAAsB;AAWvB,SAAS,iBAAiB,UACjC;AACC,QAAM,UAAU,SAAS,KAAK;AAC9B,QAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,SAAO,QAAQ,KAAK,QAAQ,QAAQ,SAAS;AAC9C;AAEA,IAAI,WAA6B;AACjC,IAAI,gBAAwC;AAE5C,SAAS,SACT;AACC,QAAM,OAAO,QAAQ;AACrB,SAAO,KAAK,SAAS,IAAI,KAAK,CAAC,IAAK,cAAc,eAAe;AAClE;AAGA,SAAS,QACT;AACC,MAAI,CAAC,UACL;AACC,eAAW,aAAa,OAAO,CAAC;AAChC,QAAI,QAAQ,IAAI,wBAAwB,IAAK,0BAAyB,UAAU,aAAa,IAAI;AAAA,EAClG;AACA,SAAO;AACR;AAEA,SAAS,YACT;AACC,MAAI,CAAC,eACL;AACC,oBAAgB,WAAW,OAAO,CAAC;AACnC,QAAI,QAAQ,IAAI,wBAAwB,IAAK,wBAAuB,eAAe,aAAa,IAAI;AAAA,EACrG;AACA,SAAO;AACR;AAEA,eAAsB,sBAAsB,UAC5C;AACC,QAAM,QAAQ,SAAS,QAAQ,GAAG;AAClC,QAAM,SAAS,SAAS,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE,YAAY;AAC3D,QAAM,UAAU,SAAS,MAAM,QAAQ,CAAC,EAAE,KAAK;AAC/C,MAAI,CAAC,UAAU,CAAC,SAChB;AACC,UAAM,IAAI,MAAM,qBAAqB,QAAQ,uEAAkE;AAAA,EAChH;AAEA,MAAI,gBAAgB,OAAO,GAC3B;AACC,UAAM,IAAI,MAAM,kBAAkB,OAAO,uBAAuB,MAAM,4EAA4E;AAAA,EACnJ;AAEA,QAAM,KAAK,MAAM;AACjB,QAAM,OAAO,MAAM,QAAQ;AAAA,IAC1B,WAAW,IAAI,SAAS;AAAA,IACxB,MAAM,eAAe,MAAM,MAAM;AAAA,IACjC,MAAM,aAAa,MAAM,QAAQ,YAAY,CAAC;AAAA,IAC9C,MAAM,UAAU,MAAM,IAAI;AAAA,IAC1B,MAAM,CAAC;AAAA,EACR,CAAC;AACD,MAAI,KAAK,OACT;AACC,UAAM,IAAI,MAAM,kBAAkB,OAAO,uBAAuB,MAAM,4EAA4E;AAAA,EACnJ;AAEA,QAAM,UAAU,KAAK,KAAK,CAAC;AAC3B,QAAM,OAAO,QAAQ,KAAK;AAC1B,QAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAC3E,MAAI,CAAC,YACL;AACC,UAAM,IAAI,MAAM,QAAQ,MAAM,IAAI,OAAO,+BAA+B;AAAA,EACzE;AACA,QAAM,aAAa,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa,WAAW,QAAQ,EAAE;AAEhG,QAAM,QAAQ,MAAM,SAAS,IAAI,UAAU,GAAG,UAAU,CAAC;AACzD,QAAM,SAAS,IAAI,YAAY,EAAE,OAAO,KAAK;AAE7C,SAAO,EAAC,QAAQ,YAAY,OAAO,GAAG,MAAM,IAAI,OAAO,GAAE;AAC1D;;;AD3DA,eAAsB,SAAS,SAC/B;AACC,MAAI,QAAQ,UACZ;AACC,WAAO,eAAe,EAAC,GAAG,SAAS,UAAU,QAAQ,SAAQ,CAAC;AAAA,EAC/D;AACA,SAAO,aAAa,OAAO;AAC5B;AAIA,eAAe,eAAe,SAC9B;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AAEzD,UAAQ,IAAI;AAAA,SAAY,QAAQ,UAAU,EAAE;AAC5C,UAAQ,IAAI,eAAe,QAAQ,QAAQ;AAAA,CAAI;AAE/C,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI;AACJ,MAAI,iBAAiB,QAAQ,QAAQ,GACrC;AAGC,YAAQ,IAAI,kCAAkC;AAC9C,UAAM,SAAS,MAAM,sBAAsB,QAAQ,QAAQ;AAC3D,UAAM,aAAa,MAAM,uBAAuB,QAAQ,YAAY,QAAQ,UAAU;AACtF,aAAS,MAAM,eAAe,YAAY,OAAO,QAAQ,EAAC,MAAM,QAAQ,QAAQ,EAAC,CAAC;AAAA,EACnF,OAEA;AACC,UAAM,aAAa,IAAI,UAAU,QAAQ,YAAY,QAAQ,UAAU;AACvE,UAAM,iBAAiB,gBAAgB,QAAQ,QAAQ;AACvD,aAAS,MAAM,aAAa,YAAY,gBAAgB;AAAA,MACvD,MAAM,QAAQ;AAAA,MACd,gBAAgB,sBAAsB;AAAA,IACvC,CAAC;AAAA,EACF;AACA,QAAM,UAAU,KAAK,IAAI,IAAI;AAE7B,QAAM,EAAC,aAAa,aAAa,MAAK,IAAI;AAC1C,QAAM,QAAQ,cAAc,cAAc;AAC1C,QAAM,UAAU,OAAO,WAAW,aAAa,QAC5C,OAAO,WAAW,aAAa,SAC9B;AAEJ,UAAQ,IAAI,aAAa,OAAO,EAAE;AAClC,UAAQ,IAAI,KAAK,QAAQ,UAAU,KAAK,WAAW,SAAS,QAAQ,QAAQ,KAAK,WAAW,gBAAgB,KAAK,EAAE;AACnH,UAAQ,IAAI,MAAM,KAAK,eAAe,OAAO;AAAA,CAAO;AAEpD,MAAI,OAAO,WAAW,YACtB;AACC,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;AAIA,eAAe,aAAa,SAC5B;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AACzD,QAAM,aAAa,IAAI,UAAU,QAAQ,YAAY,QAAQ,UAAU;AAEvE,QAAM,YAAY,mBAAmB;AACrC,UAAQ,IAAI;AAAA,aAAgB,QAAQ,UAAU,YAAY,UAAU,MAAM;AAAA,CAAqB;AAE/F,QAAM,UAAwB,CAAC;AAC/B,QAAM,eAAe,KAAK,IAAI;AAE9B,aAAW,gBAAgB,WAC3B;AACC,UAAM,iBAAiB,gBAAgB,YAAY;AACnD,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,SAAS,MAAM,aAAa,YAAY,gBAAgB;AAAA,MAC7D,MAAM,QAAQ;AAAA,MACd,gBAAgB,sBAAsB;AAAA,IACvC,CAAC;AACD,UAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,UAAM,QAAQ,WAAW,MAAM;AAE/B,YAAQ,KAAK;AAAA,MACZ,UAAU;AAAA,MACV,QAAQ,OAAO;AAAA,MACf,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO;AAAA,MACpB,OAAO,OAAO;AAAA,MACd;AAAA,MACA,WAAW;AAAA,IACZ,CAAC;AAED,UAAM,UAAU,OAAO,WAAW,aAAa,MAC5C,OAAO,WAAW,aAAa,MAC9B;AACJ,UAAM,MAAM,aAAa,OAAO,EAAE;AAClC,YAAQ,IAAI,KAAK,GAAG,IAAI,OAAO,KAAK,OAAO,WAAW,IAAI,OAAO,WAAW,IAAI,OAAO,KAAK,MAAM,OAAO,KAAK;AAAA,EAC/G;AAEA,QAAM,eAAe,KAAK,IAAI,IAAI;AAClC,QAAM,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAC5D,QAAM,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAC9D,QAAM,YAAY,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EAAE;AAC7D,QAAM,aAAa,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AAC9D,QAAM,WAAW,UAAU,SAAS;AAEpC,UAAQ,IAAI;AAAA,aAAgB,IAAI,KAAK,MAAM,KAAK,SAAS,YAAY,UAAU,MAAM,YAAY;AACjG,UAAQ,IAAI,YAAY,WAAW,QAAQ,CAAC,CAAC,MAAM,SAAS,QAAQ,CAAC,CAAC,MAAO,aAAa,WAAY,KAAK,QAAQ,CAAC,CAAC,IAAI;AACzH,UAAQ,IAAI,kBAAkB,eAAe,KAAM,QAAQ,CAAC,CAAC,GAAG;AAGhE,QAAM,UAAU,YAAY,UAAU;AACtC,QAAM,WAAW,QAAQ,SAAS,IAAI,QAAQ,QAAQ,SAAS,CAAC,IAAK;AAErE,MAAI,YAAY,SAAS,YAAY,QAAQ,YAC7C;AACC,aAAS,SAAS,SAAS,OAAO;AAAA,EACnC;AAGA,QAAM,UAAwB;AAAA,IAC7B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,SAAS,QAAQ;AAAA,IACjB,SAAS;AAAA,IACT,SAAS,EAAC,MAAM,QAAQ,OAAO,WAAW,OAAO,YAAY,SAAQ;AAAA,EACtE;AACA,cAAY,YAAY,SAAS,OAAO;AACxC,UAAQ,IAAI,EAAE;AACf;AAIA,SAAS,eAAe,YACxB;AACC,SAAOC,MAAK,KAAK,YAAY,eAAe,cAAc;AAC3D;AAEA,SAAS,YAAY,YACrB;AACC,QAAM,cAAc,eAAe,UAAU;AAC7C,MAAI,CAACC,IAAG,WAAW,WAAW,EAAG,QAAO,CAAC;AACzC,MACA;AACC,UAAM,MAAMA,IAAG,aAAa,aAAa,OAAO;AAEhD,WAAO,KAAK,MAAM,GAAG;AAAA,EACtB,QAEA;AACC,WAAO,CAAC;AAAA,EACT;AACD;AAEA,SAAS,YAAY,YAAoB,SAAyB,SAClE;AACC,QAAM,cAAc,eAAe,UAAU;AAC7C,QAAM,MAAMD,MAAK,QAAQ,WAAW;AACpC,EAAAC,IAAG,UAAU,KAAK,EAAC,WAAW,KAAI,CAAC;AAGnC,QAAM,UAAU,CAAC,GAAG,QAAQ,MAAM,GAAG,GAAG,OAAO;AAC/C,EAAAA,IAAG,cAAc,aAAa,KAAK,UAAU,SAAS,MAAM,GAAI,IAAI,IAAI;AACzE;AAEA,SAAS,SAAS,SAAuB,UACzC;AACC,QAAM,UAAU,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;AAC5D,QAAM,UAAoB,CAAC;AAE3B,aAAW,SAAS,SACpB;AACC,UAAM,OAAO,QAAQ,IAAI,MAAM,QAAQ;AACvC,QAAI,CAAC,KAAM;AAEX,UAAM,cAAc,KAAK,WAAW,aAAa,MAAM,KAAK,WAAW,aAAa,MAAM;AAC1F,UAAM,aAAa,MAAM,WAAW,aAAa,MAAM,MAAM,WAAW,aAAa,MAAM;AAE3F,QAAI,gBAAgB,YACpB;AACC,cAAQ,KAAK,OAAO,MAAM,SAAS,OAAO,EAAE,CAAC,IAAI,WAAW,OAAO,UAAU,EAAE;AAAA,IAChF;AAAA,EACD;AAEA,QAAM,YAAY,SAAS,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AAC9D,QAAM,WAAW,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AAC5D,QAAM,OAAO,WAAW;AAExB,MAAI,QAAQ,SAAS,KAAK,KAAK,IAAI,IAAI,IAAI,KAC3C;AACC,YAAQ,IAAI,kBAAkB;AAC9B,QAAI,KAAK,IAAI,IAAI,IAAI,KACrB;AACC,YAAM,OAAO,OAAO,IAAI,MAAM;AAC9B,cAAQ,IAAI,cAAc,IAAI,GAAG,KAAK,QAAQ,CAAC,CAAC,EAAE;AAAA,IACnD;AACA,eAAW,UAAU,SACrB;AACC,cAAQ,IAAI,MAAM;AAAA,IACnB;AAAA,EACD;AACD;;;AE5OA;AAAA,EACC,aAAAC;AAAA,EAAW;AAAA,EAAiB;AAAA,EAC5B;AAAA,EAAoB;AAAA,EAAgB;AAAA,EAAmB;AAAA,EACvD;AAAA,EAAe;AAAA,EACf;AAAA,EAAc;AAAA,OACR;AAgBP,eAAsB,SAAS,SAC/B;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AAEzD,QAAM,WAAW,QAAQ,YAAY;AACrC,UAAQ,IAAI;AAAA,WAAc,QAAQ,UAAU,YAAY,QAAQ,QAAQ,qBAAqB,QAAQ,YAAY,QAAQ,QAAQ,CAAC;AAAA,CAAI;AAEtI,MAAI;AACJ,MAAI,iBAAiB,QAAQ,QAAQ,GACrC;AAGC,YAAQ,IAAI,kCAAkC;AAC9C,UAAM,SAAS,MAAM,sBAAsB,QAAQ,QAAQ;AAC3D,UAAM,aAAa,MAAM,uBAAuB,QAAQ,YAAY,QAAQ,UAAU;AACtF,aAAS,MAAM,kBAAkB,YAAY,OAAO,QAAQ;AAAA,MAC3D,MAAM,QAAQ,QAAQ;AAAA,MACtB,eAAe;AAAA,MACf,UAAU,QAAQ,YAAY;AAAA,IAC/B,CAAC;AAAA,EACF,OAEA;AACC,UAAM,aAAa,IAAIC,WAAU,QAAQ,YAAY,QAAQ,UAAU;AACvE,UAAM,iBAAiB,gBAAgB,QAAQ,QAAQ;AACvD,aAAS,MAAM,gBAAgB,YAAY,gBAAgB;AAAA,MAC1D,MAAM,QAAQ,QAAQ;AAAA,MACtB,eAAe;AAAA,MACf,UAAU,QAAQ,YAAY;AAAA,MAC9B,gBAAgB,sBAAsB;AAAA,IACvC,CAAC;AAAA,EACF;AAEA,QAAM,UAAU,OAAO;AACvB,MAAI,QAAQ,WAAW,GACvB;AACC,YAAQ,IAAI,2BAA2B;AACvC;AAAA,EACD;AAGA,QAAM,SAAS,mBAAmB,SAAS,OAAO,MAAM;AACxD,UAAQ,IAAI,kBAAkB,MAAM,CAAC;AAGrC,QAAM,UAAU,eAAe,QAAQ,QAAQ,QAAQ,YAAY,QAAQ,QAAQ;AACnF,UAAQ,IAAI,OAAO,mBAAmB,OAAO,CAAC;AAG9C,QAAM,QAAQ,aAAa,MAAM;AACjC,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,YAAY,OAAO,QAAQ,UAAU,CAAC;AAGlD,QAAM,OAAO,cAAc,QAAQ,OAAO;AAC1C,MAAI,KAAK,SAAS,GAClB;AACC,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,gBAAgB,IAAI,CAAC;AAAA,EAClC;AACA,UAAQ,IAAI,EAAE;AACf;;;ACpFA,SAAQ,aAAAC,YAAW,gBAAAC,eAAc,cAAAC,aAAY,2BAA0B;AA0BvE,eAAsB,cAAc,SACpC;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AACzD,QAAM,aAAa,IAAIC,WAAU,QAAQ,YAAY,QAAQ,UAAU;AAGvE,QAAM,gBAAgB,QAAQ,aAAa,QAAQ,UAAU,SAAS,IACnE,QAAQ,YACR,mBAAmB;AAGtB,QAAM,eAAoD;AAAA,IACzD,EAAC,MAAM,QAAQ,YAAY,QAAQ,WAAU;AAAA,EAC9C;AAEA,aAAW,QAAQ,eACnB;AACC,iBAAa,KAAK,EAAC,MAAM,QAAQ,gBAAgB,IAAI,EAAC,CAAC;AAAA,EACxD;AAEA,UAAQ,IAAI;AAAA,gBAAmB,aAAa,MAAM,kBAAkB,aAAa,UAAU,aAAa,SAAS,KAAK,CAAC;AAAA,CAAc;AAGrI,QAAM,WAAsB,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KACzC;AACC,aAAS,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAC7C;AACC,eAAS,KAAK;AAAA,QACb,UAAU,aAAa,CAAC,EAAG;AAAA,QAC3B,UAAU,aAAa,CAAC,EAAG;AAAA,QAC3B,YAAY,aAAa,CAAC,EAAG;AAAA,QAC7B,YAAY,aAAa,CAAC,EAAG;AAAA,MAC9B,CAAC;AAAA,IACF;AAAA,EACD;AAGA,QAAM,UAA2B,CAAC;AAClC,QAAM,eAAe,KAAK,IAAI;AAE9B,aAAW,WAAW,UACtB;AACC,UAAM,SAAS,MAAMC,cAAa,QAAQ,YAAY,QAAQ,YAAY;AAAA,MACzE,gBAAgB,sBAAsB;AAAA,IACvC,CAAC;AACD,YAAQ,KAAK;AAAA,MACZ,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB;AAAA,IACD,CAAC;AAED,UAAM,UAAU,OAAO,WAAW,aAAa,GAAG,QAAQ,QAAQ,UAC/D,OAAO,WAAW,aAAa,GAAG,QAAQ,QAAQ,UACjD;AACJ,YAAQ,IAAI,KAAK,QAAQ,QAAQ,OAAO,QAAQ,QAAQ,KAAK,OAAO,WAAW,IAAI,OAAO,WAAW,IAAI,OAAO,KAAK,KAAK,OAAO,GAAG;AAAA,EACrI;AAGA,QAAM,SAAS,oBAAI,IAAoB;AACvC,QAAM,OAAO,oBAAI,IAAoB;AAErC,aAAW,KAAK,cAChB;AACC,WAAO,IAAI,EAAE,MAAM,CAAC;AACpB,SAAK,IAAI,EAAE,MAAM,CAAC;AAAA,EACnB;AAEA,aAAW,KAAK,SAChB;AACC,UAAM,SAASC,YAAW,EAAE,MAAM;AAClC,UAAM,SAAS,oBAAoB,EAAE,MAAM;AAE3C,WAAO,IAAI,EAAE,WAAW,OAAO,IAAI,EAAE,QAAQ,KAAK,KAAK,MAAM;AAC7D,WAAO,IAAI,EAAE,WAAW,OAAO,IAAI,EAAE,QAAQ,KAAK,KAAK,MAAM;AAC7D,SAAK,IAAI,EAAE,WAAW,KAAK,IAAI,EAAE,QAAQ,KAAK,KAAK,EAAE,OAAO,WAAW;AACvE,SAAK,IAAI,EAAE,WAAW,KAAK,IAAI,EAAE,QAAQ,KAAK,KAAK,EAAE,OAAO,WAAW;AAAA,EACxE;AAEA,QAAM,eAAe,KAAK,IAAI,IAAI;AAGlC,QAAM,YAAY,CAAC,GAAG,OAAO,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MACjD;AACC,QAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AACpC,YAAQ,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC,KAAK;AAAA,EACnD,CAAC;AAED,UAAQ,IAAI,gBAAgB;AAC5B,UAAQ,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;AACjC,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KACtC;AACC,UAAM,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC;AAC/B,UAAM,IAAI,KAAK,IAAI,IAAI,KAAK;AAC5B,UAAM,OAAO,KAAK,IAAI,GAAG,SAAS,EAAE,SAAS,CAAC,CAAC;AAC/C,UAAM,SAAS,SAAS,QAAQ,aAAa,OAAO;AACpD,YAAQ,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC,SAAS,CAAC,IAAI,MAAM,EAAE;AAAA,EAClF;AAEA,UAAQ,IAAI;AAAA,iBAAoB,eAAe,KAAM,QAAQ,CAAC,CAAC;AAAA,CAAK;AACrE;;;AC9HA,SAAQ,cAAc,qBAAoB;AAC1C,SAAQ,aAAAC,YAAW,cAAc,cAAAC,aAAY,oBAAoB,yBAAwB;AAwBzF,IAAM,YAAY;AAElB,SAAS,cAAc,GACvB;AACC,QAAM,IAAI,WAAW,EAAE,KAAK,CAAC;AAC7B,MAAI,OAAO,MAAM,CAAC,EAAG,OAAM,IAAI,MAAM,sCAAsC,EAAE,KAAK,CAAC,GAAG;AACtF,SAAO;AACR;AAEO,SAAS,YAAY,QAC5B;AACC,QAAM,SAAwB,CAAC;AAC/B,QAAM,KAAK,IAAI,OAAO,UAAU,QAAQ,GAAG;AAC3C,MAAI;AAEJ,UAAQ,QAAQ,GAAG,KAAK,MAAM,OAAO,MACrC;AACC,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,eAAe,cAAc,MAAM,CAAC,CAAE;AAC5C,UAAM,UAAU,MAAM,CAAC;AAEvB,QAAI;AACJ,QAAI;AACJ,QAAI;AAEJ,QAAI,SACJ;AACC,YAAM,WAAW,QAAQ,MAAM,oBAAoB;AACnD,YAAM,WAAW,QAAQ,MAAM,oBAAoB;AACnD,YAAM,YAAY,QAAQ,MAAM,qBAAqB;AACrD,UAAI,SAAU,OAAM,cAAc,SAAS,CAAC,CAAE;AAC9C,UAAI,SAAU,OAAM,cAAc,SAAS,CAAC,CAAE;AAC9C,UAAI,UAAW,QAAO,cAAc,UAAU,CAAC,CAAE;AAAA,IAClD;AAEA,WAAO,KAAK,EAAC,MAAM,cAAc,KAAK,KAAK,KAAI,CAAC;AAAA,EACjD;AAEA,SAAO;AACR;AAEA,SAAS,mBAAmB,GAC5B;AACC,SAAO;AAAA,IACN,MAAM,EAAE;AAAA,IACR,OAAO,EAAE;AAAA,IACT,KAAK,EAAE;AAAA,IACP,KAAK,EAAE;AAAA,IACP,OAAO,EAAE,QAAQ;AAAA,EAClB;AACD;AAMA,IAAM,kBAAkB,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG;AAChD,IAAM,QAAQ,CAAC,IAAI,KAAK,GAAG;AAE3B,SAAS,mBACR,SACA,SAED;AACC,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,QAAQ;AACZ,QAAM,UAA4B,CAAC;AAEnC,aAAW,QAAQ,OACnB;AACC,eAAW,QAAQ,iBACnB;AACC,YAAM,IAAI,QAAQ,SAAS;AAAA,QAC1B;AAAA,QACA,eAAe;AAAA,QACf,aAAa;AAAA,QACb;AAAA,MACD,CAAC;AACD,UAAI,EAAE,WAAW,WAAY;AAAA,eACpB,EAAE,WAAW,WAAY;AAAA,UAC7B;AAEL,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD;AAEA,SAAO;AAAA,IACN,aAAa;AAAA,IACb,aAAa;AAAA,IACb;AAAA,IACA,QAAS,KAAK,KAAK,aAAa,KAAK,KAAK,aAAa;AAAA,IACvD;AAAA,EACD;AACD;AAEA,eAAe,eACd,YACA,iBACA,SAED;AACC,MAAI,aAAa;AACjB,aAAW,YAAY,iBACvB;AACC,UAAM,UAAU,MAAM,aAAa,OAAO,YAAY,UAAU;AAAA,MAC/D,gBAAgB,sBAAsB;AAAA,IACvC,CAAC;AACD,QACA;AACC,YAAM,SAAS,mBAAmB,SAAS,OAAO;AAClD,oBAAcC,YAAW,MAAM;AAAA,IAChC,UACA;AAEC,cAAQ,QAAQ;AAAA,IACjB;AAAA,EACD;AACA,SAAO;AACR;AAMO,SAAS,qBAAqB,WACrC;AACC,MAAI,CAAC,aAAa,UAAU,WAAW,GACvC;AACC,WAAO,mBAAmB;AAAA,EAC3B;AAGA,QAAM,WAAW,mBAAmB;AACpC,aAAW,QAAQ,WACnB;AACC,QAAI,CAAC,SAAS,SAAS,IAAI,GAC3B;AACC,YAAM,IAAI;AAAA,QACT,sBAAsB,IAAI;AAAA,IAAyB,SAAS,KAAK,IAAI,CAAC;AAAA,MACvE;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AAEA,eAAsB,YAAY,SAClC;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AAEzD,QAAM,SAAS,aAAa,QAAQ,YAAY,OAAO;AACvD,QAAM,SAAS,YAAY,MAAM;AAEjC,MAAI,OAAO,WAAW,GACtB;AACC,YAAQ,IAAI,4CAA4C;AACxD,YAAQ,IAAI,iFAAiF;AAC7F;AAAA,EACD;AAEA,UAAQ,IAAI;AAAA,SAAY,QAAQ,UAAU,EAAE;AAC5C,UAAQ,IAAI,iBAAiB,OAAO,MAAM,EAAE;AAC5C,SAAO,QAAQ,CAAC,MAAM,QAAQ,IAAI,OAAO,EAAE,IAAI,MAAM,EAAE,YAAY,KAAK,EAAE,OAAO,MAAM,OAAO,EAAE,OAAO,MAAM,GAAG,CAAC;AAEjH,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,YAAY,QAAQ,UAAU;AACpC,QAAM,gBAAgB,qBAAqB,QAAQ,SAAS;AAC5D,QAAM,kBAAkB,cAAc,IAAI,CAAC,SAAS,gBAAgB,IAAI,CAAC;AACzE,QAAM,aAAa,IAAIC,WAAU,QAAQ,YAAY,QAAQ,UAAU;AAEvE,UAAQ,IAAI,gBAAgB,gBAAgB,MAAM,EAAE;AACpD,UAAQ,IAAI,sBAAsB,KAAK,EAAE;AACzC,UAAQ,IAAI,iBAAiB,SAAS;AAAA,CAAI;AAG1C,QAAM,OAA+B,CAAC;AACtC,aAAW,KAAK,OAAQ,MAAK,EAAE,IAAI,IAAI,EAAE;AAGzC,MAAI,YAAY,MAAM,eAAe,YAAY,iBAAiB,IAAI;AACtE,UAAQ,IAAI,qBAAqB,UAAU,QAAQ,CAAC,CAAC,OAAO,gBAAgB,SAAS,gBAAgB,SAAS,MAAM,SAAS,KAAK,QAAQ,CAAC,CAAC;AAAA,CAAI;AAGhJ,WAAS,QAAQ,GAAG,QAAQ,WAAW,SACvC;AACC,QAAI,WAAW;AACf,YAAQ,IAAI,WAAW,QAAQ,CAAC,GAAG;AAEnC,eAAW,KAAK,QAChB;AACC,YAAM,OAAO,mBAAmB,CAAC;AACjC,YAAM,QAAQ,kBAAkB,IAAI;AACpC,YAAM,aAAa,mBAAmB,MAAM,KAAK,MAAM,KAAK,KAAK;AAEjE,UAAI,YAAY,KAAK,EAAE,IAAI;AAC3B,UAAI,iBAAiB;AAErB,iBAAW,aAAa,YACxB;AACC,YAAI,KAAK,IAAI,YAAY,SAAS,IAAI,KAAO;AAE7C,cAAM,QAAQ,EAAC,GAAG,MAAM,CAAC,EAAE,IAAI,GAAG,UAAS;AAC3C,cAAM,QAAQ,MAAM,eAAe,YAAY,iBAAiB,KAAK;AAErE,YAAI,QAAQ,gBACZ;AACC,sBAAY;AACZ,2BAAiB;AAAA,QAClB;AAAA,MACD;AAEA,UAAI,cAAc,KAAK,EAAE,IAAI,GAC7B;AACC,gBAAQ,IAAI,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,OAAO,SAAS,OAAO,iBAAiB,WAAW,QAAQ,CAAC,CAAC,GAAG;AAC1G,aAAK,EAAE,IAAI,IAAI;AACf,oBAAY;AACZ,mBAAW;AAAA,MACZ,OAEA;AACC,gBAAQ,IAAI,OAAO,EAAE,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,mBAAmB;AAAA,MAC9D;AAAA,IACD;AAEA,QAAI,CAAC,UACL;AACC,cAAQ,IAAI,sCAAsC;AAClD;AAAA,IACD;AACA,YAAQ,IAAI,WAAW,QAAQ,CAAC,WAAW,UAAU,QAAQ,CAAC,CAAC;AAAA,CAAI;AAAA,EACpE;AAGA,MAAI,UAAU;AACd,aAAW,KAAK,QAChB;AACC,UAAM,SAAS,KAAK,EAAE,IAAI;AAC1B,QAAI,WAAW,EAAE,cACjB;AACC,YAAM,UAAU,IAAI;AAAA,QACnB,uBAAuB,YAAY,EAAE,IAAI,CAAC,iBAAiB,YAAY,OAAO,EAAE,YAAY,CAAC,CAAC;AAAA,MAC/F;AACA,gBAAU,QAAQ,QAAQ,SAAS,KAAK,MAAM,EAAE;AAAA,IACjD;AAAA,EACD;AAEA,MAAI,YAAY,QAChB;AACC,kBAAc,QAAQ,YAAY,OAAO;AACzC,YAAQ,IAAI,qBAAqB,QAAQ,UAAU,EAAE;AAAA,EACtD,OAEA;AACC,YAAQ,IAAI,kCAAkC;AAAA,EAC/C;AAEA,UAAQ,IAAI,kBAAkB,UAAU,QAAQ,CAAC,CAAC,OAAO,gBAAgB,SAAS,gBAAgB,SAAS,MAAM,SAAS,KAAK,QAAQ,CAAC,CAAC;AAAA,CAAI;AAC9I;AAEA,SAAS,YAAY,GACrB;AACC,SAAO,EAAE,QAAQ,uBAAuB,MAAM;AAC/C;;;ACnSA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAQ,aAAAC,YAAW,0BAAyB;AAW5C,eAAsB,SAAS,SAC/B;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AACzD,QAAM,gBAAgB,kBAAkB;AAExC,QAAM,aAAa,IAAIC,WAAU,QAAQ,YAAY,QAAQ,UAAU;AACvE,QAAM,iBAAiB,gBAAgB,QAAQ,QAAQ;AAEvD,UAAQ,IAAI;AAAA,cAAiB,QAAQ,UAAU,OAAO,QAAQ,QAAQ,KAAK;AAE3E,QAAM,QAAQ,KAAK,IAAI;AACvB,QAAM,SAAS,MAAM,mBAAmB,YAAY,gBAAgB;AAAA,IACnE,OAAO;AAAA,MACN,oBAAoB,gBAAgB;AAAA,IACrC;AAAA,EACD,CAAC;AACD,QAAM,UAAU,KAAK,IAAI,IAAI;AAE7B,QAAM,UAAU,QAAQ,UAAU,QAAQ,QAAQ,UAAU,OAAO,QAAQ,QAAQ;AACnF,QAAM,SAASC,MAAK,QAAQA,MAAK,QAAQ,OAAO,CAAC;AACjD,EAAAC,IAAG,UAAU,QAAQ,EAAC,WAAW,KAAI,CAAC;AACtC,EAAAA,IAAG,cAAcD,MAAK,QAAQ,OAAO,GAAG,MAAM;AAE9C,QAAM,UAAU,OAAO,SAAS,MAAM,QAAQ,CAAC;AAC/C,UAAQ,IAAI,aAAa,OAAO,KAAK,MAAM,MAAM;AACjD,UAAQ,IAAI,iBAAiB,OAAO;AAAA,CAAM;AAC3C;;;ACvCA,SAAQ,YAAY,gBAAe;AAQ5B,SAAS,QAAQ,SACxB;AACC,MAAI,QAAQ,MACZ;AACC,kBAAc,QAAQ,IAAI;AAC1B;AAAA,EACD;AACA,cAAY;AACb;AAEA,SAAS,cACT;AACC,UAAQ,IAAI,iEAA4D;AAExE,aAAW,SAAS,YACpB;AACC,YAAQ,IAAI,KAAK,MAAM,KAAK,GAAG;AAC/B,eAAW,OAAO,MAAM,MACxB;AACC,YAAM,OAAO,SAAS,QAAQ,GAAG,IAAI;AACrC,YAAM,YAAY,IAAI,OAAO,IAAI,IAAI,IAAI,KAAK;AAC9C,YAAM,UAAU,IAAI,OAAO,IAAI,EAAE,SAAS,CAAC,CAAC;AAC5C,cAAQ,IAAI,OAAO,OAAO,IAAI,SAAS,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC,IAAI,IAAI,WAAW,EAAE;AAAA,IACpF;AACA,YAAQ,IAAI,EAAE;AAAA,EACf;AACD;AAEA,SAAS,cAAc,MACvB;AACC,QAAM,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC;AAC5E,MAAI,CAAC,KACL;AACC,UAAM,YAAY,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI;AACvD,YAAQ,MAAM;AAAA,kBAAqB,IAAI;AAAA,eAAmB,SAAS;AAAA,CAAI;AACvE,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,QAAM,OAAO,SAAS,QAAQ,GAAG,IAAI;AAErC,UAAQ,IAAI;AAAA,IAAO,IAAI,IAAI,EAAE;AAC7B,UAAQ,IAAI,KAAK,SAAI,OAAO,EAAE,CAAC,EAAE;AACjC,UAAQ,IAAI,mBAAmB,IAAI,OAAO,SAAS,MAAM,EAAE;AAC3D,UAAQ,IAAI,kBAAkB,IAAI,KAAK,EAAE;AACzC,MAAI,IAAI,KAAM,SAAQ,IAAI,kBAAkB,IAAI,IAAI,OAAO;AAC3D,UAAQ,IAAI,kBAAkB,IAAI,WAAW,EAAE;AAC/C,UAAQ,IAAI,kBAAkB,oBAAoB,GAAG,CAAC,EAAE;AAGxD,MAAI,IAAI,QAAQ,IAAI,UAAU,cAC9B;AACC,UAAM,YAAY,WAAW,KAAK,CAAC,MAAM,EAAE,UAAU,IAAI,KAAK,GAAG,QAAQ,CAAC;AAC1E,QAAI,UAAU,SAAS,GACvB;AACC,cAAQ,IAAI;AAAA,IAAO,IAAI,KAAK,eAAe;AAC3C,iBAAW,MAAM,WACjB;AACC,cAAM,SAAS,SAAS,QAAQ,EAAE,IAAI;AACtC,cAAM,SAAS,GAAG,SAAS,IAAI,OAAO,YAAO;AAC7C,gBAAQ,IAAI,QAAQ,GAAG,IAAI,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC,KAAK,MAAM,WAAM,GAAG,WAAW,GAAG,MAAM,EAAE;AAAA,MAC5F;AAAA,IACD;AAAA,EACD;AAEA,UAAQ,IAAI;AAAA,2CAA8C,IAAI,IAAI,EAAE;AACpE,UAAQ,IAAI,4CAA4C,IAAI,IAAI;AAAA,CAAI;AACrE;AAEA,SAAS,oBAAoB,KAC7B;AACC,UAAQ,IAAI,OACZ;AAAA,IACC,KAAK;AACJ,UAAI,IAAI,SAAS,cAAe,QAAO;AACvC,UAAI,IAAI,SAAS,UAAW,QAAO;AACnC,UAAI,IAAI,SAAS,SAAU,QAAO;AAClC,UAAI,IAAI,SAAS,SAAU,QAAO;AAClC,UAAI,IAAI,SAAS,cAAe,QAAO;AACvC,aAAO,IAAI;AAAA,IACZ,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAS,aAAO;AAAA,IACrB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAU,aAAO;AAAA,IACtB,KAAK;AAAW,aAAO;AAAA,IACvB,KAAK;AAAa,aAAO;AAAA,IACzB,KAAK;AAAS,aAAO;AAAA,IACrB;AAAS,aAAO,IAAI;AAAA,EACrB;AACD;;;AC/FA,OAAOE,SAAQ;;;ACEf,SAAQ,YAAY,mBAAkB;;;ACHtC,SAAQ,WAAW,YAAY,WAAW,gBAAAC,eAAc,QAAQ,iBAAAC,sBAAoB;AACpF,SAAQ,eAAc;AACtB,SAAQ,YAAW;AAUnB,SAAS,YACT;AACC,SAAO,QAAQ,IAAI,yBAAyB,KAAK,QAAQ,GAAG,aAAa;AAC1E;AAEA,SAAS,kBACT;AACC,SAAO,KAAK,UAAU,GAAG,kBAAkB;AAC5C;AAEO,SAAS,kBAChB;AACC,QAAMC,QAAO,gBAAgB;AAC7B,MAAI,CAAC,WAAWA,KAAI,EAAG,QAAO;AAC9B,MACA;AACC,UAAM,SAAkB,KAAK,MAAMF,cAAaE,OAAM,OAAO,CAAC;AAC9D,QACC,OAAO,WAAW,YAAY,WAAW,QACtC,kBAAkB,UAAU,OAAO,OAAO,iBAAiB,YAC3D,iBAAiB,UAAU,OAAO,OAAO,gBAAgB,YACzD,eAAe,UAAU,OAAO,OAAO,cAAc,UAEzD;AACC,aAAO,EAAC,cAAc,OAAO,cAAc,aAAa,OAAO,aAAa,WAAW,OAAO,UAAS;AAAA,IACxG;AACA,WAAO;AAAA,EACR,QAEA;AACC,WAAO;AAAA,EACR;AACD;AAEO,SAAS,gBAAgB,aAChC;AACC,YAAU,UAAU,GAAG,EAAC,WAAW,KAAI,CAAC;AACxC,QAAMA,QAAO,gBAAgB;AAC7B,EAAAD,eAAcC,OAAM,KAAK,UAAU,aAAa,MAAM,CAAC,GAAG,EAAC,MAAM,IAAK,CAAC;AAEvE,MACA;AACC,cAAUA,OAAM,GAAK;AAAA,EACtB,QAEA;AAAA,EAEA;AACD;AAEO,SAAS,mBAChB;AACC,MACA;AACC,WAAO,gBAAgB,GAAG,EAAC,OAAO,KAAI,CAAC;AAAA,EACxC,QAEA;AAAA,EAEA;AACD;;;ADjEO,IAAM,eAAe,QAAQ,IAAI,sBAAsB;AAEvD,IAAM,mBAAN,cAA+B,MACtC;AAAA,EACC,cACA;AACC,UAAM,sCAAsC;AAC5C,SAAK,OAAO;AAAA,EACb;AACD;AAQO,SAAS,eAChB;AACC,QAAM,WAAW,YAAY,EAAE,EAAE,SAAS,WAAW;AACrD,QAAM,YAAY,WAAW,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,WAAW;AAC1E,SAAO,EAAC,UAAU,UAAS;AAC5B;AAGA,eAAsB,eAAe,aACrC;AACC,QAAM,MAAM,MAAM,MAAM,GAAG,YAAY,aAAa;AAAA,IACnD,QAAQ;AAAA,IACR,SAAS,EAAC,gBAAgB,mBAAkB;AAAA,IAC5C,MAAM,KAAK,UAAU,EAAC,eAAe,CAAC,WAAW,GAAG,aAAa,iBAAgB,CAAC;AAAA,EACnF,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,+BAA+B,IAAI,MAAM,IAAI;AAC1E,QAAM,OAAgB,MAAM,IAAI,KAAK;AACrC,QAAM,WAAW,OAAO,SAAS,YAAY,SAAS,QAAQ,eAAe,QAAQ,OAAO,KAAK,cAAc,WAC5G,KAAK,YACL;AACH,MAAI,CAAC,SAAU,OAAM,IAAI,MAAM,4CAA4C;AAC3E,SAAO;AACR;AAEA,SAAS,mBAAmB,MAAe,iBAC3C;AACC,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,OAAM,IAAI,MAAM,yBAAyB;AACxF,QAAM,cAAc,kBAAkB,QAAQ,OAAO,KAAK,iBAAiB,WAAW,KAAK,eAAe;AAC1G,MAAI,CAAC,YAAa,OAAM,IAAI,MAAM,sCAAsC;AACxE,QAAM,eAAe,mBAAmB,QAAQ,OAAO,KAAK,kBAAkB,WAAW,KAAK,gBAAgB;AAC9G,QAAM,YAAY,gBAAgB,QAAQ,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAClG,SAAO,EAAC,aAAa,cAAc,WAAW,KAAK,IAAI,IAAI,YAAY,IAAI;AAC5E;AAGA,eAAsB,aAAa,MAAc,cACjD;AACC,QAAM,MAAM,MAAM,MAAM,GAAG,YAAY,UAAU;AAAA,IAChD,QAAQ;AAAA,IACR,SAAS,EAAC,gBAAgB,mBAAkB;AAAA,IAC5C,MAAM,KAAK,UAAU,EAAC,YAAY,sBAAsB,MAAM,eAAe,aAAY,CAAC;AAAA,EAC3F,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,MAAM,MAAM,IAAI,KAAK,CAAC,EAAE;AACzF,QAAM,QAAQ,mBAAmB,MAAM,IAAI,KAAK,GAAG,EAAE;AACrD,kBAAgB,KAAK;AACrB,SAAO;AACR;AAEA,eAAe,mBAAmB,cAClC;AACC,QAAM,MAAM,MAAM,MAAM,GAAG,YAAY,UAAU;AAAA,IAChD,QAAQ;AAAA,IACR,SAAS,EAAC,gBAAgB,mBAAkB;AAAA,IAC5C,MAAM,KAAK,UAAU,EAAC,YAAY,iBAAiB,eAAe,aAAY,CAAC;AAAA,EAChF,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,iBAAiB;AACxC,QAAM,QAAQ,mBAAmB,MAAM,IAAI,KAAK,GAAG,YAAY;AAC/D,kBAAgB,KAAK;AACrB,SAAO;AACR;AAEA,IAAM,kBAAkB;AAGxB,eAAsB,iBACtB;AACC,QAAM,QAAQ,gBAAgB;AAC9B,MAAI,CAAC,MAAO,OAAM,IAAI,iBAAiB;AACvC,MAAI,MAAM,YAAY,KAAK,IAAI,IAAI,gBAAiB,QAAO,MAAM;AACjE,QAAM,YAAY,MAAM,mBAAmB,MAAM,YAAY;AAC7D,SAAO,UAAU;AAClB;;;AE9FA,OAAO,QAAQ;AACf,SAAQ,gBAAAC,qBAAmB;AAC3B,OAAOC,WAAU;AACjB,SAAQ,qBAAoB;AAerB,SAAS,mBAAmB,MACnC;AACC,aAAW,OAAO,CAAC,sBAAsB,mBAAmB,uBAAuB,GACnF;AACC,QACA;AACC,YAAM,SAAkB,KAAK,MAAMD,cAAaC,MAAK,QAAQ,MAAM,GAAG,GAAG,MAAM,CAAC;AAChF,UAAI,OAAO,WAAW,YAAY,WAAW,KAAM;AACnD,UAAI,EAAE,UAAU,WAAW,EAAE,aAAa,QAAS;AACnD,YAAM,EAAC,MAAM,QAAO,IAAI;AACxB,UAAI,SAAS,gBAAgB,OAAO,YAAY,SAAU,QAAO;AAAA,IAClE,QAEA;AAAA,IAEA;AAAA,EACD;AACA,SAAO;AACR;AAEA,SAAS,iBACT;AACC,MACA;AACC,WAAO,mBAAmBA,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,CAAC;AAAA,EACvE,QAEA;AAEC,WAAO;AAAA,EACR;AACD;AAMO,SAAS,gBAAgB,KAOhC;AACC,QAAM,UAAkC,CAAC;AACzC,QAAM,MAAM,CAAC,KAAa,UAC1B;AACC,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,QAAS,SAAQ,GAAG,IAAI,QAAQ,MAAM,GAAG,EAAE;AAAA,EAChD;AACA,MAAI,mBAAmB,IAAI,QAAQ;AACnC,MAAI,2BAA2B,IAAI,OAAO;AAC1C,MAAI,qBAAqB,IAAI,IAAI;AACjC,MAAI,qBAAqB,IAAI,WAAW;AACxC,MAAI,oBAAoB,IAAI,UAAU;AACtC,SAAO;AACR;AAGO,SAAS,aAChB;AACC,MACA;AACC,WAAO,gBAAgB;AAAA,MACtB,UAAU,GAAG,SAAS;AAAA,MACtB,SAAS,GAAG,QAAQ;AAAA,MACpB,MAAM,GAAG,KAAK;AAAA,MACd,aAAa,QAAQ;AAAA,MACrB,YAAY,eAAe;AAAA,IAC5B,CAAC;AAAA,EACF,QAEA;AACC,WAAO,CAAC;AAAA,EACT;AACD;;;AChFA,eAAsB,UAAU,SAChC;AACC,QAAM,QAAQ,MAAM,eAAe;AACnC,QAAM,MAAM,MAAM,MAAM,GAAG,YAAY,eAAe;AAAA,IACrD,QAAQ;AAAA;AAAA,IAER,SAAS,EAAC,gBAAgB,oBAAoB,eAAe,UAAU,KAAK,IAAI,GAAG,WAAW,EAAC;AAAA,IAC/F,MAAM,KAAK,UAAU,OAAO;AAAA,EAC7B,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,kBAAkB,IAAI,MAAM,MAAM,MAAM,IAAI,KAAK,CAAC,EAAE;AACjF,QAAM,OAAgB,MAAM,IAAI,KAAK;AACrC,QAAM,WAAW,OAAO,SAAS,YAAY,SAAS,QAAQ,cAAc,QAAQ,OAAO,KAAK,aAAa,WAC1G,KAAK,WACL;AACH,QAAM,UAAU,OAAO,SAAS,YAAY,SAAS,QAAQ,aAAa,QAAQ,OAAO,KAAK,YAAY,WACvG,KAAK,UACL;AACH,SAAO,EAAC,UAAU,QAAO;AAC1B;AAEA,eAAsB,WAAW,MACjC;AACC,QAAM,QAAQ,MAAM,eAAe;AACnC,QAAM,MAAM,MAAM,MAAM,GAAG,YAAY,kBAAkB,mBAAmB,IAAI,CAAC,IAAI;AAAA,IACpF,SAAS,EAAC,eAAe,UAAU,KAAK,IAAI,GAAG,WAAW,EAAC;AAAA,EAC5D,CAAC;AACD,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,gBAAgB,IAAI,MAAM,MAAM,MAAM,IAAI,KAAK,CAAC,EAAE;AAC/E,QAAM,OAAgB,MAAM,IAAI,KAAK;AACrC,QAAM,SAAS,OAAO,SAAS,YAAY,SAAS,QAAQ,gBAAgB,QAAQ,OAAO,KAAK,eAAe,WAC5G,KAAK,aACL;AACH,MAAI,OAAQ,QAAO;AACnB,QAAM,QAAQ,OAAO,SAAS,YAAY,SAAS,QAAQ,WAAW,QAAQ,OAAO,KAAK,UAAU,WACjG,KAAK,QACL;AACH,QAAM,IAAI,MAAM,KAAK;AACtB;;;AJvCA,IAAM,mBAAmB,MAAM;AAE/B,eAAsB,UAAU,SAChC;AACC,QAAM,aAAa,QAAQ,IAAI;AAC/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,GAAG;AAEzD,UAAQ,IAAI;AAAA,cAAiB,QAAQ,UAAU,KAAK;AACpD,QAAM,SAAS,MAAM,uBAAuB,QAAQ,YAAY,QAAQ,UAAU;AAClF,QAAM,UAAU,OAAO,SAAS,MAAM,QAAQ,CAAC;AAC/C,UAAQ,IAAI,aAAa,MAAM,KAAK;AAEpC,MAAI,OAAO,SAAS,kBACpB;AACC,YAAQ,MAAM,8BAA8B,MAAM,aAAa,mBAAmB,IAAI,MAAM;AAC5F,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,MAAI,aAAa;AACjB,MACA;AACC,iBAAaC,IAAG,aAAa,QAAQ,YAAY,OAAO;AAAA,EACzD,QAEA;AAAA,EAEA;AAEA,UAAQ,IAAI,aAAa,QAAQ,UAAU,EAAE;AAC7C,UAAQ,IAAI,8BAA8B;AAE1C,MACA;AACC,UAAM,SAAS,MAAM,UAAU;AAAA,MAC9B;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,YAAY,QAAQ;AAAA,MACpB;AAAA,IACD,CAAC;AACD,YAAQ,IAAI,YAAO,OAAO,OAAO,EAAE;AACnC,QAAI,OAAO,SAAU,SAAQ,IAAI,gBAAgB,OAAO,QAAQ,EAAE;AAClE,YAAQ,IAAI,kBAAkB,QAAQ,UAAU;AAAA,CAAuB;AAAA,EACxE,SACM,KACN;AACC,QAAI,eAAe,kBACnB;AACC,cAAQ,MAAM,4CAA4C;AAAA,IAC3D,OAEA;AACC,cAAQ,MAAM,2BAAsB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAAA,IACzF;AACA,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;;;AKnEA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAUjB,eAAsB,QAAQ,SAC9B;AACC,QAAM,aAAa,QAAQ,IAAI;AAG/B,QAAM,UAAU,MAAM,YAAY,YAAY,QAAQ,KAAK,EAAC,kBAAkB,KAAI,CAAC;AACnF,QAAM,QAAQ,CAACC,IAAG,WAAW,QAAQ,UAAU;AAE/C,UAAQ,IAAI;AAAA,8BAAiC,QAAQ,UAAU,KAAK;AAEpE,MACA;AACC,UAAM,aAAa,MAAM,WAAW,QAAQ,UAAU;AAEtD,IAAAA,IAAG,UAAUC,MAAK,QAAQ,QAAQ,UAAU,GAAG,EAAC,WAAW,KAAI,CAAC;AAChE,IAAAD,IAAG,cAAc,QAAQ,YAAY,UAAU;AAC/C,YAAQ,IAAI,YAAO,QAAQ,YAAY,SAAS,IAAI,QAAQ,UAAU,EAAE;AACxE,YAAQ,IAAI,MAAM,WAAW,SAAS,MAAM,QAAQ,CAAC,CAAC,aAAa;AAAA,EACpE,SACM,KACN;AACC,QAAI,eAAe,kBACnB;AACC,cAAQ,MAAM,4CAA4C;AAAA,IAC3D,OAEA;AACC,cAAQ,MAAM,kBAAkB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAClF,cAAQ,MAAM,0CAA0C;AAAA,IACzD;AACA,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;;;ACxCA,SAAQ,oBAA8D;AACtE,SAAQ,eAAAE,oBAAkB;AAC1B,SAAQ,aAAY;AACpB,SAAQ,uBAAsB;AAQvB,SAAS,kBACf,SACA,QAED;AACC,QAAM,IAAI,IAAI,IAAI,GAAG,OAAO,YAAY;AACxC,IAAE,aAAa,IAAI,iBAAiB,MAAM;AAC1C,IAAE,aAAa,IAAI,aAAa,OAAO,QAAQ;AAC/C,IAAE,aAAa,IAAI,gBAAgB,OAAO,WAAW;AACrD,IAAE,aAAa,IAAI,kBAAkB,OAAO,SAAS;AACrD,IAAE,aAAa,IAAI,yBAAyB,MAAM;AAClD,IAAE,aAAa,IAAI,SAAS,OAAO,KAAK;AACxC,SAAO,EAAE,SAAS;AACnB;AAEO,SAAS,wBAAwB,QAAgB,eACxD;AACC,QAAM,IAAI,IAAI,IAAI,QAAQ,kBAAkB;AAC5C,QAAM,OAAO,EAAE,aAAa,IAAI,MAAM;AACtC,QAAM,QAAQ,EAAE,aAAa,IAAI,OAAO;AACxC,MAAI,CAAC,KAAM,QAAO,EAAC,OAAO,yCAAwC;AAClE,MAAI,UAAU,cAAe,QAAO,EAAC,OAAO,mDAA6C;AACzF,SAAO,EAAC,KAAI;AACb;AAEA,SAASC,aAAY,KACrB;AACC,MACA;AACC,UAAM,QAAQ,QAAQ,aAAa,UAChC,MAAM,OAAO,CAAC,MAAM,SAAS,IAAI,GAAG,GAAG,EAAC,OAAO,UAAU,UAAU,KAAI,CAAC,IACxE,MAAM,QAAQ,aAAa,WAAW,SAAS,YAAY,CAAC,GAAG,GAAG,EAAC,OAAO,UAAU,UAAU,KAAI,CAAC;AACtG,UAAM,MAAM;AAAA,EACb,QAEA;AAAA,EAEA;AACD;AASA,SAAS,oBAAoB,eAC7B;AACC,SAAO,IAAI,QAAQ,CAAC,kBACpB;AACC,QAAI,cAAsC,MAAM;AAChD,QAAI,aAAmC,MAAM;AAC7C,UAAM,cAAc,IAAI,QAAgB,CAAC,KAAK,QAC9C;AACC,oBAAc;AACd,mBAAa;AAAA,IACd,CAAC;AAED,UAAM,SAAS,aAAa,CAAC,KAAsB,QACnD;AACC,YAAM,SAAS,wBAAwB,IAAI,OAAO,IAAI,aAAa;AACnE,UAAI,WAAW,QACf;AACC,YAAI,UAAU,KAAK,EAAC,gBAAgB,YAAW,CAAC;AAChD,YAAI,IAAI,mEAAmE;AAC3E,mBAAW,IAAI,MAAM,OAAO,KAAK,CAAC;AAClC;AAAA,MACD;AACA,UAAI,UAAU,KAAK,EAAC,gBAAgB,YAAW,CAAC;AAChD,UAAI,IAAI,6FAA6F;AACrG,kBAAY,OAAO,IAAI;AAAA,IACxB,CAAC;AAED,WAAO,OAAO,GAAG,aAAa,MAC9B;AACC,YAAM,OAAO,OAAO,QAAQ;AAC5B,YAAM,OAAO,OAAO,SAAS,YAAY,SAAS,OAAO,KAAK,OAAO;AACrE,oBAAc,EAAC,MAAM,aAAa,OAAO,MAAM,OAAO,MAAM,EAAC,CAAC;AAAA,IAC/D,CAAC;AAAA,EACF,CAAC;AACF;AAEA,eAAe,gBAAgB,WAAmB,UAAkB,OACpE;AACC,QAAM,EAAC,MAAM,aAAa,MAAK,IAAI,MAAM,oBAAoB,KAAK;AAClE,QAAM,cAAc,oBAAoB,IAAI;AAC5C,MACA;AACC,UAAM,WAAW,MAAM,eAAe,WAAW;AACjD,UAAM,UAAU,kBAAkB,cAAc,EAAC,UAAU,aAAa,WAAW,MAAK,CAAC;AACzF,YAAQ,IAAI,oDAAoD;AAChE,YAAQ,IAAI;AAAA,IAAmC,OAAO;AAAA,CAAI;AAC1D,IAAAA,aAAY,OAAO;AACnB,UAAM,OAAO,MAAM;AACnB,UAAM,aAAa,MAAM,QAAQ;AACjC,YAAQ,IAAI,4DAAuD;AAAA,EACpE,UACA;AAEC,UAAM;AAAA,EACP;AACD;AAEA,eAAe,cAAc,WAAmB,UAAkB,OAClE;AACC,QAAM,cAAc,GAAG,YAAY;AACnC,QAAM,WAAW,MAAM,eAAe,WAAW;AACjD,QAAM,UAAU,kBAAkB,cAAc,EAAC,UAAU,aAAa,WAAW,MAAK,CAAC;AACzF,UAAQ,IAAI,uEAAuE;AACnF,UAAQ,IAAI,KAAK,OAAO;AAAA,CAAI;AAC5B,QAAM,KAAK,gBAAgB,EAAC,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAM,CAAC;AACzE,QAAM,QAAQ,MAAM,GAAG,SAAS,gBAAgB,GAAG,KAAK;AACxD,KAAG,MAAM;AACT,MAAI,CAAC,MACL;AACC,YAAQ,MAAM,oBAAoB;AAClC,YAAQ,KAAK,CAAC;AAAA,EACf;AACA,QAAM,aAAa,MAAM,QAAQ;AACjC,UAAQ,IAAI,uBAAkB;AAC/B;AAEA,eAAsB,SAAS,SAC/B;AACC,QAAM,EAAC,UAAU,UAAS,IAAI,aAAa;AAC3C,QAAM,QAAQC,aAAY,EAAE,EAAE,SAAS,KAAK;AAC5C,MAAI,QAAQ,WACZ;AACC,UAAM,cAAc,WAAW,UAAU,KAAK;AAAA,EAC/C,OAEA;AACC,UAAM,gBAAgB,WAAW,UAAU,KAAK;AAAA,EACjD;AACD;;;AC9IA,eAAsB,cAAc,OACpC;AACC,MAAI,CAAC,MAAO,QAAO;AACnB,MACA;AACC,UAAM,MAAM,MAAM,MAAM,GAAG,YAAY,WAAW;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAC,gBAAgB,mBAAkB;AAAA,MAC5C,MAAM,KAAK,UAAU,EAAC,MAAK,CAAC;AAAA,IAC7B,CAAC;AACD,WAAO,IAAI;AAAA,EACZ,QAEA;AACC,WAAO;AAAA,EACR;AACD;;;AClBA,eAAsB,YACtB;AACC,QAAM,cAAc,gBAAgB;AACpC,QAAM,UAAU,cAAc,MAAM,cAAc,YAAY,WAAW,IAAI;AAE7E,mBAAiB;AAEjB,MAAI,eAAe,CAAC,SACpB;AACC,YAAQ,IAAI,+EAA+E;AAC3F,YAAQ,IAAI,4DAA4D;AACxE;AAAA,EACD;AACA,UAAQ,IAAI,eAAe;AAC5B;;;ACtBA,eAAsB,YAAY,SAClC;AACC,QAAM,UAAU,QAAQ,QAAQ,KAAK;AACrC,MAAI,CAAC,SACL;AACC,YAAQ,MAAM,4CAA4C;AAC1D,YAAQ,KAAK,CAAC;AAAA,EACf;AAEA,UAAQ,IAAI,4BAA4B;AAExC,MACA;AACC,UAAM,EAAC,eAAAC,eAAa,IAAI,MAAM,OAAO,cAAc;AACnD,UAAM,EAAC,cAAc,cAAa,IAAI,MAAM,OAAO,oBAAoB;AACvE,UAAM,EAAC,iBAAAC,iBAAe,IAAI,MAAM,OAAO,+BAAuB;AAE9D,UAAM,MAAMD,eAAcC,gBAAe;AAEzC,UAAM,YAAY,aAAa,KAAK,aAAa;AACjD,UAAM,WAAW,cAAc,WAAW,gBAAgB;AAC1D,UAAM,SAAS,EAAC,QAAO,CAAC;AAExB,YAAQ,IAAI,oCAAoC;AAAA,EACjD,SACM,KACN;AACC,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAQ,MAAM,uBAAuB,GAAG;AAAA,CAAI;AAC5C,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;;;ACpCA,SAAQ,0BAA0B,cAAc,kBAAkB,8BAA6B;AAUxF,SAAS,eAAe,SAC/B;AACC,QAAM,SAAS;AAAA,IACd,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,UAAU,QAAQ;AAAA,IAClB,UAAU,QAAQ;AAAA,EACnB;AAEA,QAAM,cAAc,yBAAyB,MAAM;AACnD,QAAM,aAAa,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,gBAAgB,CAAC;AACzE,QAAM,SAAS,eAAe;AAC9B,QAAM,gBAAgB,cAAc;AACpC,QAAM,MAAM,OAAO,SAAS;AAC5B,QAAM,QAAQ,OAAO,QAAQ,OAAO;AACpC,QAAM,SAAS,uBAAuB,OAAO,MAAM;AAEnD,UAAQ,IAAI;AAAA;AAAA;AAAA,uBAGU,OAAO,MAAM,WAAW,OAAO,KAAK,cAAc,OAAO,QAAQ,cAAc,OAAO,QAAQ;AAAA,gBACrG,YAAY,QAAQ,CAAC,CAAC,OAAO,UAAU;AAAA,gBACvC,MAAM,OAAO,YAAY;AAAA,gBACzB,cAAc,QAAQ,CAAC,CAAC;AAAA,gBACxB,IAAI,QAAQ,CAAC,CAAC;AAAA,gBACd,KAAK;AAAA,gBACL,OAAO,QAAQ,CAAC,CAAC;AAAA,CAChC;AACD;;;ACrBA,OAAOC,SAAQ;AACf,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAKjB,IAAM,aAAa;AASZ,SAAS,mBAAmB,KACnC;AACC,QAAM,MAAM,CAAC,UACb;AACC,QAAI,UAAU,OAAW,QAAO;AAChC,UAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,WAAO,MAAM,OAAO,MAAM,WAAW,MAAM,SAAS,MAAM;AAAA,EAC3D;AACA,QAAM,KAAK,CAAC,UACZ;AACC,QAAI,UAAU,OAAW,QAAO;AAChC,UAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,WAAO,MAAM,OAAO,MAAM,UAAU,MAAM,QAAQ,MAAM;AAAA,EACzD;AAEA,MAAI,IAAI,IAAI,oBAAoB,EAAG,QAAO;AAC1C,MAAI,GAAG,IAAI,YAAY,EAAG,QAAO;AAEjC,MAAI,GAAG,IAAI,EAAE,EAAG,QAAO;AACvB,SAAO;AACR;AAGO,IAAM,mBACZ;AAKD,SAAS,aACT;AACC,SAAOC,MAAK,KAAKC,IAAG,QAAQ,GAAG,eAAe,wBAAwB;AACvE;AAMO,SAAS,eAAe,SAAiB,WAAW,GAC3D;AACC,MACA;AACC,QAAIC,IAAG,WAAW,MAAM,EAAG,QAAO;AAClC,IAAAA,IAAG,UAAUF,MAAK,QAAQ,MAAM,GAAG,EAAC,WAAW,KAAI,CAAC;AACpD,IAAAE,IAAG,cAAc,SAAQ,oBAAI,KAAK,GAAE,YAAY,CAAC;AACjD,YAAQ,IAAI,gBAAgB;AAC5B,WAAO;AAAA,EACR,QAEA;AAEC,WAAO;AAAA,EACR;AACD;AAOA,eAAsB,mBAAmBC,UAAiB,MAAyB,QAAQ,KAAK,SAAiB,WAAW,GAC5H;AACC,MAAI,CAAC,mBAAmB,GAAG,EAAG;AAI9B,iBAAe,MAAM;AAErB,MACA;AAGC,UAAM,UAAU,WAAW;AAC3B,UAAM,MAAM,GAAG,YAAY,kBAAkB;AAAA,MAC5C,QAAQ;AAAA,MACR,SAAS,EAAC,gBAAgB,oBAAoB,GAAG,QAAO;AAAA,MACxD,MAAM,KAAK,UAAU,EAAC,SAAAA,SAAO,CAAC;AAAA,MAC9B,QAAQ,YAAY,QAAQ,UAAU;AAAA,IACvC,CAAC;AAAA,EACF,QAEA;AAAA,EAEA;AACD;;;ACtFA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,IAAM,UAAU,KAAK,CAAC;AAEtB,SAAS,UAAU,MACnB;AACC,QAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,QAAQ,MAAM,MAAM,IAAI,KAAK,QACjC;AACC,WAAO,KAAK,MAAM,CAAC;AAAA,EACpB;AACA,SAAO;AACR;AAEA,SAAS,aAAa,MAAc,UACpC;AACC,QAAM,MAAM,UAAU,IAAI;AAC1B,MAAI,QAAQ,OAAW,QAAO;AAC9B,QAAM,IAAI,SAAS,KAAK,EAAE;AAC1B,MAAI,OAAO,MAAM,CAAC,GAClB;AACC,YAAQ,MAAM,UAAU,IAAI,2BAA2B,GAAG,IAAI;AAC9D,YAAQ,KAAK,CAAC;AAAA,EACf;AACA,SAAO;AACR;AAEA,SAAS,YACT;AACC,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CA2DZ;AACD;AAEA,eAAe,OACf;AACC,MAAI,CAAC,WAAW,YAAY,YAAY,YAAY,MACpD;AACC,cAAU;AACV;AAAA,EACD;AAMA,OAAK,mBAAmB,OAAO;AAE/B,UAAQ,SACR;AAAA,IACC,KAAK,OACL;AACC,YAAM,OAAO,aAAa,UAAU,IAAI;AACxC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,OAAO,EAAC,MAAM,IAAG,CAAC;AACxB;AAAA,IACD;AAAA,IAEA,KAAK,QACL;AACC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,QAAQ,EAAC,IAAG,CAAC;AACnB;AAAA,IACD;AAAA,IAEA,KAAK,SACL;AACC,YAAM,WAAW,UAAU,YAAY;AACvC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,OAAO,UAAU,QAAQ,MAAM,SAAY,aAAa,UAAU,CAAC,IAAI;AAC7E,YAAM,SAAS,EAAC,UAAU,KAAK,KAAI,CAAC;AACpC;AAAA,IACD;AAAA,IAEA,KAAK,SACL;AACC,YAAM,WAAW,UAAU,YAAY;AACvC,UAAI,CAAC,UACL;AACC,cAAM,EAAC,oBAAAC,oBAAkB,IAAI,MAAM,OAAO,iCAAwB;AAClE,cAAM,QAAQA,oBAAmB;AACjC,cAAM,OAAO,MAAM,IAAI,CAAC,MAAM,gBAAgB,CAAC,EAAE,EAAE,KAAK,IAAI;AAC5D,gBAAQ,MAAM,4CAA4C;AAC1D,gBAAQ,MAAM;AAAA;AAAA,EAA2B,IAAI;AAAA,CAAI;AACjD,gBAAQ,MAAM,+CAA+C;AAC7D,gBAAQ,KAAK,CAAC;AAAA,MACf;AACA,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,OAAO,UAAU,QAAQ,MAAM,SAAY,aAAa,UAAU,CAAC,IAAI;AAC7E,YAAM,WAAW,UAAU,YAAY,MAAM,SAAY,aAAa,cAAc,GAAG,IAAI;AAC3F,YAAM,SAAS,EAAC,UAAU,KAAK,MAAM,SAAQ,CAAC;AAC9C;AAAA,IACD;AAAA,IAEA,KAAK,QACL;AACC,YAAM,OAAO,UAAU,QAAQ,KAAK,KAAK,CAAC;AAC1C,cAAQ,EAAC,MAAM,MAAM,WAAW,IAAI,IAAI,SAAY,KAAI,CAAC;AACzD;AAAA,IACD;AAAA,IAEA,KAAK,cACL;AACC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,cAAc,oBAAI,IAAY;AACpC,eAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KACjC;AACC,YAAI,KAAK,CAAC,EAAG,WAAW,IAAI,GAC5B;AACC,sBAAY,IAAI,CAAC;AACjB,sBAAY,IAAI,IAAI,CAAC;AAAA,QACtB;AAAA,MACD;AACA,YAAM,YAAY,KAAK,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;AACxE,YAAM,cAAc,EAAC,WAAW,IAAG,CAAC;AACpC;AAAA,IACD;AAAA,IAEA,KAAK,YACL;AACC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,eAAe,UAAU,aAAa;AAC5C,YAAM,YAAY,eAAe,aAAa,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO,IAAI;AAChG,YAAM,YAAY;AAAA,QACjB;AAAA,QACA,OAAO,UAAU,SAAS,MAAM,SAAY,aAAa,WAAW,CAAC,IAAI;AAAA,QACzE,QAAQ,UAAU,UAAU,MAAM,SAAY,aAAa,YAAY,CAAC,IAAI;AAAA,QAC5E;AAAA,MACD,CAAC;AACD;AAAA,IACD;AAAA,IAEA,KAAK,SACL;AACC,YAAM,WAAW,UAAU,YAAY;AACvC,UAAI,CAAC,UACL;AACC,gBAAQ,MAAM,kDAAkD;AAChE,gBAAQ,MAAM,+CAA+C;AAC7D,gBAAQ,KAAK,CAAC;AAAA,MACf;AACA,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,SAAS,UAAU,UAAU;AACnC,YAAM,SAAS,EAAC,UAAU,KAAK,OAAM,CAAC;AACtC;AAAA,IACD;AAAA,IAEA,KAAK,UACL;AACC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,UAAU,EAAC,IAAG,CAAC;AACrB;AAAA,IACD;AAAA,IAEA,KAAK,QACL;AACC,YAAM,MAAM,UAAU,OAAO;AAC7B,YAAM,QAAQ,EAAC,IAAG,CAAC;AACnB;AAAA,IACD;AAAA,IAEA,KAAK,SACL;AACC,YAAM,SAAS,EAAC,WAAW,KAAK,SAAS,cAAc,EAAC,CAAC;AACzD;AAAA,IACD;AAAA,IAEA,KAAK,UACL;AACC,YAAM,UAAU;AAChB;AAAA,IACD;AAAA,IAEA,KAAK,YACL;AACC,YAAM,UAAU,KAAK,MAAM,CAAC,EAAE,KAAK,GAAG;AACtC,YAAM,YAAY,EAAC,QAAO,CAAC;AAC3B;AAAA,IACD;AAAA,IAEA,KAAK,gBACL;AACC,qBAAe;AAAA,QACd,QAAQ,aAAa,YAAY,EAAE;AAAA,QACnC,OAAO,aAAa,WAAW,CAAC;AAAA,QAChC,UAAU,aAAa,cAAc,GAAG;AAAA,QACxC,UAAU,aAAa,cAAc,CAAC;AAAA,MACvC,CAAC;AACD;AAAA,IACD;AAAA,IAEA;AACC,cAAQ,MAAM,oBAAoB,OAAO,EAAE;AAC3C,gBAAU;AACV,cAAQ,KAAK,CAAC;AAAA,EAChB;AACD;AAEA,KAAK,EAAE,MAAM,CAAC,UACd;AACC,UAAQ,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,KAAK;AACtE,UAAQ,KAAK,CAAC;AACf,CAAC;","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","openBrowser","randomBytes","initializeApp","FIREBASE_CONFIG","os","fs","path","path","os","fs","command","getBuiltinBotNames"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibemancer",
3
- "version": "0.2.1",
3
+ "version": "1.0.0",
4
4
  "description": "Vibemancer devkit - dev server, testing, and tournament tools for wizard bots",
5
5
  "type": "module",
6
6
  "author": "Low Entry",
@@ -23,16 +23,20 @@
23
23
  "lint": "eslint .",
24
24
  "format": "eslint . --fix",
25
25
  "type-check": "tsc --noEmit",
26
- "test": "pnpm run lint && vitest run",
26
+ "test": "pnpm run type-check && pnpm run lint && vitest run",
27
27
  "clean": "rm -rf dist",
28
- "prepublishOnly": "pnpm run test && pnpm run clean && pnpm run build"
28
+ "prepublishOnly": "pnpm run test && pnpm run clean && pnpm run build",
29
+ "test:mutate": "stryker run"
29
30
  },
30
31
  "dependencies": {
31
- "@vibemancer/core": "~0.2.1",
32
+ "@vibemancer/core": "~1.0.0",
32
33
  "firebase": "^12.12.1"
33
34
  },
34
35
  "devDependencies": {
35
36
  "@eslint/js": "^10.0.1",
37
+ "@stryker-mutator/core": "^9.6.1",
38
+ "@stryker-mutator/typescript-checker": "^9.6.1",
39
+ "@stryker-mutator/vitest-runner": "^9.6.1",
36
40
  "@stylistic/eslint-plugin": "^5.10.0",
37
41
  "@types/node": "^25.6.0",
38
42
  "eslint": "^10.3.0",