vibemancer 1.0.7 → 1.0.9

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Low Entry
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/cli.js CHANGED
@@ -382,6 +382,37 @@ import fs3 from "fs";
382
382
  import path3 from "path";
383
383
  import { BotBundle, sandboxFight, scoreFight, runBundleFight } from "@vibemancer/core";
384
384
 
385
+ // src/commands/fight-errors.ts
386
+ var MAX_SHOWN = 5;
387
+ function formatBotErrors(result, botName, opponentName) {
388
+ const errors = result.allErrors ?? (result.matches ?? []).flatMap((m) => m.errors ?? []);
389
+ if (errors.length === 0) return [];
390
+ const byFault = /* @__PURE__ */ new Map();
391
+ for (const err of errors) {
392
+ const owner = /^missile-(wizard-[12])-/.exec(err.entityId);
393
+ const side = owner ? owner[1] : err.entityId;
394
+ const name = side === "wizard-2" ? opponentName : botName;
395
+ const who = owner ? `${name} (in its missile AI)` : name;
396
+ const key = `${who} ${err.message}`;
397
+ const seen = byFault.get(key);
398
+ if (!seen) {
399
+ byFault.set(key, { who, message: err.message, first: err.tick, last: err.tick, count: 1 });
400
+ continue;
401
+ }
402
+ seen.count++;
403
+ if (err.tick < seen.first) seen.first = err.tick;
404
+ if (err.tick > seen.last) seen.last = err.tick;
405
+ }
406
+ const all = [...byFault.values()].sort((a, b) => b.count - a.count);
407
+ const out = [" BOT ERRORS \u2014 a bot that throws does nothing on that tick:"];
408
+ for (const f of all.slice(0, MAX_SHOWN)) {
409
+ const span = f.first === f.last ? `tick ${f.first}` : `ticks ${f.first}-${f.last}`;
410
+ out.push(` ${f.who}: ${f.message} (${span}, ${f.count}x)`);
411
+ }
412
+ if (all.length > MAX_SHOWN) out.push(` \u2026 and ${all.length - MAX_SHOWN} more distinct error message(s) not shown`);
413
+ return out;
414
+ }
415
+
385
416
  // src/remote-opponent.ts
386
417
  import { initializeApp, getApps } from "firebase/app";
387
418
  import { getFirestore, collection, query, where, limit, getDocs, connectFirestoreEmulator } from "firebase/firestore";
@@ -492,6 +523,7 @@ async function runSingleFight(options) {
492
523
  console.log(` ${botInfo.exportName}: ${wizard1Wins}W | ${options.opponent}: ${wizard2Wins}W | Draws: ${draws}`);
493
524
  console.log(` (${total} matches in ${elapsed}ms)
494
525
  `);
526
+ for (const line of formatBotErrors(result, botInfo.exportName, options.opponent)) console.log(line);
495
527
  if (result.winner === "wizard-2") {
496
528
  process.exit(1);
497
529
  }
@@ -801,7 +833,11 @@ function runFightWithParams(sandbox, params1) {
801
833
  wizard2Wins: w2,
802
834
  draws,
803
835
  winner: w1 > w2 ? "wizard-1" : w2 > w1 ? "wizard-2" : "draw",
804
- matches
836
+ matches,
837
+ // The optimizer builds its own fight result rather than calling fight(), and it scores
838
+ // on outcomes only — it never inspects errors. Collected anyway so the shape is honest:
839
+ // an empty array here means "this path records none", not "this bot never threw".
840
+ allErrors: matches.flatMap((m) => m.errors ?? [])
805
841
  };
806
842
  }
807
843
  async function evaluateParams(userBundle, opponentBundles, params1) {
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli-version.ts","../src/commands/dev.ts","../src/bot-discovery.ts","../src/server.ts","../src/compile-single-bot.ts","../src/commands/test.ts","../src/commands/fight.ts","../src/remote-opponent.ts","../src/firebase-config.ts","../src/commands/trace.ts","../src/commands/tournament.ts","../src/commands/optimize.ts","../src/commands/build.ts","../src/commands/bots.ts","../src/commands/upload.ts","../src/auth/env-headers.ts","../src/auth/gateway-client.ts","../src/commands/pull.ts","../src/commands/login.ts","../src/auth/revoke.ts","../src/commands/logout.ts","../src/commands/feedback.ts","../src/commands/missile-calc.ts","../src/auth/telemetry.ts","../src/cli.ts"],"sourcesContent":["/**\n * The CLI's own version, for `vibemancer --version`.\n *\n * This existed already, in a sense, and that is the point. `readCliVersion()` in\n * auth/env-headers.ts walks up from the bundle to find this package's manifest and ships the\n * version to the server as a telemetry header on every authed call. So the CLI knew its\n * version, reported it to us, and had no way to tell the person running it: `--version`,\n * `-v` and `version` all answered \"Unknown command\" and dumped the help.\n *\n * That is the first thing a user types when something misbehaves and the first thing a\n * maintainer asks for in a bug report.\n *\n * The read is injected so the failure modes can be tested without a filesystem: a missing\n * manifest, malformed JSON, a manifest with no version, and — the one worth guarding —\n * finding the CONSUMER's package.json instead of ours while walking up from `dist/`.\n * Reporting the user's project version as the CLI version would be worse than saying\n * nothing, so the name is checked.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\n/** Reads a manifest's text, or throws if it is not there. */\nexport type ReadManifest = () => string;\n\nexport function resolveCliVersion(read: ReadManifest): string\n{\n\ttry\n\t{\n\t\tconst parsed: unknown = JSON.parse(read());\n\t\tif (typeof parsed !== 'object' || parsed === null) return 'unknown';\n\t\tif (!('name' in parsed) || !('version' in parsed)) return 'unknown';\n\t\tconst {name, version} = parsed as {name?: unknown; version?: unknown};\n\t\tif (name !== 'vibemancer' || typeof version !== 'string' || !version) return 'unknown';\n\t\treturn version;\n\t}\n\tcatch\n\t{\n\t\t// A CLI must never fail to start because it could not introspect itself.\n\t\treturn 'unknown';\n\t}\n}\n\n/**\n * Find this package's manifest by walking up from the running module.\n *\n * Both `dist/cli.js` (published) and `src/cli.ts` (dev) are one or two levels below the\n * manifest, so two candidates cover both. Each is tried independently — an earlier version\n * of this walk wrapped the whole loop in one try/catch, so the first missing path aborted\n * the search and the version came back empty in exactly the layout that mattered.\n */\nexport function cliVersion(): string\n{\n\tconst here = path.dirname(fileURLToPath(import.meta.url));\n\tfor (const rel of ['../package.json', '../../package.json'])\n\t{\n\t\tconst candidate = path.resolve(here, rel);\n\t\tconst version = resolveCliVersion(() => fs.readFileSync(candidate, 'utf8'));\n\t\tif (version !== 'unknown') return version;\n\t}\n\treturn 'unknown';\n}\n","/**\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\t// Local Network Access. A page served from a PUBLIC origin reaching a LOOPBACK\n\t\t// address is gated by Chrome behind a permission prompt, and the preflight is\n\t\t// rejected outright unless the target opts in with this header. Without it the\n\t\t// advertised `vibemancer dev` loop simply fails in a default browser, and the failure\n\t\t// looks like the local server being down when it is answering fine.\n\t\t//\n\t\t// Granting it is what this server is FOR: it exists to be called by the hosted\n\t\t// viewer, it serves only the developer's own bot bundles, and it is bound to their\n\t\t// machine. Both header spellings are sent because the name changed mid-standard and\n\t\t// which one a given Chrome honours depends on its version.\n\t\tres.setHeader('Access-Control-Allow-Private-Network', 'true');\n\t\tres.setHeader('Access-Control-Allow-Local-Network-Access', 'true');\n\n\t\tif (req.method === 'OPTIONS')\n\t\t{\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url ?? '/', `http://localhost:${port}`);\n\t\tconst pathname = url.pathname;\n\n\t\ttry\n\t\t{\n\t\t\tif (pathname === '/health')\n\t\t\t{\n\t\t\t\trespond(res, 200, {status: 'ok'});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pathname === '/local-bots')\n\t\t\t{\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst body: LocalBotsResponse = {bots: bots.map(botInfoToWire)};\n\t\t\t\trespond(res, 200, body);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bundleMatch = /^\\/local-bots\\/([A-Za-z_][A-Za-z0-9_]*)\\/bundle$/.exec(pathname);\n\t\t\tif (bundleMatch)\n\t\t\t{\n\t\t\t\tconst requestedName = bundleMatch[1]!;\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst target = bots.find((b) => b.exportName === requestedName);\n\t\t\t\tif (!target)\n\t\t\t\t{\n\t\t\t\t\trespond(res, 404, {error: `No local bot named \"${requestedName}\". Found: ${bots.map((b) => b.exportName).join(', ') || '(none)'}`});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst start = Date.now();\n\t\t\t\tconst bundle = await compileSingleBotBundle(target.sourcePath, target.exportName);\n\t\t\t\tconst elapsed = Date.now() - start;\n\t\t\t\tconsole.log(` Compiled ${target.exportName} (${(bundle.length / 1024).toFixed(1)} KB) in ${elapsed}ms`);\n\n\t\t\t\tres.writeHead(200, {'Content-Type': 'text/javascript'});\n\t\t\t\tres.end(bundle);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trespond(res, 404, {error: `Not found: ${pathname}`});\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(` Error: ${message}`);\n\t\t\trespond(res, 500, {error: message});\n\t\t}\n\t});\n\n\tserver.listen(port, () =>\n\t{\n\t\tconsole.log(`\\nVibemancer dev server running at http://localhost:${port}`);\n\t\tvoid (async(): Promise<void> =>\n\t\t{\n\t\t\tconst bots = await loadBots();\n\t\t\tif (bots.length === 0)\n\t\t\t{\n\t\t\t\tconsole.log(' (no bots discovered in src/ — add a .ts file with a PascalCase export)');\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconsole.log(` Bots: ${bots.map((b) => b.exportName).join(', ')}`);\n\t\t\t}\n\t\t\tconsole.log('');\n\t\t\tconsole.log('Open your browser to play:');\n\t\t\tconsole.log(` https://vibemancer.com/#botserver=localhost:${port}\\n`);\n\t\t\tconsole.log('Endpoints:');\n\t\t\tconsole.log(' GET /local-bots - List of locally-discovered bots');\n\t\t\tconsole.log(' GET /local-bots/<name>/bundle - Compile a single bot to a sandbox-ready bundle');\n\t\t\tconsole.log(' GET /health - Server health check\\n');\n\t\t})();\n\t});\n\n\treturn server;\n}\n\nfunction respond(res: http.ServerResponse, status: number, data: unknown): void\n{\n\tres.writeHead(status, {'Content-Type': 'application/json'});\n\tres.end(JSON.stringify(data));\n}\n","/**\n * Compile a single bot to a self-contained IIFE bundle.\n *\n * The output sets `globalThis.__injectedBot1` to the bot's exported function.\n * This is the canonical \"uploaded wizard\" bundle shape — the same format the\n * Storage-uploaded wizards live in, the same format the fight-runner /\n * BrowserMatchSandbox concatenates with MATCH_TEMPLATE / MANUAL_MATCH_TEMPLATE.\n *\n * Used by:\n * - `vibemancer upload` (CLI) — uploads to Firebase Storage\n * - dev server's /local-bots/:name/bundle endpoint — served to the web\n * client when picking a local bot\n *\n * `@vibemancer/core` is aliased to the package's TypeScript source (mirroring\n * seed-bots.ts) so the bundle is fully self-contained — no runtime shims, no\n * CJS `require()`, just an IIFE that runs anywhere a Web Worker can.\n */\n\nimport {build} from 'esbuild';\nimport {findCoreSourceDir} from './opponent-resolver.js';\n\nexport async function compileSingleBotBundle(\n\tsourcePath: string,\n\texportName: string,\n): Promise<string>\n{\n\tconst coreSourceDir = findCoreSourceDir();\n\n\tconst result = await build({\n\t\tentryPoints: [sourcePath],\n\t\tbundle: true,\n\t\twrite: false,\n\t\tformat: 'iife',\n\t\tglobalName: '__botExport',\n\t\tplatform: 'neutral',\n\t\ttarget: 'es2022',\n\t\tlogLevel: 'error',\n\t\tfooter: {js: `globalThis.__injectedBot1 = __botExport.${exportName};`},\n\t\texternal: [\n\t\t\t'isolated-vm', 'esbuild',\n\t\t\t'node:*',\n\t\t],\n\t\talias: {\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\n\t\t},\n\t});\n\n\tif (!result.outputFiles?.[0])\n\t{\n\t\tthrow new Error('esbuild produced no output');\n\t}\n\n\treturn result.outputFiles[0].text;\n}\n","/**\n * vibemancer test\n *\n * Runs the user's vitest test suite. Scaffolded projects include a\n * tests/ directory with example tests using the testBot() helper.\n */\n\nimport {spawn} from 'node:child_process';\n\nexport interface TestOptions\n{\n\tbot?: string;\n}\n\nexport async function runTest(_options: TestOptions): Promise<void>\n{\n\tconsole.log('\\n Running tests...\\n');\n\n\t// spawn + await, NOT execSync. execSync blocks the entire event loop, and the CLI fires\n\t// a fire-and-forget telemetry request at command start: while the loop is blocked that\n\t// request cannot progress, and its 1s abort then fires the moment the block ends, so it\n\t// is cancelled before ever being sent. `test` was the ONE local command missing from\n\t// the analytics, which is how this was found. Blocking also stops any other timer or\n\t// I/O the CLI may rely on later, so this is not only about telemetry.\n\tconst code = await new Promise<number>((resolve) =>\n\t{\n\t\t// One command STRING with shell:true, not a string plus an args array.\n\t\t//\n\t\t// DEP0190 (\"Passing args to a child process with shell option true can lead to\n\t\t// security vulnerabilities\") fires only for the args-array form, and it printed on\n\t\t// the very first command a new user runs — the word \"vulnerabilities\" on step one of\n\t\t// a tutorial is a bad look. Dropping the shell entirely was tried first and fails\n\t\t// with EINVAL: Node 24 refuses to spawn a Windows .cmd shim without one.\n\t\t//\n\t\t// No injection surface: the command is a fixed literal with no interpolation.\n\t\tconst child = spawn('npx vitest run', {\n\t\t\tstdio: 'inherit',\n\t\t\tcwd: process.cwd(),\n\t\t\tshell: true,\n\t\t});\n\t\tchild.on('error', () => resolve(1));\n\t\tchild.on('close', (status) => resolve(status ?? 1));\n\t});\n\n\tif (code !== 0)\n\t{\n\t\tprocess.exit(code);\n\t}\n}\n","/**\r\n * vibemancer fight\r\n *\r\n * With no args: fights your bot against all 29 built-in bots and shows ranking.\r\n * With --opponent: quick fight against a single opponent.\r\n *\r\n * Results are saved to .vibemancer/history.json for comparison across runs.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {BotBundle, sandboxFight, scoreFight, runBundleFight} from '@vibemancer/core';\r\nimport type {FightWinner, FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface FightOptions\r\n{\r\n\topponent?: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n}\r\n\r\ninterface FightEntry\r\n{\r\n\topponent: string;\r\n\twinner: FightWinner;\r\n\twizard1Wins: number;\r\n\twizard2Wins: number;\r\n\tdraws: number;\r\n\tscore: number;\r\n\telapsedMs: number;\r\n}\r\n\r\ninterface HistoryEntry\r\n{\r\n\ttimestamp: string;\r\n\tbotName: string;\r\n\tresults: FightEntry[];\r\n\tsummary: {wins: number; losses: number; draws: number; score: number; maxScore: number};\r\n}\r\n\r\nexport async function runFight(options: FightOptions): Promise<void>\r\n{\r\n\tif (options.opponent)\r\n\t{\r\n\t\treturn runSingleFight({...options, opponent: options.opponent});\r\n\t}\r\n\treturn runFullFight(options);\r\n}\r\n\r\n// ─── Single opponent fight ───────────────────────────────────────────────────\r\n\r\nasync function runSingleFight(options: FightOptions & {opponent: string}): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\r\n\tconsole.log(` Opponent: ${options.opponent}\\n`);\r\n\r\n\tconst start = Date.now();\r\n\tlet result: FightResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// run locally through the same isolated-vm engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleFight(userBundle, remote.bundle, {seed: options.seed ?? 1});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxFight(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\tconst elapsed = Date.now() - start;\r\n\r\n\tconst {wizard1Wins, wizard2Wins, draws} = result;\r\n\tconst total = wizard1Wins + wizard2Wins + draws;\r\n\tconst outcome = result.winner === 'wizard-1' ? 'WIN'\r\n\t\t: result.winner === 'wizard-2' ? 'LOSS'\r\n\t\t\t: 'DRAW';\r\n\r\n\tconsole.log(` Result: ${outcome}`);\r\n\tconsole.log(` ${botInfo.exportName}: ${wizard1Wins}W | ${options.opponent}: ${wizard2Wins}W | Draws: ${draws}`);\r\n\tconsole.log(` (${total} matches in ${elapsed}ms)\\n`);\r\n\r\n\tif (result.winner === 'wizard-2')\r\n\t{\r\n\t\tprocess.exit(1);\r\n\t}\r\n}\r\n\r\n// ─── Full fight (all built-in bots) ─────────────────────────────────────────\r\n\r\nasync function runFullFight(options: FightOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\tconst opponents = getBuiltinBotNames();\r\n\tconsole.log(`\\n Fighting ${botInfo.exportName} against ${opponents.length} built-in bots...\\n`);\r\n\r\n\tconst entries: FightEntry[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const opponentName of opponents)\r\n\t{\r\n\t\tconst opponentBundle = resolveOpponent(opponentName);\r\n\t\tconst start = Date.now();\r\n\t\tconst result = await sandboxFight(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tconst elapsed = Date.now() - start;\r\n\t\tconst score = scoreFight(result);\r\n\r\n\t\tentries.push({\r\n\t\t\topponent: opponentName,\r\n\t\t\twinner: result.winner,\r\n\t\t\twizard1Wins: result.wizard1Wins,\r\n\t\t\twizard2Wins: result.wizard2Wins,\r\n\t\t\tdraws: result.draws,\r\n\t\t\tscore,\r\n\t\t\telapsedMs: elapsed,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? 'W'\r\n\t\t\t: result.winner === 'wizard-2' ? 'L'\r\n\t\t\t\t: 'D';\r\n\t\tconst pad = opponentName.padEnd(14);\r\n\t\tconsole.log(` ${pad} ${outcome} ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${elapsed}ms)`);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\tconst wins = entries.filter((e) => e.winner === 'wizard-1').length;\r\n\tconst losses = entries.filter((e) => e.winner === 'wizard-2').length;\r\n\tconst drawCount = entries.filter((e) => e.winner === 'draw').length;\r\n\tconst totalScore = entries.reduce((sum, e) => sum + e.score, 0);\r\n\tconst maxScore = opponents.length * 17.5; // 5 matches × 3.5 max per match per opponent\r\n\r\n\tconsole.log(`\\n Summary: ${wins}W ${losses}L ${drawCount}D out of ${opponents.length} opponents`);\r\n\tconsole.log(` Score: ${totalScore.toFixed(1)} / ${maxScore.toFixed(1)} (${((totalScore / maxScore) * 100).toFixed(1)}%)`);\r\n\tconsole.log(` Total time: ${(totalElapsed / 1000).toFixed(1)}s`);\r\n\r\n\t// Load previous results and show diff\r\n\tconst history = loadHistory(projectDir);\r\n\tconst previous = history.length > 0 ? history[history.length - 1]! : null;\r\n\r\n\tif (previous && previous.botName === botInfo.exportName)\r\n\t{\r\n\t\tshowDiff(entries, previous.results);\r\n\t}\r\n\r\n\t// Save current results\r\n\tconst current: HistoryEntry = {\r\n\t\ttimestamp: new Date().toISOString(),\r\n\t\tbotName: botInfo.exportName,\r\n\t\tresults: entries,\r\n\t\tsummary: {wins, losses, draws: drawCount, score: totalScore, maxScore},\r\n\t};\r\n\tsaveHistory(projectDir, history, current);\r\n\tconsole.log('');\r\n}\r\n\r\n// ─── History persistence ─────────────────────────────────────────────────────\r\n\r\nfunction getHistoryPath(projectDir: string): string\r\n{\r\n\treturn path.join(projectDir, '.vibemancer', 'history.json');\r\n}\r\n\r\nfunction loadHistory(projectDir: string): HistoryEntry[]\r\n{\r\n\tconst historyPath = getHistoryPath(projectDir);\r\n\tif (!fs.existsSync(historyPath)) return [];\r\n\ttry\r\n\t{\r\n\t\tconst raw = fs.readFileSync(historyPath, 'utf-8');\r\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- JSON file we wrote\r\n\t\treturn JSON.parse(raw) as HistoryEntry[];\r\n\t}\r\n\tcatch\r\n\t{\r\n\t\treturn [];\r\n\t}\r\n}\r\n\r\nfunction saveHistory(projectDir: string, history: HistoryEntry[], current: HistoryEntry): void\r\n{\r\n\tconst historyPath = getHistoryPath(projectDir);\r\n\tconst dir = path.dirname(historyPath);\r\n\tfs.mkdirSync(dir, {recursive: true});\r\n\r\n\t// Keep last 20 runs\r\n\tconst updated = [...history.slice(-19), current];\r\n\tfs.writeFileSync(historyPath, JSON.stringify(updated, null, '\\t') + '\\n');\r\n}\r\n\r\nfunction showDiff(current: FightEntry[], previous: FightEntry[]): void\r\n{\r\n\tconst prevMap = new Map(previous.map((e) => [e.opponent, e]));\r\n\tconst changes: string[] = [];\r\n\r\n\tfor (const entry of current)\r\n\t{\r\n\t\tconst prev = prevMap.get(entry.opponent);\r\n\t\tif (!prev) continue;\r\n\r\n\t\tconst prevOutcome = prev.winner === 'wizard-1' ? 'W' : prev.winner === 'wizard-2' ? 'L' : 'D';\r\n\t\tconst curOutcome = entry.winner === 'wizard-1' ? 'W' : entry.winner === 'wizard-2' ? 'L' : 'D';\r\n\r\n\t\tif (prevOutcome !== curOutcome)\r\n\t\t{\r\n\t\t\tchanges.push(` ${entry.opponent.padEnd(14)} ${prevOutcome} -> ${curOutcome}`);\r\n\t\t}\r\n\t}\r\n\r\n\tconst prevScore = previous.reduce((sum, e) => sum + e.score, 0);\r\n\tconst curScore = current.reduce((sum, e) => sum + e.score, 0);\r\n\tconst diff = curScore - prevScore;\r\n\r\n\tif (changes.length > 0 || Math.abs(diff) > 0.1)\r\n\t{\r\n\t\tconsole.log('\\n vs last run:');\r\n\t\tif (Math.abs(diff) > 0.1)\r\n\t\t{\r\n\t\t\tconst sign = diff > 0 ? '+' : '';\r\n\t\t\tconsole.log(` Score: ${sign}${diff.toFixed(1)}`);\r\n\t\t}\r\n\t\tfor (const change of changes)\r\n\t\t{\r\n\t\t\tconsole.log(change);\r\n\t\t}\r\n\t}\r\n}\r\n","/**\n * Resolve a `handle/botname` selector to a downloaded, ready-to-run opponent\n * bundle — so the devkit can fight any user's uploaded bot, identically to the\n * MCP fight tool and the live ladder.\n *\n * All reads are PUBLIC (no login): the wizards collection is world-readable and\n * compiled bundles in Storage are public (required for browser spectating), so\n * resolution + download need no auth. The fight then runs locally via core's\n * runBundleFight — the same isolated-vm engine the matchmaker uses.\n */\n\nimport {initializeApp, getApps, type FirebaseApp} from 'firebase/app';\nimport {getFirestore, collection, query, where, limit, getDocs, connectFirestoreEmulator, type Firestore} from 'firebase/firestore';\nimport {getStorage, ref, getBytes, connectStorageEmulator, type FirebaseStorage} from 'firebase/storage';\nimport {isBannedBotName} from '@vibemancer/core';\nimport {FIREBASE_CONFIG} from './firebase-config.js';\n\nexport interface RemoteOpponent\n{\n\tbundle: string;\n\texportName: string;\n\tlabel: string;\n}\n\n/** True when the opponent string is a `handle/botname` selector (vs a built-in name). */\nexport function isHandleSelector(opponent: string): boolean\n{\n\tconst trimmed = opponent.trim();\n\tconst slash = trimmed.indexOf('/');\n\treturn slash > 0 && slash < trimmed.length - 1;\n}\n\nlet cachedDb: Firestore | null = null;\nlet cachedStorage: FirebaseStorage | null = null;\n\nfunction getApp(): FirebaseApp\n{\n\tconst apps = getApps();\n\treturn apps.length > 0 ? apps[0]! : initializeApp(FIREBASE_CONFIG);\n}\n\n/** Talk to the local emulator instead of prod when VIBEMANCER_EMULATOR=1 (E2E tests). */\nfunction getDb(): Firestore\n{\n\tif (!cachedDb)\n\t{\n\t\tcachedDb = getFirestore(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectFirestoreEmulator(cachedDb, '127.0.0.1', 8085);\n\t}\n\treturn cachedDb;\n}\n\nfunction getBucket(): FirebaseStorage\n{\n\tif (!cachedStorage)\n\t{\n\t\tcachedStorage = getStorage(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectStorageEmulator(cachedStorage, '127.0.0.1', 9199);\n\t}\n\treturn cachedStorage;\n}\n\nexport async function resolveRemoteOpponent(selector: string): Promise<RemoteOpponent>\n{\n\tconst slash = selector.indexOf('/');\n\tconst handle = selector.slice(0, slash).trim().toLowerCase();\n\tconst botName = selector.slice(slash + 1).trim();\n\tif (!handle || !botName)\n\t{\n\t\tthrow new Error(`Invalid opponent \"${selector}\" — expected handle/botname (e.g. happy-golden-banana/FireMage).`);\n\t}\n\t// A filtered (banned) name resolves to nothing — same message as not-found.\n\tif (isBannedBotName(botName))\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst db = getDb();\n\tconst snap = await getDocs(query(\n\t\tcollection(db, 'wizards'),\n\t\twhere('ownerHandle', '==', handle),\n\t\twhere('nameLower', '==', botName.toLowerCase()),\n\t\twhere('active', '==', true),\n\t\tlimit(1),\n\t));\n\tif (snap.empty)\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst docSnap = snap.docs[0]!;\n\tconst data = docSnap.data() as {exportName?: unknown; bundlePath?: unknown};\n\tconst exportName = typeof data.exportName === 'string' ? data.exportName : '';\n\tif (!exportName)\n\t{\n\t\tthrow new Error(`Bot \"${handle}/${botName}\" is missing its export name.`);\n\t}\n\tconst bundlePath = typeof data.bundlePath === 'string' ? data.bundlePath : `bundles/${docSnap.id}.js`;\n\n\tconst bytes = await getBytes(ref(getBucket(), bundlePath));\n\tconst bundle = new TextDecoder().decode(bytes);\n\n\treturn {bundle, exportName, label: `${handle}/${botName}`};\n}\n","export const FIREBASE_CONFIG = {\n\tapiKey: 'AIzaSyDSUJ2jlk5_vlpGOypMtvqKjHhDmbgomIY',\n\tauthDomain: 'le-vibemancer.firebaseapp.com',\n\tprojectId: 'le-vibemancer',\n\tstorageBucket: 'le-vibemancer.firebasestorage.app',\n} as const;\n","/**\r\n * vibemancer trace\r\n *\r\n * Runs a single match and prints a full event trace for debugging.\r\n * Shows both bots' actions: state changes, missile launches (with config),\r\n * hits, damage, dodge proximity, movement patterns, and stats.\r\n */\r\n\r\nimport {\r\n\tBotBundle, sandboxSimulate, runBundleSimulate,\r\n\textractTraceEvents, summarizeTrace, formatTraceEvents, formatTraceSummary,\r\n\tdiagnoseTrace, formatDiagnosis,\r\n\textractStats, formatStats,\r\n} from '@vibemancer/core';\r\nimport type {SimulateResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface TraceOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n\tdistance?: number;\r\n\tmaxTicks?: number;\r\n}\r\n\r\nexport async function runTrace(options: TraceOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst distance = options.distance ?? 600;\r\n\tconsole.log(`\\n Trace: ${botInfo.exportName} (W1) vs ${options.opponent} (W2) | distance: ${distance} | seed: ${options.seed ?? 1}\\n`);\r\n\r\n\tlet result: SimulateResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// simulate locally through the same engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleSimulate(userBundle, remote.bundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxSimulate(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\r\n\tconst history = result.history;\r\n\tif (history.length === 0)\r\n\t{\r\n\t\tconsole.log(' No history available.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Extract and print full event trace (including any bot runtime errors)\r\n\tconst events = extractTraceEvents(history, result.errors);\r\n\tconsole.log(formatTraceEvents(events));\r\n\r\n\t// Print summary (both bots)\r\n\tconst summary = summarizeTrace(events, result, botInfo.exportName, options.opponent);\r\n\tconsole.log('\\n' + formatTraceSummary(summary));\r\n\r\n\t// Print detailed stats for the user's bot\r\n\tconst stats = extractStats(result);\r\n\tconsole.log('');\r\n\tconsole.log(formatStats(stats, botInfo.exportName));\r\n\r\n\t// Print auto-diagnosis (tips for common problems)\r\n\tconst tips = diagnoseTrace(events, summary);\r\n\tif (tips.length > 0)\r\n\t{\r\n\t\tconsole.log('');\r\n\t\tconsole.log(formatDiagnosis(tips));\r\n\t}\r\n\tconsole.log('');\r\n}\r\n","/**\r\n * vibemancer tournament\r\n *\r\n * Runs the user's bot in a round-robin tournament against selected opponents.\r\n * Each pairing is a fight (10 matches: 5 spawn distances × 2 sides).\r\n */\r\n\r\nimport {BotBundle, sandboxFight, scoreFight, scoreFightAsWizard2} from '@vibemancer/core';\r\nimport type {FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface TournamentOptions\r\n{\r\n\topponents?: string[];\r\n\tbot?: string;\r\n}\r\n\r\ninterface Pairing\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tbot1Bundle: BotBundle;\r\n\tbot2Bundle: BotBundle;\r\n}\r\n\r\ninterface PairingResult\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tresult: FightResult;\r\n}\r\n\r\nexport async function runTournament(options: TournamentOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\t// Determine opponents\r\n\tconst opponentNames = options.opponents && options.opponents.length > 0\r\n\t\t? options.opponents\r\n\t\t: getBuiltinBotNames();\r\n\r\n\t// Build list of all participants\r\n\tconst participants: {name: string; bundle: BotBundle}[] = [\r\n\t\t{name: botInfo.exportName, bundle: userBundle},\r\n\t];\r\n\r\n\tfor (const name of opponentNames)\r\n\t{\r\n\t\tparticipants.push({name, bundle: resolveOpponent(name)});\r\n\t}\r\n\r\n\tconsole.log(`\\n Tournament: ${participants.length} participants (${participants.length * (participants.length - 1) / 2} pairings)\\n`);\r\n\r\n\t// Generate all pairings\r\n\tconst pairings: Pairing[] = [];\r\n\tfor (let i = 0; i < participants.length; i++)\r\n\t{\r\n\t\tfor (let j = i + 1; j < participants.length; j++)\r\n\t\t{\r\n\t\t\tpairings.push({\r\n\t\t\t\tbot1Name: participants[i]!.name,\r\n\t\t\t\tbot2Name: participants[j]!.name,\r\n\t\t\t\tbot1Bundle: participants[i]!.bundle,\r\n\t\t\t\tbot2Bundle: participants[j]!.bundle,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t// Run all fights\r\n\tconst results: PairingResult[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const pairing of pairings)\r\n\t{\r\n\t\tconst result = await sandboxFight(pairing.bot1Bundle, pairing.bot2Bundle, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tresults.push({\r\n\t\t\tbot1Name: pairing.bot1Name,\r\n\t\t\tbot2Name: pairing.bot2Name,\r\n\t\t\tresult,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? `${pairing.bot1Name} wins`\r\n\t\t\t: result.winner === 'wizard-2' ? `${pairing.bot2Name} wins`\r\n\t\t\t\t: 'Draw';\r\n\t\tconsole.log(` ${pairing.bot1Name} vs ${pairing.bot2Name}: ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${outcome})`);\r\n\t}\r\n\r\n\t// Calculate standings\r\n\tconst points = new Map<string, number>();\r\n\tconst wins = new Map<string, number>();\r\n\r\n\tfor (const p of participants)\r\n\t{\r\n\t\tpoints.set(p.name, 0);\r\n\t\twins.set(p.name, 0);\r\n\t}\r\n\r\n\tfor (const r of results)\r\n\t{\r\n\t\tconst score1 = scoreFight(r.result);\r\n\t\tconst score2 = scoreFightAsWizard2(r.result);\r\n\r\n\t\tpoints.set(r.bot1Name, (points.get(r.bot1Name) ?? 0) + score1);\r\n\t\tpoints.set(r.bot2Name, (points.get(r.bot2Name) ?? 0) + score2);\r\n\t\twins.set(r.bot1Name, (wins.get(r.bot1Name) ?? 0) + r.result.wizard1Wins);\r\n\t\twins.set(r.bot2Name, (wins.get(r.bot2Name) ?? 0) + r.result.wizard2Wins);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\r\n\t// Sort standings by points desc, then wins desc\r\n\tconst standings = [...points.entries()].sort((a, b) =>\r\n\t{\r\n\t\tif (b[1] !== a[1]) return b[1] - a[1];\r\n\t\treturn (wins.get(b[0]) ?? 0) - (wins.get(a[0]) ?? 0);\r\n\t});\r\n\r\n\tconsole.log('\\n Standings:');\r\n\tconsole.log(' ' + '-'.repeat(40));\r\n\tfor (let i = 0; i < standings.length; i++)\r\n\t{\r\n\t\tconst [name, pts] = standings[i]!;\r\n\t\tconst w = wins.get(name) ?? 0;\r\n\t\tconst rank = `#${(i + 1).toString().padStart(2)}`;\r\n\t\tconst isUser = name === botInfo.exportName ? ' *' : '';\r\n\t\tconsole.log(` ${rank} ${name.padEnd(16)} ${pts.toFixed(1)} pts ${w}W${isUser}`);\r\n\t}\r\n\r\n\tconsole.log(`\\n Total time: ${(totalElapsed / 1000).toFixed(1)}s\\n`);\r\n}\r\n","/**\r\n * vibemancer optimize\r\n *\r\n * Runs parameter optimization for the user's bot.\r\n * Scans for useParam() calls, runs coordinate descent against\r\n * all built-in opponents, and rewrites source with optimal values.\r\n */\r\n\r\nimport {readFileSync, writeFileSync} from 'node:fs';\r\nimport {BotBundle, MatchSandbox, scoreFight, generateCandidates, getEffectiveRange} from '@vibemancer/core';\r\nimport type {FightResult, FightWinner, SimulateResult, ParamDeclaration} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface OptimizeOptions\r\n{\r\n\tbot?: string;\r\n\tsteps?: number;\r\n\trounds?: number;\r\n\topponents?: string[];\r\n}\r\n\r\nexport interface ParsedParam\r\n{\r\n\tname: string;\r\n\tdefaultValue: number;\r\n\tmin?: number;\r\n\tmax?: number;\r\n\tstep?: number;\r\n}\r\n\r\n// Parser-style capture: grab everything until the next , or ) instead of matching specific number formats.\r\n// This handles integers, floats, scientific notation (1e-5), negative numbers, etc.\r\nconst USEPAR_RE = /useParam\\(\\s*['\"](\\w+)['\"]\\s*,\\s*([^,)]+?)\\s*(?:,\\s*\\{([^}]*)\\})?\\s*\\)/g;\r\n\r\nfunction parseNumValue(s: string): number\r\n{\r\n\tconst n = parseFloat(s.trim());\r\n\tif (Number.isNaN(n)) throw new Error(`useParam default is not a number: \"${s.trim()}\"`);\r\n\treturn n;\r\n}\r\n\r\nexport function parseParams(source: string): ParsedParam[]\r\n{\r\n\tconst params: ParsedParam[] = [];\r\n\tconst re = new RegExp(USEPAR_RE.source, 'g');\r\n\tlet match: RegExpExecArray | null;\r\n\r\n\twhile ((match = re.exec(source)) !== null)\r\n\t{\r\n\t\tconst name = match[1]!;\r\n\t\tconst defaultValue = parseNumValue(match[2]!);\r\n\t\tconst optsStr = match[3];\r\n\r\n\t\tlet min: number | undefined;\r\n\t\tlet max: number | undefined;\r\n\t\tlet step: number | undefined;\r\n\r\n\t\tif (optsStr)\r\n\t\t{\r\n\t\t\tconst minMatch = optsStr.match(/min\\s*:\\s*([^,}]+)/);\r\n\t\t\tconst maxMatch = optsStr.match(/max\\s*:\\s*([^,}]+)/);\r\n\t\t\tconst stepMatch = optsStr.match(/step\\s*:\\s*([^,}]+)/);\r\n\t\t\tif (minMatch) min = parseNumValue(minMatch[1]!);\r\n\t\t\tif (maxMatch) max = parseNumValue(maxMatch[1]!);\r\n\t\t\tif (stepMatch) step = parseNumValue(stepMatch[1]!);\r\n\t\t}\r\n\r\n\t\tparams.push({name, defaultValue, min, max, step});\r\n\t}\r\n\r\n\treturn params;\r\n}\r\n\r\nfunction toParamDeclaration(p: ParsedParam): ParamDeclaration\r\n{\r\n\treturn {\r\n\t\tname: p.name,\r\n\t\tvalue: p.defaultValue,\r\n\t\tmin: p.min,\r\n\t\tmax: p.max,\r\n\t\tsteps: p.step ?? 5,\r\n\t};\r\n}\r\n\r\n/**\r\n * Run a full fight (10 matches: 5 spawn distances × 2 sides)\r\n * using sandbox.simulate() with param overrides.\r\n */\r\nconst SPAWN_DISTANCES = [200, 300, 400, 500, 600];\r\nconst SEEDS = [42, 137, 256];\r\n\r\nfunction runFightWithParams(\r\n\tsandbox: MatchSandbox,\r\n\tparams1: Record<string, number>,\r\n): FightResult\r\n{\r\n\tlet w1 = 0;\r\n\tlet w2 = 0;\r\n\tlet draws = 0;\r\n\tconst matches: SimulateResult[] = [];\r\n\r\n\tfor (const seed of SEEDS)\r\n\t{\r\n\t\tfor (const dist of SPAWN_DISTANCES)\r\n\t\t{\r\n\t\t\tconst r = sandbox.simulate({\r\n\t\t\t\tseed,\r\n\t\t\t\tspawnDistance: dist,\r\n\t\t\t\tskipHistory: true,\r\n\t\t\t\tparams1,\r\n\t\t\t});\r\n\t\t\tif (r.winner === 'wizard-1') w1++;\r\n\t\t\telse if (r.winner === 'wizard-2') w2++;\r\n\t\t\telse draws++;\r\n\r\n\t\t\tmatches.push(r);\r\n\t\t}\r\n\t}\r\n\r\n\treturn {\r\n\t\twizard1Wins: w1,\r\n\t\twizard2Wins: w2,\r\n\t\tdraws,\r\n\t\twinner: (w1 > w2 ? 'wizard-1' : w2 > w1 ? 'wizard-2' : 'draw') as FightWinner,\r\n\t\tmatches,\r\n\t};\r\n}\r\n\r\nasync function evaluateParams(\r\n\tuserBundle: BotBundle,\r\n\topponentBundles: BotBundle[],\r\n\tparams1: Record<string, number>,\r\n): Promise<number>\r\n{\r\n\tlet totalScore = 0;\r\n\tfor (const opponent of opponentBundles)\r\n\t{\r\n\t\tconst sandbox = await MatchSandbox.create(userBundle, opponent, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\ttry\r\n\t\t{\r\n\t\t\tconst result = runFightWithParams(sandbox, params1);\r\n\t\t\ttotalScore += scoreFight(result);\r\n\t\t}\r\n\t\tfinally\r\n\t\t{\r\n\t\t\tsandbox.dispose();\r\n\t\t}\r\n\t}\r\n\treturn totalScore;\r\n}\r\n\r\n/**\r\n * Resolve the opponent names to use for optimization.\r\n * If opponents are specified, validates them. Otherwise uses all built-in bots.\r\n */\r\nexport function resolveOpponentNames(opponents: string[] | undefined): string[]\r\n{\r\n\tif (!opponents || opponents.length === 0)\r\n\t{\r\n\t\treturn getBuiltinBotNames();\r\n\t}\r\n\r\n\t// Validate all names before starting\r\n\tconst allNames = getBuiltinBotNames();\r\n\tfor (const name of opponents)\r\n\t{\r\n\t\tif (!allNames.includes(name))\r\n\t\t{\r\n\t\t\tthrow new Error(\r\n\t\t\t\t`Unknown opponent: \"${name}\". Available bots:\\n ${allNames.join(', ')}`,\r\n\t\t\t);\r\n\t\t}\r\n\t}\r\n\r\n\treturn opponents;\r\n}\r\n\r\nexport async function runOptimize(options: OptimizeOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst source = readFileSync(botInfo.sourcePath, 'utf-8');\r\n\tconst params = parseParams(source);\r\n\r\n\tif (params.length === 0)\r\n\t{\r\n\t\tconsole.log('\\n No useParam() calls found in your bot.');\r\n\t\tconsole.log(' Add useParam(\"paramName\", defaultValue, {min, max}) to enable optimization.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\r\n\tconsole.log(` Parameters: ${params.length}`);\r\n\tparams.forEach((p) => console.log(` ${p.name} = ${p.defaultValue} [${p.min ?? 'auto'} .. ${p.max ?? 'auto'}]`));\r\n\r\n\tconst steps = options.steps ?? 5;\r\n\tconst maxRounds = options.rounds ?? 3;\r\n\tconst opponentNames = resolveOpponentNames(options.opponents);\r\n\tconst opponentBundles = opponentNames.map((name) => resolveOpponent(name));\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\tconsole.log(` Opponents: ${opponentBundles.length}`);\r\n\tconsole.log(` Steps per param: ${steps}`);\r\n\tconsole.log(` Max rounds: ${maxRounds}\\n`);\r\n\r\n\t// Current best values\r\n\tconst best: Record<string, number> = {};\r\n\tfor (const p of params) best[p.name] = p.defaultValue;\r\n\r\n\t// Baseline score\r\n\tlet bestScore = await evaluateParams(userBundle, opponentBundles, best);\r\n\tconsole.log(` Baseline score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\r\n\r\n\t// Coordinate descent\r\n\tfor (let round = 0; round < maxRounds; round++)\r\n\t{\r\n\t\tlet improved = false;\r\n\t\tconsole.log(` Round ${round + 1}:`);\r\n\r\n\t\tfor (const p of params)\r\n\t\t{\r\n\t\t\tconst decl = toParamDeclaration(p);\r\n\t\t\tconst range = getEffectiveRange(decl);\r\n\t\t\tconst candidates = generateCandidates(range.min, range.max, steps);\r\n\r\n\t\t\tlet paramBest = best[p.name]!;\r\n\t\t\tlet paramBestScore = bestScore;\r\n\r\n\t\t\tfor (const candidate of candidates)\r\n\t\t\t{\r\n\t\t\t\tif (Math.abs(candidate - paramBest) < 0.001) continue;\r\n\r\n\t\t\t\tconst trial = {...best, [p.name]: candidate};\r\n\t\t\t\tconst score = await evaluateParams(userBundle, opponentBundles, trial);\r\n\r\n\t\t\t\tif (score > paramBestScore)\r\n\t\t\t\t{\r\n\t\t\t\t\tparamBest = candidate;\r\n\t\t\t\t\tparamBestScore = score;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (paramBest !== best[p.name])\r\n\t\t\t{\r\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} -> ${paramBest} (+${(paramBestScore - bestScore).toFixed(1)})`);\r\n\t\t\t\tbest[p.name] = paramBest;\r\n\t\t\t\tbestScore = paramBestScore;\r\n\t\t\t\timproved = true;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} (no improvement)`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!improved)\r\n\t\t{\r\n\t\t\tconsole.log(' No improvements found, stopping.\\n');\r\n\t\t\tbreak;\r\n\t\t}\r\n\t\tconsole.log(` Round ${round + 1} score: ${bestScore.toFixed(1)}\\n`);\r\n\t}\r\n\r\n\t// Rewrite source\r\n\tlet updated = source;\r\n\tfor (const p of params)\r\n\t{\r\n\t\tconst newVal = best[p.name]!;\r\n\t\tif (newVal !== p.defaultValue)\r\n\t\t{\r\n\t\t\tconst pattern = new RegExp(\r\n\t\t\t\t`(useParam\\\\(\\\\s*['\"]${escapeRegex(p.name)}['\"]\\\\s*,\\\\s*)${escapeRegex(String(p.defaultValue))}`,\r\n\t\t\t);\r\n\t\t\tupdated = updated.replace(pattern, `$1${newVal}`);\r\n\t\t}\r\n\t}\r\n\r\n\tif (updated !== source)\r\n\t{\r\n\t\twriteFileSync(botInfo.sourcePath, updated);\r\n\t\tconsole.log(` Source updated: ${botInfo.sourcePath}`);\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconsole.log(' No parameter changes to write.');\r\n\t}\r\n\r\n\tconsole.log(` Final score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\r\n}\r\n\r\nfunction escapeRegex(s: string): string\r\n{\r\n\treturn s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\r\n}\r\n","/**\r\n * vibemancer build\r\n *\r\n * Compiles the user's bot against an opponent into a standalone bundle.\r\n */\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport {BotBundle, compileMatchBundle} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, findCoreSourceDir} from '../opponent-resolver.js';\r\n\r\nexport interface BuildOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\toutput?: string;\r\n}\r\n\r\nexport async function runBuild(options: BuildOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst coreSourceDir = findCoreSourceDir();\r\n\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\r\n\tconsole.log(`\\n Compiling ${botInfo.exportName} vs ${options.opponent}...`);\r\n\r\n\tconst start = Date.now();\r\n\tconst bundle = await compileMatchBundle(userBundle, opponentBundle, {\r\n\t\talias: {\r\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\r\n\t\t},\r\n\t});\r\n\tconst elapsed = Date.now() - start;\r\n\r\n\tconst outFile = options.output ?? `dist/${botInfo.exportName}-vs-${options.opponent}.js`;\r\n\tconst outDir = path.dirname(path.resolve(outFile));\r\n\tfs.mkdirSync(outDir, {recursive: true});\r\n\tfs.writeFileSync(path.resolve(outFile), bundle);\r\n\r\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\r\n\tconsole.log(` Output: ${outFile} (${sizeKb} KB)`);\r\n\tconsole.log(` Compiled in ${elapsed}ms\\n`);\r\n}\r\n","/**\r\n * vibemancer bots\r\n *\r\n * Lists all built-in bots with descriptions, grouped by archetype.\r\n * With --name: shows detailed info about a specific bot.\r\n */\r\n\r\nimport {BOT_GROUPS, ALL_BOTS} from '@vibemancer/core';\r\nimport type {WizardEntry} from '@vibemancer/core';\r\n\r\nexport interface BotsOptions\r\n{\r\n\tname?: string;\r\n}\r\n\r\nexport function runBots(options: BotsOptions): void\r\n{\r\n\tif (options.name)\r\n\t{\r\n\t\tshowBotDetail(options.name);\r\n\t\treturn;\r\n\t}\r\n\tlistAllBots();\r\n}\r\n\r\nfunction listAllBots(): void\r\n{\r\n\t// The order is round-robin POINTS (every bot vs every bot), not a prediction about\r\n\t// your bot. Matchups are non-transitive: a low-ranked bot with the right archetype\r\n\t// can beat you while a higher-ranked one cannot. Saying so stops the ladder being\r\n\t// read as difficulty-for-you, which is exactly how it misled a newcomer.\r\n\tconsole.log('\\n Built-in Bots (29 total, by round-robin points — weakest first)');\r\n\tconsole.log(' Matchups are non-transitive: a low-ranked bot may still counter yours.\\n');\r\n\r\n\tfor (const group of BOT_GROUPS)\r\n\t{\r\n\t\tconsole.log(` ${group.label}:`);\r\n\t\tfor (const bot of group.bots)\r\n\t\t{\r\n\t\t\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\t\t\tconst tierLabel = bot.tier ? `T${bot.tier}` : ' ';\r\n\t\t\tconst rankStr = `#${String(rank).padStart(2)}`;\r\n\t\t\tconsole.log(` ${rankStr} ${tierLabel} ${bot.name.padEnd(14)} ${bot.description}`);\r\n\t\t}\r\n\t\tconsole.log('');\r\n\t}\r\n}\r\n\r\nfunction showBotDetail(name: string): void\r\n{\r\n\tconst bot = ALL_BOTS.find((b) => b.name.toLowerCase() === name.toLowerCase());\r\n\tif (!bot)\r\n\t{\r\n\t\tconst available = ALL_BOTS.map((b) => b.name).join(', ');\r\n\t\tconsole.error(`\\n Unknown bot: \"${name}\"\\n Available: ${available}\\n`);\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\r\n\tconsole.log(`\\n ${bot.name}`);\r\n\tconsole.log(` ${'─'.repeat(40)}`);\r\n\tconsole.log(` Rank: #${rank} of ${ALL_BOTS.length}`);\r\n\tconsole.log(` Group: ${bot.group}`);\r\n\tif (bot.tier) console.log(` Tier: ${bot.tier} of 3`);\r\n\tconsole.log(` Description: ${bot.description}`);\r\n\tconsole.log(` Style: ${getStyleDescription(bot)}`);\r\n\r\n\t// Show group progression if tiered\r\n\tif (bot.tier && bot.group !== 'Standalone')\r\n\t{\r\n\t\tconst groupBots = BOT_GROUPS.find((g) => g.label === bot.group)?.bots ?? [];\r\n\t\tif (groupBots.length > 1)\r\n\t\t{\r\n\t\t\tconsole.log(`\\n ${bot.group} progression:`);\r\n\t\t\tfor (const gb of groupBots)\r\n\t\t\t{\r\n\t\t\t\tconst gbRank = ALL_BOTS.indexOf(gb) + 1;\r\n\t\t\t\tconst marker = gb.name === bot.name ? ' ←' : '';\r\n\t\t\t\tconsole.log(` T${gb.tier} ${gb.name.padEnd(14)} #${gbRank} — ${gb.description}${marker}`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconsole.log(`\\n To fight: vibemancer fight --opponent ${bot.name}`);\r\n\tconsole.log(` To trace: vibemancer trace --opponent ${bot.name}\\n`);\r\n}\r\n\r\nfunction getStyleDescription(bot: WizardEntry): string\r\n{\r\n\tswitch (bot.group)\r\n\t{\r\n\t\tcase 'Standalone':\r\n\t\t\tif (bot.name === 'TargetDummy') return 'Does nothing. Use for basic testing.';\r\n\t\t\tif (bot.name === 'Critter') return 'Random actions. Tests handling of unpredictable opponents.';\r\n\t\t\tif (bot.name === 'Rookie') return 'Simple homing missiles. Good first benchmark.';\r\n\t\t\tif (bot.name === 'Hogger') return 'Random but with real damage. Chaos test.';\r\n\t\t\tif (bot.name === 'Doombringer') return 'One huge missile. Tests shield timing.';\r\n\t\t\treturn bot.description;\r\n\t\tcase 'Defensive': return 'Prioritizes shields and survival. Punishes aggression with counter-missiles. Weak to chip damage and shield baiting.';\r\n\t\tcase 'Melee': return 'Blinks in close, fires fast low-range stabs. Weak to kiting and ranged pressure.';\r\n\t\tcase 'Homing': return 'Slow tracking missiles that are hard to dodge. Weak to shields and fast burst.';\r\n\t\tcase 'Caster': return 'Medium-range homing with adaptive missile fitting. Balanced offense and defense.';\r\n\t\tcase 'Sniper': return 'Intercept-predicted straight shots. High accuracy, weak to erratic movement.';\r\n\t\tcase 'Duelist': return 'Close-range fighters with balanced offense/defense. Jack of all trades.';\r\n\t\tcase 'Berserker': return 'Aggressive traders who close distance fast. Weak to kiting and strong defense.';\r\n\t\tcase 'Kiter': return 'Maintains distance while firing homing missiles. Weak to fast closers and blink gap-close.';\r\n\t\tdefault: return bot.description;\r\n\t}\r\n}\r\n","/**\n * vibemancer upload\n *\n * Compiles the user's bot into a standalone bundle and uploads it to Vibemancer\n * via the authed gateway (`POST /api/upload`), owned by the canonical Firebase\n * identity from `vibemancer login`. The server validates + dedupes; if the same\n * code was uploaded before, the old wizard is reactivated (rating/history kept).\n */\n\nimport fs from 'node:fs';\nimport {discoverBot} from '../bot-discovery.js';\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\nimport {uploadBot} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface UploadOptions\n{\n\tbot?: string;\n}\n\nconst MAX_BUNDLE_BYTES = 500 * 1024;\n\nexport async function runUpload(options: UploadOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\n\tconsole.log(`\\n Compiling ${botInfo.exportName}...`);\n\tconst bundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\n\tconsole.log(` Bundle: ${sizeKb} KB`);\n\n\tif (bundle.length > MAX_BUNDLE_BYTES)\n\t{\n\t\tconsole.error(` Error: Bundle too large (${sizeKb} KB). Max ${MAX_BUNDLE_BYTES / 1024} KB.`);\n\t\tprocess.exit(1);\n\t}\n\n\tlet sourceCode = '';\n\ttry\n\t{\n\t\tsourceCode = fs.readFileSync(botInfo.sourcePath, 'utf-8');\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — source storage is optional\n\t}\n\n\tconsole.log(` Wizard: ${botInfo.exportName}`);\n\tconsole.log(' Uploading to Vibemancer...');\n\n\ttry\n\t{\n\t\tconst result = await uploadBot({\n\t\t\tbundle,\n\t\t\tname: botInfo.exportName,\n\t\t\texportName: botInfo.exportName,\n\t\t\tsourceCode,\n\t\t});\n\t\tconsole.log(` ✓ ${result.message}`);\n\t\tif (result.wizardId) console.log(` Wizard ID: ${result.wizardId}`);\n\t\tconsole.log(` Your wizard \"${botInfo.exportName}\" is now competing.\\n`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` ✗ Upload failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * Environment headers the CLI attaches to requests it ALREADY makes, so the server can\n * answer \"which OS are CLI users on\" and \"MCP vs CLI\" without the CLI issuing a single\n * extra outbound request. See docs/decisions/0001-usage-analytics-bigquery.md.\n *\n * Deliberately narrow: platform, release, arch, node version, CLI version. No username,\n * no hostname, no paths — none of which we need, and all of which would be a liability.\n */\n\nimport os from 'node:os';\nimport {readFileSync} from 'node:fs';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\n/**\n * Walk upwards from `here` looking for this package's own manifest.\n *\n * The try/catch sits INSIDE the loop deliberately. With one try around the whole loop, the\n * first candidate that does not exist aborted the entire search — which is what happens in\n * every built layout (`dist/cli.js` has nothing two levels up) and in every published\n * install. The result was a CLI that reported no version at all, invisible in the tests\n * because the SOURCE layout happens to match the first candidate, and only visible as a\n * column of nulls in the analytics.\n *\n * Exported so the layouts can be exercised directly rather than only the one the tests\n * happen to run in.\n */\nexport function findCliVersionFrom(here: string): string\n{\n\tfor (const rel of ['../../package.json', '../package.json', '../../../package.json'])\n\t{\n\t\ttry\n\t\t{\n\t\t\tconst parsed: unknown = JSON.parse(readFileSync(path.resolve(here, rel), 'utf8'));\n\t\t\tif (typeof parsed !== 'object' || parsed === null) continue;\n\t\t\tif (!('name' in parsed) || !('version' in parsed)) continue;\n\t\t\tconst {name, version} = parsed;\n\t\t\tif (name === 'vibemancer' && typeof version === 'string') return version;\n\t\t}\n\t\tcatch\n\t\t{\n\t\t\t// A candidate that is missing or unreadable is ordinary; try the next one.\n\t\t}\n\t}\n\treturn '';\n}\n\nfunction readCliVersion(): string\n{\n\ttry\n\t{\n\t\treturn findCliVersionFrom(path.dirname(fileURLToPath(import.meta.url)));\n\t}\n\tcatch\n\t{\n\t\t// Version is nice-to-have; never worth failing a command over.\n\t\treturn '';\n\t}\n}\n\n/**\n * Build the telemetry headers. Pure given its inputs so it can be tested without touching\n * the real environment.\n */\nexport function buildEnvHeaders(env: {\n\tplatform: string;\n\trelease: string;\n\tarch: string;\n\tnodeVersion: string;\n\tcliVersion: string;\n}): Record<string, string>\n{\n\tconst headers: Record<string, string> = {};\n\tconst put = (key: string, value: string): void =>\n\t{\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed) headers[key] = trimmed.slice(0, 64);\n\t};\n\tput('x-vibemancer-os', env.platform);\n\tput('x-vibemancer-os-release', env.release);\n\tput('x-vibemancer-arch', env.arch);\n\tput('x-vibemancer-node', env.nodeVersion);\n\tput('x-vibemancer-cli', env.cliVersion);\n\treturn headers;\n}\n\n/** The headers for THIS machine. */\nexport function envHeaders(): Record<string, string>\n{\n\ttry\n\t{\n\t\treturn buildEnvHeaders({\n\t\t\tplatform: os.platform(),\n\t\t\trelease: os.release(),\n\t\t\tarch: os.arch(),\n\t\t\tnodeVersion: process.version,\n\t\t\tcliVersion: readCliVersion(),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\treturn {};\n\t}\n}\n","/**\n * Client for the authed gateway REST endpoints. Attaches the Bearer session\n * token (carrying the canonical Firebase uid) and parses responses. This is the\n * single network path the CLI uses to upload + pull.\n */\n\nimport {getAccessToken, MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\nexport interface UploadPayload\n{\n\tbundle: string;\n\tname: string;\n\texportName: string;\n\tsourceCode: string;\n}\n\nexport interface UploadResult\n{\n\twizardId: string;\n\tmessage: string;\n}\n\nexport async function uploadBot(payload: UploadPayload): Promise<UploadResult>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/upload`, {\n\t\tmethod: 'POST',\n\t\t// Environment headers ride along on a request already being made — no extra call.\n\t\theaders: {'Content-Type': 'application/json', Authorization: `Bearer ${token}`, ...envHeaders()},\n\t\tbody: JSON.stringify(payload),\n\t});\n\tif (!res.ok) throw new Error(`Upload failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst wizardId = typeof data === 'object' && data !== null && 'wizardId' in data && typeof data.wizardId === 'string'\n\t\t? data.wizardId\n\t\t: '';\n\tconst message = typeof data === 'object' && data !== null && 'message' in data && typeof data.message === 'string'\n\t\t? data.message\n\t\t: 'Uploaded.';\n\treturn {wizardId, message};\n}\n\nexport async function pullSource(name: string): Promise<string>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/pull?name=${encodeURIComponent(name)}`, {\n\t\theaders: {Authorization: `Bearer ${token}`, ...envHeaders()},\n\t});\n\tif (!res.ok) throw new Error(`Pull failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst source = typeof data === 'object' && data !== null && 'sourceCode' in data && typeof data.sourceCode === 'string'\n\t\t? data.sourceCode\n\t\t: '';\n\tif (source) return source;\n\tconst error = typeof data === 'object' && data !== null && 'error' in data && typeof data.error === 'string'\n\t\t? data.error\n\t\t: 'No source returned.';\n\tthrow new Error(error);\n}\n","/**\n * vibemancer pull\n *\n * Downloads the latest source of your active wizard (by export name) from the\n * authed gateway (`GET /api/pull`) and writes it to the local bot file. Enables\n * round-tripping between MCP chat sessions and local CLI development.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {discoverBot} from '../bot-discovery.js';\nimport {pullSource} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface PullOptions\n{\n\tbot?: string;\n}\n\nexport async function runPull(options: PullOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\t// pull RESTORES source, so the file legitimately may not exist yet — a new machine, a\n\t// fresh clone, or a bot authored in an MCP chat session. See DiscoverOptions.\n\tconst botInfo = await discoverBot(projectDir, options.bot, {allowMissingFile: true});\n\tconst isNew = !fs.existsSync(botInfo.sourcePath);\n\n\tconsole.log(`\\n Pulling latest source for ${botInfo.exportName}...`);\n\n\ttry\n\t{\n\t\tconst sourceCode = await pullSource(botInfo.exportName);\n\t\t// On a fresh machine the containing directory (src/) may not exist either.\n\t\tfs.mkdirSync(path.dirname(botInfo.sourcePath), {recursive: true});\n\t\tfs.writeFileSync(botInfo.sourcePath, sourceCode);\n\t\tconsole.log(` ✓ ${isNew ? 'Created' : 'Updated'} ${botInfo.sourcePath}`);\n\t\tconsole.log(` ${(sourceCode.length / 1024).toFixed(1)} KB written`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` Pull failed: ${err instanceof Error ? err.message : String(err)}`);\n\t\t\tconsole.error(' Upload first with: vibemancer upload\\n');\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * vibemancer login\n *\n * Authenticates the CLI as an OAuth client of the MCP gateway. The resulting\n * session token carries the canonical Firebase uid (the same identity the web\n * and MCP use), so uploads from the CLI are owned by the same account.\n *\n * Default: browser loopback (a localhost server catches the redirect).\n * `--no-browser`: print the URL + paste the code shown on the gateway page.\n */\n\nimport {createServer, type IncomingMessage, type ServerResponse} from 'node:http';\nimport {randomBytes} from 'node:crypto';\nimport {spawn} from 'node:child_process';\nimport {createInterface} from 'node:readline/promises';\nimport {generatePkce, registerClient, exchangeCode, MCP_BASE_URL} from '../auth/oauth-client.js';\n\nexport interface LoginOptions\n{\n\tnoBrowser?: boolean;\n}\n\nexport function buildAuthorizeUrl(\n\tbaseUrl: string,\n\tparams: {clientId: string; redirectUri: string; challenge: string; state: string},\n): string\n{\n\tconst u = new URL(`${baseUrl}/authorize`);\n\tu.searchParams.set('response_type', 'code');\n\tu.searchParams.set('client_id', params.clientId);\n\tu.searchParams.set('redirect_uri', params.redirectUri);\n\tu.searchParams.set('code_challenge', params.challenge);\n\tu.searchParams.set('code_challenge_method', 'S256');\n\tu.searchParams.set('state', params.state);\n\treturn u.toString();\n}\n\nexport function extractCodeFromCallback(reqUrl: string, expectedState: string): {code: string} | {error: string}\n{\n\tconst u = new URL(reqUrl, 'http://localhost');\n\tconst code = u.searchParams.get('code');\n\tconst state = u.searchParams.get('state');\n\tif (!code) return {error: 'No authorization code in the callback.'};\n\tif (state !== expectedState) return {error: 'State mismatch (possible CSRF) — try again.'};\n\treturn {code};\n}\n\nfunction openBrowser(url: string): void\n{\n\ttry\n\t{\n\t\tconst child = process.platform === 'win32'\n\t\t\t? spawn('cmd', ['/c', 'start', '', url], {stdio: 'ignore', detached: true})\n\t\t\t: spawn(process.platform === 'darwin' ? 'open' : 'xdg-open', [url], {stdio: 'ignore', detached: true});\n\t\tchild.unref();\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — the URL is also printed for manual opening\n\t}\n}\n\ninterface LoopbackServer\n{\n\tport: number;\n\twaitForCode: Promise<string>;\n\tclose: () => void;\n}\n\nfunction startLoopbackServer(expectedState: string): Promise<LoopbackServer>\n{\n\treturn new Promise((resolveServer) =>\n\t{\n\t\tlet resolveCode: (code: string) => void = () => undefined;\n\t\tlet rejectCode: (err: Error) => void = () => undefined;\n\t\tconst waitForCode = new Promise<string>((res, rej) =>\n\t\t{\n\t\t\tresolveCode = res;\n\t\t\trejectCode = rej;\n\t\t});\n\n\t\tconst server = createServer((req: IncomingMessage, res: ServerResponse) =>\n\t\t{\n\t\t\tconst result = extractCodeFromCallback(req.url ?? '', expectedState);\n\t\t\tif ('error' in result)\n\t\t\t{\n\t\t\t\tres.writeHead(400, {'Content-Type': 'text/html'});\n\t\t\t\tres.end('<h2>Login failed</h2><p>You can close this tab and try again.</p>');\n\t\t\t\trejectCode(new Error(result.error));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.writeHead(200, {'Content-Type': 'text/html'});\n\t\t\tres.end('<h2>Vibemancer login complete</h2><p>You can close this tab and return to the terminal.</p>');\n\t\t\tresolveCode(result.code);\n\t\t});\n\n\t\tserver.listen(0, '127.0.0.1', () =>\n\t\t{\n\t\t\tconst addr = server.address();\n\t\t\tconst port = typeof addr === 'object' && addr !== null ? addr.port : 0;\n\t\t\tresolveServer({port, waitForCode, close: () => server.close()});\n\t\t});\n\t});\n}\n\nasync function runBrowserLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst {port, waitForCode, close} = await startLoopbackServer(state);\n\tconst redirectUri = `http://localhost:${port}/callback`;\n\ttry\n\t{\n\t\tconst clientId = await registerClient(redirectUri);\n\t\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\t\tconsole.log('\\n Opening your browser to sign in with Google...');\n\t\tconsole.log(` If it doesn't open, visit:\\n ${authUrl}\\n`);\n\t\topenBrowser(authUrl);\n\t\tconst code = await waitForCode;\n\t\tawait exchangeCode(code, verifier);\n\t\tconsole.log(' ✓ Logged in. You can now run `vibemancer upload`.\\n');\n\t}\n\tfinally\n\t{\n\t\tclose();\n\t}\n}\n\nasync function runPasteLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst redirectUri = `${MCP_BASE_URL}/cli-code`;\n\tconst clientId = await registerClient(redirectUri);\n\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\tconsole.log('\\n Open this URL in a browser, sign in, then paste the code shown:\\n');\n\tconsole.log(` ${authUrl}\\n`);\n\tconst rl = createInterface({input: process.stdin, output: process.stdout});\n\tconst code = (await rl.question(' Paste code: ')).trim();\n\trl.close();\n\tif (!code)\n\t{\n\t\tconsole.error(' No code entered.');\n\t\tprocess.exit(1);\n\t}\n\tawait exchangeCode(code, verifier);\n\tconsole.log(' ✓ Logged in.\\n');\n}\n\nexport async function runLogin(options: LoginOptions): Promise<void>\n{\n\tconst {verifier, challenge} = generatePkce();\n\tconst state = randomBytes(16).toString('hex');\n\tif (options.noBrowser)\n\t{\n\t\tawait runPasteLogin(challenge, verifier, state);\n\t}\n\telse\n\t{\n\t\tawait runBrowserLogin(challenge, verifier, state);\n\t}\n}\n","/**\n * Server-side session revocation for the CLI.\n *\n * `clearCredentials()` only deletes the local file; the refresh token stayed valid on the\n * gateway for the rest of its 30 days, so a copied token survived a logout. This calls\n * the gateway so the session actually ends.\n *\n * Best-effort by design: it reports failure rather than throwing, because the local\n * credentials must still be cleared when the network is down — or when the user is\n * logging out precisely because something has gone wrong.\n */\n\nimport {MCP_BASE_URL} from './oauth-client.js';\n\n/** Revoke the session behind `token`. Returns whether the gateway confirmed it. */\nexport async function revokeSession(token: string): Promise<boolean>\n{\n\tif (!token) return false;\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/revoke`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json'},\n\t\t\tbody: JSON.stringify({token}),\n\t\t});\n\t\treturn res.ok;\n\t}\n\tcatch\n\t{\n\t\treturn false;\n\t}\n}\n","/**\n * vibemancer logout — end the session, then clear the cached OAuth credentials.\n *\n * Clearing the local file alone used to leave the refresh token valid on the gateway for\n * the rest of its 30 days, so a copied credential survived a logout. The revoke call is\n * best-effort: the local credentials are cleared either way, because a user with no\n * network — or one logging out BECAUSE something is wrong — must still be able to get\n * their credentials off the machine.\n */\n\nimport {clearCredentials, loadCredentials} from '../auth/credentials-store.js';\nimport {revokeSession} from '../auth/revoke.js';\n\nexport async function runLogout(): Promise<void>\n{\n\tconst credentials = loadCredentials();\n\tconst revoked = credentials ? await revokeSession(credentials.accessToken) : false;\n\n\tclearCredentials();\n\n\tif (credentials && !revoked)\n\t{\n\t\tconsole.log(' Logged out locally, but the server could not be reached to end the session.');\n\t\tconsole.log(' Run `vibemancer logout` again while online to revoke it.');\n\t\treturn;\n\t}\n\tconsole.log(' Logged out.');\n}\n","/**\n * vibemancer feedback \"what went wrong\"\n *\n * Posts to the PUBLIC `/feedback` endpoint — the same one the web page documents, which\n * needs no account at all.\n *\n * It used to call the `submitFeedback` Firebase callable from a bare `initializeApp`, with\n * no credential attached: no Firebase Auth session, and not the gateway JWT that `login`\n * caches. The callable requires `request.auth`, so the command answered \"Sign in to submit\n * feedback\" to everyone — including users who were signed in. It could not succeed for\n * anybody, and had been that way since CLI auth moved to the MCP gateway.\n *\n * A cached token is attached when there is one, so a signed-in report stays attributable.\n * Its absence never blocks the report: the endpoint exists precisely so that someone whose\n * sign-in is broken can tell us that, and requiring a token here would rebuild the dead end.\n */\n\nimport {MCP_BASE_URL} from '../auth/oauth-client.js';\nimport {envHeaders} from '../auth/env-headers.js';\n\nexport interface FeedbackOptions\n{\n\tmessage: string;\n}\n\n/** Resolve the cached access token, or null when not signed in. Injected for testing. */\nexport type TokenLookup = () => Promise<string | null>;\n\nasync function defaultTokenLookup(): Promise<string | null>\n{\n\tconst {getAccessToken} = await import('../auth/oauth-client.js');\n\treturn await getAccessToken();\n}\n\nexport async function runFeedback(options: FeedbackOptions, tokenLookup: TokenLookup = defaultTokenLookup): Promise<void>\n{\n\tconst message = options.message.trim();\n\tif (!message)\n\t{\n\t\tconsole.error(' Error: feedback message cannot be empty.');\n\t\tprocess.exit(1);\n\t\treturn;\n\t}\n\n\tconsole.log('\\n Submitting feedback...');\n\n\t// Best effort. Not being signed in is the NORMAL case for a bug report about signing in.\n\tlet token: string | null;\n\ttry\n\t{\n\t\ttoken = await tokenLookup();\n\t}\n\tcatch\n\t{\n\t\t// No cached credential, or a refresh that failed. Neither is a reason to drop a\n\t\t// bug report — especially one that might be about signing in.\n\t\ttoken = null;\n\t}\n\n\tconst headers: Record<string, string> = {'Content-Type': 'application/json', ...envHeaders()};\n\tif (token) headers.Authorization = `Bearer ${token}`;\n\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/feedback`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({message}),\n\t\t\tsignal: AbortSignal.timeout(15_000),\n\t\t});\n\n\t\tif (!res.ok)\n\t\t{\n\t\t\tconst body = await res.text();\n\t\t\tlet detail = body;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst parsed: unknown = JSON.parse(body);\n\t\t\t\tif (typeof parsed === 'object' && parsed !== null && 'error' in parsed)\n\t\t\t\t{\n\t\t\t\t\tdetail = String((parsed as {error: unknown}).error);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch\n\t\t\t{\n\t\t\t\t// Keep the raw body; a non-JSON error is still worth showing.\n\t\t\t}\n\t\t\tconsole.error(` Failed to submit: ${detail}\\n`);\n\t\t\tprocess.exit(1);\n\t\t\treturn;\n\t\t}\n\n\t\t// `token` is only a SIGN-IN INDICATOR here - the value is never printed. Naming that\n\t\t// intention reads better, and it also stops a PII-in-logs scanner from reading this\n\t\t// call as a credential leak, which it otherwise does.\n\t\tconst signedIn = token !== null;\n\t\tconsole.log(signedIn\n\t\t\t? ' Sent! Thanks for the feedback.\\n'\n\t\t\t: ' Sent! Thanks for the feedback. (Not signed in, so we have no way to reply.)\\n');\n\t}\n\tcatch(err: unknown)\n\t{\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tconsole.error(` Failed to submit: ${msg}\\n`);\n\t\tprocess.exit(1);\n\t}\n}\n","import {calculateMissileCastTime, GCD_DURATION, TICKS_PER_SECOND, calculateMissileRadius} from '@vibemancer/core';\n\nexport interface MissileCalcOptions\n{\n\tdamage: number;\n\tspeed: number;\n\tduration: number;\n\tturnRate: number;\n}\n\nexport function runMissileCalc(options: MissileCalcOptions): void\n{\n\tconst config = {\n\t\tdamage: options.damage,\n\t\tspeed: options.speed,\n\t\tduration: options.duration,\n\t\tturnRate: options.turnRate,\n\t};\n\n\tconst castTimeSec = calculateMissileCastTime(config);\n\tconst castFrames = Math.max(1, Math.round(castTimeSec * TICKS_PER_SECOND));\n\tconst gcdSec = GCD_DURATION / TICKS_PER_SECOND;\n\tconst totalCycleSec = castTimeSec + gcdSec;\n\tconst dps = config.damage / totalCycleSec;\n\tconst range = config.speed * config.duration;\n\tconst radius = calculateMissileRadius(config.damage);\n\n\tconsole.log(`\n Missile Calculator\n ──────────────────\n Config: damage=${config.damage} speed=${config.speed} duration=${config.duration} turnRate=${config.turnRate}\n Cast time: ${castTimeSec.toFixed(3)}s (${castFrames} frames)\n GCD: ${gcdSec}s (${GCD_DURATION} frames)\n Full cycle: ${totalCycleSec.toFixed(3)}s (cast + GCD)\n Eff. DPS: ${dps.toFixed(2)} HP/s\n Range: ${range} units (speed × duration)\n Hitbox: ${radius.toFixed(2)} radius\n`);\n}\n","/**\n * CLI telemetry for LOCAL commands (dev / fight / test / optimize / trace / build).\n *\n * Commands that talk to the gateway are already measured by the headers in\n * env-headers.ts. Local commands are not, and that gap is the important one: without\n * them the only people counted are those who successfully signed in and uploaded, so\n * \"what fraction of installs never upload?\" — the question that decides whether the CLI\n * is worth maintaining — would be computed over survivors only.\n *\n * Three rules this must never break:\n * 1. It must never block. Sent at command START so a long command overlaps the request,\n * with a hard timeout so an unreachable server cannot delay the exit.\n * 2. It must never throw. A telemetry failure is not a CLI failure.\n * 3. It must be refusable, and say so once. Developers are the audience most likely to\n * object to a tool phoning home, and the least likely to forgive doing it silently.\n */\n\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\n/** Milliseconds before an unreachable server is abandoned. */\nconst TIMEOUT_MS = 1000;\n\n/**\n * Is telemetry allowed?\n *\n * Honours our own switch AND `DO_NOT_TRACK`, the cross-tool convention — a developer who\n * has set that globally has already expressed the preference, and ignoring it because it\n * is not our variable would be obtuse.\n */\nexport function isTelemetryEnabled(env: NodeJS.ProcessEnv): boolean\n{\n\tconst off = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '0' || v === 'false' || v === 'off' || v === 'no';\n\t};\n\tconst on = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '1' || v === 'true' || v === 'on' || v === 'yes';\n\t};\n\n\tif (off(env.VIBEMANCER_TELEMETRY)) return false;\n\tif (on(env.DO_NOT_TRACK)) return false;\n\t// CI machines are not people; counting them would inflate every figure.\n\tif (on(env.CI)) return false;\n\treturn true;\n}\n\n/** The one-time notice. Exported so its wording can be asserted rather than drift. */\nexport const TELEMETRY_NOTICE =\n\t' Vibemancer records which commands are run, your OS and version numbers, to decide\\n'\n\t+ ' which platforms to support. No code, file paths or personal files are ever sent.\\n'\n\t+ ' Opt out any time with VIBEMANCER_TELEMETRY=0 (DO_NOT_TRACK is honoured too).\\n';\n\n/** Where the \"already told them\" marker lives. */\nfunction noticePath(): string\n{\n\treturn path.join(os.homedir(), '.vibemancer', 'telemetry-notice-shown');\n}\n\n/**\n * Print the notice the first time only. Returns whether it printed, so tests can assert\n * the once-only behaviour rather than trusting it.\n */\nexport function showNoticeOnce(marker: string = noticePath()): boolean\n{\n\ttry\n\t{\n\t\tif (fs.existsSync(marker)) return false;\n\t\tfs.mkdirSync(path.dirname(marker), {recursive: true});\n\t\tfs.writeFileSync(marker, new Date().toISOString());\n\t\tconsole.log(TELEMETRY_NOTICE);\n\t\treturn true;\n\t}\n\tcatch\n\t{\n\t\t// If the marker cannot be written, stay silent rather than nagging every run.\n\t\treturn false;\n\t}\n}\n\n/**\n * Record that a local command ran. Fire-and-forget by construction: the returned promise\n * is resolved even on failure, so a caller that forgets to await cannot produce an\n * unhandled rejection.\n */\nexport async function recordLocalCommand(command: string, env: NodeJS.ProcessEnv = process.env, marker: string = noticePath()): Promise<void>\n{\n\tif (!isTelemetryEnabled(env)) return;\n\t// `marker` is injectable so the test suite cannot consume the real first-run notice on\n\t// whichever machine runs it — otherwise the one person certain to have run the tests is\n\t// the one person who never sees the notice.\n\tshowNoticeOnce(marker);\n\n\ttry\n\t{\n\t\t// envHeaders() rather than hand-built ones: it resolves the CLI version too, and the\n\t\t// version spread of people who never upload is the half we could not otherwise see.\n\t\tconst headers = envHeaders();\n\t\tawait fetch(`${MCP_BASE_URL}/cli-telemetry`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json', ...headers},\n\t\t\tbody: JSON.stringify({command}),\n\t\t\tsignal: AbortSignal.timeout(TIMEOUT_MS),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\t// Never a CLI failure.\n\t}\n}\n","/**\r\n * Vibemancer CLI\r\n *\r\n * Development tools for building wizard bots.\r\n *\r\n * Usage:\r\n * vibemancer dev [--port 4242] [--bot src/bot.ts]\r\n * vibemancer test\r\n * vibemancer fight [--opponent Battlemage]\r\n * vibemancer trace --opponent Battlemage\r\n * vibemancer tournament [opponents...]\r\n * vibemancer optimize [--opponents Battlemage,Warmage]\r\n * vibemancer build --opponent Battlemage\r\n */\r\n\r\nimport {cliVersion} from './cli-version.js';\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 Round-robin against all 29 ranked built-ins (or --opponent <name>).\r\n The showcase bot is excluded: fight it with --opponent Hero\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\t// `--version`, `-v` and `version` all used to fall through to \"Unknown command\" and\r\n\t\t// dump the help — while the CLI was quietly shipping its version to the server as a\r\n\t\t// telemetry header. It is the first thing a user types when something misbehaves.\r\n\t\tcase '--version':\r\n\t\tcase '-v':\r\n\t\tcase 'version':\r\n\t\t\tconsole.log(cliVersion());\r\n\t\t\tbreak;\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","fs","path","path","fs","BotBundle","BotBundle","BotBundle","sandboxFight","scoreFight","BotBundle","sandboxFight","scoreFight","BotBundle","scoreFight","scoreFight","BotBundle","fs","path","BotBundle","BotBundle","path","fs","fs","readFileSync","path","fileURLToPath","fs","fs","path","fs","path","spawn","openBrowser","spawn","getAccessToken","os","fs","path","path","os","fs","command","getBuiltinBotNames"]}
1
+ {"version":3,"sources":["../src/cli-version.ts","../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/commands/fight-errors.ts","../src/remote-opponent.ts","../src/firebase-config.ts","../src/commands/trace.ts","../src/commands/tournament.ts","../src/commands/optimize.ts","../src/commands/build.ts","../src/commands/bots.ts","../src/commands/upload.ts","../src/auth/env-headers.ts","../src/auth/gateway-client.ts","../src/commands/pull.ts","../src/commands/login.ts","../src/auth/revoke.ts","../src/commands/logout.ts","../src/commands/feedback.ts","../src/commands/missile-calc.ts","../src/auth/telemetry.ts","../src/cli.ts"],"sourcesContent":["/**\n * The CLI's own version, for `vibemancer --version`.\n *\n * This existed already, in a sense, and that is the point. `readCliVersion()` in\n * auth/env-headers.ts walks up from the bundle to find this package's manifest and ships the\n * version to the server as a telemetry header on every authed call. So the CLI knew its\n * version, reported it to us, and had no way to tell the person running it: `--version`,\n * `-v` and `version` all answered \"Unknown command\" and dumped the help.\n *\n * That is the first thing a user types when something misbehaves and the first thing a\n * maintainer asks for in a bug report.\n *\n * The read is injected so the failure modes can be tested without a filesystem: a missing\n * manifest, malformed JSON, a manifest with no version, and — the one worth guarding —\n * finding the CONSUMER's package.json instead of ours while walking up from `dist/`.\n * Reporting the user's project version as the CLI version would be worse than saying\n * nothing, so the name is checked.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\n/** Reads a manifest's text, or throws if it is not there. */\nexport type ReadManifest = () => string;\n\nexport function resolveCliVersion(read: ReadManifest): string\n{\n\ttry\n\t{\n\t\tconst parsed: unknown = JSON.parse(read());\n\t\tif (typeof parsed !== 'object' || parsed === null) return 'unknown';\n\t\tif (!('name' in parsed) || !('version' in parsed)) return 'unknown';\n\t\tconst {name, version} = parsed as {name?: unknown; version?: unknown};\n\t\tif (name !== 'vibemancer' || typeof version !== 'string' || !version) return 'unknown';\n\t\treturn version;\n\t}\n\tcatch\n\t{\n\t\t// A CLI must never fail to start because it could not introspect itself.\n\t\treturn 'unknown';\n\t}\n}\n\n/**\n * Find this package's manifest by walking up from the running module.\n *\n * Both `dist/cli.js` (published) and `src/cli.ts` (dev) are one or two levels below the\n * manifest, so two candidates cover both. Each is tried independently — an earlier version\n * of this walk wrapped the whole loop in one try/catch, so the first missing path aborted\n * the search and the version came back empty in exactly the layout that mattered.\n */\nexport function cliVersion(): string\n{\n\tconst here = path.dirname(fileURLToPath(import.meta.url));\n\tfor (const rel of ['../package.json', '../../package.json'])\n\t{\n\t\tconst candidate = path.resolve(here, rel);\n\t\tconst version = resolveCliVersion(() => fs.readFileSync(candidate, 'utf8'));\n\t\tif (version !== 'unknown') return version;\n\t}\n\treturn 'unknown';\n}\n","/**\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\t// Local Network Access. A page served from a PUBLIC origin reaching a LOOPBACK\n\t\t// address is gated by Chrome behind a permission prompt, and the preflight is\n\t\t// rejected outright unless the target opts in with this header. Without it the\n\t\t// advertised `vibemancer dev` loop simply fails in a default browser, and the failure\n\t\t// looks like the local server being down when it is answering fine.\n\t\t//\n\t\t// Granting it is what this server is FOR: it exists to be called by the hosted\n\t\t// viewer, it serves only the developer's own bot bundles, and it is bound to their\n\t\t// machine. Both header spellings are sent because the name changed mid-standard and\n\t\t// which one a given Chrome honours depends on its version.\n\t\tres.setHeader('Access-Control-Allow-Private-Network', 'true');\n\t\tres.setHeader('Access-Control-Allow-Local-Network-Access', 'true');\n\n\t\tif (req.method === 'OPTIONS')\n\t\t{\n\t\t\tres.writeHead(204);\n\t\t\tres.end();\n\t\t\treturn;\n\t\t}\n\n\t\tconst url = new URL(req.url ?? '/', `http://localhost:${port}`);\n\t\tconst pathname = url.pathname;\n\n\t\ttry\n\t\t{\n\t\t\tif (pathname === '/health')\n\t\t\t{\n\t\t\t\trespond(res, 200, {status: 'ok'});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (pathname === '/local-bots')\n\t\t\t{\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst body: LocalBotsResponse = {bots: bots.map(botInfoToWire)};\n\t\t\t\trespond(res, 200, body);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bundleMatch = /^\\/local-bots\\/([A-Za-z_][A-Za-z0-9_]*)\\/bundle$/.exec(pathname);\n\t\t\tif (bundleMatch)\n\t\t\t{\n\t\t\t\tconst requestedName = bundleMatch[1]!;\n\t\t\t\tconst bots = await loadBots();\n\t\t\t\tconst target = bots.find((b) => b.exportName === requestedName);\n\t\t\t\tif (!target)\n\t\t\t\t{\n\t\t\t\t\trespond(res, 404, {error: `No local bot named \"${requestedName}\". Found: ${bots.map((b) => b.exportName).join(', ') || '(none)'}`});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst start = Date.now();\n\t\t\t\tconst bundle = await compileSingleBotBundle(target.sourcePath, target.exportName);\n\t\t\t\tconst elapsed = Date.now() - start;\n\t\t\t\tconsole.log(` Compiled ${target.exportName} (${(bundle.length / 1024).toFixed(1)} KB) in ${elapsed}ms`);\n\n\t\t\t\tres.writeHead(200, {'Content-Type': 'text/javascript'});\n\t\t\t\tres.end(bundle);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\trespond(res, 404, {error: `Not found: ${pathname}`});\n\t\t}\n\t\tcatch(error)\n\t\t{\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tconsole.error(` Error: ${message}`);\n\t\t\trespond(res, 500, {error: message});\n\t\t}\n\t});\n\n\tserver.listen(port, () =>\n\t{\n\t\tconsole.log(`\\nVibemancer dev server running at http://localhost:${port}`);\n\t\tvoid (async(): Promise<void> =>\n\t\t{\n\t\t\tconst bots = await loadBots();\n\t\t\tif (bots.length === 0)\n\t\t\t{\n\t\t\t\tconsole.log(' (no bots discovered in src/ — add a .ts file with a PascalCase export)');\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconsole.log(` Bots: ${bots.map((b) => b.exportName).join(', ')}`);\n\t\t\t}\n\t\t\tconsole.log('');\n\t\t\tconsole.log('Open your browser to play:');\n\t\t\tconsole.log(` https://vibemancer.com/#botserver=localhost:${port}\\n`);\n\t\t\tconsole.log('Endpoints:');\n\t\t\tconsole.log(' GET /local-bots - List of locally-discovered bots');\n\t\t\tconsole.log(' GET /local-bots/<name>/bundle - Compile a single bot to a sandbox-ready bundle');\n\t\t\tconsole.log(' GET /health - Server health check\\n');\n\t\t})();\n\t});\n\n\treturn server;\n}\n\nfunction respond(res: http.ServerResponse, status: number, data: unknown): void\n{\n\tres.writeHead(status, {'Content-Type': 'application/json'});\n\tres.end(JSON.stringify(data));\n}\n","/**\n * Compile a single bot to a self-contained IIFE bundle.\n *\n * The output sets `globalThis.__injectedBot1` to the bot's exported function.\n * This is the canonical \"uploaded wizard\" bundle shape — the same format the\n * Storage-uploaded wizards live in, the same format the fight-runner /\n * BrowserMatchSandbox concatenates with MATCH_TEMPLATE / MANUAL_MATCH_TEMPLATE.\n *\n * Used by:\n * - `vibemancer upload` (CLI) — uploads to Firebase Storage\n * - dev server's /local-bots/:name/bundle endpoint — served to the web\n * client when picking a local bot\n *\n * `@vibemancer/core` is aliased to the package's TypeScript source (mirroring\n * seed-bots.ts) so the bundle is fully self-contained — no runtime shims, no\n * CJS `require()`, just an IIFE that runs anywhere a Web Worker can.\n */\n\nimport {build} from 'esbuild';\nimport {findCoreSourceDir} from './opponent-resolver.js';\n\nexport async function compileSingleBotBundle(\n\tsourcePath: string,\n\texportName: string,\n): Promise<string>\n{\n\tconst coreSourceDir = findCoreSourceDir();\n\n\tconst result = await build({\n\t\tentryPoints: [sourcePath],\n\t\tbundle: true,\n\t\twrite: false,\n\t\tformat: 'iife',\n\t\tglobalName: '__botExport',\n\t\tplatform: 'neutral',\n\t\ttarget: 'es2022',\n\t\tlogLevel: 'error',\n\t\tfooter: {js: `globalThis.__injectedBot1 = __botExport.${exportName};`},\n\t\texternal: [\n\t\t\t'isolated-vm', 'esbuild',\n\t\t\t'node:*',\n\t\t],\n\t\talias: {\n\t\t\t'@vibemancer/core': coreSourceDir + '/index-browser.ts',\n\t\t},\n\t});\n\n\tif (!result.outputFiles?.[0])\n\t{\n\t\tthrow new Error('esbuild produced no output');\n\t}\n\n\treturn result.outputFiles[0].text;\n}\n","/**\n * vibemancer test\n *\n * Runs the user's vitest test suite. Scaffolded projects include a\n * tests/ directory with example tests using the testBot() helper.\n */\n\nimport {spawn} from 'node:child_process';\n\nexport interface TestOptions\n{\n\tbot?: string;\n}\n\nexport async function runTest(_options: TestOptions): Promise<void>\n{\n\tconsole.log('\\n Running tests...\\n');\n\n\t// spawn + await, NOT execSync. execSync blocks the entire event loop, and the CLI fires\n\t// a fire-and-forget telemetry request at command start: while the loop is blocked that\n\t// request cannot progress, and its 1s abort then fires the moment the block ends, so it\n\t// is cancelled before ever being sent. `test` was the ONE local command missing from\n\t// the analytics, which is how this was found. Blocking also stops any other timer or\n\t// I/O the CLI may rely on later, so this is not only about telemetry.\n\tconst code = await new Promise<number>((resolve) =>\n\t{\n\t\t// One command STRING with shell:true, not a string plus an args array.\n\t\t//\n\t\t// DEP0190 (\"Passing args to a child process with shell option true can lead to\n\t\t// security vulnerabilities\") fires only for the args-array form, and it printed on\n\t\t// the very first command a new user runs — the word \"vulnerabilities\" on step one of\n\t\t// a tutorial is a bad look. Dropping the shell entirely was tried first and fails\n\t\t// with EINVAL: Node 24 refuses to spawn a Windows .cmd shim without one.\n\t\t//\n\t\t// No injection surface: the command is a fixed literal with no interpolation.\n\t\tconst child = spawn('npx vitest run', {\n\t\t\tstdio: 'inherit',\n\t\t\tcwd: process.cwd(),\n\t\t\tshell: true,\n\t\t});\n\t\tchild.on('error', () => resolve(1));\n\t\tchild.on('close', (status) => resolve(status ?? 1));\n\t});\n\n\tif (code !== 0)\n\t{\n\t\tprocess.exit(code);\n\t}\n}\n","/**\n * vibemancer fight\n *\n * With no args: fights your bot against all 29 built-in bots and shows ranking.\n * With --opponent: quick fight against a single opponent.\n *\n * Results are saved to .vibemancer/history.json for comparison across runs.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {BotBundle, sandboxFight, scoreFight, runBundleFight} from '@vibemancer/core';\nimport type {FightWinner, FightResult} from '@vibemancer/core';\nimport {formatBotErrors} from './fight-errors.js';\nimport {discoverBot} from '../bot-discovery.js';\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\n\nexport interface FightOptions\n{\n\topponent?: string;\n\tbot?: string;\n\tseed?: number;\n}\n\ninterface FightEntry\n{\n\topponent: string;\n\twinner: FightWinner;\n\twizard1Wins: number;\n\twizard2Wins: number;\n\tdraws: number;\n\tscore: number;\n\telapsedMs: number;\n}\n\ninterface HistoryEntry\n{\n\ttimestamp: string;\n\tbotName: string;\n\tresults: FightEntry[];\n\tsummary: {wins: number; losses: number; draws: number; score: number; maxScore: number};\n}\n\nexport async function runFight(options: FightOptions): Promise<void>\n{\n\tif (options.opponent)\n\t{\n\t\treturn runSingleFight({...options, opponent: options.opponent});\n\t}\n\treturn runFullFight(options);\n}\n\n// ─── Single opponent fight ───────────────────────────────────────────────────\n\nasync function runSingleFight(options: FightOptions & {opponent: string}): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\n\tconsole.log(` Opponent: ${options.opponent}\\n`);\n\n\tconst start = Date.now();\n\tlet result: FightResult;\n\tif (isHandleSelector(options.opponent))\n\t{\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\n\t\t// run locally through the same isolated-vm engine the matchmaker uses.\n\t\tconsole.log(' Resolving uploaded opponent...');\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\n\t\tresult = await runBundleFight(userBundle, remote.bundle, {seed: options.seed ?? 1});\n\t}\n\telse\n\t{\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\n\t\tresult = await sandboxFight(userBundle, opponentBundle, {\n\t\t\tseed: options.seed,\n\t\t\tcompileOptions: getCoreCompileOptions(),\n\t\t});\n\t}\n\tconst elapsed = Date.now() - start;\n\n\tconst {wizard1Wins, wizard2Wins, draws} = result;\n\tconst total = wizard1Wins + wizard2Wins + draws;\n\tconst outcome = result.winner === 'wizard-1' ? 'WIN'\n\t\t: result.winner === 'wizard-2' ? 'LOSS'\n\t\t\t: 'DRAW';\n\n\tconsole.log(` Result: ${outcome}`);\n\tconsole.log(` ${botInfo.exportName}: ${wizard1Wins}W | ${options.opponent}: ${wizard2Wins}W | Draws: ${draws}`);\n\tconsole.log(` (${total} matches in ${elapsed}ms)\\n`);\n\n\tfor (const line of formatBotErrors(result, botInfo.exportName, options.opponent)) console.log(line);\n\n\tif (result.winner === 'wizard-2')\n\t{\n\t\tprocess.exit(1);\n\t}\n}\n\n// ─── Full fight (all built-in bots) ─────────────────────────────────────────\n\nasync function runFullFight(options: FightOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\n\n\tconst opponents = getBuiltinBotNames();\n\tconsole.log(`\\n Fighting ${botInfo.exportName} against ${opponents.length} built-in bots...\\n`);\n\n\tconst entries: FightEntry[] = [];\n\tconst overallStart = Date.now();\n\n\tfor (const opponentName of opponents)\n\t{\n\t\tconst opponentBundle = resolveOpponent(opponentName);\n\t\tconst start = Date.now();\n\t\tconst result = await sandboxFight(userBundle, opponentBundle, {\n\t\t\tseed: options.seed,\n\t\t\tcompileOptions: getCoreCompileOptions(),\n\t\t});\n\t\tconst elapsed = Date.now() - start;\n\t\tconst score = scoreFight(result);\n\n\t\tentries.push({\n\t\t\topponent: opponentName,\n\t\t\twinner: result.winner,\n\t\t\twizard1Wins: result.wizard1Wins,\n\t\t\twizard2Wins: result.wizard2Wins,\n\t\t\tdraws: result.draws,\n\t\t\tscore,\n\t\t\telapsedMs: elapsed,\n\t\t});\n\n\t\tconst outcome = result.winner === 'wizard-1' ? 'W'\n\t\t\t: result.winner === 'wizard-2' ? 'L'\n\t\t\t\t: 'D';\n\t\tconst pad = opponentName.padEnd(14);\n\t\tconsole.log(` ${pad} ${outcome} ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${elapsed}ms)`);\n\t}\n\n\tconst totalElapsed = Date.now() - overallStart;\n\tconst wins = entries.filter((e) => e.winner === 'wizard-1').length;\n\tconst losses = entries.filter((e) => e.winner === 'wizard-2').length;\n\tconst drawCount = entries.filter((e) => e.winner === 'draw').length;\n\tconst totalScore = entries.reduce((sum, e) => sum + e.score, 0);\n\tconst maxScore = opponents.length * 17.5; // 5 matches × 3.5 max per match per opponent\n\n\tconsole.log(`\\n Summary: ${wins}W ${losses}L ${drawCount}D out of ${opponents.length} opponents`);\n\tconsole.log(` Score: ${totalScore.toFixed(1)} / ${maxScore.toFixed(1)} (${((totalScore / maxScore) * 100).toFixed(1)}%)`);\n\tconsole.log(` Total time: ${(totalElapsed / 1000).toFixed(1)}s`);\n\n\t// Load previous results and show diff\n\tconst history = loadHistory(projectDir);\n\tconst previous = history.length > 0 ? history[history.length - 1]! : null;\n\n\tif (previous && previous.botName === botInfo.exportName)\n\t{\n\t\tshowDiff(entries, previous.results);\n\t}\n\n\t// Save current results\n\tconst current: HistoryEntry = {\n\t\ttimestamp: new Date().toISOString(),\n\t\tbotName: botInfo.exportName,\n\t\tresults: entries,\n\t\tsummary: {wins, losses, draws: drawCount, score: totalScore, maxScore},\n\t};\n\tsaveHistory(projectDir, history, current);\n\tconsole.log('');\n}\n\n// ─── History persistence ─────────────────────────────────────────────────────\n\nfunction getHistoryPath(projectDir: string): string\n{\n\treturn path.join(projectDir, '.vibemancer', 'history.json');\n}\n\nfunction loadHistory(projectDir: string): HistoryEntry[]\n{\n\tconst historyPath = getHistoryPath(projectDir);\n\tif (!fs.existsSync(historyPath)) return [];\n\ttry\n\t{\n\t\tconst raw = fs.readFileSync(historyPath, 'utf-8');\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- JSON file we wrote\n\t\treturn JSON.parse(raw) as HistoryEntry[];\n\t}\n\tcatch\n\t{\n\t\treturn [];\n\t}\n}\n\nfunction saveHistory(projectDir: string, history: HistoryEntry[], current: HistoryEntry): void\n{\n\tconst historyPath = getHistoryPath(projectDir);\n\tconst dir = path.dirname(historyPath);\n\tfs.mkdirSync(dir, {recursive: true});\n\n\t// Keep last 20 runs\n\tconst updated = [...history.slice(-19), current];\n\tfs.writeFileSync(historyPath, JSON.stringify(updated, null, '\\t') + '\\n');\n}\n\nfunction showDiff(current: FightEntry[], previous: FightEntry[]): void\n{\n\tconst prevMap = new Map(previous.map((e) => [e.opponent, e]));\n\tconst changes: string[] = [];\n\n\tfor (const entry of current)\n\t{\n\t\tconst prev = prevMap.get(entry.opponent);\n\t\tif (!prev) continue;\n\n\t\tconst prevOutcome = prev.winner === 'wizard-1' ? 'W' : prev.winner === 'wizard-2' ? 'L' : 'D';\n\t\tconst curOutcome = entry.winner === 'wizard-1' ? 'W' : entry.winner === 'wizard-2' ? 'L' : 'D';\n\n\t\tif (prevOutcome !== curOutcome)\n\t\t{\n\t\t\tchanges.push(` ${entry.opponent.padEnd(14)} ${prevOutcome} -> ${curOutcome}`);\n\t\t}\n\t}\n\n\tconst prevScore = previous.reduce((sum, e) => sum + e.score, 0);\n\tconst curScore = current.reduce((sum, e) => sum + e.score, 0);\n\tconst diff = curScore - prevScore;\n\n\tif (changes.length > 0 || Math.abs(diff) > 0.1)\n\t{\n\t\tconsole.log('\\n vs last run:');\n\t\tif (Math.abs(diff) > 0.1)\n\t\t{\n\t\t\tconst sign = diff > 0 ? '+' : '';\n\t\t\tconsole.log(` Score: ${sign}${diff.toFixed(1)}`);\n\t\t}\n\t\tfor (const change of changes)\n\t\t{\n\t\t\tconsole.log(change);\n\t\t}\n\t}\n}\n","/**\n * Telling a CLI player that their bot threw.\n *\n * `vibemancer fight` printed `Result: DRAW` for a bot that threw on every one of 300,000\n * ticks, with no hint anything was wrong — the exact defect that cost a first-time player\n * four bisect fights on 2026-09-08. That was fixed in the MCP tools and never carried here,\n * even though every tool description points account-less players at this command: \"the\n * `vibemancer` CLI runs the same fight locally with no account\". It did not run the same\n * fight; it ran the same simulation with the fix missing.\n *\n * Kept as its own module so the formatting is testable without running a fight.\n */\n\n/** The shape this needs from a fight, structurally typed so tests need no engine. */\nexport interface FightErrorSource\n{\n\tallErrors?: ReadonlyArray<{tick: number; entityId: string; message: string}>;\n\tmatches?: ReadonlyArray<{errors?: ReadonlyArray<{tick: number; entityId: string; message: string}>}>;\n}\n\n/** At most this many distinct faults are listed; the rest are counted in a note. */\nconst MAX_SHOWN = 5;\n\n/**\n * Summarise, never dump: a bot that throws in tick 1 throws in all 30,000, across ten\n * matches. Identical messages collapse, keeping the first and last tick, because \"it broke\n * immediately\" and \"it broke after 4,000 ticks\" are different bugs.\n */\nexport function formatBotErrors(result: FightErrorSource, botName: string, opponentName: string): string[]\n{\n\t// allErrors covers all ten matches. `matches` holds only the five kept for playback, so\n\t// the fallback is strictly worse and exists only for an older core that lacks the field.\n\tconst errors = result.allErrors ?? (result.matches ?? []).flatMap((m) => m.errors ?? []);\n\tif (errors.length === 0) return [];\n\n\tconst byFault = new Map<string, {who: string; message: string; first: number; last: number; count: number}>();\n\tfor (const err of errors)\n\t{\n\t\t// A missile's throw is recorded against the projectile, whose id carries its owner.\n\t\t// Saying which of the two it was matters: a fault in your missile AI is a different\n\t\t// file from a fault in your tick function.\n\t\tconst owner = /^missile-(wizard-[12])-/.exec(err.entityId);\n\t\tconst side = owner ? owner[1]! : err.entityId;\n\t\tconst name = side === 'wizard-2' ? opponentName : botName;\n\t\tconst who = owner ? `${name} (in its missile AI)` : name;\n\t\tconst key = `${who} ${err.message}`;\n\n\t\tconst seen = byFault.get(key);\n\t\tif (!seen)\n\t\t{\n\t\t\tbyFault.set(key, {who, message: err.message, first: err.tick, last: err.tick, count: 1});\n\t\t\tcontinue;\n\t\t}\n\t\tseen.count++;\n\t\tif (err.tick < seen.first) seen.first = err.tick;\n\t\tif (err.tick > seen.last) seen.last = err.tick;\n\t}\n\n\tconst all = [...byFault.values()].sort((a, b) => b.count - a.count);\n\tconst out = [' BOT ERRORS — a bot that throws does nothing on that tick:'];\n\tfor (const f of all.slice(0, MAX_SHOWN))\n\t{\n\t\tconst span = f.first === f.last ? `tick ${f.first}` : `ticks ${f.first}-${f.last}`;\n\t\tout.push(` ${f.who}: ${f.message} (${span}, ${f.count}x)`);\n\t}\n\t// Never a silent cap: five shown out of nine must not read as nine.\n\tif (all.length > MAX_SHOWN) out.push(` … and ${all.length - MAX_SHOWN} more distinct error message(s) not shown`);\n\treturn out;\n}\n","/**\n * Resolve a `handle/botname` selector to a downloaded, ready-to-run opponent\n * bundle — so the devkit can fight any user's uploaded bot, identically to the\n * MCP fight tool and the live ladder.\n *\n * All reads are PUBLIC (no login): the wizards collection is world-readable and\n * compiled bundles in Storage are public (required for browser spectating), so\n * resolution + download need no auth. The fight then runs locally via core's\n * runBundleFight — the same isolated-vm engine the matchmaker uses.\n */\n\nimport {initializeApp, getApps, type FirebaseApp} from 'firebase/app';\nimport {getFirestore, collection, query, where, limit, getDocs, connectFirestoreEmulator, type Firestore} from 'firebase/firestore';\nimport {getStorage, ref, getBytes, connectStorageEmulator, type FirebaseStorage} from 'firebase/storage';\nimport {isBannedBotName} from '@vibemancer/core';\nimport {FIREBASE_CONFIG} from './firebase-config.js';\n\nexport interface RemoteOpponent\n{\n\tbundle: string;\n\texportName: string;\n\tlabel: string;\n}\n\n/** True when the opponent string is a `handle/botname` selector (vs a built-in name). */\nexport function isHandleSelector(opponent: string): boolean\n{\n\tconst trimmed = opponent.trim();\n\tconst slash = trimmed.indexOf('/');\n\treturn slash > 0 && slash < trimmed.length - 1;\n}\n\nlet cachedDb: Firestore | null = null;\nlet cachedStorage: FirebaseStorage | null = null;\n\nfunction getApp(): FirebaseApp\n{\n\tconst apps = getApps();\n\treturn apps.length > 0 ? apps[0]! : initializeApp(FIREBASE_CONFIG);\n}\n\n/** Talk to the local emulator instead of prod when VIBEMANCER_EMULATOR=1 (E2E tests). */\nfunction getDb(): Firestore\n{\n\tif (!cachedDb)\n\t{\n\t\tcachedDb = getFirestore(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectFirestoreEmulator(cachedDb, '127.0.0.1', 8085);\n\t}\n\treturn cachedDb;\n}\n\nfunction getBucket(): FirebaseStorage\n{\n\tif (!cachedStorage)\n\t{\n\t\tcachedStorage = getStorage(getApp());\n\t\tif (process.env.VIBEMANCER_EMULATOR === '1') connectStorageEmulator(cachedStorage, '127.0.0.1', 9199);\n\t}\n\treturn cachedStorage;\n}\n\nexport async function resolveRemoteOpponent(selector: string): Promise<RemoteOpponent>\n{\n\tconst slash = selector.indexOf('/');\n\tconst handle = selector.slice(0, slash).trim().toLowerCase();\n\tconst botName = selector.slice(slash + 1).trim();\n\tif (!handle || !botName)\n\t{\n\t\tthrow new Error(`Invalid opponent \"${selector}\" — expected handle/botname (e.g. happy-golden-banana/FireMage).`);\n\t}\n\t// A filtered (banned) name resolves to nothing — same message as not-found.\n\tif (isBannedBotName(botName))\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst db = getDb();\n\tconst snap = await getDocs(query(\n\t\tcollection(db, 'wizards'),\n\t\twhere('ownerHandle', '==', handle),\n\t\twhere('nameLower', '==', botName.toLowerCase()),\n\t\twhere('active', '==', true),\n\t\tlimit(1),\n\t));\n\tif (snap.empty)\n\t{\n\t\tthrow new Error(`No active bot \"${botName}\" found for handle \"${handle}\". Check the handle + bot name (both case-insensitive) on the leaderboard.`);\n\t}\n\n\tconst docSnap = snap.docs[0]!;\n\tconst data = docSnap.data() as {exportName?: unknown; bundlePath?: unknown};\n\tconst exportName = typeof data.exportName === 'string' ? data.exportName : '';\n\tif (!exportName)\n\t{\n\t\tthrow new Error(`Bot \"${handle}/${botName}\" is missing its export name.`);\n\t}\n\tconst bundlePath = typeof data.bundlePath === 'string' ? data.bundlePath : `bundles/${docSnap.id}.js`;\n\n\tconst bytes = await getBytes(ref(getBucket(), bundlePath));\n\tconst bundle = new TextDecoder().decode(bytes);\n\n\treturn {bundle, exportName, label: `${handle}/${botName}`};\n}\n","export const FIREBASE_CONFIG = {\n\tapiKey: 'AIzaSyDSUJ2jlk5_vlpGOypMtvqKjHhDmbgomIY',\n\tauthDomain: 'le-vibemancer.firebaseapp.com',\n\tprojectId: 'le-vibemancer',\n\tstorageBucket: 'le-vibemancer.firebasestorage.app',\n} as const;\n","/**\r\n * vibemancer trace\r\n *\r\n * Runs a single match and prints a full event trace for debugging.\r\n * Shows both bots' actions: state changes, missile launches (with config),\r\n * hits, damage, dodge proximity, movement patterns, and stats.\r\n */\r\n\r\nimport {\r\n\tBotBundle, sandboxSimulate, runBundleSimulate,\r\n\textractTraceEvents, summarizeTrace, formatTraceEvents, formatTraceSummary,\r\n\tdiagnoseTrace, formatDiagnosis,\r\n\textractStats, formatStats,\r\n} from '@vibemancer/core';\r\nimport type {SimulateResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getCoreCompileOptions} from '../opponent-resolver.js';\r\nimport {isHandleSelector, resolveRemoteOpponent} from '../remote-opponent.js';\r\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\r\n\r\nexport interface TraceOptions\r\n{\r\n\topponent: string;\r\n\tbot?: string;\r\n\tseed?: number;\r\n\tdistance?: number;\r\n\tmaxTicks?: number;\r\n}\r\n\r\nexport async function runTrace(options: TraceOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\r\n\tconst distance = options.distance ?? 600;\r\n\tconsole.log(`\\n Trace: ${botInfo.exportName} (W1) vs ${options.opponent} (W2) | distance: ${distance} | seed: ${options.seed ?? 1}\\n`);\r\n\r\n\tlet result: SimulateResult;\r\n\tif (isHandleSelector(options.opponent))\r\n\t{\r\n\t\t// Another user's uploaded bot: resolve + download its public bundle, then\r\n\t\t// simulate locally through the same engine the matchmaker uses.\r\n\t\tconsole.log(' Resolving uploaded opponent...');\r\n\t\tconst remote = await resolveRemoteOpponent(options.opponent);\r\n\t\tconst userBundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tresult = await runBundleSimulate(userBundle, remote.bundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t});\r\n\t}\r\n\telse\r\n\t{\r\n\t\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\t\tconst opponentBundle = resolveOpponent(options.opponent);\r\n\t\tresult = await sandboxSimulate(userBundle, opponentBundle, {\r\n\t\t\tseed: options.seed ?? 1,\r\n\t\t\tspawnDistance: distance,\r\n\t\t\tmaxTicks: options.maxTicks ?? 3000,\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t}\r\n\r\n\tconst history = result.history;\r\n\tif (history.length === 0)\r\n\t{\r\n\t\tconsole.log(' No history available.\\n');\r\n\t\treturn;\r\n\t}\r\n\r\n\t// Extract and print full event trace (including any bot runtime errors)\r\n\tconst events = extractTraceEvents(history, result.errors);\r\n\tconsole.log(formatTraceEvents(events));\r\n\r\n\t// Print summary (both bots)\r\n\tconst summary = summarizeTrace(events, result, botInfo.exportName, options.opponent);\r\n\tconsole.log('\\n' + formatTraceSummary(summary));\r\n\r\n\t// Print detailed stats for the user's bot\r\n\tconst stats = extractStats(result);\r\n\tconsole.log('');\r\n\tconsole.log(formatStats(stats, botInfo.exportName));\r\n\r\n\t// Print auto-diagnosis (tips for common problems)\r\n\tconst tips = diagnoseTrace(events, summary);\r\n\tif (tips.length > 0)\r\n\t{\r\n\t\tconsole.log('');\r\n\t\tconsole.log(formatDiagnosis(tips));\r\n\t}\r\n\tconsole.log('');\r\n}\r\n","/**\r\n * vibemancer tournament\r\n *\r\n * Runs the user's bot in a round-robin tournament against selected opponents.\r\n * Each pairing is a fight (10 matches: 5 spawn distances × 2 sides).\r\n */\r\n\r\nimport {BotBundle, sandboxFight, scoreFight, scoreFightAsWizard2} from '@vibemancer/core';\r\nimport type {FightResult} from '@vibemancer/core';\r\nimport {discoverBot} from '../bot-discovery.js';\r\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\r\n\r\nexport interface TournamentOptions\r\n{\r\n\topponents?: string[];\r\n\tbot?: string;\r\n}\r\n\r\ninterface Pairing\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tbot1Bundle: BotBundle;\r\n\tbot2Bundle: BotBundle;\r\n}\r\n\r\ninterface PairingResult\r\n{\r\n\tbot1Name: string;\r\n\tbot2Name: string;\r\n\tresult: FightResult;\r\n}\r\n\r\nexport async function runTournament(options: TournamentOptions): Promise<void>\r\n{\r\n\tconst projectDir = process.cwd();\r\n\tconst botInfo = await discoverBot(projectDir, options.bot);\r\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\r\n\r\n\t// Determine opponents\r\n\tconst opponentNames = options.opponents && options.opponents.length > 0\r\n\t\t? options.opponents\r\n\t\t: getBuiltinBotNames();\r\n\r\n\t// Build list of all participants\r\n\tconst participants: {name: string; bundle: BotBundle}[] = [\r\n\t\t{name: botInfo.exportName, bundle: userBundle},\r\n\t];\r\n\r\n\tfor (const name of opponentNames)\r\n\t{\r\n\t\tparticipants.push({name, bundle: resolveOpponent(name)});\r\n\t}\r\n\r\n\tconsole.log(`\\n Tournament: ${participants.length} participants (${participants.length * (participants.length - 1) / 2} pairings)\\n`);\r\n\r\n\t// Generate all pairings\r\n\tconst pairings: Pairing[] = [];\r\n\tfor (let i = 0; i < participants.length; i++)\r\n\t{\r\n\t\tfor (let j = i + 1; j < participants.length; j++)\r\n\t\t{\r\n\t\t\tpairings.push({\r\n\t\t\t\tbot1Name: participants[i]!.name,\r\n\t\t\t\tbot2Name: participants[j]!.name,\r\n\t\t\t\tbot1Bundle: participants[i]!.bundle,\r\n\t\t\t\tbot2Bundle: participants[j]!.bundle,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\r\n\t// Run all fights\r\n\tconst results: PairingResult[] = [];\r\n\tconst overallStart = Date.now();\r\n\r\n\tfor (const pairing of pairings)\r\n\t{\r\n\t\tconst result = await sandboxFight(pairing.bot1Bundle, pairing.bot2Bundle, {\r\n\t\t\tcompileOptions: getCoreCompileOptions(),\r\n\t\t});\r\n\t\tresults.push({\r\n\t\t\tbot1Name: pairing.bot1Name,\r\n\t\t\tbot2Name: pairing.bot2Name,\r\n\t\t\tresult,\r\n\t\t});\r\n\r\n\t\tconst outcome = result.winner === 'wizard-1' ? `${pairing.bot1Name} wins`\r\n\t\t\t: result.winner === 'wizard-2' ? `${pairing.bot2Name} wins`\r\n\t\t\t\t: 'Draw';\r\n\t\tconsole.log(` ${pairing.bot1Name} vs ${pairing.bot2Name}: ${result.wizard1Wins}-${result.wizard2Wins}-${result.draws} (${outcome})`);\r\n\t}\r\n\r\n\t// Calculate standings\r\n\tconst points = new Map<string, number>();\r\n\tconst wins = new Map<string, number>();\r\n\r\n\tfor (const p of participants)\r\n\t{\r\n\t\tpoints.set(p.name, 0);\r\n\t\twins.set(p.name, 0);\r\n\t}\r\n\r\n\tfor (const r of results)\r\n\t{\r\n\t\tconst score1 = scoreFight(r.result);\r\n\t\tconst score2 = scoreFightAsWizard2(r.result);\r\n\r\n\t\tpoints.set(r.bot1Name, (points.get(r.bot1Name) ?? 0) + score1);\r\n\t\tpoints.set(r.bot2Name, (points.get(r.bot2Name) ?? 0) + score2);\r\n\t\twins.set(r.bot1Name, (wins.get(r.bot1Name) ?? 0) + r.result.wizard1Wins);\r\n\t\twins.set(r.bot2Name, (wins.get(r.bot2Name) ?? 0) + r.result.wizard2Wins);\r\n\t}\r\n\r\n\tconst totalElapsed = Date.now() - overallStart;\r\n\r\n\t// Sort standings by points desc, then wins desc\r\n\tconst standings = [...points.entries()].sort((a, b) =>\r\n\t{\r\n\t\tif (b[1] !== a[1]) return b[1] - a[1];\r\n\t\treturn (wins.get(b[0]) ?? 0) - (wins.get(a[0]) ?? 0);\r\n\t});\r\n\r\n\tconsole.log('\\n Standings:');\r\n\tconsole.log(' ' + '-'.repeat(40));\r\n\tfor (let i = 0; i < standings.length; i++)\r\n\t{\r\n\t\tconst [name, pts] = standings[i]!;\r\n\t\tconst w = wins.get(name) ?? 0;\r\n\t\tconst rank = `#${(i + 1).toString().padStart(2)}`;\r\n\t\tconst isUser = name === botInfo.exportName ? ' *' : '';\r\n\t\tconsole.log(` ${rank} ${name.padEnd(16)} ${pts.toFixed(1)} pts ${w}W${isUser}`);\r\n\t}\r\n\r\n\tconsole.log(`\\n Total time: ${(totalElapsed / 1000).toFixed(1)}s\\n`);\r\n}\r\n","/**\n * vibemancer optimize\n *\n * Runs parameter optimization for the user's bot.\n * Scans for useParam() calls, runs coordinate descent against\n * all built-in opponents, and rewrites source with optimal values.\n */\n\nimport {readFileSync, writeFileSync} from 'node:fs';\nimport {BotBundle, MatchSandbox, scoreFight, generateCandidates, getEffectiveRange} from '@vibemancer/core';\nimport type {FightResult, FightWinner, SimulateResult, ParamDeclaration} from '@vibemancer/core';\nimport {discoverBot} from '../bot-discovery.js';\nimport {resolveOpponent, getBuiltinBotNames, getCoreCompileOptions} from '../opponent-resolver.js';\n\nexport interface OptimizeOptions\n{\n\tbot?: string;\n\tsteps?: number;\n\trounds?: number;\n\topponents?: string[];\n}\n\nexport interface ParsedParam\n{\n\tname: string;\n\tdefaultValue: number;\n\tmin?: number;\n\tmax?: number;\n\tstep?: number;\n}\n\n// Parser-style capture: grab everything until the next , or ) instead of matching specific number formats.\n// This handles integers, floats, scientific notation (1e-5), negative numbers, etc.\nconst USEPAR_RE = /useParam\\(\\s*['\"](\\w+)['\"]\\s*,\\s*([^,)]+?)\\s*(?:,\\s*\\{([^}]*)\\})?\\s*\\)/g;\n\nfunction parseNumValue(s: string): number\n{\n\tconst n = parseFloat(s.trim());\n\tif (Number.isNaN(n)) throw new Error(`useParam default is not a number: \"${s.trim()}\"`);\n\treturn n;\n}\n\nexport function parseParams(source: string): ParsedParam[]\n{\n\tconst params: ParsedParam[] = [];\n\tconst re = new RegExp(USEPAR_RE.source, 'g');\n\tlet match: RegExpExecArray | null;\n\n\twhile ((match = re.exec(source)) !== null)\n\t{\n\t\tconst name = match[1]!;\n\t\tconst defaultValue = parseNumValue(match[2]!);\n\t\tconst optsStr = match[3];\n\n\t\tlet min: number | undefined;\n\t\tlet max: number | undefined;\n\t\tlet step: number | undefined;\n\n\t\tif (optsStr)\n\t\t{\n\t\t\tconst minMatch = optsStr.match(/min\\s*:\\s*([^,}]+)/);\n\t\t\tconst maxMatch = optsStr.match(/max\\s*:\\s*([^,}]+)/);\n\t\t\tconst stepMatch = optsStr.match(/step\\s*:\\s*([^,}]+)/);\n\t\t\tif (minMatch) min = parseNumValue(minMatch[1]!);\n\t\t\tif (maxMatch) max = parseNumValue(maxMatch[1]!);\n\t\t\tif (stepMatch) step = parseNumValue(stepMatch[1]!);\n\t\t}\n\n\t\tparams.push({name, defaultValue, min, max, step});\n\t}\n\n\treturn params;\n}\n\nfunction toParamDeclaration(p: ParsedParam): ParamDeclaration\n{\n\treturn {\n\t\tname: p.name,\n\t\tvalue: p.defaultValue,\n\t\tmin: p.min,\n\t\tmax: p.max,\n\t\tsteps: p.step ?? 5,\n\t};\n}\n\n/**\n * Run a full fight (10 matches: 5 spawn distances × 2 sides)\n * using sandbox.simulate() with param overrides.\n */\nconst SPAWN_DISTANCES = [200, 300, 400, 500, 600];\nconst SEEDS = [42, 137, 256];\n\nfunction runFightWithParams(\n\tsandbox: MatchSandbox,\n\tparams1: Record<string, number>,\n): FightResult\n{\n\tlet w1 = 0;\n\tlet w2 = 0;\n\tlet draws = 0;\n\tconst matches: SimulateResult[] = [];\n\n\tfor (const seed of SEEDS)\n\t{\n\t\tfor (const dist of SPAWN_DISTANCES)\n\t\t{\n\t\t\tconst r = sandbox.simulate({\n\t\t\t\tseed,\n\t\t\t\tspawnDistance: dist,\n\t\t\t\tskipHistory: true,\n\t\t\t\tparams1,\n\t\t\t});\n\t\t\tif (r.winner === 'wizard-1') w1++;\n\t\t\telse if (r.winner === 'wizard-2') w2++;\n\t\t\telse draws++;\n\n\t\t\tmatches.push(r);\n\t\t}\n\t}\n\n\treturn {\n\t\twizard1Wins: w1,\n\t\twizard2Wins: w2,\n\t\tdraws,\n\t\twinner: (w1 > w2 ? 'wizard-1' : w2 > w1 ? 'wizard-2' : 'draw') as FightWinner,\n\t\tmatches,\n\t\t// The optimizer builds its own fight result rather than calling fight(), and it scores\n\t\t// on outcomes only — it never inspects errors. Collected anyway so the shape is honest:\n\t\t// an empty array here means \"this path records none\", not \"this bot never threw\".\n\t\tallErrors: matches.flatMap((m) => m.errors ?? []),\n\t};\n}\n\nasync function evaluateParams(\n\tuserBundle: BotBundle,\n\topponentBundles: BotBundle[],\n\tparams1: Record<string, number>,\n): Promise<number>\n{\n\tlet totalScore = 0;\n\tfor (const opponent of opponentBundles)\n\t{\n\t\tconst sandbox = await MatchSandbox.create(userBundle, opponent, {\n\t\t\tcompileOptions: getCoreCompileOptions(),\n\t\t});\n\t\ttry\n\t\t{\n\t\t\tconst result = runFightWithParams(sandbox, params1);\n\t\t\ttotalScore += scoreFight(result);\n\t\t}\n\t\tfinally\n\t\t{\n\t\t\tsandbox.dispose();\n\t\t}\n\t}\n\treturn totalScore;\n}\n\n/**\n * Resolve the opponent names to use for optimization.\n * If opponents are specified, validates them. Otherwise uses all built-in bots.\n */\nexport function resolveOpponentNames(opponents: string[] | undefined): string[]\n{\n\tif (!opponents || opponents.length === 0)\n\t{\n\t\treturn getBuiltinBotNames();\n\t}\n\n\t// Validate all names before starting\n\tconst allNames = getBuiltinBotNames();\n\tfor (const name of opponents)\n\t{\n\t\tif (!allNames.includes(name))\n\t\t{\n\t\t\tthrow new Error(\n\t\t\t\t`Unknown opponent: \"${name}\". Available bots:\\n ${allNames.join(', ')}`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn opponents;\n}\n\nexport async function runOptimize(options: OptimizeOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\n\tconst source = readFileSync(botInfo.sourcePath, 'utf-8');\n\tconst params = parseParams(source);\n\n\tif (params.length === 0)\n\t{\n\t\tconsole.log('\\n No useParam() calls found in your bot.');\n\t\tconsole.log(' Add useParam(\"paramName\", defaultValue, {min, max}) to enable optimization.\\n');\n\t\treturn;\n\t}\n\n\tconsole.log(`\\n Bot: ${botInfo.exportName}`);\n\tconsole.log(` Parameters: ${params.length}`);\n\tparams.forEach((p) => console.log(` ${p.name} = ${p.defaultValue} [${p.min ?? 'auto'} .. ${p.max ?? 'auto'}]`));\n\n\tconst steps = options.steps ?? 5;\n\tconst maxRounds = options.rounds ?? 3;\n\tconst opponentNames = resolveOpponentNames(options.opponents);\n\tconst opponentBundles = opponentNames.map((name) => resolveOpponent(name));\n\tconst userBundle = new BotBundle(botInfo.sourcePath, botInfo.exportName);\n\n\tconsole.log(` Opponents: ${opponentBundles.length}`);\n\tconsole.log(` Steps per param: ${steps}`);\n\tconsole.log(` Max rounds: ${maxRounds}\\n`);\n\n\t// Current best values\n\tconst best: Record<string, number> = {};\n\tfor (const p of params) best[p.name] = p.defaultValue;\n\n\t// Baseline score\n\tlet bestScore = await evaluateParams(userBundle, opponentBundles, best);\n\tconsole.log(` Baseline score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\n\n\t// Coordinate descent\n\tfor (let round = 0; round < maxRounds; round++)\n\t{\n\t\tlet improved = false;\n\t\tconsole.log(` Round ${round + 1}:`);\n\n\t\tfor (const p of params)\n\t\t{\n\t\t\tconst decl = toParamDeclaration(p);\n\t\t\tconst range = getEffectiveRange(decl);\n\t\t\tconst candidates = generateCandidates(range.min, range.max, steps);\n\n\t\t\tlet paramBest = best[p.name]!;\n\t\t\tlet paramBestScore = bestScore;\n\n\t\t\tfor (const candidate of candidates)\n\t\t\t{\n\t\t\t\tif (Math.abs(candidate - paramBest) < 0.001) continue;\n\n\t\t\t\tconst trial = {...best, [p.name]: candidate};\n\t\t\t\tconst score = await evaluateParams(userBundle, opponentBundles, trial);\n\n\t\t\t\tif (score > paramBestScore)\n\t\t\t\t{\n\t\t\t\t\tparamBest = candidate;\n\t\t\t\t\tparamBestScore = score;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (paramBest !== best[p.name])\n\t\t\t{\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} -> ${paramBest} (+${(paramBestScore - bestScore).toFixed(1)})`);\n\t\t\t\tbest[p.name] = paramBest;\n\t\t\t\tbestScore = paramBestScore;\n\t\t\t\timproved = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconsole.log(` ${p.name}: ${best[p.name]} (no improvement)`);\n\t\t\t}\n\t\t}\n\n\t\tif (!improved)\n\t\t{\n\t\t\tconsole.log(' No improvements found, stopping.\\n');\n\t\t\tbreak;\n\t\t}\n\t\tconsole.log(` Round ${round + 1} score: ${bestScore.toFixed(1)}\\n`);\n\t}\n\n\t// Rewrite source\n\tlet updated = source;\n\tfor (const p of params)\n\t{\n\t\tconst newVal = best[p.name]!;\n\t\tif (newVal !== p.defaultValue)\n\t\t{\n\t\t\tconst pattern = new RegExp(\n\t\t\t\t`(useParam\\\\(\\\\s*['\"]${escapeRegex(p.name)}['\"]\\\\s*,\\\\s*)${escapeRegex(String(p.defaultValue))}`,\n\t\t\t);\n\t\t\tupdated = updated.replace(pattern, `$1${newVal}`);\n\t\t}\n\t}\n\n\tif (updated !== source)\n\t{\n\t\twriteFileSync(botInfo.sourcePath, updated);\n\t\tconsole.log(` Source updated: ${botInfo.sourcePath}`);\n\t}\n\telse\n\t{\n\t\tconsole.log(' No parameter changes to write.');\n\t}\n\n\tconsole.log(` Final score: ${bestScore.toFixed(1)} / ${(opponentBundles.length * SPAWN_DISTANCES.length * SEEDS.length * 3.5).toFixed(1)}\\n`);\n}\n\nfunction escapeRegex(s: string): string\n{\n\treturn s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\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\t// The order is round-robin POINTS (every bot vs every bot), not a prediction about\r\n\t// your bot. Matchups are non-transitive: a low-ranked bot with the right archetype\r\n\t// can beat you while a higher-ranked one cannot. Saying so stops the ladder being\r\n\t// read as difficulty-for-you, which is exactly how it misled a newcomer.\r\n\tconsole.log('\\n Built-in Bots (29 total, by round-robin points — weakest first)');\r\n\tconsole.log(' Matchups are non-transitive: a low-ranked bot may still counter yours.\\n');\r\n\r\n\tfor (const group of BOT_GROUPS)\r\n\t{\r\n\t\tconsole.log(` ${group.label}:`);\r\n\t\tfor (const bot of group.bots)\r\n\t\t{\r\n\t\t\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\t\t\tconst tierLabel = bot.tier ? `T${bot.tier}` : ' ';\r\n\t\t\tconst rankStr = `#${String(rank).padStart(2)}`;\r\n\t\t\tconsole.log(` ${rankStr} ${tierLabel} ${bot.name.padEnd(14)} ${bot.description}`);\r\n\t\t}\r\n\t\tconsole.log('');\r\n\t}\r\n}\r\n\r\nfunction showBotDetail(name: string): void\r\n{\r\n\tconst bot = ALL_BOTS.find((b) => b.name.toLowerCase() === name.toLowerCase());\r\n\tif (!bot)\r\n\t{\r\n\t\tconst available = ALL_BOTS.map((b) => b.name).join(', ');\r\n\t\tconsole.error(`\\n Unknown bot: \"${name}\"\\n Available: ${available}\\n`);\r\n\t\tprocess.exit(1);\r\n\t}\r\n\r\n\tconst rank = ALL_BOTS.indexOf(bot) + 1;\r\n\r\n\tconsole.log(`\\n ${bot.name}`);\r\n\tconsole.log(` ${'─'.repeat(40)}`);\r\n\tconsole.log(` Rank: #${rank} of ${ALL_BOTS.length}`);\r\n\tconsole.log(` Group: ${bot.group}`);\r\n\tif (bot.tier) console.log(` Tier: ${bot.tier} of 3`);\r\n\tconsole.log(` Description: ${bot.description}`);\r\n\tconsole.log(` Style: ${getStyleDescription(bot)}`);\r\n\r\n\t// Show group progression if tiered\r\n\tif (bot.tier && bot.group !== 'Standalone')\r\n\t{\r\n\t\tconst groupBots = BOT_GROUPS.find((g) => g.label === bot.group)?.bots ?? [];\r\n\t\tif (groupBots.length > 1)\r\n\t\t{\r\n\t\t\tconsole.log(`\\n ${bot.group} progression:`);\r\n\t\t\tfor (const gb of groupBots)\r\n\t\t\t{\r\n\t\t\t\tconst gbRank = ALL_BOTS.indexOf(gb) + 1;\r\n\t\t\t\tconst marker = gb.name === bot.name ? ' ←' : '';\r\n\t\t\t\tconsole.log(` T${gb.tier} ${gb.name.padEnd(14)} #${gbRank} — ${gb.description}${marker}`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tconsole.log(`\\n To fight: vibemancer fight --opponent ${bot.name}`);\r\n\tconsole.log(` To trace: vibemancer trace --opponent ${bot.name}\\n`);\r\n}\r\n\r\nfunction getStyleDescription(bot: WizardEntry): string\r\n{\r\n\tswitch (bot.group)\r\n\t{\r\n\t\tcase 'Standalone':\r\n\t\t\tif (bot.name === 'TargetDummy') return 'Does nothing. Use for basic testing.';\r\n\t\t\tif (bot.name === 'Critter') return 'Random actions. Tests handling of unpredictable opponents.';\r\n\t\t\tif (bot.name === 'Rookie') return 'Simple homing missiles. Good first benchmark.';\r\n\t\t\tif (bot.name === 'Hogger') return 'Random but with real damage. Chaos test.';\r\n\t\t\tif (bot.name === 'Doombringer') return 'One huge missile. Tests shield timing.';\r\n\t\t\treturn bot.description;\r\n\t\tcase 'Defensive': return 'Prioritizes shields and survival. Punishes aggression with counter-missiles. Weak to chip damage and shield baiting.';\r\n\t\tcase 'Melee': return 'Blinks in close, fires fast low-range stabs. Weak to kiting and ranged pressure.';\r\n\t\tcase 'Homing': return 'Slow tracking missiles that are hard to dodge. Weak to shields and fast burst.';\r\n\t\tcase 'Caster': return 'Medium-range homing with adaptive missile fitting. Balanced offense and defense.';\r\n\t\tcase 'Sniper': return 'Intercept-predicted straight shots. High accuracy, weak to erratic movement.';\r\n\t\tcase 'Duelist': return 'Close-range fighters with balanced offense/defense. Jack of all trades.';\r\n\t\tcase 'Berserker': return 'Aggressive traders who close distance fast. Weak to kiting and strong defense.';\r\n\t\tcase 'Kiter': return 'Maintains distance while firing homing missiles. Weak to fast closers and blink gap-close.';\r\n\t\tdefault: return bot.description;\r\n\t}\r\n}\r\n","/**\n * vibemancer upload\n *\n * Compiles the user's bot into a standalone bundle and uploads it to Vibemancer\n * via the authed gateway (`POST /api/upload`), owned by the canonical Firebase\n * identity from `vibemancer login`. The server validates + dedupes; if the same\n * code was uploaded before, the old wizard is reactivated (rating/history kept).\n */\n\nimport fs from 'node:fs';\nimport {discoverBot} from '../bot-discovery.js';\nimport {compileSingleBotBundle} from '../compile-single-bot.js';\nimport {uploadBot} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface UploadOptions\n{\n\tbot?: string;\n}\n\nconst MAX_BUNDLE_BYTES = 500 * 1024;\n\nexport async function runUpload(options: UploadOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\tconst botInfo = await discoverBot(projectDir, options.bot);\n\n\tconsole.log(`\\n Compiling ${botInfo.exportName}...`);\n\tconst bundle = await compileSingleBotBundle(botInfo.sourcePath, botInfo.exportName);\n\tconst sizeKb = (bundle.length / 1024).toFixed(1);\n\tconsole.log(` Bundle: ${sizeKb} KB`);\n\n\tif (bundle.length > MAX_BUNDLE_BYTES)\n\t{\n\t\tconsole.error(` Error: Bundle too large (${sizeKb} KB). Max ${MAX_BUNDLE_BYTES / 1024} KB.`);\n\t\tprocess.exit(1);\n\t}\n\n\tlet sourceCode = '';\n\ttry\n\t{\n\t\tsourceCode = fs.readFileSync(botInfo.sourcePath, 'utf-8');\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — source storage is optional\n\t}\n\n\tconsole.log(` Wizard: ${botInfo.exportName}`);\n\tconsole.log(' Uploading to Vibemancer...');\n\n\ttry\n\t{\n\t\tconst result = await uploadBot({\n\t\t\tbundle,\n\t\t\tname: botInfo.exportName,\n\t\t\texportName: botInfo.exportName,\n\t\t\tsourceCode,\n\t\t});\n\t\tconsole.log(` ✓ ${result.message}`);\n\t\tif (result.wizardId) console.log(` Wizard ID: ${result.wizardId}`);\n\t\tconsole.log(` Your wizard \"${botInfo.exportName}\" is now competing.\\n`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` ✗ Upload failed: ${err instanceof Error ? err.message : String(err)}\\n`);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * Environment headers the CLI attaches to requests it ALREADY makes, so the server can\n * answer \"which OS are CLI users on\" and \"MCP vs CLI\" without the CLI issuing a single\n * extra outbound request. See docs/decisions/0001-usage-analytics-bigquery.md.\n *\n * Deliberately narrow: platform, release, arch, node version, CLI version. No username,\n * no hostname, no paths — none of which we need, and all of which would be a liability.\n */\n\nimport os from 'node:os';\nimport {readFileSync} from 'node:fs';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\n/**\n * Walk upwards from `here` looking for this package's own manifest.\n *\n * The try/catch sits INSIDE the loop deliberately. With one try around the whole loop, the\n * first candidate that does not exist aborted the entire search — which is what happens in\n * every built layout (`dist/cli.js` has nothing two levels up) and in every published\n * install. The result was a CLI that reported no version at all, invisible in the tests\n * because the SOURCE layout happens to match the first candidate, and only visible as a\n * column of nulls in the analytics.\n *\n * Exported so the layouts can be exercised directly rather than only the one the tests\n * happen to run in.\n */\nexport function findCliVersionFrom(here: string): string\n{\n\tfor (const rel of ['../../package.json', '../package.json', '../../../package.json'])\n\t{\n\t\ttry\n\t\t{\n\t\t\tconst parsed: unknown = JSON.parse(readFileSync(path.resolve(here, rel), 'utf8'));\n\t\t\tif (typeof parsed !== 'object' || parsed === null) continue;\n\t\t\tif (!('name' in parsed) || !('version' in parsed)) continue;\n\t\t\tconst {name, version} = parsed;\n\t\t\tif (name === 'vibemancer' && typeof version === 'string') return version;\n\t\t}\n\t\tcatch\n\t\t{\n\t\t\t// A candidate that is missing or unreadable is ordinary; try the next one.\n\t\t}\n\t}\n\treturn '';\n}\n\nfunction readCliVersion(): string\n{\n\ttry\n\t{\n\t\treturn findCliVersionFrom(path.dirname(fileURLToPath(import.meta.url)));\n\t}\n\tcatch\n\t{\n\t\t// Version is nice-to-have; never worth failing a command over.\n\t\treturn '';\n\t}\n}\n\n/**\n * Build the telemetry headers. Pure given its inputs so it can be tested without touching\n * the real environment.\n */\nexport function buildEnvHeaders(env: {\n\tplatform: string;\n\trelease: string;\n\tarch: string;\n\tnodeVersion: string;\n\tcliVersion: string;\n}): Record<string, string>\n{\n\tconst headers: Record<string, string> = {};\n\tconst put = (key: string, value: string): void =>\n\t{\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed) headers[key] = trimmed.slice(0, 64);\n\t};\n\tput('x-vibemancer-os', env.platform);\n\tput('x-vibemancer-os-release', env.release);\n\tput('x-vibemancer-arch', env.arch);\n\tput('x-vibemancer-node', env.nodeVersion);\n\tput('x-vibemancer-cli', env.cliVersion);\n\treturn headers;\n}\n\n/** The headers for THIS machine. */\nexport function envHeaders(): Record<string, string>\n{\n\ttry\n\t{\n\t\treturn buildEnvHeaders({\n\t\t\tplatform: os.platform(),\n\t\t\trelease: os.release(),\n\t\t\tarch: os.arch(),\n\t\t\tnodeVersion: process.version,\n\t\t\tcliVersion: readCliVersion(),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\treturn {};\n\t}\n}\n","/**\n * Client for the authed gateway REST endpoints. Attaches the Bearer session\n * token (carrying the canonical Firebase uid) and parses responses. This is the\n * single network path the CLI uses to upload + pull.\n */\n\nimport {getAccessToken, MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\nexport interface UploadPayload\n{\n\tbundle: string;\n\tname: string;\n\texportName: string;\n\tsourceCode: string;\n}\n\nexport interface UploadResult\n{\n\twizardId: string;\n\tmessage: string;\n}\n\nexport async function uploadBot(payload: UploadPayload): Promise<UploadResult>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/upload`, {\n\t\tmethod: 'POST',\n\t\t// Environment headers ride along on a request already being made — no extra call.\n\t\theaders: {'Content-Type': 'application/json', Authorization: `Bearer ${token}`, ...envHeaders()},\n\t\tbody: JSON.stringify(payload),\n\t});\n\tif (!res.ok) throw new Error(`Upload failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst wizardId = typeof data === 'object' && data !== null && 'wizardId' in data && typeof data.wizardId === 'string'\n\t\t? data.wizardId\n\t\t: '';\n\tconst message = typeof data === 'object' && data !== null && 'message' in data && typeof data.message === 'string'\n\t\t? data.message\n\t\t: 'Uploaded.';\n\treturn {wizardId, message};\n}\n\nexport async function pullSource(name: string): Promise<string>\n{\n\tconst token = await getAccessToken();\n\tconst res = await fetch(`${MCP_BASE_URL}/api/pull?name=${encodeURIComponent(name)}`, {\n\t\theaders: {Authorization: `Bearer ${token}`, ...envHeaders()},\n\t});\n\tif (!res.ok) throw new Error(`Pull failed (${res.status}): ${await res.text()}`);\n\tconst data: unknown = await res.json();\n\tconst source = typeof data === 'object' && data !== null && 'sourceCode' in data && typeof data.sourceCode === 'string'\n\t\t? data.sourceCode\n\t\t: '';\n\tif (source) return source;\n\tconst error = typeof data === 'object' && data !== null && 'error' in data && typeof data.error === 'string'\n\t\t? data.error\n\t\t: 'No source returned.';\n\tthrow new Error(error);\n}\n","/**\n * vibemancer pull\n *\n * Downloads the latest source of your active wizard (by export name) from the\n * authed gateway (`GET /api/pull`) and writes it to the local bot file. Enables\n * round-tripping between MCP chat sessions and local CLI development.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {discoverBot} from '../bot-discovery.js';\nimport {pullSource} from '../auth/gateway-client.js';\nimport {NotLoggedInError} from '../auth/oauth-client.js';\n\nexport interface PullOptions\n{\n\tbot?: string;\n}\n\nexport async function runPull(options: PullOptions): Promise<void>\n{\n\tconst projectDir = process.cwd();\n\t// pull RESTORES source, so the file legitimately may not exist yet — a new machine, a\n\t// fresh clone, or a bot authored in an MCP chat session. See DiscoverOptions.\n\tconst botInfo = await discoverBot(projectDir, options.bot, {allowMissingFile: true});\n\tconst isNew = !fs.existsSync(botInfo.sourcePath);\n\n\tconsole.log(`\\n Pulling latest source for ${botInfo.exportName}...`);\n\n\ttry\n\t{\n\t\tconst sourceCode = await pullSource(botInfo.exportName);\n\t\t// On a fresh machine the containing directory (src/) may not exist either.\n\t\tfs.mkdirSync(path.dirname(botInfo.sourcePath), {recursive: true});\n\t\tfs.writeFileSync(botInfo.sourcePath, sourceCode);\n\t\tconsole.log(` ✓ ${isNew ? 'Created' : 'Updated'} ${botInfo.sourcePath}`);\n\t\tconsole.log(` ${(sourceCode.length / 1024).toFixed(1)} KB written`);\n\t}\n\tcatch(err)\n\t{\n\t\tif (err instanceof NotLoggedInError)\n\t\t{\n\t\t\tconsole.error('\\n Not logged in. Run: vibemancer login\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconsole.error(` Pull failed: ${err instanceof Error ? err.message : String(err)}`);\n\t\t\tconsole.error(' Upload first with: vibemancer upload\\n');\n\t\t}\n\t\tprocess.exit(1);\n\t}\n}\n","/**\n * vibemancer login\n *\n * Authenticates the CLI as an OAuth client of the MCP gateway. The resulting\n * session token carries the canonical Firebase uid (the same identity the web\n * and MCP use), so uploads from the CLI are owned by the same account.\n *\n * Default: browser loopback (a localhost server catches the redirect).\n * `--no-browser`: print the URL + paste the code shown on the gateway page.\n */\n\nimport {createServer, type IncomingMessage, type ServerResponse} from 'node:http';\nimport {randomBytes} from 'node:crypto';\nimport {spawn} from 'node:child_process';\nimport {createInterface} from 'node:readline/promises';\nimport {generatePkce, registerClient, exchangeCode, MCP_BASE_URL} from '../auth/oauth-client.js';\n\nexport interface LoginOptions\n{\n\tnoBrowser?: boolean;\n}\n\nexport function buildAuthorizeUrl(\n\tbaseUrl: string,\n\tparams: {clientId: string; redirectUri: string; challenge: string; state: string},\n): string\n{\n\tconst u = new URL(`${baseUrl}/authorize`);\n\tu.searchParams.set('response_type', 'code');\n\tu.searchParams.set('client_id', params.clientId);\n\tu.searchParams.set('redirect_uri', params.redirectUri);\n\tu.searchParams.set('code_challenge', params.challenge);\n\tu.searchParams.set('code_challenge_method', 'S256');\n\tu.searchParams.set('state', params.state);\n\treturn u.toString();\n}\n\nexport function extractCodeFromCallback(reqUrl: string, expectedState: string): {code: string} | {error: string}\n{\n\tconst u = new URL(reqUrl, 'http://localhost');\n\tconst code = u.searchParams.get('code');\n\tconst state = u.searchParams.get('state');\n\tif (!code) return {error: 'No authorization code in the callback.'};\n\tif (state !== expectedState) return {error: 'State mismatch (possible CSRF) — try again.'};\n\treturn {code};\n}\n\nfunction openBrowser(url: string): void\n{\n\ttry\n\t{\n\t\tconst child = process.platform === 'win32'\n\t\t\t? spawn('cmd', ['/c', 'start', '', url], {stdio: 'ignore', detached: true})\n\t\t\t: spawn(process.platform === 'darwin' ? 'open' : 'xdg-open', [url], {stdio: 'ignore', detached: true});\n\t\tchild.unref();\n\t}\n\tcatch\n\t{\n\t\t// non-fatal — the URL is also printed for manual opening\n\t}\n}\n\ninterface LoopbackServer\n{\n\tport: number;\n\twaitForCode: Promise<string>;\n\tclose: () => void;\n}\n\nfunction startLoopbackServer(expectedState: string): Promise<LoopbackServer>\n{\n\treturn new Promise((resolveServer) =>\n\t{\n\t\tlet resolveCode: (code: string) => void = () => undefined;\n\t\tlet rejectCode: (err: Error) => void = () => undefined;\n\t\tconst waitForCode = new Promise<string>((res, rej) =>\n\t\t{\n\t\t\tresolveCode = res;\n\t\t\trejectCode = rej;\n\t\t});\n\n\t\tconst server = createServer((req: IncomingMessage, res: ServerResponse) =>\n\t\t{\n\t\t\tconst result = extractCodeFromCallback(req.url ?? '', expectedState);\n\t\t\tif ('error' in result)\n\t\t\t{\n\t\t\t\tres.writeHead(400, {'Content-Type': 'text/html'});\n\t\t\t\tres.end('<h2>Login failed</h2><p>You can close this tab and try again.</p>');\n\t\t\t\trejectCode(new Error(result.error));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.writeHead(200, {'Content-Type': 'text/html'});\n\t\t\tres.end('<h2>Vibemancer login complete</h2><p>You can close this tab and return to the terminal.</p>');\n\t\t\tresolveCode(result.code);\n\t\t});\n\n\t\tserver.listen(0, '127.0.0.1', () =>\n\t\t{\n\t\t\tconst addr = server.address();\n\t\t\tconst port = typeof addr === 'object' && addr !== null ? addr.port : 0;\n\t\t\tresolveServer({port, waitForCode, close: () => server.close()});\n\t\t});\n\t});\n}\n\nasync function runBrowserLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst {port, waitForCode, close} = await startLoopbackServer(state);\n\tconst redirectUri = `http://localhost:${port}/callback`;\n\ttry\n\t{\n\t\tconst clientId = await registerClient(redirectUri);\n\t\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\t\tconsole.log('\\n Opening your browser to sign in with Google...');\n\t\tconsole.log(` If it doesn't open, visit:\\n ${authUrl}\\n`);\n\t\topenBrowser(authUrl);\n\t\tconst code = await waitForCode;\n\t\tawait exchangeCode(code, verifier);\n\t\tconsole.log(' ✓ Logged in. You can now run `vibemancer upload`.\\n');\n\t}\n\tfinally\n\t{\n\t\tclose();\n\t}\n}\n\nasync function runPasteLogin(challenge: string, verifier: string, state: string): Promise<void>\n{\n\tconst redirectUri = `${MCP_BASE_URL}/cli-code`;\n\tconst clientId = await registerClient(redirectUri);\n\tconst authUrl = buildAuthorizeUrl(MCP_BASE_URL, {clientId, redirectUri, challenge, state});\n\tconsole.log('\\n Open this URL in a browser, sign in, then paste the code shown:\\n');\n\tconsole.log(` ${authUrl}\\n`);\n\tconst rl = createInterface({input: process.stdin, output: process.stdout});\n\tconst code = (await rl.question(' Paste code: ')).trim();\n\trl.close();\n\tif (!code)\n\t{\n\t\tconsole.error(' No code entered.');\n\t\tprocess.exit(1);\n\t}\n\tawait exchangeCode(code, verifier);\n\tconsole.log(' ✓ Logged in.\\n');\n}\n\nexport async function runLogin(options: LoginOptions): Promise<void>\n{\n\tconst {verifier, challenge} = generatePkce();\n\tconst state = randomBytes(16).toString('hex');\n\tif (options.noBrowser)\n\t{\n\t\tawait runPasteLogin(challenge, verifier, state);\n\t}\n\telse\n\t{\n\t\tawait runBrowserLogin(challenge, verifier, state);\n\t}\n}\n","/**\n * Server-side session revocation for the CLI.\n *\n * `clearCredentials()` only deletes the local file; the refresh token stayed valid on the\n * gateway for the rest of its 30 days, so a copied token survived a logout. This calls\n * the gateway so the session actually ends.\n *\n * Best-effort by design: it reports failure rather than throwing, because the local\n * credentials must still be cleared when the network is down — or when the user is\n * logging out precisely because something has gone wrong.\n */\n\nimport {MCP_BASE_URL} from './oauth-client.js';\n\n/** Revoke the session behind `token`. Returns whether the gateway confirmed it. */\nexport async function revokeSession(token: string): Promise<boolean>\n{\n\tif (!token) return false;\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/revoke`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json'},\n\t\t\tbody: JSON.stringify({token}),\n\t\t});\n\t\treturn res.ok;\n\t}\n\tcatch\n\t{\n\t\treturn false;\n\t}\n}\n","/**\n * vibemancer logout — end the session, then clear the cached OAuth credentials.\n *\n * Clearing the local file alone used to leave the refresh token valid on the gateway for\n * the rest of its 30 days, so a copied credential survived a logout. The revoke call is\n * best-effort: the local credentials are cleared either way, because a user with no\n * network — or one logging out BECAUSE something is wrong — must still be able to get\n * their credentials off the machine.\n */\n\nimport {clearCredentials, loadCredentials} from '../auth/credentials-store.js';\nimport {revokeSession} from '../auth/revoke.js';\n\nexport async function runLogout(): Promise<void>\n{\n\tconst credentials = loadCredentials();\n\tconst revoked = credentials ? await revokeSession(credentials.accessToken) : false;\n\n\tclearCredentials();\n\n\tif (credentials && !revoked)\n\t{\n\t\tconsole.log(' Logged out locally, but the server could not be reached to end the session.');\n\t\tconsole.log(' Run `vibemancer logout` again while online to revoke it.');\n\t\treturn;\n\t}\n\tconsole.log(' Logged out.');\n}\n","/**\n * vibemancer feedback \"what went wrong\"\n *\n * Posts to the PUBLIC `/feedback` endpoint — the same one the web page documents, which\n * needs no account at all.\n *\n * It used to call the `submitFeedback` Firebase callable from a bare `initializeApp`, with\n * no credential attached: no Firebase Auth session, and not the gateway JWT that `login`\n * caches. The callable requires `request.auth`, so the command answered \"Sign in to submit\n * feedback\" to everyone — including users who were signed in. It could not succeed for\n * anybody, and had been that way since CLI auth moved to the MCP gateway.\n *\n * A cached token is attached when there is one, so a signed-in report stays attributable.\n * Its absence never blocks the report: the endpoint exists precisely so that someone whose\n * sign-in is broken can tell us that, and requiring a token here would rebuild the dead end.\n */\n\nimport {MCP_BASE_URL} from '../auth/oauth-client.js';\nimport {envHeaders} from '../auth/env-headers.js';\n\nexport interface FeedbackOptions\n{\n\tmessage: string;\n}\n\n/** Resolve the cached access token, or null when not signed in. Injected for testing. */\nexport type TokenLookup = () => Promise<string | null>;\n\nasync function defaultTokenLookup(): Promise<string | null>\n{\n\tconst {getAccessToken} = await import('../auth/oauth-client.js');\n\treturn await getAccessToken();\n}\n\nexport async function runFeedback(options: FeedbackOptions, tokenLookup: TokenLookup = defaultTokenLookup): Promise<void>\n{\n\tconst message = options.message.trim();\n\tif (!message)\n\t{\n\t\tconsole.error(' Error: feedback message cannot be empty.');\n\t\tprocess.exit(1);\n\t\treturn;\n\t}\n\n\tconsole.log('\\n Submitting feedback...');\n\n\t// Best effort. Not being signed in is the NORMAL case for a bug report about signing in.\n\tlet token: string | null;\n\ttry\n\t{\n\t\ttoken = await tokenLookup();\n\t}\n\tcatch\n\t{\n\t\t// No cached credential, or a refresh that failed. Neither is a reason to drop a\n\t\t// bug report — especially one that might be about signing in.\n\t\ttoken = null;\n\t}\n\n\tconst headers: Record<string, string> = {'Content-Type': 'application/json', ...envHeaders()};\n\tif (token) headers.Authorization = `Bearer ${token}`;\n\n\ttry\n\t{\n\t\tconst res = await fetch(`${MCP_BASE_URL}/feedback`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify({message}),\n\t\t\tsignal: AbortSignal.timeout(15_000),\n\t\t});\n\n\t\tif (!res.ok)\n\t\t{\n\t\t\tconst body = await res.text();\n\t\t\tlet detail = body;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tconst parsed: unknown = JSON.parse(body);\n\t\t\t\tif (typeof parsed === 'object' && parsed !== null && 'error' in parsed)\n\t\t\t\t{\n\t\t\t\t\tdetail = String((parsed as {error: unknown}).error);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch\n\t\t\t{\n\t\t\t\t// Keep the raw body; a non-JSON error is still worth showing.\n\t\t\t}\n\t\t\tconsole.error(` Failed to submit: ${detail}\\n`);\n\t\t\tprocess.exit(1);\n\t\t\treturn;\n\t\t}\n\n\t\t// `token` is only a SIGN-IN INDICATOR here - the value is never printed. Naming that\n\t\t// intention reads better, and it also stops a PII-in-logs scanner from reading this\n\t\t// call as a credential leak, which it otherwise does.\n\t\tconst signedIn = token !== null;\n\t\tconsole.log(signedIn\n\t\t\t? ' Sent! Thanks for the feedback.\\n'\n\t\t\t: ' Sent! Thanks for the feedback. (Not signed in, so we have no way to reply.)\\n');\n\t}\n\tcatch(err: unknown)\n\t{\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tconsole.error(` Failed to submit: ${msg}\\n`);\n\t\tprocess.exit(1);\n\t}\n}\n","import {calculateMissileCastTime, GCD_DURATION, TICKS_PER_SECOND, calculateMissileRadius} from '@vibemancer/core';\n\nexport interface MissileCalcOptions\n{\n\tdamage: number;\n\tspeed: number;\n\tduration: number;\n\tturnRate: number;\n}\n\nexport function runMissileCalc(options: MissileCalcOptions): void\n{\n\tconst config = {\n\t\tdamage: options.damage,\n\t\tspeed: options.speed,\n\t\tduration: options.duration,\n\t\tturnRate: options.turnRate,\n\t};\n\n\tconst castTimeSec = calculateMissileCastTime(config);\n\tconst castFrames = Math.max(1, Math.round(castTimeSec * TICKS_PER_SECOND));\n\tconst gcdSec = GCD_DURATION / TICKS_PER_SECOND;\n\tconst totalCycleSec = castTimeSec + gcdSec;\n\tconst dps = config.damage / totalCycleSec;\n\tconst range = config.speed * config.duration;\n\tconst radius = calculateMissileRadius(config.damage);\n\n\tconsole.log(`\n Missile Calculator\n ──────────────────\n Config: damage=${config.damage} speed=${config.speed} duration=${config.duration} turnRate=${config.turnRate}\n Cast time: ${castTimeSec.toFixed(3)}s (${castFrames} frames)\n GCD: ${gcdSec}s (${GCD_DURATION} frames)\n Full cycle: ${totalCycleSec.toFixed(3)}s (cast + GCD)\n Eff. DPS: ${dps.toFixed(2)} HP/s\n Range: ${range} units (speed × duration)\n Hitbox: ${radius.toFixed(2)} radius\n`);\n}\n","/**\n * CLI telemetry for LOCAL commands (dev / fight / test / optimize / trace / build).\n *\n * Commands that talk to the gateway are already measured by the headers in\n * env-headers.ts. Local commands are not, and that gap is the important one: without\n * them the only people counted are those who successfully signed in and uploaded, so\n * \"what fraction of installs never upload?\" — the question that decides whether the CLI\n * is worth maintaining — would be computed over survivors only.\n *\n * Three rules this must never break:\n * 1. It must never block. Sent at command START so a long command overlaps the request,\n * with a hard timeout so an unreachable server cannot delay the exit.\n * 2. It must never throw. A telemetry failure is not a CLI failure.\n * 3. It must be refusable, and say so once. Developers are the audience most likely to\n * object to a tool phoning home, and the least likely to forgive doing it silently.\n */\n\nimport os from 'node:os';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {MCP_BASE_URL} from './oauth-client.js';\nimport {envHeaders} from './env-headers.js';\n\n/** Milliseconds before an unreachable server is abandoned. */\nconst TIMEOUT_MS = 1000;\n\n/**\n * Is telemetry allowed?\n *\n * Honours our own switch AND `DO_NOT_TRACK`, the cross-tool convention — a developer who\n * has set that globally has already expressed the preference, and ignoring it because it\n * is not our variable would be obtuse.\n */\nexport function isTelemetryEnabled(env: NodeJS.ProcessEnv): boolean\n{\n\tconst off = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '0' || v === 'false' || v === 'off' || v === 'no';\n\t};\n\tconst on = (value: string | undefined): boolean =>\n\t{\n\t\tif (value === undefined) return false;\n\t\tconst v = value.trim().toLowerCase();\n\t\treturn v === '1' || v === 'true' || v === 'on' || v === 'yes';\n\t};\n\n\tif (off(env.VIBEMANCER_TELEMETRY)) return false;\n\tif (on(env.DO_NOT_TRACK)) return false;\n\t// CI machines are not people; counting them would inflate every figure.\n\tif (on(env.CI)) return false;\n\treturn true;\n}\n\n/** The one-time notice. Exported so its wording can be asserted rather than drift. */\nexport const TELEMETRY_NOTICE =\n\t' Vibemancer records which commands are run, your OS and version numbers, to decide\\n'\n\t+ ' which platforms to support. No code, file paths or personal files are ever sent.\\n'\n\t+ ' Opt out any time with VIBEMANCER_TELEMETRY=0 (DO_NOT_TRACK is honoured too).\\n';\n\n/** Where the \"already told them\" marker lives. */\nfunction noticePath(): string\n{\n\treturn path.join(os.homedir(), '.vibemancer', 'telemetry-notice-shown');\n}\n\n/**\n * Print the notice the first time only. Returns whether it printed, so tests can assert\n * the once-only behaviour rather than trusting it.\n */\nexport function showNoticeOnce(marker: string = noticePath()): boolean\n{\n\ttry\n\t{\n\t\tif (fs.existsSync(marker)) return false;\n\t\tfs.mkdirSync(path.dirname(marker), {recursive: true});\n\t\tfs.writeFileSync(marker, new Date().toISOString());\n\t\tconsole.log(TELEMETRY_NOTICE);\n\t\treturn true;\n\t}\n\tcatch\n\t{\n\t\t// If the marker cannot be written, stay silent rather than nagging every run.\n\t\treturn false;\n\t}\n}\n\n/**\n * Record that a local command ran. Fire-and-forget by construction: the returned promise\n * is resolved even on failure, so a caller that forgets to await cannot produce an\n * unhandled rejection.\n */\nexport async function recordLocalCommand(command: string, env: NodeJS.ProcessEnv = process.env, marker: string = noticePath()): Promise<void>\n{\n\tif (!isTelemetryEnabled(env)) return;\n\t// `marker` is injectable so the test suite cannot consume the real first-run notice on\n\t// whichever machine runs it — otherwise the one person certain to have run the tests is\n\t// the one person who never sees the notice.\n\tshowNoticeOnce(marker);\n\n\ttry\n\t{\n\t\t// envHeaders() rather than hand-built ones: it resolves the CLI version too, and the\n\t\t// version spread of people who never upload is the half we could not otherwise see.\n\t\tconst headers = envHeaders();\n\t\tawait fetch(`${MCP_BASE_URL}/cli-telemetry`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: {'Content-Type': 'application/json', ...headers},\n\t\t\tbody: JSON.stringify({command}),\n\t\t\tsignal: AbortSignal.timeout(TIMEOUT_MS),\n\t\t});\n\t}\n\tcatch\n\t{\n\t\t// Never a CLI failure.\n\t}\n}\n","/**\r\n * Vibemancer CLI\r\n *\r\n * Development tools for building wizard bots.\r\n *\r\n * Usage:\r\n * vibemancer dev [--port 4242] [--bot src/bot.ts]\r\n * vibemancer test\r\n * vibemancer fight [--opponent Battlemage]\r\n * vibemancer trace --opponent Battlemage\r\n * vibemancer tournament [opponents...]\r\n * vibemancer optimize [--opponents Battlemage,Warmage]\r\n * vibemancer build --opponent Battlemage\r\n */\r\n\r\nimport {cliVersion} from './cli-version.js';\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 Round-robin against all 29 ranked built-ins (or --opponent <name>).\r\n The showcase bot is excluded: fight it with --opponent Hero\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\t// `--version`, `-v` and `version` all used to fall through to \"Unknown command\" and\r\n\t\t// dump the help — while the CLI was quietly shipping its version to the server as a\r\n\t\t// telemetry header. It is the first thing a user types when something misbehaves.\r\n\t\tcase '--version':\r\n\t\tcase '-v':\r\n\t\tcase 'version':\r\n\t\t\tconsole.log(cliVersion());\r\n\t\t\tbreak;\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","fs","path","path","fs","BotBundle","BotBundle","BotBundle","sandboxFight","scoreFight","BotBundle","sandboxFight","scoreFight","BotBundle","scoreFight","scoreFight","BotBundle","fs","path","BotBundle","BotBundle","path","fs","fs","readFileSync","path","fileURLToPath","fs","fs","path","fs","path","spawn","openBrowser","spawn","getAccessToken","os","fs","path","path","os","fs","command","getBuiltinBotNames"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibemancer",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Vibemancer devkit - dev server, testing, and tournament tools for wizard bots",
5
5
  "type": "module",
6
6
  "author": "Low Entry",
@@ -30,7 +30,7 @@
30
30
  "test:coverage": "vitest run --coverage"
31
31
  },
32
32
  "dependencies": {
33
- "@vibemancer/core": "~1.0.7",
33
+ "@vibemancer/core": "~1.0.9",
34
34
  "firebase": "^12.12.1"
35
35
  },
36
36
  "devDependencies": {