UNPKG

claude-arcade

Version:

Add classic arcade games to your Claude Code workflow with Ctrl+G

232 lines (231 loc) 7.83 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); // Suppress deprecation warnings from dependencies process.removeAllListeners('warning'); process.on('warning', (warning) => { if (warning.name === 'DeprecationWarning') return; console.warn(warning); }); const pty = __importStar(require("node-pty")); const snake_1 = require("./games/snake"); const leaderboard_1 = require("./leaderboard"); class SnakeGameWrapper { constructor() { this.inGameMode = false; this.ptyProcess = null; this.gameLoop = null; this.game = new snake_1.SnakeGame(); this.awaitingLeaderboardInput = false; } start() { this.ptyProcess = pty.spawn('claude', process.argv.slice(2), { name: 'xterm-256color', cols: process.stdout.columns || 80, rows: process.stdout.rows || 24, cwd: process.cwd(), env: process.env }); this.ptyProcess.onData((data) => { if (!this.inGameMode) { process.stdout.write(data); } }); this.ptyProcess.onExit(() => { if (this.inGameMode) { process.stdout.write('\x1b[?1049l'); } process.exit(0); }); process.stdout.on('resize', () => { if (this.ptyProcess && !this.inGameMode) { this.ptyProcess.resize(process.stdout.columns || 80, process.stdout.rows || 24); } }); this.setupInputHandling(); } setupInputHandling() { if (process.stdin.isTTY) { process.stdin.setRawMode(true); } process.stdin.resume(); process.stdin.on('data', (key) => { if (key[0] === 7) { this.toggleGame(); return; } if (this.inGameMode) { this.handleGameInput(key); } else { if (this.ptyProcess) { this.ptyProcess.write(key); } } }); } toggleGame() { if (!this.inGameMode) { process.stdout.write('\x1b[?1049h\x1b[2J\x1b[?25l'); this.inGameMode = true; process.stdout.write(this.game.drawWelcome()); } else { this.stopGame(); process.stdout.write('\x1b[?25h\x1b[?1049l'); this.inGameMode = false; } } startGame() { this.game.start(); if (this.gameLoop) clearInterval(this.gameLoop); this.gameLoop = setInterval(() => this.update(), 150); } stopGame() { if (this.gameLoop) clearInterval(this.gameLoop); this.gameLoop = null; this.game.stop(); } async handleGameOver(gameOverScreen) { this.stopGame(); process.stdout.write(gameOverScreen); this.awaitingLeaderboardInput = true; (0, leaderboard_1.promptForName)(async (name, action) => { this.awaitingLeaderboardInput = false; if (action === 'submit' && name) { process.stdout.write('\x1b[2J\x1b[10;1H\x1b[33mSubmitting score...\x1b[0m\n'); const success = await (0, leaderboard_1.submitScore)('snake', name, this.game.getScore()); if (success) { process.stdout.write('\x1b[32m✓ Score submitted successfully!\x1b[0m\n\n'); } else { process.stdout.write('\x1b[31m✗ Failed to submit score\x1b[0m\n\n'); } process.stdout.write('\x1b[32mPress P to play again | Press Q to exit\x1b[0m\n'); } else if (action === 'play') { this.startGame(); } else if (action === 'quit') { this.toggleGame(); } }); } update() { this.game.update(); if (this.game.isGameOver()) { this.handleGameOver(this.game.drawGameOver()); return; } process.stdout.write(this.game.draw()); } handleGameInput(key) { const char = key.toString(); // Ignore input if waiting for leaderboard submission if (this.awaitingLeaderboardInput) { return; } // Ctrl+G, Ctrl+C, or Q to exit game if (key[0] === 7 || key[0] === 3 || char === 'q' || char === 'Q') { this.toggleGame(); return; } if ((char === 'p' || char === 'P') && !this.game.isPlaying()) { this.startGame(); return; } if (this.game.isPlaying() && !this.game.isGameOver()) { if (char === 'w' || char === 'W') { this.game.setDirection(0, -1); } else if (char === 's' || char === 'S') { this.game.setDirection(0, 1); } else if (char === 'a' || char === 'A') { this.game.setDirection(-1, 0); } else if (char === 'd' || char === 'D') { this.game.setDirection(1, 0); } else if (key[0] === 27 && key[1] === 91) { if (key[2] === 65) { this.game.setDirection(0, -1); } else if (key[2] === 66) { this.game.setDirection(0, 1); } else if (key[2] === 68) { this.game.setDirection(-1, 0); } else if (key[2] === 67) { this.game.setDirection(1, 0); } } } } } const wrapper = new SnakeGameWrapper(); wrapper.start(); process.on('SIGINT', () => { if (wrapper['ptyProcess']) { wrapper['ptyProcess'].kill(); } if (process.stdin.isTTY) { process.stdin.setRawMode(false); } process.exit(0); }); process.on('exit', () => { if (wrapper['inGameMode']) { process.stdout.write('\x1b[?25h\x1b[?1049l'); } if (process.stdin.isTTY) { process.stdin.setRawMode(false); } }); process.on('uncaughtException', (err) => { if (wrapper['inGameMode']) { process.stdout.write('\x1b[?25h\x1b[?1049l'); } if (process.stdin.isTTY) { process.stdin.setRawMode(false); } console.error('Uncaught exception:', err); process.exit(1); });