commit 4f17b10f0c4832929ce6f4a14ed627f646d01247 parent 962ed001682846c521fe882fc3140b5a0e8025b2 Author: Brian Graham <brian@buildingbetterteams.de> Date: Tue, 7 Apr 2026 03:50:51 +0200 Checkpoint: 95 runs (470 total) Diffstat:
82 files changed, 21377 insertions(+), 1137 deletions(-)
diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/dist/tetris.js b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/dist/tetris.js @@ -0,0 +1,524 @@ +"use strict"; +// ============================================================ +// Tetris – full DOM-based implementation in TypeScript +// ============================================================ +// ---- Constants ---- +const COLS = 10; +const ROWS = 20; +const SHAPES = { + I: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], + O: [[1, 1], [1, 1]], + T: [[0, 1, 0], [1, 1, 1], [0, 0, 0]], + S: [[0, 1, 1], [1, 1, 0], [0, 0, 0]], + Z: [[1, 1, 0], [0, 1, 1], [0, 0, 0]], + J: [[1, 0, 0], [1, 1, 1], [0, 0, 0]], + L: [[0, 0, 1], [1, 1, 1], [0, 0, 0]], +}; +const PIECE_COLORS = ["I", "O", "T", "S", "Z", "J", "L"]; +// Scoring: index = number of lines cleared +const LINE_SCORES = [0, 100, 300, 500, 800]; +const LEVEL_SPEEDS = {}; +for (let lvl = 1; lvl <= 15; lvl++) { + LEVEL_SPEEDS[lvl] = Math.max(80, 800 - (lvl - 1) * 55); +} +// ---- Game State ---- +let board; +let currentPiece; +let nextPiece; +let score; +let lines; +let level; +let gameOver; +let paused; +let dropTimer; +let lastDropTime; +let bag; +// ---- DOM refs ---- +let boardCells = []; +let previewCells = []; +let scoreEl; +let linesEl; +let levelEl; +let overlayEl; +let overlayTitleEl; +let overlayBodyEl; +// ---- Initialization ---- +function createBoardDOM() { + const boardEl = document.getElementById("board"); + boardEl.innerHTML = ""; + boardCells = []; + for (let r = 0; r < ROWS; r++) { + boardCells[r] = []; + for (let c = 0; c < COLS; c++) { + const cell = document.createElement("div"); + cell.className = "cell"; + boardEl.appendChild(cell); + boardCells[r][c] = cell; + } + } +} +function createPreviewDOM() { + const previewEl = document.getElementById("next-preview"); + previewEl.innerHTML = ""; + previewCells = []; + for (let r = 0; r < 4; r++) { + previewCells[r] = []; + for (let c = 0; c < 4; c++) { + const cell = document.createElement("div"); + cell.className = "preview-cell"; + previewEl.appendChild(cell); + previewCells[r][c] = cell; + } + } +} +function initDOMRefs() { + scoreEl = document.getElementById("score-value"); + linesEl = document.getElementById("lines-value"); + levelEl = document.getElementById("level-value"); + overlayEl = document.getElementById("overlay"); + overlayTitleEl = document.getElementById("overlay-title"); + overlayBodyEl = document.getElementById("overlay-body"); +} +// ---- Board helpers ---- +function emptyBoard() { + return Array.from({ length: ROWS }, () => Array(COLS).fill(null)); +} +// ---- 7-bag randomizer ---- +function shuffleArray(arr) { + const a = [...arr]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; +} +function pullFromBag() { + if (bag.length === 0) { + bag = shuffleArray([...PIECE_COLORS]); + } + return bag.pop(); +} +function spawnPiece(color) { + const c = color ?? pullFromBag(); + const shape = SHAPES[c].map(row => [...row]); + return { + shape, + color: c, + x: Math.floor((COLS - shape[0].length) / 2), + y: c === "I" ? -1 : 0, + }; +} +// ---- Collision ---- +function collides(shape, px, py) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const bx = px + c; + const by = py + r; + if (bx < 0 || bx >= COLS || by >= ROWS) + return true; + if (by >= 0 && board[by][bx] !== null) + return true; + } + } + return false; +} +// ---- Rotation (clockwise) ---- +function rotateCW(shape) { + const rows = shape.length; + const cols = shape[0].length; + const result = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + result[c][rows - 1 - r] = shape[r][c]; + } + } + return result; +} +// Wall kick offsets to try on rotation +const KICK_OFFSETS = [ + [0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1], [-2, 0], [2, 0], +]; +function tryRotate() { + if (!currentPiece || currentPiece.color === "O") + return false; + const rotated = rotateCW(currentPiece.shape); + for (const [dx, dy] of KICK_OFFSETS) { + if (!collides(rotated, currentPiece.x + dx, currentPiece.y + dy)) { + currentPiece.shape = rotated; + currentPiece.x += dx; + currentPiece.y += dy; + return true; + } + } + return false; +} +// ---- Ghost piece ---- +function ghostY() { + if (!currentPiece) + return 0; + let gy = currentPiece.y; + while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) { + gy++; + } + return gy; +} +// ---- Lock piece ---- +function lockPiece() { + if (!currentPiece) + return; + const { shape, color, x, y } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const by = y + r; + const bx = x + c; + if (by < 0) { + // piece locked above the board → game over + endGame(); + return; + } + board[by][bx] = color; + } + } + checkLines(); + spawnNext(); +} +// ---- Line clearing ---- +function checkLines() { + const fullRows = []; + for (let r = 0; r < ROWS; r++) { + if (board[r].every(cell => cell !== null)) { + fullRows.push(r); + } + } + if (fullRows.length === 0) + return; + // Flash animation + for (const r of fullRows) { + for (let c = 0; c < COLS; c++) { + boardCells[r][c].classList.add("clearing"); + } + } + // After animation, actually clear the rows + setTimeout(() => { + // Remove rows from top to bottom (sort descending so indices don't shift) + const sorted = [...fullRows].sort((a, b) => b - a); + for (const r of sorted) { + board.splice(r, 1); + board.unshift(Array(COLS).fill(null)); + } + // Update scoring + const cleared = fullRows.length; + lines += cleared; + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel > level) { + level = newLevel; + } + score += LINE_SCORES[cleared] * level; + updateStats(); + render(); + }, 300); +} +// ---- Spawn next ---- +function spawnNext() { + currentPiece = nextPiece ? { ...nextPiece, shape: nextPiece.shape.map(r => [...r]) } : spawnPiece(); + // Reset position + currentPiece.x = Math.floor((COLS - currentPiece.shape[0].length) / 2); + currentPiece.y = currentPiece.color === "I" ? -1 : 0; + nextPiece = spawnPiece(); + if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) { + endGame(); + } + renderPreview(); +} +// ---- Movement ---- +function moveLeft() { + if (!currentPiece || gameOver || paused) + return false; + if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) { + currentPiece.x--; + return true; + } + return false; +} +function moveRight() { + if (!currentPiece || gameOver || paused) + return false; + if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) { + currentPiece.x++; + return true; + } + return false; +} +function moveDown() { + if (!currentPiece || gameOver || paused) + return false; + if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + return true; + } + lockPiece(); + return false; +} +function hardDrop() { + if (!currentPiece || gameOver || paused) + return; + let dropped = 0; + while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + dropped++; + } + score += dropped * 2; + updateStats(); + lockPiece(); +} +function softDrop() { + if (moveDown()) { + score += 1; + updateStats(); + } +} +// ---- Rendering ---- +function render() { + // Clear board + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = boardCells[r][c]; + const val = board[r][c]; + if (val) { + cell.setAttribute("data-color", val); + cell.removeAttribute("data-ghost"); + } + else { + cell.removeAttribute("data-color"); + cell.removeAttribute("data-ghost"); + } + cell.classList.remove("clearing"); + } + } + if (!currentPiece || gameOver) + return; + // Draw ghost + const gy = ghostY(); + const { shape, color, x } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const by = gy + r; + const bx = x + c; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + const cell = boardCells[by][bx]; + // Only draw ghost if no locked piece there + if (!board[by][bx]) { + cell.setAttribute("data-ghost", ""); + cell.setAttribute("data-color", color); + } + } + } + } + // Draw current piece (overwrites ghost cells if overlap) + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const by = currentPiece.y + r; + const bx = x + c; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + const cell = boardCells[by][bx]; + cell.setAttribute("data-color", color); + cell.removeAttribute("data-ghost"); + } + } + } +} +function renderPreview() { + if (!nextPiece) + return; + // Clear preview + for (let r = 0; r < 4; r++) { + for (let c = 0; c < 4; c++) { + previewCells[r][c].removeAttribute("data-color"); + } + } + const { shape, color } = nextPiece; + // Center in 4×4 preview + const offsetR = Math.floor((4 - shape.length) / 2); + const offsetC = Math.floor((4 - shape[0].length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const pr = r + offsetR; + const pc = c + offsetC; + if (pr < 4 && pc < 4) { + previewCells[pr][pc].setAttribute("data-color", color); + } + } + } +} +function updateStats() { + scoreEl.textContent = score.toLocaleString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} +// ---- Game loop ---- +function getSpeed() { + return LEVEL_SPEEDS[level] ?? 80; +} +function gameLoop(timestamp) { + if (gameOver) + return; + if (paused) { + dropTimer = requestAnimationFrame(gameLoop); + return; + } + const elapsed = timestamp - lastDropTime; + if (elapsed >= getSpeed()) { + moveDown(); + lastDropTime = timestamp; + render(); + } + dropTimer = requestAnimationFrame(gameLoop); +} +// ---- Game lifecycle ---- +function startGame() { + board = emptyBoard(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + bag = []; + currentPiece = null; + nextPiece = null; + initDOMRefs(); + createBoardDOM(); + createPreviewDOM(); + updateStats(); + overlayEl.classList.add("hidden"); + spawnNext(); + render(); + lastDropTime = performance.now(); + if (dropTimer !== null) + cancelAnimationFrame(dropTimer); + dropTimer = requestAnimationFrame(gameLoop); +} +function endGame() { + gameOver = true; + currentPiece = null; + if (dropTimer !== null) { + cancelAnimationFrame(dropTimer); + dropTimer = null; + } + render(); + overlayTitleEl.textContent = "Game Over"; + overlayBodyEl.innerHTML = ` + <p class="score-line">Score: ${score.toLocaleString()}</p> + <p>Level ${level} · ${lines} lines</p> + <p style="margin-top:16px;color:#8888bb">Press <kbd>R</kbd> to restart</p> + `; + overlayEl.classList.remove("hidden"); +} +function togglePause() { + if (gameOver) + return; + paused = !paused; + if (paused) { + overlayTitleEl.textContent = "Paused"; + overlayBodyEl.innerHTML = `<p>Press <kbd>P</kbd> to resume</p>`; + overlayEl.classList.remove("hidden"); + } + else { + overlayEl.classList.add("hidden"); + lastDropTime = performance.now(); + } +} +// ---- Input ---- +// Repeat tracking for held keys +let keyRepeatTimers = {}; +const REPEAT_DELAY = 170; // initial delay (ms) +const REPEAT_RATE = 50; // repeat interval (ms) +function handleKeyAction(key) { + switch (key) { + case "ArrowLeft": + if (moveLeft()) + render(); + break; + case "ArrowRight": + if (moveRight()) + render(); + break; + case "ArrowDown": + softDrop(); + render(); + break; + case "ArrowUp": + if (tryRotate()) + render(); + break; + case " ": + hardDrop(); + render(); + break; + case "p": + case "P": + togglePause(); + break; + case "r": + case "R": + if (gameOver) + startGame(); + break; + } +} +function startRepeat(key) { + clearRepeat(key); + // First action already happened in keydown; set delayed repeat + keyRepeatTimers[key] = window.setTimeout(() => { + keyRepeatTimers[key] = window.setInterval(() => { + handleKeyAction(key); + }, REPEAT_RATE); + }, REPEAT_DELAY); +} +function clearRepeat(key) { + if (keyRepeatTimers[key] !== null) { + clearTimeout(keyRepeatTimers[key]); + clearInterval(keyRepeatTimers[key]); + keyRepeatTimers[key] = null; + } +} +function clearAllRepeats() { + for (const key of Object.keys(keyRepeatTimers)) { + clearRepeat(key); + } +} +document.addEventListener("keydown", (e) => { + // Prevent page scrolling for game keys + if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", " "].includes(e.key)) { + e.preventDefault(); + } + if (e.repeat) + return; // We handle repeat ourselves + handleKeyAction(e.key); + // Set up repeat for movement keys + if (["ArrowLeft", "ArrowRight", "ArrowDown"].includes(e.key)) { + startRepeat(e.key); + } +}); +document.addEventListener("keyup", (e) => { + clearRepeat(e.key); +}); +// Lose focus → pause & clear repeats +window.addEventListener("blur", () => { + clearAllRepeats(); + if (!gameOver && !paused) + togglePause(); +}); +// ---- Bootstrap ---- +window.addEventListener("DOMContentLoaded", () => { + startGame(); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/index.html b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/index.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Tetris</title> + <link rel="stylesheet" href="src/styles.css" /> +</head> +<body> + <div id="game-container"> + <div id="board-wrapper"> + <div id="board"></div> + <div id="overlay"> + <h2 id="overlay-title"></h2> + <div id="overlay-body"></div> + </div> + </div> + <div id="side-panel"> + <div class="panel-box"> + <h3>Next</h3> + <div id="next-preview"></div> + </div> + <div class="panel-box"> + <h3>Score</h3> + <div class="value" id="score-value">0</div> + </div> + <div class="panel-box"> + <h3>Lines</h3> + <div class="value" id="lines-value">0</div> + </div> + <div class="panel-box"> + <h3>Level</h3> + <div class="value" id="level-value">1</div> + </div> + <div class="panel-box"> + <h3>Controls</h3> + <div id="controls"> + <kbd>←</kbd> <kbd>→</kbd> Move<br /> + <kbd>↑</kbd> Rotate<br /> + <kbd>↓</kbd> Soft drop<br /> + <kbd>Space</kbd> Hard drop<br /> + <kbd>P</kbd> Pause + </div> + </div> + </div> + </div> + <script src="dist/tetris.js"></script> +</body> +</html> diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package-lock.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package-lock.json @@ -0,0 +1,3415 @@ +{ + "name": "loop-bench-50cbv41e", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "loop-bench-50cbv41e", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@playwright/test": "^1.59.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "html-validate": "^10.11.3", + "jscpd": "^4.0.8", + "serve": "^14.2.6", + "typescript": "^6.0.2" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", + "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.4", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", + "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", + "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", + "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", + "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@html-validate/stylish": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@html-validate/stylish/-/stylish-5.1.0.tgz", + "integrity": "sha512-Tyx/ZbHBpVZjvSleNplNMUhqT4UY1HwAMC97GSmasJXggWuvjNFLBS2scqnEb+ZG1szLq4zgjOioj7cVWV9WuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^4.0.0" + }, + "engines": { + "node": "^20.11 || >= 22.16" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jscpd/badge-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.0.4.tgz", + "integrity": "sha512-I9b4MmLXPM2vo0SxSUWnNGKcA4PjQlD3GzXvFK60z43cN/EIdLbOq3FVwCL+dg2obUqGXKIzAm7EsDFTg0D+mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "badgen": "^3.2.3", + "colors": "^1.4.0", + "fs-extra": "^11.2.0" + } + }, + "node_modules/@jscpd/core": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.0.4.tgz", + "integrity": "sha512-QGMT3iXEX1fI6lgjPH+x8eyJwhwr2KkpSF5uBpjC0Z5Xloj0yFTFLtwJT+RhxP/Ob4WYrtx2jvpKB269oIwgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1" + } + }, + "node_modules/@jscpd/finder": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.0.4.tgz", + "integrity": "sha512-qVUWY7Nzuvfd5OIk+n7/5CM98LmFroLqblRXAI2gDABwZrc7qS+WH2SNr0qoUq0f4OqwM+piiwKvwL/VDNn/Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "blamer": "^1.0.6", + "bytes": "^3.1.2", + "cli-table3": "^0.6.5", + "colors": "^1.4.0", + "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", + "markdown-table": "^2.0.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/html-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.0.4.tgz", + "integrity": "sha512-YiepyeYkeH74Kx59PJRdUdonznct0wHPFkf6FLQN+mCBoy6leAWCcOfHtcexnp+UsBFDlItG5nRdKrDSxSH+Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "1.4.0", + "fs-extra": "^11.2.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/tokenizer": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.0.4.tgz", + "integrity": "sha512-xxYYY/qaLah/FlwogEbGIxx9CjDO+G9E6qawcy26WwrflzJb6wsnhjwdneN6Wb0RNCDsqvzY+bzG453jsin4UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "reprism": "^0.0.11", + "spark-md5": "^3.0.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@playwright/test": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz", + "integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@zeit/schemas": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/@zeit/schemas/-/schemas-2.36.0.tgz", + "integrity": "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/badgen": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/badgen/-/badgen-3.2.3.tgz", + "integrity": "sha512-svDuwkc63E/z0ky3drpUppB83s/nlgDciH9m+STwwQoWyq7yCgew1qEfJ+9axkKdNq7MskByptWUN9j1PGMwFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/blamer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/blamer/-/blamer-1.0.7.tgz", + "integrity": "sha512-GbBStl/EVlSWkiJQBZps3H1iARBrC7vt++Jb/TTmCNu/jZ04VW7tSN1nScbFXBUy1AN+jzeL7Zep9sbQxLhXKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/blamer/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/blamer/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/blamer/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/boxen": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", + "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.0", + "chalk": "^5.0.1", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", + "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", + "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clipboardy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", + "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arch": "^2.2.0", + "execa": "^5.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gitignore-to-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gitignore-to-glob/-/gitignore-to-glob-0.3.0.tgz", + "integrity": "sha512-mk74BdnK7lIwDHnotHddx1wsjMOFIThpLY3cPNniJ/2fA/tlLzHnFxIdR+4sLOu5KGgQJdij4kjJ2RoUNnCNMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.4 <5 || >=6.9" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-validate": { + "version": "10.11.3", + "resolved": "https://registry.npmjs.org/html-validate/-/html-validate-10.11.3.tgz", + "integrity": "sha512-wKUq9iR6bukMgiHhs/ORThZzEbQoFiiPNN7aZfQ8dlmhttPb2sM2Ji2p+Fy5Xj1aH7QHJ1biT2SUDw7A01P2oA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/html-validate" + } + ], + "license": "MIT", + "dependencies": { + "@html-validate/stylish": "^5.0.0", + "@sidvind/better-ajv-errors": "4.0.1", + "ajv": "^8.0.0", + "glob": "^13.0.0", + "kleur": "^4.1.0", + "minimist": "^1.2.0", + "prompts": "^2.0.0", + "semver": "^7.0.0" + }, + "bin": { + "html-validate": "bin/html-validate.mjs" + }, + "engines": { + "node": "^20.19.0 || >= 22.16.0" + }, + "peerDependencies": { + "jest": "^28.1.3 || ^29.0.3 || ^30.0.0", + "jest-diff": "^28.1.3 || ^29.0.3 || ^30.0.0", + "jest-snapshot": "^28.1.3 || ^29.0.3 || ^30.0.0", + "vitest": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.1" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + }, + "jest-diff": { + "optional": true + }, + "jest-snapshot": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/html-validate/node_modules/@sidvind/better-ajv-errors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sidvind/better-ajv-errors/-/better-ajv-errors-4.0.1.tgz", + "integrity": "sha512-6arF1ssKxItxgitPYXafUoLmsVBA6K7m9+ZGj6hLDoBl7nWpJ33EInwQUdHTle2METeWGxgQiqSex20KZRykew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "kleur": "^4.1.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "ajv": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/html-validate/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/html-validate/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-port-reachable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-4.0.0.tgz", + "integrity": "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jscpd": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.0.8.tgz", + "integrity": "sha512-d2VNT/2Hv4dxT2/59He8Lyda4DYOxPRyRG9zBaOpTZAqJCVf2xLrBlZkT8Va6Lo9u3X2qz8Bpq4HrDi4JsrQhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/badge-reporter": "4.0.4", + "@jscpd/core": "4.0.4", + "@jscpd/finder": "4.0.4", + "@jscpd/html-reporter": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "colors": "^1.4.0", + "commander": "^5.0.0", + "fs-extra": "^11.2.0", + "gitignore-to-glob": "^0.3.0", + "jscpd-sarif-reporter": "4.0.6" + }, + "bin": { + "jscpd": "bin/jscpd" + } + }, + "node_modules/jscpd-sarif-reporter": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.0.6.tgz", + "integrity": "sha512-b9Sm3IPZ3+m8Lwa4gZa+4/LhDhlc/ZLEsLXKSOy1DANQ6kx0ueqZT+fUHWEdQ6m0o3+RIVIa7DmvLSojQD05ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "^1.4.0", + "fs-extra": "^11.2.0", + "node-sarif-builder": "^3.4.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.2.tgz", + "integrity": "sha512-wgWa6FWQ3QRRJbIjbsldRJZxdxYngT/dO0I5Ynmlnin8qy7tC6xYzbcJjtN4wHLXtkbVwHzk0C+OejVw1XM+DQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "~1.33.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", + "integrity": "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", + "integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.59.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.59.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz", + "integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pug": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.4.tgz", + "integrity": "sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.4", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.4.tgz", + "integrity": "sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/reprism": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/reprism/-/reprism-0.0.11.tgz", + "integrity": "sha512-VsxDR5QxZo08M/3nRypNlScw5r3rKeSOPdU/QhDmu3Ai3BJxHn/qgfXGWQp/tAxUtzwYNo9W6997JZR0tPLZsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serve": { + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/serve/-/serve-14.2.6.tgz", + "integrity": "sha512-QEjUSA+sD4Rotm1znR8s50YqA3kYpRGPmtd5GlFxbaL9n/FdUNbqMhxClqdditSk0LlZyA/dhud6XNRTOC9x2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zeit/schemas": "2.36.0", + "ajv": "8.18.0", + "arg": "5.0.2", + "boxen": "7.0.0", + "chalk": "5.0.1", + "chalk-template": "0.4.0", + "clipboardy": "3.0.0", + "compression": "1.8.1", + "is-port-reachable": "4.0.0", + "serve-handler": "6.1.7", + "update-check": "1.5.4" + }, + "bin": { + "serve": "build/main.js" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/serve-handler": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.7.tgz", + "integrity": "sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.0.0", + "content-disposition": "0.5.2", + "mime-types": "2.1.18", + "minimatch": "3.1.5", + "path-is-inside": "1.0.2", + "path-to-regexp": "3.3.0", + "range-parser": "1.2.0" + } + }, + "node_modules/serve-handler/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/serve-handler/node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/serve-handler/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-handler/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/serve/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/serve/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/spark-md5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz", + "integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-check": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/update-check/-/update-check-1.5.4.tgz", + "integrity": "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package.json @@ -0,0 +1,23 @@ +{ + "name": "loop-bench-50cbv41e", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@playwright/test": "^1.59.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "html-validate": "^10.11.3", + "jscpd": "^4.0.8", + "serve": "^14.2.6", + "typescript": "^6.0.2" + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/src/styles.css b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/src/styles.css @@ -0,0 +1,197 @@ +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +:root { + --bg: #0f0f1a; + --fg: #e0e0f0; + --accent: #6c5ce7; + --board-bg: #1a1a2e; + --grid-line: rgba(255,255,255,0.04); + --cell-size: 30px; + --border-color: #2d2d5e; +} + +body { + font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; + background: var(--bg); + color: var(--fg); + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + overflow: hidden; + user-select: none; +} + +#game-container { + display: flex; + gap: 24px; + align-items: flex-start; +} + +/* ---- Game Board ---- */ + +#board-wrapper { + position: relative; + background: var(--board-bg); + border: 2px solid var(--border-color); + border-radius: 6px; + padding: 2px; + box-shadow: 0 0 40px rgba(108, 92, 231, 0.15), inset 0 0 30px rgba(0,0,0,0.3); +} + +#board { + display: grid; + grid-template-columns: repeat(10, var(--cell-size)); + grid-template-rows: repeat(20, var(--cell-size)); + gap: 0; +} + +.cell { + width: var(--cell-size); + height: var(--cell-size); + border: 1px solid var(--grid-line); + transition: background-color 0.05s ease; + border-radius: 2px; +} + +/* ---- Cell Colors (Tetrominoes) ---- */ + +.cell[data-color="I"] { background: #00e5ff; box-shadow: inset 0 0 8px rgba(0,229,255,0.4); } +.cell[data-color="O"] { background: #ffea00; box-shadow: inset 0 0 8px rgba(255,234,0,0.4); } +.cell[data-color="T"] { background: #d500f9; box-shadow: inset 0 0 8px rgba(213,0,249,0.4); } +.cell[data-color="S"] { background: #00e676; box-shadow: inset 0 0 8px rgba(0,230,118,0.4); } +.cell[data-color="Z"] { background: #ff1744; box-shadow: inset 0 0 8px rgba(255,23,68,0.4); } +.cell[data-color="J"] { background: #2979ff; box-shadow: inset 0 0 8px rgba(41,121,255,0.4); } +.cell[data-color="L"] { background: #ff9100; box-shadow: inset 0 0 8px rgba(255,145,0,0.4); } + +.cell[data-ghost] { + background: transparent !important; + box-shadow: none !important; + border: 2px dashed rgba(255,255,255,0.25) !important; +} + +/* ---- Side Panel ---- */ + +#side-panel { + display: flex; + flex-direction: column; + gap: 16px; + width: 180px; +} + +.panel-box { + background: var(--board-bg); + border: 2px solid var(--border-color); + border-radius: 6px; + padding: 14px; + box-shadow: 0 0 20px rgba(108, 92, 231, 0.08); +} + +.panel-box h3 { + font-size: 11px; + text-transform: uppercase; + letter-spacing: 2px; + color: #8888aa; + margin-bottom: 8px; + font-weight: 600; +} + +.panel-box .value { + font-size: 28px; + font-weight: 700; + color: var(--fg); + font-variant-numeric: tabular-nums; +} + +/* ---- Next Piece Preview ---- */ + +#next-preview { + display: grid; + grid-template-columns: repeat(4, 20px); + grid-template-rows: repeat(4, 20px); + gap: 0; + justify-content: center; +} + +.preview-cell { + width: 20px; + height: 20px; + border-radius: 2px; +} + +/* ---- Overlay ---- */ + +#overlay { + position: absolute; + inset: 0; + background: rgba(15, 15, 26, 0.85); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 10; + border-radius: 6px; + backdrop-filter: blur(4px); +} + +#overlay.hidden { + display: none; +} + +#overlay h2 { + font-size: 28px; + margin-bottom: 8px; + color: var(--accent); + font-weight: 800; + letter-spacing: 1px; +} + +#overlay p { + font-size: 14px; + color: #9999bb; + margin-bottom: 4px; +} + +#overlay .score-line { + font-size: 22px; + font-weight: 700; + color: var(--fg); + margin: 8px 0; +} + +/* ---- Controls Help ---- */ + +#controls { + font-size: 12px; + line-height: 1.8; + color: #7777aa; +} + +#controls kbd { + display: inline-block; + background: #252545; + border: 1px solid #3a3a6e; + border-radius: 3px; + padding: 1px 6px; + font-family: inherit; + font-size: 11px; + color: #bbbbdd; + min-width: 22px; + text-align: center; +} + +/* ---- Line clear flash ---- */ + +@keyframes line-clear-flash { + 0% { background: #ffffff !important; box-shadow: 0 0 12px #ffffff !important; } + 50% { background: #ffffff !important; box-shadow: 0 0 20px #ffffff !important; } + 100% { background: transparent !important; box-shadow: none !important; } +} + +.cell.clearing { + animation: line-clear-flash 0.3s ease-out; +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/src/tetris.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/src/tetris.ts @@ -0,0 +1,583 @@ +// ============================================================ +// Tetris – full DOM-based implementation in TypeScript +// ============================================================ + +// ---- Types ---- + +type Color = "I" | "O" | "T" | "S" | "Z" | "J" | "L"; + +interface Piece { + shape: number[][]; + color: Color; + x: number; + y: number; +} + +type Board = (Color | null)[][]; + +// ---- Constants ---- + +const COLS = 10; +const ROWS = 20; + +const SHAPES: Record<Color, number[][]> = { + I: [[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]], + O: [[1,1],[1,1]], + T: [[0,1,0],[1,1,1],[0,0,0]], + S: [[0,1,1],[1,1,0],[0,0,0]], + Z: [[1,1,0],[0,1,1],[0,0,0]], + J: [[1,0,0],[1,1,1],[0,0,0]], + L: [[0,0,1],[1,1,1],[0,0,0]], +}; + +const PIECE_COLORS: Color[] = ["I","O","T","S","Z","J","L"]; + +// Scoring: index = number of lines cleared +const LINE_SCORES = [0, 100, 300, 500, 800]; + +const LEVEL_SPEEDS: Record<number, number> = {}; +for (let lvl = 1; lvl <= 15; lvl++) { + LEVEL_SPEEDS[lvl] = Math.max(80, 800 - (lvl - 1) * 55); +} + +// ---- Game State ---- + +let board: Board; +let currentPiece: Piece | null; +let nextPiece: Piece | null; +let score: number; +let lines: number; +let level: number; +let gameOver: boolean; +let paused: boolean; +let dropTimer: number | null; +let lastDropTime: number; +let bag: Color[]; + +// ---- DOM refs ---- + +let boardCells: HTMLDivElement[][] = []; +let previewCells: HTMLDivElement[][] = []; +let scoreEl!: HTMLElement; +let linesEl!: HTMLElement; +let levelEl!: HTMLElement; +let overlayEl!: HTMLElement; +let overlayTitleEl!: HTMLElement; +let overlayBodyEl!: HTMLElement; + +// ---- Initialization ---- + +function createBoardDOM(): void { + const boardEl = document.getElementById("board")!; + boardEl.innerHTML = ""; + boardCells = []; + for (let r = 0; r < ROWS; r++) { + boardCells[r] = []; + for (let c = 0; c < COLS; c++) { + const cell = document.createElement("div"); + cell.className = "cell"; + boardEl.appendChild(cell); + boardCells[r][c] = cell; + } + } +} + +function createPreviewDOM(): void { + const previewEl = document.getElementById("next-preview")!; + previewEl.innerHTML = ""; + previewCells = []; + for (let r = 0; r < 4; r++) { + previewCells[r] = []; + for (let c = 0; c < 4; c++) { + const cell = document.createElement("div"); + cell.className = "preview-cell"; + previewEl.appendChild(cell); + previewCells[r][c] = cell; + } + } +} + +function initDOMRefs(): void { + scoreEl = document.getElementById("score-value")!; + linesEl = document.getElementById("lines-value")!; + levelEl = document.getElementById("level-value")!; + overlayEl = document.getElementById("overlay")!; + overlayTitleEl = document.getElementById("overlay-title")!; + overlayBodyEl = document.getElementById("overlay-body")!; +} + +// ---- Board helpers ---- + +function emptyBoard(): Board { + return Array.from({ length: ROWS }, () => Array<Color | null>(COLS).fill(null)); +} + +// ---- 7-bag randomizer ---- + +function shuffleArray<T>(arr: T[]): T[] { + const a = [...arr]; + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; +} + +function pullFromBag(): Color { + if (bag.length === 0) { + bag = shuffleArray([...PIECE_COLORS]); + } + return bag.pop()!; +} + +function spawnPiece(color?: Color): Piece { + const c = color ?? pullFromBag(); + const shape = SHAPES[c].map(row => [...row]); + return { + shape, + color: c, + x: Math.floor((COLS - shape[0].length) / 2), + y: c === "I" ? -1 : 0, + }; +} + +// ---- Collision ---- + +function collides(shape: number[][], px: number, py: number): boolean { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const bx = px + c; + const by = py + r; + if (bx < 0 || bx >= COLS || by >= ROWS) return true; + if (by >= 0 && board[by][bx] !== null) return true; + } + } + return false; +} + +// ---- Rotation (clockwise) ---- + +function rotateCW(shape: number[][]): number[][] { + const rows = shape.length; + const cols = shape[0].length; + const result: number[][] = Array.from({ length: cols }, () => Array(rows).fill(0)); + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + result[c][rows - 1 - r] = shape[r][c]; + } + } + return result; +} + +// Wall kick offsets to try on rotation +const KICK_OFFSETS: [number, number][] = [ + [0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1], [-2, 0], [2, 0], +]; + +function tryRotate(): boolean { + if (!currentPiece || currentPiece.color === "O") return false; + const rotated = rotateCW(currentPiece.shape); + for (const [dx, dy] of KICK_OFFSETS) { + if (!collides(rotated, currentPiece.x + dx, currentPiece.y + dy)) { + currentPiece.shape = rotated; + currentPiece.x += dx; + currentPiece.y += dy; + return true; + } + } + return false; +} + +// ---- Ghost piece ---- + +function ghostY(): number { + if (!currentPiece) return 0; + let gy = currentPiece.y; + while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) { + gy++; + } + return gy; +} + +// ---- Lock piece ---- + +function lockPiece(): void { + if (!currentPiece) return; + const { shape, color, x, y } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const by = y + r; + const bx = x + c; + if (by < 0) { + // piece locked above the board → game over + endGame(); + return; + } + board[by][bx] = color; + } + } + checkLines(); + spawnNext(); +} + +// ---- Line clearing ---- + +function checkLines(): void { + const fullRows: number[] = []; + for (let r = 0; r < ROWS; r++) { + if (board[r].every(cell => cell !== null)) { + fullRows.push(r); + } + } + if (fullRows.length === 0) return; + + // Flash animation + for (const r of fullRows) { + for (let c = 0; c < COLS; c++) { + boardCells[r][c].classList.add("clearing"); + } + } + + // After animation, actually clear the rows + setTimeout(() => { + // Remove rows from top to bottom (sort descending so indices don't shift) + const sorted = [...fullRows].sort((a, b) => b - a); + for (const r of sorted) { + board.splice(r, 1); + board.unshift(Array<Color | null>(COLS).fill(null)); + } + // Update scoring + const cleared = fullRows.length; + lines += cleared; + const newLevel = Math.floor(lines / 10) + 1; + if (newLevel > level) { + level = newLevel; + } + score += LINE_SCORES[cleared] * level; + updateStats(); + render(); + }, 300); +} + +// ---- Spawn next ---- + +function spawnNext(): void { + currentPiece = nextPiece ? { ...nextPiece, shape: nextPiece.shape.map(r => [...r]) } : spawnPiece(); + // Reset position + currentPiece.x = Math.floor((COLS - currentPiece.shape[0].length) / 2); + currentPiece.y = currentPiece.color === "I" ? -1 : 0; + nextPiece = spawnPiece(); + + if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) { + endGame(); + } + renderPreview(); +} + +// ---- Movement ---- + +function moveLeft(): boolean { + if (!currentPiece || gameOver || paused) return false; + if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) { + currentPiece.x--; + return true; + } + return false; +} + +function moveRight(): boolean { + if (!currentPiece || gameOver || paused) return false; + if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) { + currentPiece.x++; + return true; + } + return false; +} + +function moveDown(): boolean { + if (!currentPiece || gameOver || paused) return false; + if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + return true; + } + lockPiece(); + return false; +} + +function hardDrop(): void { + if (!currentPiece || gameOver || paused) return; + let dropped = 0; + while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) { + currentPiece.y++; + dropped++; + } + score += dropped * 2; + updateStats(); + lockPiece(); +} + +function softDrop(): void { + if (moveDown()) { + score += 1; + updateStats(); + } +} + +// ---- Rendering ---- + +function render(): void { + // Clear board + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = boardCells[r][c]; + const val = board[r][c]; + if (val) { + cell.setAttribute("data-color", val); + cell.removeAttribute("data-ghost"); + } else { + cell.removeAttribute("data-color"); + cell.removeAttribute("data-ghost"); + } + cell.classList.remove("clearing"); + } + } + + if (!currentPiece || gameOver) return; + + // Draw ghost + const gy = ghostY(); + const { shape, color, x } = currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const by = gy + r; + const bx = x + c; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + const cell = boardCells[by][bx]; + // Only draw ghost if no locked piece there + if (!board[by][bx]) { + cell.setAttribute("data-ghost", ""); + cell.setAttribute("data-color", color); + } + } + } + } + + // Draw current piece (overwrites ghost cells if overlap) + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const by = currentPiece.y + r; + const bx = x + c; + if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) { + const cell = boardCells[by][bx]; + cell.setAttribute("data-color", color); + cell.removeAttribute("data-ghost"); + } + } + } +} + +function renderPreview(): void { + if (!nextPiece) return; + // Clear preview + for (let r = 0; r < 4; r++) { + for (let c = 0; c < 4; c++) { + previewCells[r][c].removeAttribute("data-color"); + } + } + const { shape, color } = nextPiece; + // Center in 4×4 preview + const offsetR = Math.floor((4 - shape.length) / 2); + const offsetC = Math.floor((4 - shape[0].length) / 2); + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const pr = r + offsetR; + const pc = c + offsetC; + if (pr < 4 && pc < 4) { + previewCells[pr][pc].setAttribute("data-color", color); + } + } + } +} + +function updateStats(): void { + scoreEl.textContent = score.toLocaleString(); + linesEl.textContent = lines.toString(); + levelEl.textContent = level.toString(); +} + +// ---- Game loop ---- + +function getSpeed(): number { + return LEVEL_SPEEDS[level] ?? 80; +} + +function gameLoop(timestamp: number): void { + if (gameOver) return; + if (paused) { + dropTimer = requestAnimationFrame(gameLoop); + return; + } + const elapsed = timestamp - lastDropTime; + if (elapsed >= getSpeed()) { + moveDown(); + lastDropTime = timestamp; + render(); + } + dropTimer = requestAnimationFrame(gameLoop); +} + +// ---- Game lifecycle ---- + +function startGame(): void { + board = emptyBoard(); + score = 0; + lines = 0; + level = 1; + gameOver = false; + paused = false; + bag = []; + currentPiece = null; + nextPiece = null; + + initDOMRefs(); + createBoardDOM(); + createPreviewDOM(); + updateStats(); + + overlayEl.classList.add("hidden"); + + spawnNext(); + render(); + lastDropTime = performance.now(); + if (dropTimer !== null) cancelAnimationFrame(dropTimer); + dropTimer = requestAnimationFrame(gameLoop); +} + +function endGame(): void { + gameOver = true; + currentPiece = null; + if (dropTimer !== null) { + cancelAnimationFrame(dropTimer); + dropTimer = null; + } + render(); + + overlayTitleEl.textContent = "Game Over"; + overlayBodyEl.innerHTML = ` + <p class="score-line">Score: ${score.toLocaleString()}</p> + <p>Level ${level} · ${lines} lines</p> + <p style="margin-top:16px;color:#8888bb">Press <kbd>R</kbd> to restart</p> + `; + overlayEl.classList.remove("hidden"); +} + +function togglePause(): void { + if (gameOver) return; + paused = !paused; + if (paused) { + overlayTitleEl.textContent = "Paused"; + overlayBodyEl.innerHTML = `<p>Press <kbd>P</kbd> to resume</p>`; + overlayEl.classList.remove("hidden"); + } else { + overlayEl.classList.add("hidden"); + lastDropTime = performance.now(); + } +} + +// ---- Input ---- + +// Repeat tracking for held keys +let keyRepeatTimers: Record<string, number | null> = {}; +const REPEAT_DELAY = 170; // initial delay (ms) +const REPEAT_RATE = 50; // repeat interval (ms) + +function handleKeyAction(key: string): void { + switch (key) { + case "ArrowLeft": + if (moveLeft()) render(); + break; + case "ArrowRight": + if (moveRight()) render(); + break; + case "ArrowDown": + softDrop(); + render(); + break; + case "ArrowUp": + if (tryRotate()) render(); + break; + case " ": + hardDrop(); + render(); + break; + case "p": + case "P": + togglePause(); + break; + case "r": + case "R": + if (gameOver) startGame(); + break; + } +} + +function startRepeat(key: string): void { + clearRepeat(key); + // First action already happened in keydown; set delayed repeat + keyRepeatTimers[key] = window.setTimeout(() => { + keyRepeatTimers[key] = window.setInterval(() => { + handleKeyAction(key); + }, REPEAT_RATE); + }, REPEAT_DELAY); +} + +function clearRepeat(key: string): void { + if (keyRepeatTimers[key] !== null) { + clearTimeout(keyRepeatTimers[key]); + clearInterval(keyRepeatTimers[key]); + keyRepeatTimers[key] = null; + } +} + +function clearAllRepeats(): void { + for (const key of Object.keys(keyRepeatTimers)) { + clearRepeat(key); + } +} + +document.addEventListener("keydown", (e: KeyboardEvent) => { + // Prevent page scrolling for game keys + if (["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"," "].includes(e.key)) { + e.preventDefault(); + } + + if (e.repeat) return; // We handle repeat ourselves + + handleKeyAction(e.key); + + // Set up repeat for movement keys + if (["ArrowLeft","ArrowRight","ArrowDown"].includes(e.key)) { + startRepeat(e.key); + } +}); + +document.addEventListener("keyup", (e: KeyboardEvent) => { + clearRepeat(e.key); +}); + +// Lose focus → pause & clear repeats +window.addEventListener("blur", () => { + clearAllRepeats(); + if (!gameOver && !paused) togglePause(); +}); + +// ---- Bootstrap ---- + +window.addEventListener("DOMContentLoaded", () => { + startGame(); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/test-results/.last-run.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} +\ No newline at end of file diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 30_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/tetris.spec.ts @@ -0,0 +1,96 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + }); + + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Give the page a moment to finish initializing + await page.waitForTimeout(2000); + + expect(errors).toEqual([]); + }); + + test("game board is visible", async ({ page }) => { + // A Tetris game should render either a <canvas> or a grid of DOM elements + const canvas = page.locator("canvas"); + const gridContainer = page.locator( + [ + '[class*="board"]', + '[class*="grid"]', + '[class*="game"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); + + const canvasCount = await canvas.count(); + const gridCount = await gridContainer.count(); + + expect( + canvasCount + gridCount, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + }); + + test("keyboard input does not crash the game", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Press every key a Tetris game should handle + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + for (const key of keys) { + await page.keyboard.press(key); + await page.waitForTimeout(150); + } + + expect(errors).toEqual([]); + }); + + test("game state changes over time", async ({ page }) => { + // If the game is running, the visual output should change as pieces fall + const shot1 = await page.screenshot(); + await page.waitForTimeout(3000); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the page to visually change over 3 seconds (pieces should be falling)" + ).toBe(false); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 60_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/tetris.spec.ts @@ -0,0 +1,474 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +// Find the game surface: canvas or a grid-like DOM container. +function gameBoard(page: Page) { + return page.locator( + [ + "canvas", + '[class*="board"]', + '[class*="grid"]', + '[class*="game-area"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); +} + +// Click the board area to make sure it has focus, then try common +// start interactions in case the game waits for user action. +async function ensureGameStarted(page: Page) { + const board = gameBoard(page); + const count = await board.count(); + if (count > 0) { + try { + await board.first().click({ timeout: 2000 }); + } catch { + // click failed, continue anyway + } + } + + // Some games need a key press or button click to start + const startButton = page.locator( + 'button:has-text("start"), button:has-text("Start"), button:has-text("play"), button:has-text("Play"), [class*="start"], [id*="start"]' + ); + if ((await startButton.count()) > 0) { + try { + await startButton.first().click({ timeout: 2000 }); + } catch { + // ignore + } + } + + // Press Enter/Space as a fallback start trigger + await page.keyboard.press("Enter"); + await page.waitForTimeout(300); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + await page.waitForTimeout(1000); + await ensureGameStarted(page); + }); + + // ---- 1. Page loads without errors ---- + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + await page.waitForTimeout(2000); + expect(errors).toEqual([]); + }); + + // ---- 2. Game board is visible ---- + test("game board is visible", async ({ page }) => { + const board = gameBoard(page); + const count = await board.count(); + + expect( + count, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + + // The board element should have meaningful dimensions + const box = await board.first().boundingBox(); + expect(box, "Game board should be visible on screen").not.toBeNull(); + expect(box!.width).toBeGreaterThan(50); + expect(box!.height).toBeGreaterThan(50); + }); + + // ---- 3. Game starts automatically or via interaction ---- + test("game starts", async ({ page }) => { + // After beforeEach, the game should be running. Verify by checking that + // the page is not static: take two screenshots separated by time. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the game to show visual activity after starting" + ).toBe(false); + }); + + // ---- 4. Piece falls automatically (auto-drop) ---- + test("piece falls automatically", async ({ page }) => { + // Take screenshots at intervals without pressing any keys. + // A falling piece should cause visual changes. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot3 = await page.screenshot(); + + const buf1 = Buffer.from(shot1); + const buf2 = Buffer.from(shot2); + const buf3 = Buffer.from(shot3); + + // At least one pair should differ (piece is moving down) + const changed = !buf1.equals(buf2) || !buf2.equals(buf3); + expect(changed, "Expected piece to fall over time without input").toBe( + true + ); + }); + + // ---- 5. Left arrow moves piece left ---- + test("left arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + // The piece should have moved, so the screenshots should differ + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing left arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 6. Right arrow moves piece right ---- + test("right arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing right arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 7. Down arrow moves piece down faster ---- + test("down arrow accelerates piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + for (let i = 0; i < 10; i++) { + await page.keyboard.press("ArrowDown"); + await page.waitForTimeout(50); + } + await page.waitForTimeout(200); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing down arrow repeatedly" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 8. Up arrow (or Z) rotates piece ---- + test("rotation changes the piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowUp"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing rotate key" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 9. Space bar hard-drops piece ---- + test("space bar hard-drops piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing space (hard drop)" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 10. Pieces lock at the bottom ---- + test("pieces lock at the bottom", async ({ page }) => { + // Hard-drop several pieces and check that the bottom of the board + // accumulates filled cells (the visual should change cumulatively). + const shots: Buffer[] = []; + + shots.push(Buffer.from(await page.screenshot())); + + for (let i = 0; i < 3; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(800); + } + + shots.push(Buffer.from(await page.screenshot())); + + // After 3 hard drops, the board should look different from the start + // because pieces have stacked up at the bottom. + expect( + shots[0].equals(shots[1]), + "Expected pieces to stack up at the bottom after hard drops" + ).toBe(false); + }); + + // ---- 11. New piece spawns after lock ---- + test("new piece spawns after locking", async ({ page }) => { + // Hard-drop to lock a piece, then wait and verify the game is still + // showing activity (a new piece should be falling). + await page.keyboard.press("Space"); + await page.waitForTimeout(1000); + + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + + // If a new piece spawned and is falling, the screen should change + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected a new piece to spawn and fall after the previous one locked" + ).toBe(false); + }); + + // ---- 12. Multiple different pieces appear ---- + test("multiple different pieces appear", async ({ page }) => { + // Play through several pieces and capture screenshots. Different piece + // shapes should produce visually distinct patterns. + const shots: Buffer[] = []; + + for (let i = 0; i < 6; i++) { + // Move each piece to a different column so they don't overlap identically + if (i % 2 === 0) { + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + } else { + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(600); + shots.push(Buffer.from(await page.screenshot())); + } + + // At least some consecutive screenshots should differ (different piece shapes) + let differences = 0; + for (let i = 1; i < shots.length; i++) { + if (!shots[i - 1].equals(shots[i])) differences++; + } + + expect( + differences, + "Expected to see visual differences between consecutive pieces (different shapes)" + ).toBeGreaterThanOrEqual(2); + }); + + // ---- 13. Completed line clears ---- + test("completed line clears", async ({ page }) => { + // Fill a row by dropping many pieces. Observe whether any row disappears. + // We can detect this by tracking the total filled area -- after a line clear, + // the board should have less filled content than just before the clear. + const pageText = async () => + (await page.evaluate(() => document.body.innerText)) || ""; + + // Drop many pieces rapidly to fill rows + for (let i = 0; i < 30; i++) { + // Vary positions to try to complete a row + const moves = (i % 5) - 2; // -2, -1, 0, 1, 2 + for (let m = 0; m < Math.abs(moves); m++) { + await page.keyboard.press( + moves < 0 ? "ArrowLeft" : "ArrowRight" + ); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + // Check if a score or lines counter changed (common indicators of line clears) + const text = await pageText(); + const numbers = (text.match(/\d+/g) || []).map(Number); + const hasNonZero = numbers.some((n) => n > 0); + + // Also check visual: the board should not be completely static + const shot1 = await page.screenshot(); + await page.waitForTimeout(1000); + const shot2 = await page.screenshot(); + + // Either: score/lines increased, or game is still active (meaning lines cleared + // and made room for more pieces instead of game over) + const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + hasNonZero || stillActive, + "Expected evidence of line clearing (score > 0 or game still active after many drops)" + ).toBe(true); + }); + + // ---- 14. Score increases during play ---- + test("score increases during play", async ({ page }) => { + // Look for a score display on the page + const getNumbers = async () => { + const text = (await page.evaluate(() => document.body.innerText)) || ""; + return (text.match(/\d+/g) || []).map(Number); + }; + + const numbersBefore = await getNumbers(); + + // Play for a while: drop several pieces + for (let i = 0; i < 15; i++) { + const offset = (i % 5) - 2; + for (let m = 0; m < Math.abs(offset); m++) { + await page.keyboard.press(offset < 0 ? "ArrowLeft" : "ArrowRight"); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + const numbersAfter = await getNumbers(); + + // At least one number on the page should have increased + // (score, lines counter, level, etc.) + let anyIncreased = false; + const maxLen = Math.min(numbersBefore.length, numbersAfter.length); + for (let i = 0; i < maxLen; i++) { + if (numbersAfter[i] > numbersBefore[i]) { + anyIncreased = true; + break; + } + } + + // Also accept if new numbers appeared + if (!anyIncreased && numbersAfter.length > numbersBefore.length) { + anyIncreased = true; + } + + // Also accept if the max number increased + if (!anyIncreased) { + const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0; + const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0; + if (maxAfter > maxBefore) anyIncreased = true; + } + + expect( + anyIncreased, + "Expected at least one numeric value on the page to increase during play (score, lines, level)" + ).toBe(true); + }); + + // ---- 15. Game over when pieces reach top ---- + test("game over when pieces reach top", async ({ page }) => { + // Stack pieces in the center until the game ends. + // Drop as many pieces as possible straight down. + for (let i = 0; i < 50; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(200); + } + + await page.waitForTimeout(2000); + + // After stacking to overflow, the game should show some game-over indicator: + // - text saying "game over", "you lose", "try again", "restart", "end" + // - or the game stops updating (static screen) + const text = ((await page.evaluate(() => document.body.innerText)) || "").toLowerCase(); + const gameOverText = + text.includes("game over") || + text.includes("gameover") || + text.includes("you lose") || + text.includes("try again") || + text.includes("restart") || + text.includes("play again") || + text.includes("ended"); + + // Check if the game stopped (screen is static) + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + gameOverText || isStatic, + "Expected game-over text or the game to stop after stacking pieces to the top" + ).toBe(true); + }); + + // ---- 16. Game runs for 30 seconds without crashing ---- + test("game runs for 30 seconds without crashing", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Simulate varied gameplay for 30 seconds + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + const start = Date.now(); + + while (Date.now() - start < 30_000) { + const key = keys[Math.floor(Math.random() * keys.length)]; + await page.keyboard.press(key); + await page.waitForTimeout(150 + Math.random() * 200); + } + + // The page should still be alive (not crashed, not blank) + const text = await page.evaluate(() => document.body.innerText); + expect(text, "Page body should not be empty after 30s of play").toBeTruthy(); + expect( + errors.length, + `Expected no console errors during 30s of play, got: ${errors.join("; ")}` + ).toBe(0); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tsconfig.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "sourceMap": false, + "lib": ["ES2020", "DOM", "DOM.Iterable"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/dist/tetris.js b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/dist/tetris.js @@ -0,0 +1,550 @@ +"use strict"; +// ─── Types & Constants ──────────────────────────────────────────────── +const COLS = 10; +const ROWS = 20; +const HIDDEN_ROWS = 2; // buffer rows above visible area +// Standard NES-style scoring +const LINE_SCORES = [0, 100, 300, 500, 800]; +// Gravity intervals in ms per level (index = level, faster as level increases) +const GRAVITY_TABLE = [ + 800, 720, 630, 550, 470, 380, 300, 220, 150, 100, + 80, 80, 80, 70, 70, 70, 50, 50, 50, 30, +]; +function getGravity(level) { + if (level < GRAVITY_TABLE.length) + return GRAVITY_TABLE[level]; + return 20; // cap +} +// Tetromino definitions (shapes in their spawn orientation) +const TETROMINOES = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I - cyan + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O - yellow + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T - purple + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S - green + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z - red + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J - blue + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L - orange +]; +// ─── Utility ────────────────────────────────────────────────────────── +function createBoard() { + const rows = ROWS + HIDDEN_ROWS; + const board = []; + for (let r = 0; r < rows; r++) { + board.push(new Array(COLS).fill(null)); + } + return board; +} +function rotateMatrix(matrix) { + const rows = matrix.length; + const cols = matrix[0].length; + const result = []; + for (let c = 0; c < cols; c++) { + const newRow = []; + for (let r = rows - 1; r >= 0; r--) { + newRow.push(matrix[r][c]); + } + result.push(newRow); + } + return result; +} +// Wall-kick offsets to try when rotation is blocked +const WALL_KICKS = [ + { x: 0, y: 0 }, + { x: -1, y: 0 }, + { x: 1, y: 0 }, + { x: -2, y: 0 }, + { x: 2, y: 0 }, + { x: 0, y: -1 }, + { x: -1, y: -1 }, + { x: 1, y: -1 }, +]; +// ─── Bag Randomiser (7-bag) ─────────────────────────────────────────── +class Bag { + constructor() { + this.bag = []; + } + next() { + if (this.bag.length === 0) { + this.bag = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop(); + } +} +// ─── Game ───────────────────────────────────────────────────────────── +class TetrisGame { + constructor() { + this.board = createBoard(); + this.currentPiece = null; + this.bag = new Bag(); + this.score = 0; + this.level = 0; + this.linesCleared = 0; + this.gameOver = false; + this.paused = false; + // Timing + this.lastTick = 0; + this.gravityInterval = getGravity(0); + this.animFrameId = 0; + // DAS (Delayed Auto Shift) for held keys + this.dasDirection = null; + this.dasTimer = 0; + this.dasDelay = 170; // ms before auto-repeat starts + this.dasRate = 50; // ms between auto-repeats + this.dasActive = false; + this.keysDown = new Set(); + this.cells = []; + this.nextCells = []; + this.loop = (now) => { + if (this.gameOver) + return; + if (this.paused) { + this.animFrameId = requestAnimationFrame(this.loop); + return; + } + const dt = now - this.lastTick; + // DAS handling + this.handleDAS(now); + // Gravity + if (dt >= this.gravityInterval) { + this.tick(); + this.lastTick = now; + } + this.draw(); + this.animFrameId = requestAnimationFrame(this.loop); + }; + // ── Input Handling ──────────────────────────────────────────────── + this.started = false; + this.nextPieceIndex = this.bag.next(); + // Grab DOM elements + this.boardEl = document.getElementById("board"); + this.scoreEl = document.getElementById("score"); + this.levelEl = document.getElementById("level"); + this.linesEl = document.getElementById("lines"); + this.nextPieceEl = document.getElementById("next-piece"); + this.overlayEl = document.getElementById("overlay"); + this.overlayTitleEl = document.getElementById("overlay-title"); + this.overlaySubEl = document.getElementById("overlay-sub"); + this.buildBoardDOM(); + this.buildNextPieceDOM(); + // Input + window.addEventListener("keydown", (e) => this.onKeyDown(e)); + window.addEventListener("keyup", (e) => this.onKeyUp(e)); + // Start + this.spawnPiece(); + this.showOverlay("TETRIS", "Press any key to start"); + this.draw(); + } + // ── DOM Construction ────────────────────────────────────────────── + buildBoardDOM() { + this.boardEl.innerHTML = ""; + this.cells = []; + for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) { + const rowCells = []; + const rowDiv = document.createElement("div"); + rowDiv.className = "board-row"; + for (let c = 0; c < COLS; c++) { + const cell = document.createElement("div"); + cell.className = "cell"; + rowDiv.appendChild(cell); + rowCells.push(cell); + } + this.boardEl.appendChild(rowDiv); + this.cells.push(rowCells); + } + } + buildNextPieceDOM() { + this.nextPieceEl.innerHTML = ""; + this.nextCells = []; + for (let r = 0; r < 4; r++) { + const rowCells = []; + const rowDiv = document.createElement("div"); + rowDiv.className = "next-row"; + for (let c = 0; c < 4; c++) { + const cell = document.createElement("div"); + cell.className = "next-cell"; + rowDiv.appendChild(cell); + rowCells.push(cell); + } + this.nextPieceEl.appendChild(rowDiv); + this.nextCells.push(rowCells); + } + } + // ── Overlay ─────────────────────────────────────────────────────── + showOverlay(title, sub) { + this.overlayTitleEl.textContent = title; + this.overlaySubEl.textContent = sub; + this.overlayEl.classList.remove("hidden"); + } + hideOverlay() { + this.overlayEl.classList.add("hidden"); + } + // ── Game Loop ───────────────────────────────────────────────────── + start() { + this.hideOverlay(); + this.lastTick = performance.now(); + this.loop(this.lastTick); + } + tick() { + if (!this.currentPiece || this.gameOver) + return; + if (!this.movePiece(0, 1)) { + this.lockPiece(); + const cleared = this.clearLines(); + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * (this.level + 1); + this.linesCleared += cleared; + const newLevel = Math.floor(this.linesCleared / 10); + if (newLevel > this.level) { + this.level = newLevel; + this.gravityInterval = getGravity(this.level); + } + } + if (!this.spawnPiece()) { + this.endGame(); + return; + } + } + } + // ── Piece Management ────────────────────────────────────────────── + spawnPiece() { + const idx = this.nextPieceIndex; + this.nextPieceIndex = this.bag.next(); + const t = TETROMINOES[idx]; + const shape = t.shape.map((row) => [...row]); + const piece = { + shape, + color: t.color, + pos: { + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }, + }; + this.currentPiece = piece; + if (!this.isValid(piece.shape, piece.pos)) { + return false; + } + return true; + } + lockPiece() { + if (!this.currentPiece) + return; + const { shape, pos, color } = this.currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const br = pos.y + r; + const bc = pos.x + c; + if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) { + this.board[br][bc] = color; + } + } + } + } + } + clearLines() { + let cleared = 0; + for (let r = this.board.length - 1; r >= 0; r--) { + if (this.board[r].every((cell) => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(new Array(COLS).fill(null)); + cleared++; + r++; // recheck same index + } + } + return cleared; + } + // ── Collision ───────────────────────────────────────────────────── + isValid(shape, pos) { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const br = pos.y + r; + const bc = pos.x + c; + if (bc < 0 || bc >= COLS || br >= this.board.length) + return false; + if (br < 0) + continue; // above board is OK + if (this.board[br][bc] !== null) + return false; + } + } + return true; + } + // ── Movement ────────────────────────────────────────────────────── + movePiece(dx, dy) { + if (!this.currentPiece) + return false; + const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy }; + if (this.isValid(this.currentPiece.shape, newPos)) { + this.currentPiece.pos = newPos; + return true; + } + return false; + } + rotatePiece() { + if (!this.currentPiece) + return; + const rotated = rotateMatrix(this.currentPiece.shape); + // Try wall kicks + for (const kick of WALL_KICKS) { + const testPos = { + x: this.currentPiece.pos.x + kick.x, + y: this.currentPiece.pos.y + kick.y, + }; + if (this.isValid(rotated, testPos)) { + this.currentPiece.shape = rotated; + this.currentPiece.pos = testPos; + return; + } + } + } + hardDrop() { + if (!this.currentPiece) + return; + let dropped = 0; + while (this.movePiece(0, 1)) + dropped++; + this.score += dropped * 2; + this.lockPiece(); + const cleared = this.clearLines(); + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * (this.level + 1); + this.linesCleared += cleared; + const newLevel = Math.floor(this.linesCleared / 10); + if (newLevel > this.level) { + this.level = newLevel; + this.gravityInterval = getGravity(this.level); + } + } + if (!this.spawnPiece()) { + this.endGame(); + return; + } + this.lastTick = performance.now(); + this.draw(); + } + getGhostPosition() { + if (!this.currentPiece) + return null; + let ghostY = this.currentPiece.pos.y; + while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) { + ghostY++; + } + return { x: this.currentPiece.pos.x, y: ghostY }; + } + onKeyDown(e) { + if (!this.started) { + this.started = true; + this.start(); + return; + } + if (this.gameOver) + return; + if (e.code === "KeyP") { + this.paused = !this.paused; + if (this.paused) { + this.showOverlay("PAUSED", "Press P to resume"); + } + else { + this.hideOverlay(); + this.lastTick = performance.now(); + } + return; + } + if (this.paused) + return; + this.keysDown.add(e.code); + switch (e.code) { + case "ArrowLeft": + e.preventDefault(); + this.movePiece(-1, 0); + this.dasDirection = "left"; + this.dasTimer = performance.now(); + this.dasActive = false; + break; + case "ArrowRight": + e.preventDefault(); + this.movePiece(1, 0); + this.dasDirection = "right"; + this.dasTimer = performance.now(); + this.dasActive = false; + break; + case "ArrowDown": + e.preventDefault(); + if (this.movePiece(0, 1)) + this.score += 1; + this.dasDirection = "down"; + this.dasTimer = performance.now(); + this.dasActive = false; + break; + case "ArrowUp": + case "KeyX": + e.preventDefault(); + this.rotatePiece(); + break; + case "Space": + e.preventDefault(); + this.hardDrop(); + break; + } + } + onKeyUp(e) { + this.keysDown.delete(e.code); + // If the key released matches current DAS direction, stop DAS + if ((e.code === "ArrowLeft" && this.dasDirection === "left") || + (e.code === "ArrowRight" && this.dasDirection === "right") || + (e.code === "ArrowDown" && this.dasDirection === "down")) { + this.dasDirection = null; + } + } + handleDAS(now) { + if (!this.dasDirection) + return; + // Check if the key is still held + const codeMap = { left: "ArrowLeft", right: "ArrowRight", down: "ArrowDown" }; + if (!this.keysDown.has(codeMap[this.dasDirection])) { + this.dasDirection = null; + return; + } + const elapsed = now - this.dasTimer; + if (!this.dasActive) { + if (elapsed >= this.dasDelay) { + this.dasActive = true; + this.dasTimer = now; + this.dasRepeat(); + } + } + else { + if (elapsed >= this.dasRate) { + this.dasTimer = now; + this.dasRepeat(); + } + } + } + dasRepeat() { + switch (this.dasDirection) { + case "left": + this.movePiece(-1, 0); + break; + case "right": + this.movePiece(1, 0); + break; + case "down": + if (this.movePiece(0, 1)) + this.score += 1; + break; + } + } + // ── End Game ────────────────────────────────────────────────────── + endGame() { + this.gameOver = true; + cancelAnimationFrame(this.animFrameId); + this.draw(); + this.showOverlay("GAME OVER", `Final score: ${this.score.toLocaleString()}\nPress R to restart`); + } + restart() { + this.board = createBoard(); + this.score = 0; + this.level = 0; + this.linesCleared = 0; + this.gameOver = false; + this.paused = false; + this.currentPiece = null; + this.bag = new Bag(); + this.nextPieceIndex = this.bag.next(); + this.gravityInterval = getGravity(0); + this.dasDirection = null; + this.keysDown.clear(); + this.spawnPiece(); + this.hideOverlay(); + this.lastTick = performance.now(); + this.draw(); + this.loop(this.lastTick); + } + // ── Rendering ───────────────────────────────────────────────────── + draw() { + // Draw board + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.cells[r][c]; + if (!cell) + continue; + const boardColor = this.board[r + HIDDEN_ROWS][c]; + cell.style.backgroundColor = boardColor ?? ""; + cell.className = "cell" + (boardColor ? " filled" : ""); + } + } + // Draw ghost piece + const ghost = this.getGhostPosition(); + if (this.currentPiece && ghost && !this.gameOver) { + const { shape } = this.currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const br = ghost.y + r - HIDDEN_ROWS; + const bc = ghost.x + c; + if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) { + const cell = this.cells[br][bc]; + if (cell && !this.board[br + HIDDEN_ROWS][bc]) { + cell.style.backgroundColor = this.currentPiece.color; + cell.className = "cell ghost"; + } + } + } + } + } + // Draw current piece + if (this.currentPiece && !this.gameOver) { + const { shape, pos, color } = this.currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) + continue; + const br = pos.y + r - HIDDEN_ROWS; + const bc = pos.x + c; + if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) { + const cell = this.cells[br][bc]; + if (cell) { + cell.style.backgroundColor = color; + cell.className = "cell active"; + } + } + } + } + } + // Draw next piece preview + const nextT = TETROMINOES[this.nextPieceIndex]; + const nextShape = nextT.shape; + for (let r = 0; r < 4; r++) { + for (let c = 0; c < 4; c++) { + const cell = this.nextCells[r][c]; + if (!cell) + continue; + const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1; + cell.style.backgroundColor = filled ? nextT.color : ""; + cell.className = "next-cell" + (filled ? " filled" : ""); + } + } + // Update HUD + this.scoreEl.textContent = this.score.toLocaleString(); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.linesCleared); + } +} +// ─── Bootstrap ──────────────────────────────────────────────────────── +let game; +window.addEventListener("DOMContentLoaded", () => { + game = new TetrisGame(); + window.addEventListener("keydown", (e) => { + if (e.code === "KeyR" && game.gameOver) { + game.restart(); + } + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/index.html b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/index.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Tetris</title> + <link rel="stylesheet" href="styles.css" /> +</head> +<body> + <div class="game-wrapper"> + <div class="board-container"> + <div id="board"></div> + <div id="overlay" class="overlay"> + <div id="overlay-title" class="overlay-title"></div> + <div id="overlay-sub" class="overlay-sub"></div> + </div> + </div> + + <div class="side-panel"> + <div class="panel-box"> + <h3>Next</h3> + <div id="next-piece"></div> + </div> + + <div class="panel-box"> + <h3>Score</h3> + <div id="score" class="value">0</div> + </div> + + <div class="panel-box"> + <h3>Level</h3> + <div id="level" class="value">0</div> + </div> + + <div class="panel-box"> + <h3>Lines</h3> + <div id="lines" class="value">0</div> + </div> + + <div class="panel-box controls"> + <h3>Controls</h3> + <div><kbd>←</kbd> <kbd>→</kbd> Move</div> + <div><kbd>↑</kbd> Rotate</div> + <div><kbd>↓</kbd> Soft drop</div> + <div><kbd>Space</kbd> Hard drop</div> + <div><kbd>P</kbd> Pause</div> + <div><kbd>R</kbd> Restart</div> + </div> + </div> + </div> + + <script src="dist/tetris.js"></script> +</body> +</html> +\ No newline at end of file diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package-lock.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package-lock.json @@ -0,0 +1,2519 @@ +{ + "name": "loop-bench-cfbvwgky", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "loop-bench-cfbvwgky", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "html-validate": "^10.11.3", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", + "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.4", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", + "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", + "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", + "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", + "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@html-validate/stylish": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@html-validate/stylish/-/stylish-5.1.0.tgz", + "integrity": "sha512-Tyx/ZbHBpVZjvSleNplNMUhqT4UY1HwAMC97GSmasJXggWuvjNFLBS2scqnEb+ZG1szLq4zgjOioj7cVWV9WuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^4.0.0" + }, + "engines": { + "node": "^20.11 || >= 22.16" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jscpd/badge-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.0.4.tgz", + "integrity": "sha512-I9b4MmLXPM2vo0SxSUWnNGKcA4PjQlD3GzXvFK60z43cN/EIdLbOq3FVwCL+dg2obUqGXKIzAm7EsDFTg0D+mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "badgen": "^3.2.3", + "colors": "^1.4.0", + "fs-extra": "^11.2.0" + } + }, + "node_modules/@jscpd/core": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.0.4.tgz", + "integrity": "sha512-QGMT3iXEX1fI6lgjPH+x8eyJwhwr2KkpSF5uBpjC0Z5Xloj0yFTFLtwJT+RhxP/Ob4WYrtx2jvpKB269oIwgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1" + } + }, + "node_modules/@jscpd/finder": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.0.4.tgz", + "integrity": "sha512-qVUWY7Nzuvfd5OIk+n7/5CM98LmFroLqblRXAI2gDABwZrc7qS+WH2SNr0qoUq0f4OqwM+piiwKvwL/VDNn/Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "blamer": "^1.0.6", + "bytes": "^3.1.2", + "cli-table3": "^0.6.5", + "colors": "^1.4.0", + "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", + "markdown-table": "^2.0.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/html-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.0.4.tgz", + "integrity": "sha512-YiepyeYkeH74Kx59PJRdUdonznct0wHPFkf6FLQN+mCBoy6leAWCcOfHtcexnp+UsBFDlItG5nRdKrDSxSH+Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "1.4.0", + "fs-extra": "^11.2.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/tokenizer": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.0.4.tgz", + "integrity": "sha512-xxYYY/qaLah/FlwogEbGIxx9CjDO+G9E6qawcy26WwrflzJb6wsnhjwdneN6Wb0RNCDsqvzY+bzG453jsin4UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "reprism": "^0.0.11", + "spark-md5": "^3.0.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/badgen": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/badgen/-/badgen-3.2.3.tgz", + "integrity": "sha512-svDuwkc63E/z0ky3drpUppB83s/nlgDciH9m+STwwQoWyq7yCgew1qEfJ+9axkKdNq7MskByptWUN9j1PGMwFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/blamer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/blamer/-/blamer-1.0.7.tgz", + "integrity": "sha512-GbBStl/EVlSWkiJQBZps3H1iARBrC7vt++Jb/TTmCNu/jZ04VW7tSN1nScbFXBUy1AN+jzeL7Zep9sbQxLhXKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gitignore-to-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gitignore-to-glob/-/gitignore-to-glob-0.3.0.tgz", + "integrity": "sha512-mk74BdnK7lIwDHnotHddx1wsjMOFIThpLY3cPNniJ/2fA/tlLzHnFxIdR+4sLOu5KGgQJdij4kjJ2RoUNnCNMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.4 <5 || >=6.9" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-validate": { + "version": "10.11.3", + "resolved": "https://registry.npmjs.org/html-validate/-/html-validate-10.11.3.tgz", + "integrity": "sha512-wKUq9iR6bukMgiHhs/ORThZzEbQoFiiPNN7aZfQ8dlmhttPb2sM2Ji2p+Fy5Xj1aH7QHJ1biT2SUDw7A01P2oA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/html-validate" + } + ], + "license": "MIT", + "dependencies": { + "@html-validate/stylish": "^5.0.0", + "@sidvind/better-ajv-errors": "4.0.1", + "ajv": "^8.0.0", + "glob": "^13.0.0", + "kleur": "^4.1.0", + "minimist": "^1.2.0", + "prompts": "^2.0.0", + "semver": "^7.0.0" + }, + "bin": { + "html-validate": "bin/html-validate.mjs" + }, + "engines": { + "node": "^20.19.0 || >= 22.16.0" + }, + "peerDependencies": { + "jest": "^28.1.3 || ^29.0.3 || ^30.0.0", + "jest-diff": "^28.1.3 || ^29.0.3 || ^30.0.0", + "jest-snapshot": "^28.1.3 || ^29.0.3 || ^30.0.0", + "vitest": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.1" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + }, + "jest-diff": { + "optional": true + }, + "jest-snapshot": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/html-validate/node_modules/@sidvind/better-ajv-errors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sidvind/better-ajv-errors/-/better-ajv-errors-4.0.1.tgz", + "integrity": "sha512-6arF1ssKxItxgitPYXafUoLmsVBA6K7m9+ZGj6hLDoBl7nWpJ33EInwQUdHTle2METeWGxgQiqSex20KZRykew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "kleur": "^4.1.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "ajv": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/html-validate/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/html-validate/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jscpd": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.0.8.tgz", + "integrity": "sha512-d2VNT/2Hv4dxT2/59He8Lyda4DYOxPRyRG9zBaOpTZAqJCVf2xLrBlZkT8Va6Lo9u3X2qz8Bpq4HrDi4JsrQhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/badge-reporter": "4.0.4", + "@jscpd/core": "4.0.4", + "@jscpd/finder": "4.0.4", + "@jscpd/html-reporter": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "colors": "^1.4.0", + "commander": "^5.0.0", + "fs-extra": "^11.2.0", + "gitignore-to-glob": "^0.3.0", + "jscpd-sarif-reporter": "4.0.6" + }, + "bin": { + "jscpd": "bin/jscpd" + } + }, + "node_modules/jscpd-sarif-reporter": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.0.6.tgz", + "integrity": "sha512-b9Sm3IPZ3+m8Lwa4gZa+4/LhDhlc/ZLEsLXKSOy1DANQ6kx0ueqZT+fUHWEdQ6m0o3+RIVIa7DmvLSojQD05ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "^1.4.0", + "fs-extra": "^11.2.0", + "node-sarif-builder": "^3.4.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.2.tgz", + "integrity": "sha512-wgWa6FWQ3QRRJbIjbsldRJZxdxYngT/dO0I5Ynmlnin8qy7tC6xYzbcJjtN4wHLXtkbVwHzk0C+OejVw1XM+DQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prompts/node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pug": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.4.tgz", + "integrity": "sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.4", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.4.tgz", + "integrity": "sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/reprism": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/reprism/-/reprism-0.0.11.tgz", + "integrity": "sha512-VsxDR5QxZo08M/3nRypNlScw5r3rKeSOPdU/QhDmu3Ai3BJxHn/qgfXGWQp/tAxUtzwYNo9W6997JZR0tPLZsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/spark-md5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz", + "integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package.json @@ -0,0 +1,21 @@ +{ + "name": "loop-bench-cfbvwgky", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "html-validate": "^10.11.3", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/src/tetris.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/src/tetris.ts @@ -0,0 +1,621 @@ +// ─── Types & Constants ──────────────────────────────────────────────── + +const COLS = 10; +const ROWS = 20; +const HIDDEN_ROWS = 2; // buffer rows above visible area + +type CellColor = string | null; +type Board = CellColor[][]; + +interface Position { + x: number; + y: number; +} + +interface Piece { + shape: number[][]; + color: string; + pos: Position; +} + +// Standard NES-style scoring +const LINE_SCORES = [0, 100, 300, 500, 800]; + +// Gravity intervals in ms per level (index = level, faster as level increases) +const GRAVITY_TABLE = [ + 800, 720, 630, 550, 470, 380, 300, 220, 150, 100, + 80, 80, 80, 70, 70, 70, 50, 50, 50, 30, +]; + +function getGravity(level: number): number { + if (level < GRAVITY_TABLE.length) return GRAVITY_TABLE[level]; + return 20; // cap +} + +// Tetromino definitions (shapes in their spawn orientation) +const TETROMINOES: { shape: number[][]; color: string }[] = [ + { shape: [[1, 1, 1, 1]], color: "#00f0f0" }, // I - cyan + { shape: [[1, 1], [1, 1]], color: "#f0f000" }, // O - yellow + { shape: [[0, 1, 0], [1, 1, 1]], color: "#a000f0" }, // T - purple + { shape: [[0, 1, 1], [1, 1, 0]], color: "#00f000" }, // S - green + { shape: [[1, 1, 0], [0, 1, 1]], color: "#f00000" }, // Z - red + { shape: [[1, 0, 0], [1, 1, 1]], color: "#0000f0" }, // J - blue + { shape: [[0, 0, 1], [1, 1, 1]], color: "#f0a000" }, // L - orange +]; + +// ─── Utility ────────────────────────────────────────────────────────── + +function createBoard(): Board { + const rows = ROWS + HIDDEN_ROWS; + const board: Board = []; + for (let r = 0; r < rows; r++) { + board.push(new Array<string | null>(COLS).fill(null)); + } + return board; +} + +function rotateMatrix(matrix: number[][]): number[][] { + const rows = matrix.length; + const cols = matrix[0].length; + const result: number[][] = []; + for (let c = 0; c < cols; c++) { + const newRow: number[] = []; + for (let r = rows - 1; r >= 0; r--) { + newRow.push(matrix[r][c]); + } + result.push(newRow); + } + return result; +} + +// Wall-kick offsets to try when rotation is blocked +const WALL_KICKS: Position[] = [ + { x: 0, y: 0 }, + { x: -1, y: 0 }, + { x: 1, y: 0 }, + { x: -2, y: 0 }, + { x: 2, y: 0 }, + { x: 0, y: -1 }, + { x: -1, y: -1 }, + { x: 1, y: -1 }, +]; + +// ─── Bag Randomiser (7-bag) ─────────────────────────────────────────── + +class Bag { + private bag: number[] = []; + + next(): number { + if (this.bag.length === 0) { + this.bag = [0, 1, 2, 3, 4, 5, 6]; + // Fisher-Yates shuffle + for (let i = this.bag.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]]; + } + } + return this.bag.pop()!; + } +} + +// ─── Game ───────────────────────────────────────────────────────────── + +class TetrisGame { + board: Board = createBoard(); + currentPiece: Piece | null = null; + nextPieceIndex: number; + bag = new Bag(); + score = 0; + level = 0; + linesCleared = 0; + gameOver = false; + paused = false; + + // Timing + private lastTick = 0; + private gravityInterval = getGravity(0); + private animFrameId = 0; + + // DAS (Delayed Auto Shift) for held keys + private dasDirection: "left" | "right" | "down" | null = null; + private dasTimer = 0; + private dasDelay = 170; // ms before auto-repeat starts + private dasRate = 50; // ms between auto-repeats + private dasActive = false; + private keysDown = new Set<string>(); + + // DOM references + private boardEl: HTMLElement; + private scoreEl: HTMLElement; + private levelEl: HTMLElement; + private linesEl: HTMLElement; + private nextPieceEl: HTMLElement; + private overlayEl: HTMLElement; + private overlayTitleEl: HTMLElement; + private overlaySubEl: HTMLElement; + private cells: (HTMLElement | null)[][] = []; + private nextCells: (HTMLElement | null)[][] = []; + + constructor() { + this.nextPieceIndex = this.bag.next(); + + // Grab DOM elements + this.boardEl = document.getElementById("board")!; + this.scoreEl = document.getElementById("score")!; + this.levelEl = document.getElementById("level")!; + this.linesEl = document.getElementById("lines")!; + this.nextPieceEl = document.getElementById("next-piece")!; + this.overlayEl = document.getElementById("overlay")!; + this.overlayTitleEl = document.getElementById("overlay-title")!; + this.overlaySubEl = document.getElementById("overlay-sub")!; + + this.buildBoardDOM(); + this.buildNextPieceDOM(); + + // Input + window.addEventListener("keydown", (e) => this.onKeyDown(e)); + window.addEventListener("keyup", (e) => this.onKeyUp(e)); + + // Start + this.spawnPiece(); + this.showOverlay("TETRIS", "Press any key to start"); + this.draw(); + } + + // ── DOM Construction ────────────────────────────────────────────── + + private buildBoardDOM(): void { + this.boardEl.innerHTML = ""; + this.cells = []; + for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) { + const rowCells: (HTMLElement | null)[] = []; + const rowDiv = document.createElement("div"); + rowDiv.className = "board-row"; + for (let c = 0; c < COLS; c++) { + const cell = document.createElement("div"); + cell.className = "cell"; + rowDiv.appendChild(cell); + rowCells.push(cell); + } + this.boardEl.appendChild(rowDiv); + this.cells.push(rowCells); + } + } + + private buildNextPieceDOM(): void { + this.nextPieceEl.innerHTML = ""; + this.nextCells = []; + for (let r = 0; r < 4; r++) { + const rowCells: (HTMLElement | null)[] = []; + const rowDiv = document.createElement("div"); + rowDiv.className = "next-row"; + for (let c = 0; c < 4; c++) { + const cell = document.createElement("div"); + cell.className = "next-cell"; + rowDiv.appendChild(cell); + rowCells.push(cell); + } + this.nextPieceEl.appendChild(rowDiv); + this.nextCells.push(rowCells); + } + } + + // ── Overlay ─────────────────────────────────────────────────────── + + private showOverlay(title: string, sub: string): void { + this.overlayTitleEl.textContent = title; + this.overlaySubEl.textContent = sub; + this.overlayEl.classList.remove("hidden"); + } + + private hideOverlay(): void { + this.overlayEl.classList.add("hidden"); + } + + // ── Game Loop ───────────────────────────────────────────────────── + + start(): void { + this.hideOverlay(); + this.lastTick = performance.now(); + this.loop(this.lastTick); + } + + private loop = (now: number): void => { + if (this.gameOver) return; + if (this.paused) { + this.animFrameId = requestAnimationFrame(this.loop); + return; + } + + const dt = now - this.lastTick; + + // DAS handling + this.handleDAS(now); + + // Gravity + if (dt >= this.gravityInterval) { + this.tick(); + this.lastTick = now; + } + + this.draw(); + this.animFrameId = requestAnimationFrame(this.loop); + }; + + private tick(): void { + if (!this.currentPiece || this.gameOver) return; + if (!this.movePiece(0, 1)) { + this.lockPiece(); + const cleared = this.clearLines(); + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * (this.level + 1); + this.linesCleared += cleared; + const newLevel = Math.floor(this.linesCleared / 10); + if (newLevel > this.level) { + this.level = newLevel; + this.gravityInterval = getGravity(this.level); + } + } + if (!this.spawnPiece()) { + this.endGame(); + return; + } + } + } + + // ── Piece Management ────────────────────────────────────────────── + + private spawnPiece(): boolean { + const idx = this.nextPieceIndex; + this.nextPieceIndex = this.bag.next(); + const t = TETROMINOES[idx]; + const shape = t.shape.map((row) => [...row]); + const piece: Piece = { + shape, + color: t.color, + pos: { + x: Math.floor((COLS - shape[0].length) / 2), + y: 0, + }, + }; + this.currentPiece = piece; + if (!this.isValid(piece.shape, piece.pos)) { + return false; + } + return true; + } + + private lockPiece(): void { + if (!this.currentPiece) return; + const { shape, pos, color } = this.currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (shape[r][c]) { + const br = pos.y + r; + const bc = pos.x + c; + if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) { + this.board[br][bc] = color; + } + } + } + } + } + + private clearLines(): number { + let cleared = 0; + for (let r = this.board.length - 1; r >= 0; r--) { + if (this.board[r].every((cell) => cell !== null)) { + this.board.splice(r, 1); + this.board.unshift(new Array<string | null>(COLS).fill(null)); + cleared++; + r++; // recheck same index + } + } + return cleared; + } + + // ── Collision ───────────────────────────────────────────────────── + + private isValid(shape: number[][], pos: Position): boolean { + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const br = pos.y + r; + const bc = pos.x + c; + if (bc < 0 || bc >= COLS || br >= this.board.length) return false; + if (br < 0) continue; // above board is OK + if (this.board[br][bc] !== null) return false; + } + } + return true; + } + + // ── Movement ────────────────────────────────────────────────────── + + movePiece(dx: number, dy: number): boolean { + if (!this.currentPiece) return false; + const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy }; + if (this.isValid(this.currentPiece.shape, newPos)) { + this.currentPiece.pos = newPos; + return true; + } + return false; + } + + private rotatePiece(): void { + if (!this.currentPiece) return; + const rotated = rotateMatrix(this.currentPiece.shape); + // Try wall kicks + for (const kick of WALL_KICKS) { + const testPos = { + x: this.currentPiece.pos.x + kick.x, + y: this.currentPiece.pos.y + kick.y, + }; + if (this.isValid(rotated, testPos)) { + this.currentPiece.shape = rotated; + this.currentPiece.pos = testPos; + return; + } + } + } + + private hardDrop(): void { + if (!this.currentPiece) return; + let dropped = 0; + while (this.movePiece(0, 1)) dropped++; + this.score += dropped * 2; + this.lockPiece(); + const cleared = this.clearLines(); + if (cleared > 0) { + this.score += LINE_SCORES[cleared] * (this.level + 1); + this.linesCleared += cleared; + const newLevel = Math.floor(this.linesCleared / 10); + if (newLevel > this.level) { + this.level = newLevel; + this.gravityInterval = getGravity(this.level); + } + } + if (!this.spawnPiece()) { + this.endGame(); + return; + } + this.lastTick = performance.now(); + this.draw(); + } + + private getGhostPosition(): Position | null { + if (!this.currentPiece) return null; + let ghostY = this.currentPiece.pos.y; + while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) { + ghostY++; + } + return { x: this.currentPiece.pos.x, y: ghostY }; + } + + // ── Input Handling ──────────────────────────────────────────────── + + private started = false; + + private onKeyDown(e: KeyboardEvent): void { + if (!this.started) { + this.started = true; + this.start(); + return; + } + + if (this.gameOver) return; + + if (e.code === "KeyP") { + this.paused = !this.paused; + if (this.paused) { + this.showOverlay("PAUSED", "Press P to resume"); + } else { + this.hideOverlay(); + this.lastTick = performance.now(); + } + return; + } + + if (this.paused) return; + + this.keysDown.add(e.code); + + switch (e.code) { + case "ArrowLeft": + e.preventDefault(); + this.movePiece(-1, 0); + this.dasDirection = "left"; + this.dasTimer = performance.now(); + this.dasActive = false; + break; + case "ArrowRight": + e.preventDefault(); + this.movePiece(1, 0); + this.dasDirection = "right"; + this.dasTimer = performance.now(); + this.dasActive = false; + break; + case "ArrowDown": + e.preventDefault(); + if (this.movePiece(0, 1)) this.score += 1; + this.dasDirection = "down"; + this.dasTimer = performance.now(); + this.dasActive = false; + break; + case "ArrowUp": + case "KeyX": + e.preventDefault(); + this.rotatePiece(); + break; + case "Space": + e.preventDefault(); + this.hardDrop(); + break; + } + } + + private onKeyUp(e: KeyboardEvent): void { + this.keysDown.delete(e.code); + // If the key released matches current DAS direction, stop DAS + if ( + (e.code === "ArrowLeft" && this.dasDirection === "left") || + (e.code === "ArrowRight" && this.dasDirection === "right") || + (e.code === "ArrowDown" && this.dasDirection === "down") + ) { + this.dasDirection = null; + } + } + + private handleDAS(now: number): void { + if (!this.dasDirection) return; + // Check if the key is still held + const codeMap = { left: "ArrowLeft", right: "ArrowRight", down: "ArrowDown" }; + if (!this.keysDown.has(codeMap[this.dasDirection])) { + this.dasDirection = null; + return; + } + + const elapsed = now - this.dasTimer; + if (!this.dasActive) { + if (elapsed >= this.dasDelay) { + this.dasActive = true; + this.dasTimer = now; + this.dasRepeat(); + } + } else { + if (elapsed >= this.dasRate) { + this.dasTimer = now; + this.dasRepeat(); + } + } + } + + private dasRepeat(): void { + switch (this.dasDirection) { + case "left": + this.movePiece(-1, 0); + break; + case "right": + this.movePiece(1, 0); + break; + case "down": + if (this.movePiece(0, 1)) this.score += 1; + break; + } + } + + // ── End Game ────────────────────────────────────────────────────── + + private endGame(): void { + this.gameOver = true; + cancelAnimationFrame(this.animFrameId); + this.draw(); + this.showOverlay("GAME OVER", `Final score: ${this.score.toLocaleString()}\nPress R to restart`); + } + + restart(): void { + this.board = createBoard(); + this.score = 0; + this.level = 0; + this.linesCleared = 0; + this.gameOver = false; + this.paused = false; + this.currentPiece = null; + this.bag = new Bag(); + this.nextPieceIndex = this.bag.next(); + this.gravityInterval = getGravity(0); + this.dasDirection = null; + this.keysDown.clear(); + this.spawnPiece(); + this.hideOverlay(); + this.lastTick = performance.now(); + this.draw(); + this.loop(this.lastTick); + } + + // ── Rendering ───────────────────────────────────────────────────── + + private draw(): void { + // Draw board + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + const cell = this.cells[r][c]; + if (!cell) continue; + const boardColor = this.board[r + HIDDEN_ROWS][c]; + cell.style.backgroundColor = boardColor ?? ""; + cell.className = "cell" + (boardColor ? " filled" : ""); + } + } + + // Draw ghost piece + const ghost = this.getGhostPosition(); + if (this.currentPiece && ghost && !this.gameOver) { + const { shape } = this.currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const br = ghost.y + r - HIDDEN_ROWS; + const bc = ghost.x + c; + if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) { + const cell = this.cells[br][bc]; + if (cell && !this.board[br + HIDDEN_ROWS][bc]) { + cell.style.backgroundColor = this.currentPiece.color; + cell.className = "cell ghost"; + } + } + } + } + } + + // Draw current piece + if (this.currentPiece && !this.gameOver) { + const { shape, pos, color } = this.currentPiece; + for (let r = 0; r < shape.length; r++) { + for (let c = 0; c < shape[r].length; c++) { + if (!shape[r][c]) continue; + const br = pos.y + r - HIDDEN_ROWS; + const bc = pos.x + c; + if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) { + const cell = this.cells[br][bc]; + if (cell) { + cell.style.backgroundColor = color; + cell.className = "cell active"; + } + } + } + } + } + + // Draw next piece preview + const nextT = TETROMINOES[this.nextPieceIndex]; + const nextShape = nextT.shape; + for (let r = 0; r < 4; r++) { + for (let c = 0; c < 4; c++) { + const cell = this.nextCells[r][c]; + if (!cell) continue; + const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1; + cell.style.backgroundColor = filled ? nextT.color : ""; + cell.className = "next-cell" + (filled ? " filled" : ""); + } + } + + // Update HUD + this.scoreEl.textContent = this.score.toLocaleString(); + this.levelEl.textContent = String(this.level); + this.linesEl.textContent = String(this.linesCleared); + } +} + +// ─── Bootstrap ──────────────────────────────────────────────────────── + +let game: TetrisGame; + +window.addEventListener("DOMContentLoaded", () => { + game = new TetrisGame(); + + window.addEventListener("keydown", (e) => { + if (e.code === "KeyR" && game.gameOver) { + game.restart(); + } + }); +}); +\ No newline at end of file diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/styles.css b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/styles.css @@ -0,0 +1,180 @@ +/* ── Reset & Base ──────────────────────────────────────────────────── */ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, body { + height: 100%; + background: #0a0a1a; + color: #ddd; + font-family: "Courier New", Courier, monospace; + overflow: hidden; + user-select: none; +} + +/* ── Layout ────────────────────────────────────────────────────────── */ +.game-wrapper { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + gap: 32px; +} + +.board-container { + position: relative; +} + +#board { + display: flex; + flex-direction: column; + border: 3px solid #3a3a5c; + border-radius: 4px; + background: #111122; + box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(0, 0, 0, 0.5); +} + +.board-row { + display: flex; +} + +/* ── Cells ─────────────────────────────────────────────────────────── */ +.cell { + width: 30px; + height: 30px; + border: 1px solid rgba(255, 255, 255, 0.04); + border-radius: 2px; + transition: background-color 0.05s; +} + +.cell.filled { + border-color: rgba(255, 255, 255, 0.18); + box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15); +} + +.cell.active { + border-color: rgba(255, 255, 255, 0.35); + box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.25), 0 0 6px currentColor; +} + +.cell.ghost { + opacity: 0.2; + border-color: rgba(255, 255, 255, 0.1); +} + +/* ── Side Panel ────────────────────────────────────────────────────── */ +.side-panel { + display: flex; + flex-direction: column; + gap: 24px; + min-width: 160px; +} + +.panel-box { + background: rgba(255, 255, 255, 0.03); + border: 2px solid #3a3a5c; + border-radius: 6px; + padding: 16px; +} + +.panel-box h3 { + font-size: 12px; + text-transform: uppercase; + letter-spacing: 3px; + color: #777; + margin-bottom: 8px; + border-bottom: 1px solid #333; + padding-bottom: 6px; +} + +.panel-box .value { + font-size: 26px; + font-weight: bold; + color: #fff; + text-align: right; +} + +/* ── Next Piece Preview ────────────────────────────────────────────── */ +#next-piece { + display: flex; + flex-direction: column; + align-items: center; + padding-top: 4px; +} + +.next-row { + display: flex; +} + +.next-cell { + width: 22px; + height: 22px; + border: 1px solid rgba(255, 255, 255, 0.04); + border-radius: 2px; +} + +.next-cell.filled { + border-color: rgba(255, 255, 255, 0.18); + box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15); +} + +/* ── Controls Help ─────────────────────────────────────────────────── */ +.controls { + font-size: 11px; + color: #666; + line-height: 1.8; +} + +.controls kbd { + display: inline-block; + background: #222; + border: 1px solid #444; + border-radius: 3px; + padding: 1px 6px; + font-size: 11px; + color: #aaa; + min-width: 24px; + text-align: center; +} + +/* ── Overlay ───────────────────────────────────────────────────────── */ +.overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.82); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border-radius: 4px; + z-index: 10; + transition: opacity 0.2s; +} + +.overlay.hidden { + display: none; +} + +.overlay-title { + font-size: 28px; + font-weight: bold; + letter-spacing: 6px; + margin-bottom: 12px; + color: #fff; + text-shadow: 0 0 20px rgba(100, 100, 255, 0.6); +} + +.overlay-sub { + font-size: 13px; + color: #999; + white-space: pre-line; + text-align: center; + line-height: 1.6; +} +\ No newline at end of file diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 30_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/tetris.spec.ts @@ -0,0 +1,96 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + }); + + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Give the page a moment to finish initializing + await page.waitForTimeout(2000); + + expect(errors).toEqual([]); + }); + + test("game board is visible", async ({ page }) => { + // A Tetris game should render either a <canvas> or a grid of DOM elements + const canvas = page.locator("canvas"); + const gridContainer = page.locator( + [ + '[class*="board"]', + '[class*="grid"]', + '[class*="game"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); + + const canvasCount = await canvas.count(); + const gridCount = await gridContainer.count(); + + expect( + canvasCount + gridCount, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + }); + + test("keyboard input does not crash the game", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Press every key a Tetris game should handle + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + for (const key of keys) { + await page.keyboard.press(key); + await page.waitForTimeout(150); + } + + expect(errors).toEqual([]); + }); + + test("game state changes over time", async ({ page }) => { + // If the game is running, the visual output should change as pieces fall + const shot1 = await page.screenshot(); + await page.waitForTimeout(3000); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the page to visually change over 3 seconds (pieces should be falling)" + ).toBe(false); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 60_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/tetris.spec.ts @@ -0,0 +1,474 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +// Find the game surface: canvas or a grid-like DOM container. +function gameBoard(page: Page) { + return page.locator( + [ + "canvas", + '[class*="board"]', + '[class*="grid"]', + '[class*="game-area"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); +} + +// Click the board area to make sure it has focus, then try common +// start interactions in case the game waits for user action. +async function ensureGameStarted(page: Page) { + const board = gameBoard(page); + const count = await board.count(); + if (count > 0) { + try { + await board.first().click({ timeout: 2000 }); + } catch { + // click failed, continue anyway + } + } + + // Some games need a key press or button click to start + const startButton = page.locator( + 'button:has-text("start"), button:has-text("Start"), button:has-text("play"), button:has-text("Play"), [class*="start"], [id*="start"]' + ); + if ((await startButton.count()) > 0) { + try { + await startButton.first().click({ timeout: 2000 }); + } catch { + // ignore + } + } + + // Press Enter/Space as a fallback start trigger + await page.keyboard.press("Enter"); + await page.waitForTimeout(300); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + await page.waitForTimeout(1000); + await ensureGameStarted(page); + }); + + // ---- 1. Page loads without errors ---- + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + await page.waitForTimeout(2000); + expect(errors).toEqual([]); + }); + + // ---- 2. Game board is visible ---- + test("game board is visible", async ({ page }) => { + const board = gameBoard(page); + const count = await board.count(); + + expect( + count, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + + // The board element should have meaningful dimensions + const box = await board.first().boundingBox(); + expect(box, "Game board should be visible on screen").not.toBeNull(); + expect(box!.width).toBeGreaterThan(50); + expect(box!.height).toBeGreaterThan(50); + }); + + // ---- 3. Game starts automatically or via interaction ---- + test("game starts", async ({ page }) => { + // After beforeEach, the game should be running. Verify by checking that + // the page is not static: take two screenshots separated by time. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the game to show visual activity after starting" + ).toBe(false); + }); + + // ---- 4. Piece falls automatically (auto-drop) ---- + test("piece falls automatically", async ({ page }) => { + // Take screenshots at intervals without pressing any keys. + // A falling piece should cause visual changes. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot3 = await page.screenshot(); + + const buf1 = Buffer.from(shot1); + const buf2 = Buffer.from(shot2); + const buf3 = Buffer.from(shot3); + + // At least one pair should differ (piece is moving down) + const changed = !buf1.equals(buf2) || !buf2.equals(buf3); + expect(changed, "Expected piece to fall over time without input").toBe( + true + ); + }); + + // ---- 5. Left arrow moves piece left ---- + test("left arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + // The piece should have moved, so the screenshots should differ + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing left arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 6. Right arrow moves piece right ---- + test("right arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing right arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 7. Down arrow moves piece down faster ---- + test("down arrow accelerates piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + for (let i = 0; i < 10; i++) { + await page.keyboard.press("ArrowDown"); + await page.waitForTimeout(50); + } + await page.waitForTimeout(200); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing down arrow repeatedly" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 8. Up arrow (or Z) rotates piece ---- + test("rotation changes the piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowUp"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing rotate key" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 9. Space bar hard-drops piece ---- + test("space bar hard-drops piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing space (hard drop)" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 10. Pieces lock at the bottom ---- + test("pieces lock at the bottom", async ({ page }) => { + // Hard-drop several pieces and check that the bottom of the board + // accumulates filled cells (the visual should change cumulatively). + const shots: Buffer[] = []; + + shots.push(Buffer.from(await page.screenshot())); + + for (let i = 0; i < 3; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(800); + } + + shots.push(Buffer.from(await page.screenshot())); + + // After 3 hard drops, the board should look different from the start + // because pieces have stacked up at the bottom. + expect( + shots[0].equals(shots[1]), + "Expected pieces to stack up at the bottom after hard drops" + ).toBe(false); + }); + + // ---- 11. New piece spawns after lock ---- + test("new piece spawns after locking", async ({ page }) => { + // Hard-drop to lock a piece, then wait and verify the game is still + // showing activity (a new piece should be falling). + await page.keyboard.press("Space"); + await page.waitForTimeout(1000); + + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + + // If a new piece spawned and is falling, the screen should change + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected a new piece to spawn and fall after the previous one locked" + ).toBe(false); + }); + + // ---- 12. Multiple different pieces appear ---- + test("multiple different pieces appear", async ({ page }) => { + // Play through several pieces and capture screenshots. Different piece + // shapes should produce visually distinct patterns. + const shots: Buffer[] = []; + + for (let i = 0; i < 6; i++) { + // Move each piece to a different column so they don't overlap identically + if (i % 2 === 0) { + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + } else { + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(600); + shots.push(Buffer.from(await page.screenshot())); + } + + // At least some consecutive screenshots should differ (different piece shapes) + let differences = 0; + for (let i = 1; i < shots.length; i++) { + if (!shots[i - 1].equals(shots[i])) differences++; + } + + expect( + differences, + "Expected to see visual differences between consecutive pieces (different shapes)" + ).toBeGreaterThanOrEqual(2); + }); + + // ---- 13. Completed line clears ---- + test("completed line clears", async ({ page }) => { + // Fill a row by dropping many pieces. Observe whether any row disappears. + // We can detect this by tracking the total filled area -- after a line clear, + // the board should have less filled content than just before the clear. + const pageText = async () => + (await page.evaluate(() => document.body.innerText)) || ""; + + // Drop many pieces rapidly to fill rows + for (let i = 0; i < 30; i++) { + // Vary positions to try to complete a row + const moves = (i % 5) - 2; // -2, -1, 0, 1, 2 + for (let m = 0; m < Math.abs(moves); m++) { + await page.keyboard.press( + moves < 0 ? "ArrowLeft" : "ArrowRight" + ); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + // Check if a score or lines counter changed (common indicators of line clears) + const text = await pageText(); + const numbers = (text.match(/\d+/g) || []).map(Number); + const hasNonZero = numbers.some((n) => n > 0); + + // Also check visual: the board should not be completely static + const shot1 = await page.screenshot(); + await page.waitForTimeout(1000); + const shot2 = await page.screenshot(); + + // Either: score/lines increased, or game is still active (meaning lines cleared + // and made room for more pieces instead of game over) + const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + hasNonZero || stillActive, + "Expected evidence of line clearing (score > 0 or game still active after many drops)" + ).toBe(true); + }); + + // ---- 14. Score increases during play ---- + test("score increases during play", async ({ page }) => { + // Look for a score display on the page + const getNumbers = async () => { + const text = (await page.evaluate(() => document.body.innerText)) || ""; + return (text.match(/\d+/g) || []).map(Number); + }; + + const numbersBefore = await getNumbers(); + + // Play for a while: drop several pieces + for (let i = 0; i < 15; i++) { + const offset = (i % 5) - 2; + for (let m = 0; m < Math.abs(offset); m++) { + await page.keyboard.press(offset < 0 ? "ArrowLeft" : "ArrowRight"); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + const numbersAfter = await getNumbers(); + + // At least one number on the page should have increased + // (score, lines counter, level, etc.) + let anyIncreased = false; + const maxLen = Math.min(numbersBefore.length, numbersAfter.length); + for (let i = 0; i < maxLen; i++) { + if (numbersAfter[i] > numbersBefore[i]) { + anyIncreased = true; + break; + } + } + + // Also accept if new numbers appeared + if (!anyIncreased && numbersAfter.length > numbersBefore.length) { + anyIncreased = true; + } + + // Also accept if the max number increased + if (!anyIncreased) { + const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0; + const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0; + if (maxAfter > maxBefore) anyIncreased = true; + } + + expect( + anyIncreased, + "Expected at least one numeric value on the page to increase during play (score, lines, level)" + ).toBe(true); + }); + + // ---- 15. Game over when pieces reach top ---- + test("game over when pieces reach top", async ({ page }) => { + // Stack pieces in the center until the game ends. + // Drop as many pieces as possible straight down. + for (let i = 0; i < 50; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(200); + } + + await page.waitForTimeout(2000); + + // After stacking to overflow, the game should show some game-over indicator: + // - text saying "game over", "you lose", "try again", "restart", "end" + // - or the game stops updating (static screen) + const text = ((await page.evaluate(() => document.body.innerText)) || "").toLowerCase(); + const gameOverText = + text.includes("game over") || + text.includes("gameover") || + text.includes("you lose") || + text.includes("try again") || + text.includes("restart") || + text.includes("play again") || + text.includes("ended"); + + // Check if the game stopped (screen is static) + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + gameOverText || isStatic, + "Expected game-over text or the game to stop after stacking pieces to the top" + ).toBe(true); + }); + + // ---- 16. Game runs for 30 seconds without crashing ---- + test("game runs for 30 seconds without crashing", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Simulate varied gameplay for 30 seconds + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + const start = Date.now(); + + while (Date.now() - start < 30_000) { + const key = keys[Math.floor(Math.random() * keys.length)]; + await page.keyboard.press(key); + await page.waitForTimeout(150 + Math.random() * 200); + } + + // The page should still be alive (not crashed, not blank) + const text = await page.evaluate(() => document.body.innerText); + expect(text, "Page body should not be empty after 30s of play").toBeTruthy(); + expect( + errors.length, + `Expected no console errors during 30s of play, got: ${errors.join("; ")}` + ).toBe(0); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tsconfig.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "bundler", + "ignoreDeprecations": "6.0", + "declaration": false, + "sourceMap": false + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package-lock.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package-lock.json @@ -0,0 +1,2270 @@ +{ + "name": "loop-bench-gb62gpgs", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "loop-bench-gb62gpgs", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", + "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.4", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", + "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", + "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", + "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", + "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jscpd/badge-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.0.4.tgz", + "integrity": "sha512-I9b4MmLXPM2vo0SxSUWnNGKcA4PjQlD3GzXvFK60z43cN/EIdLbOq3FVwCL+dg2obUqGXKIzAm7EsDFTg0D+mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "badgen": "^3.2.3", + "colors": "^1.4.0", + "fs-extra": "^11.2.0" + } + }, + "node_modules/@jscpd/core": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.0.4.tgz", + "integrity": "sha512-QGMT3iXEX1fI6lgjPH+x8eyJwhwr2KkpSF5uBpjC0Z5Xloj0yFTFLtwJT+RhxP/Ob4WYrtx2jvpKB269oIwgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1" + } + }, + "node_modules/@jscpd/finder": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.0.4.tgz", + "integrity": "sha512-qVUWY7Nzuvfd5OIk+n7/5CM98LmFroLqblRXAI2gDABwZrc7qS+WH2SNr0qoUq0f4OqwM+piiwKvwL/VDNn/Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "blamer": "^1.0.6", + "bytes": "^3.1.2", + "cli-table3": "^0.6.5", + "colors": "^1.4.0", + "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", + "markdown-table": "^2.0.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/html-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.0.4.tgz", + "integrity": "sha512-YiepyeYkeH74Kx59PJRdUdonznct0wHPFkf6FLQN+mCBoy6leAWCcOfHtcexnp+UsBFDlItG5nRdKrDSxSH+Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "1.4.0", + "fs-extra": "^11.2.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/tokenizer": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.0.4.tgz", + "integrity": "sha512-xxYYY/qaLah/FlwogEbGIxx9CjDO+G9E6qawcy26WwrflzJb6wsnhjwdneN6Wb0RNCDsqvzY+bzG453jsin4UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "reprism": "^0.0.11", + "spark-md5": "^3.0.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/badgen": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/badgen/-/badgen-3.2.3.tgz", + "integrity": "sha512-svDuwkc63E/z0ky3drpUppB83s/nlgDciH9m+STwwQoWyq7yCgew1qEfJ+9axkKdNq7MskByptWUN9j1PGMwFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/blamer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/blamer/-/blamer-1.0.7.tgz", + "integrity": "sha512-GbBStl/EVlSWkiJQBZps3H1iARBrC7vt++Jb/TTmCNu/jZ04VW7tSN1nScbFXBUy1AN+jzeL7Zep9sbQxLhXKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gitignore-to-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gitignore-to-glob/-/gitignore-to-glob-0.3.0.tgz", + "integrity": "sha512-mk74BdnK7lIwDHnotHddx1wsjMOFIThpLY3cPNniJ/2fA/tlLzHnFxIdR+4sLOu5KGgQJdij4kjJ2RoUNnCNMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.4 <5 || >=6.9" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jscpd": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.0.8.tgz", + "integrity": "sha512-d2VNT/2Hv4dxT2/59He8Lyda4DYOxPRyRG9zBaOpTZAqJCVf2xLrBlZkT8Va6Lo9u3X2qz8Bpq4HrDi4JsrQhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/badge-reporter": "4.0.4", + "@jscpd/core": "4.0.4", + "@jscpd/finder": "4.0.4", + "@jscpd/html-reporter": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "colors": "^1.4.0", + "commander": "^5.0.0", + "fs-extra": "^11.2.0", + "gitignore-to-glob": "^0.3.0", + "jscpd-sarif-reporter": "4.0.6" + }, + "bin": { + "jscpd": "bin/jscpd" + } + }, + "node_modules/jscpd-sarif-reporter": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.0.6.tgz", + "integrity": "sha512-b9Sm3IPZ3+m8Lwa4gZa+4/LhDhlc/ZLEsLXKSOy1DANQ6kx0ueqZT+fUHWEdQ6m0o3+RIVIa7DmvLSojQD05ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "^1.4.0", + "fs-extra": "^11.2.0", + "node-sarif-builder": "^3.4.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/pug": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.4.tgz", + "integrity": "sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.4", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.4.tgz", + "integrity": "sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/reprism": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/reprism/-/reprism-0.0.11.tgz", + "integrity": "sha512-VsxDR5QxZo08M/3nRypNlScw5r3rKeSOPdU/QhDmu3Ai3BJxHn/qgfXGWQp/tAxUtzwYNo9W6997JZR0tPLZsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/spark-md5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz", + "integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/package.json @@ -0,0 +1,20 @@ +{ + "name": "loop-bench-gb62gpgs", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 30_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-few/tetris.spec.ts @@ -0,0 +1,96 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + }); + + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Give the page a moment to finish initializing + await page.waitForTimeout(2000); + + expect(errors).toEqual([]); + }); + + test("game board is visible", async ({ page }) => { + // A Tetris game should render either a <canvas> or a grid of DOM elements + const canvas = page.locator("canvas"); + const gridContainer = page.locator( + [ + '[class*="board"]', + '[class*="grid"]', + '[class*="game"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); + + const canvasCount = await canvas.count(); + const gridCount = await gridContainer.count(); + + expect( + canvasCount + gridCount, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + }); + + test("keyboard input does not crash the game", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Press every key a Tetris game should handle + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + for (const key of keys) { + await page.keyboard.press(key); + await page.waitForTimeout(150); + } + + expect(errors).toEqual([]); + }); + + test("game state changes over time", async ({ page }) => { + // If the game is running, the visual output should change as pieces fall + const shot1 = await page.screenshot(); + await page.waitForTimeout(3000); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the page to visually change over 3 seconds (pieces should be falling)" + ).toBe(false); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 60_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/tests-full/tetris.spec.ts @@ -0,0 +1,474 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +// Find the game surface: canvas or a grid-like DOM container. +function gameBoard(page: Page) { + return page.locator( + [ + "canvas", + '[class*="board"]', + '[class*="grid"]', + '[class*="game-area"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); +} + +// Click the board area to make sure it has focus, then try common +// start interactions in case the game waits for user action. +async function ensureGameStarted(page: Page) { + const board = gameBoard(page); + const count = await board.count(); + if (count > 0) { + try { + await board.first().click({ timeout: 2000 }); + } catch { + // click failed, continue anyway + } + } + + // Some games need a key press or button click to start + const startButton = page.locator( + 'button:has-text("start"), button:has-text("Start"), button:has-text("play"), button:has-text("Play"), [class*="start"], [id*="start"]' + ); + if ((await startButton.count()) > 0) { + try { + await startButton.first().click({ timeout: 2000 }); + } catch { + // ignore + } + } + + // Press Enter/Space as a fallback start trigger + await page.keyboard.press("Enter"); + await page.waitForTimeout(300); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + await page.waitForTimeout(1000); + await ensureGameStarted(page); + }); + + // ---- 1. Page loads without errors ---- + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + await page.waitForTimeout(2000); + expect(errors).toEqual([]); + }); + + // ---- 2. Game board is visible ---- + test("game board is visible", async ({ page }) => { + const board = gameBoard(page); + const count = await board.count(); + + expect( + count, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + + // The board element should have meaningful dimensions + const box = await board.first().boundingBox(); + expect(box, "Game board should be visible on screen").not.toBeNull(); + expect(box!.width).toBeGreaterThan(50); + expect(box!.height).toBeGreaterThan(50); + }); + + // ---- 3. Game starts automatically or via interaction ---- + test("game starts", async ({ page }) => { + // After beforeEach, the game should be running. Verify by checking that + // the page is not static: take two screenshots separated by time. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the game to show visual activity after starting" + ).toBe(false); + }); + + // ---- 4. Piece falls automatically (auto-drop) ---- + test("piece falls automatically", async ({ page }) => { + // Take screenshots at intervals without pressing any keys. + // A falling piece should cause visual changes. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot3 = await page.screenshot(); + + const buf1 = Buffer.from(shot1); + const buf2 = Buffer.from(shot2); + const buf3 = Buffer.from(shot3); + + // At least one pair should differ (piece is moving down) + const changed = !buf1.equals(buf2) || !buf2.equals(buf3); + expect(changed, "Expected piece to fall over time without input").toBe( + true + ); + }); + + // ---- 5. Left arrow moves piece left ---- + test("left arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + // The piece should have moved, so the screenshots should differ + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing left arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 6. Right arrow moves piece right ---- + test("right arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing right arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 7. Down arrow moves piece down faster ---- + test("down arrow accelerates piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + for (let i = 0; i < 10; i++) { + await page.keyboard.press("ArrowDown"); + await page.waitForTimeout(50); + } + await page.waitForTimeout(200); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing down arrow repeatedly" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 8. Up arrow (or Z) rotates piece ---- + test("rotation changes the piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowUp"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing rotate key" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 9. Space bar hard-drops piece ---- + test("space bar hard-drops piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing space (hard drop)" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 10. Pieces lock at the bottom ---- + test("pieces lock at the bottom", async ({ page }) => { + // Hard-drop several pieces and check that the bottom of the board + // accumulates filled cells (the visual should change cumulatively). + const shots: Buffer[] = []; + + shots.push(Buffer.from(await page.screenshot())); + + for (let i = 0; i < 3; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(800); + } + + shots.push(Buffer.from(await page.screenshot())); + + // After 3 hard drops, the board should look different from the start + // because pieces have stacked up at the bottom. + expect( + shots[0].equals(shots[1]), + "Expected pieces to stack up at the bottom after hard drops" + ).toBe(false); + }); + + // ---- 11. New piece spawns after lock ---- + test("new piece spawns after locking", async ({ page }) => { + // Hard-drop to lock a piece, then wait and verify the game is still + // showing activity (a new piece should be falling). + await page.keyboard.press("Space"); + await page.waitForTimeout(1000); + + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + + // If a new piece spawned and is falling, the screen should change + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected a new piece to spawn and fall after the previous one locked" + ).toBe(false); + }); + + // ---- 12. Multiple different pieces appear ---- + test("multiple different pieces appear", async ({ page }) => { + // Play through several pieces and capture screenshots. Different piece + // shapes should produce visually distinct patterns. + const shots: Buffer[] = []; + + for (let i = 0; i < 6; i++) { + // Move each piece to a different column so they don't overlap identically + if (i % 2 === 0) { + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + } else { + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(600); + shots.push(Buffer.from(await page.screenshot())); + } + + // At least some consecutive screenshots should differ (different piece shapes) + let differences = 0; + for (let i = 1; i < shots.length; i++) { + if (!shots[i - 1].equals(shots[i])) differences++; + } + + expect( + differences, + "Expected to see visual differences between consecutive pieces (different shapes)" + ).toBeGreaterThanOrEqual(2); + }); + + // ---- 13. Completed line clears ---- + test("completed line clears", async ({ page }) => { + // Fill a row by dropping many pieces. Observe whether any row disappears. + // We can detect this by tracking the total filled area -- after a line clear, + // the board should have less filled content than just before the clear. + const pageText = async () => + (await page.evaluate(() => document.body.innerText)) || ""; + + // Drop many pieces rapidly to fill rows + for (let i = 0; i < 30; i++) { + // Vary positions to try to complete a row + const moves = (i % 5) - 2; // -2, -1, 0, 1, 2 + for (let m = 0; m < Math.abs(moves); m++) { + await page.keyboard.press( + moves < 0 ? "ArrowLeft" : "ArrowRight" + ); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + // Check if a score or lines counter changed (common indicators of line clears) + const text = await pageText(); + const numbers = (text.match(/\d+/g) || []).map(Number); + const hasNonZero = numbers.some((n) => n > 0); + + // Also check visual: the board should not be completely static + const shot1 = await page.screenshot(); + await page.waitForTimeout(1000); + const shot2 = await page.screenshot(); + + // Either: score/lines increased, or game is still active (meaning lines cleared + // and made room for more pieces instead of game over) + const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + hasNonZero || stillActive, + "Expected evidence of line clearing (score > 0 or game still active after many drops)" + ).toBe(true); + }); + + // ---- 14. Score increases during play ---- + test("score increases during play", async ({ page }) => { + // Look for a score display on the page + const getNumbers = async () => { + const text = (await page.evaluate(() => document.body.innerText)) || ""; + return (text.match(/\d+/g) || []).map(Number); + }; + + const numbersBefore = await getNumbers(); + + // Play for a while: drop several pieces + for (let i = 0; i < 15; i++) { + const offset = (i % 5) - 2; + for (let m = 0; m < Math.abs(offset); m++) { + await page.keyboard.press(offset < 0 ? "ArrowLeft" : "ArrowRight"); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + const numbersAfter = await getNumbers(); + + // At least one number on the page should have increased + // (score, lines counter, level, etc.) + let anyIncreased = false; + const maxLen = Math.min(numbersBefore.length, numbersAfter.length); + for (let i = 0; i < maxLen; i++) { + if (numbersAfter[i] > numbersBefore[i]) { + anyIncreased = true; + break; + } + } + + // Also accept if new numbers appeared + if (!anyIncreased && numbersAfter.length > numbersBefore.length) { + anyIncreased = true; + } + + // Also accept if the max number increased + if (!anyIncreased) { + const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0; + const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0; + if (maxAfter > maxBefore) anyIncreased = true; + } + + expect( + anyIncreased, + "Expected at least one numeric value on the page to increase during play (score, lines, level)" + ).toBe(true); + }); + + // ---- 15. Game over when pieces reach top ---- + test("game over when pieces reach top", async ({ page }) => { + // Stack pieces in the center until the game ends. + // Drop as many pieces as possible straight down. + for (let i = 0; i < 50; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(200); + } + + await page.waitForTimeout(2000); + + // After stacking to overflow, the game should show some game-over indicator: + // - text saying "game over", "you lose", "try again", "restart", "end" + // - or the game stops updating (static screen) + const text = ((await page.evaluate(() => document.body.innerText)) || "").toLowerCase(); + const gameOverText = + text.includes("game over") || + text.includes("gameover") || + text.includes("you lose") || + text.includes("try again") || + text.includes("restart") || + text.includes("play again") || + text.includes("ended"); + + // Check if the game stopped (screen is static) + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + gameOverText || isStatic, + "Expected game-over text or the game to stop after stacking pieces to the top" + ).toBe(true); + }); + + // ---- 16. Game runs for 30 seconds without crashing ---- + test("game runs for 30 seconds without crashing", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Simulate varied gameplay for 30 seconds + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + const start = Date.now(); + + while (Date.now() - start < 30_000) { + const key = keys[Math.floor(Math.random() * keys.length)]; + await page.keyboard.press(key); + await page.waitForTimeout(150 + Math.random() * 200); + } + + // The page should still be alive (not crashed, not blank) + const text = await page.evaluate(() => document.body.innerText); + expect(text, "Page body should not be empty after 30s of play").toBeTruthy(); + expect( + errors.length, + `Expected no console errors during 30s of play, got: ${errors.join("; ")}` + ).toBe(0); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package-lock.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package-lock.json @@ -0,0 +1,2270 @@ +{ + "name": "loop-bench-e8tgl0pn", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "loop-bench-e8tgl0pn", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", + "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.4", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", + "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", + "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", + "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", + "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jscpd/badge-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.0.4.tgz", + "integrity": "sha512-I9b4MmLXPM2vo0SxSUWnNGKcA4PjQlD3GzXvFK60z43cN/EIdLbOq3FVwCL+dg2obUqGXKIzAm7EsDFTg0D+mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "badgen": "^3.2.3", + "colors": "^1.4.0", + "fs-extra": "^11.2.0" + } + }, + "node_modules/@jscpd/core": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.0.4.tgz", + "integrity": "sha512-QGMT3iXEX1fI6lgjPH+x8eyJwhwr2KkpSF5uBpjC0Z5Xloj0yFTFLtwJT+RhxP/Ob4WYrtx2jvpKB269oIwgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1" + } + }, + "node_modules/@jscpd/finder": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.0.4.tgz", + "integrity": "sha512-qVUWY7Nzuvfd5OIk+n7/5CM98LmFroLqblRXAI2gDABwZrc7qS+WH2SNr0qoUq0f4OqwM+piiwKvwL/VDNn/Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "blamer": "^1.0.6", + "bytes": "^3.1.2", + "cli-table3": "^0.6.5", + "colors": "^1.4.0", + "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", + "markdown-table": "^2.0.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/html-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.0.4.tgz", + "integrity": "sha512-YiepyeYkeH74Kx59PJRdUdonznct0wHPFkf6FLQN+mCBoy6leAWCcOfHtcexnp+UsBFDlItG5nRdKrDSxSH+Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "1.4.0", + "fs-extra": "^11.2.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/tokenizer": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.0.4.tgz", + "integrity": "sha512-xxYYY/qaLah/FlwogEbGIxx9CjDO+G9E6qawcy26WwrflzJb6wsnhjwdneN6Wb0RNCDsqvzY+bzG453jsin4UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "reprism": "^0.0.11", + "spark-md5": "^3.0.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/badgen": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/badgen/-/badgen-3.2.3.tgz", + "integrity": "sha512-svDuwkc63E/z0ky3drpUppB83s/nlgDciH9m+STwwQoWyq7yCgew1qEfJ+9axkKdNq7MskByptWUN9j1PGMwFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/blamer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/blamer/-/blamer-1.0.7.tgz", + "integrity": "sha512-GbBStl/EVlSWkiJQBZps3H1iARBrC7vt++Jb/TTmCNu/jZ04VW7tSN1nScbFXBUy1AN+jzeL7Zep9sbQxLhXKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gitignore-to-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gitignore-to-glob/-/gitignore-to-glob-0.3.0.tgz", + "integrity": "sha512-mk74BdnK7lIwDHnotHddx1wsjMOFIThpLY3cPNniJ/2fA/tlLzHnFxIdR+4sLOu5KGgQJdij4kjJ2RoUNnCNMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.4 <5 || >=6.9" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jscpd": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.0.8.tgz", + "integrity": "sha512-d2VNT/2Hv4dxT2/59He8Lyda4DYOxPRyRG9zBaOpTZAqJCVf2xLrBlZkT8Va6Lo9u3X2qz8Bpq4HrDi4JsrQhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/badge-reporter": "4.0.4", + "@jscpd/core": "4.0.4", + "@jscpd/finder": "4.0.4", + "@jscpd/html-reporter": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "colors": "^1.4.0", + "commander": "^5.0.0", + "fs-extra": "^11.2.0", + "gitignore-to-glob": "^0.3.0", + "jscpd-sarif-reporter": "4.0.6" + }, + "bin": { + "jscpd": "bin/jscpd" + } + }, + "node_modules/jscpd-sarif-reporter": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.0.6.tgz", + "integrity": "sha512-b9Sm3IPZ3+m8Lwa4gZa+4/LhDhlc/ZLEsLXKSOy1DANQ6kx0ueqZT+fUHWEdQ6m0o3+RIVIa7DmvLSojQD05ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "^1.4.0", + "fs-extra": "^11.2.0", + "node-sarif-builder": "^3.4.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/pug": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.4.tgz", + "integrity": "sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.4", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.4.tgz", + "integrity": "sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/reprism": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/reprism/-/reprism-0.0.11.tgz", + "integrity": "sha512-VsxDR5QxZo08M/3nRypNlScw5r3rKeSOPdU/QhDmu3Ai3BJxHn/qgfXGWQp/tAxUtzwYNo9W6997JZR0tPLZsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/spark-md5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz", + "integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/package.json @@ -0,0 +1,20 @@ +{ + "name": "loop-bench-e8tgl0pn", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 30_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-few/tetris.spec.ts @@ -0,0 +1,96 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + }); + + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Give the page a moment to finish initializing + await page.waitForTimeout(2000); + + expect(errors).toEqual([]); + }); + + test("game board is visible", async ({ page }) => { + // A Tetris game should render either a <canvas> or a grid of DOM elements + const canvas = page.locator("canvas"); + const gridContainer = page.locator( + [ + '[class*="board"]', + '[class*="grid"]', + '[class*="game"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); + + const canvasCount = await canvas.count(); + const gridCount = await gridContainer.count(); + + expect( + canvasCount + gridCount, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + }); + + test("keyboard input does not crash the game", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Press every key a Tetris game should handle + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + for (const key of keys) { + await page.keyboard.press(key); + await page.waitForTimeout(150); + } + + expect(errors).toEqual([]); + }); + + test("game state changes over time", async ({ page }) => { + // If the game is running, the visual output should change as pieces fall + const shot1 = await page.screenshot(); + await page.waitForTimeout(3000); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the page to visually change over 3 seconds (pieces should be falling)" + ).toBe(false); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 60_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/tests-full/tetris.spec.ts @@ -0,0 +1,474 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +// Find the game surface: canvas or a grid-like DOM container. +function gameBoard(page: Page) { + return page.locator( + [ + "canvas", + '[class*="board"]', + '[class*="grid"]', + '[class*="game-area"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); +} + +// Click the board area to make sure it has focus, then try common +// start interactions in case the game waits for user action. +async function ensureGameStarted(page: Page) { + const board = gameBoard(page); + const count = await board.count(); + if (count > 0) { + try { + await board.first().click({ timeout: 2000 }); + } catch { + // click failed, continue anyway + } + } + + // Some games need a key press or button click to start + const startButton = page.locator( + 'button:has-text("start"), button:has-text("Start"), button:has-text("play"), button:has-text("Play"), [class*="start"], [id*="start"]' + ); + if ((await startButton.count()) > 0) { + try { + await startButton.first().click({ timeout: 2000 }); + } catch { + // ignore + } + } + + // Press Enter/Space as a fallback start trigger + await page.keyboard.press("Enter"); + await page.waitForTimeout(300); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + await page.waitForTimeout(1000); + await ensureGameStarted(page); + }); + + // ---- 1. Page loads without errors ---- + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + await page.waitForTimeout(2000); + expect(errors).toEqual([]); + }); + + // ---- 2. Game board is visible ---- + test("game board is visible", async ({ page }) => { + const board = gameBoard(page); + const count = await board.count(); + + expect( + count, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + + // The board element should have meaningful dimensions + const box = await board.first().boundingBox(); + expect(box, "Game board should be visible on screen").not.toBeNull(); + expect(box!.width).toBeGreaterThan(50); + expect(box!.height).toBeGreaterThan(50); + }); + + // ---- 3. Game starts automatically or via interaction ---- + test("game starts", async ({ page }) => { + // After beforeEach, the game should be running. Verify by checking that + // the page is not static: take two screenshots separated by time. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the game to show visual activity after starting" + ).toBe(false); + }); + + // ---- 4. Piece falls automatically (auto-drop) ---- + test("piece falls automatically", async ({ page }) => { + // Take screenshots at intervals without pressing any keys. + // A falling piece should cause visual changes. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot3 = await page.screenshot(); + + const buf1 = Buffer.from(shot1); + const buf2 = Buffer.from(shot2); + const buf3 = Buffer.from(shot3); + + // At least one pair should differ (piece is moving down) + const changed = !buf1.equals(buf2) || !buf2.equals(buf3); + expect(changed, "Expected piece to fall over time without input").toBe( + true + ); + }); + + // ---- 5. Left arrow moves piece left ---- + test("left arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + // The piece should have moved, so the screenshots should differ + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing left arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 6. Right arrow moves piece right ---- + test("right arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing right arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 7. Down arrow moves piece down faster ---- + test("down arrow accelerates piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + for (let i = 0; i < 10; i++) { + await page.keyboard.press("ArrowDown"); + await page.waitForTimeout(50); + } + await page.waitForTimeout(200); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing down arrow repeatedly" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 8. Up arrow (or Z) rotates piece ---- + test("rotation changes the piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowUp"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing rotate key" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 9. Space bar hard-drops piece ---- + test("space bar hard-drops piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing space (hard drop)" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 10. Pieces lock at the bottom ---- + test("pieces lock at the bottom", async ({ page }) => { + // Hard-drop several pieces and check that the bottom of the board + // accumulates filled cells (the visual should change cumulatively). + const shots: Buffer[] = []; + + shots.push(Buffer.from(await page.screenshot())); + + for (let i = 0; i < 3; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(800); + } + + shots.push(Buffer.from(await page.screenshot())); + + // After 3 hard drops, the board should look different from the start + // because pieces have stacked up at the bottom. + expect( + shots[0].equals(shots[1]), + "Expected pieces to stack up at the bottom after hard drops" + ).toBe(false); + }); + + // ---- 11. New piece spawns after lock ---- + test("new piece spawns after locking", async ({ page }) => { + // Hard-drop to lock a piece, then wait and verify the game is still + // showing activity (a new piece should be falling). + await page.keyboard.press("Space"); + await page.waitForTimeout(1000); + + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + + // If a new piece spawned and is falling, the screen should change + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected a new piece to spawn and fall after the previous one locked" + ).toBe(false); + }); + + // ---- 12. Multiple different pieces appear ---- + test("multiple different pieces appear", async ({ page }) => { + // Play through several pieces and capture screenshots. Different piece + // shapes should produce visually distinct patterns. + const shots: Buffer[] = []; + + for (let i = 0; i < 6; i++) { + // Move each piece to a different column so they don't overlap identically + if (i % 2 === 0) { + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + } else { + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(600); + shots.push(Buffer.from(await page.screenshot())); + } + + // At least some consecutive screenshots should differ (different piece shapes) + let differences = 0; + for (let i = 1; i < shots.length; i++) { + if (!shots[i - 1].equals(shots[i])) differences++; + } + + expect( + differences, + "Expected to see visual differences between consecutive pieces (different shapes)" + ).toBeGreaterThanOrEqual(2); + }); + + // ---- 13. Completed line clears ---- + test("completed line clears", async ({ page }) => { + // Fill a row by dropping many pieces. Observe whether any row disappears. + // We can detect this by tracking the total filled area -- after a line clear, + // the board should have less filled content than just before the clear. + const pageText = async () => + (await page.evaluate(() => document.body.innerText)) || ""; + + // Drop many pieces rapidly to fill rows + for (let i = 0; i < 30; i++) { + // Vary positions to try to complete a row + const moves = (i % 5) - 2; // -2, -1, 0, 1, 2 + for (let m = 0; m < Math.abs(moves); m++) { + await page.keyboard.press( + moves < 0 ? "ArrowLeft" : "ArrowRight" + ); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + // Check if a score or lines counter changed (common indicators of line clears) + const text = await pageText(); + const numbers = (text.match(/\d+/g) || []).map(Number); + const hasNonZero = numbers.some((n) => n > 0); + + // Also check visual: the board should not be completely static + const shot1 = await page.screenshot(); + await page.waitForTimeout(1000); + const shot2 = await page.screenshot(); + + // Either: score/lines increased, or game is still active (meaning lines cleared + // and made room for more pieces instead of game over) + const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + hasNonZero || stillActive, + "Expected evidence of line clearing (score > 0 or game still active after many drops)" + ).toBe(true); + }); + + // ---- 14. Score increases during play ---- + test("score increases during play", async ({ page }) => { + // Look for a score display on the page + const getNumbers = async () => { + const text = (await page.evaluate(() => document.body.innerText)) || ""; + return (text.match(/\d+/g) || []).map(Number); + }; + + const numbersBefore = await getNumbers(); + + // Play for a while: drop several pieces + for (let i = 0; i < 15; i++) { + const offset = (i % 5) - 2; + for (let m = 0; m < Math.abs(offset); m++) { + await page.keyboard.press(offset < 0 ? "ArrowLeft" : "ArrowRight"); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + const numbersAfter = await getNumbers(); + + // At least one number on the page should have increased + // (score, lines counter, level, etc.) + let anyIncreased = false; + const maxLen = Math.min(numbersBefore.length, numbersAfter.length); + for (let i = 0; i < maxLen; i++) { + if (numbersAfter[i] > numbersBefore[i]) { + anyIncreased = true; + break; + } + } + + // Also accept if new numbers appeared + if (!anyIncreased && numbersAfter.length > numbersBefore.length) { + anyIncreased = true; + } + + // Also accept if the max number increased + if (!anyIncreased) { + const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0; + const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0; + if (maxAfter > maxBefore) anyIncreased = true; + } + + expect( + anyIncreased, + "Expected at least one numeric value on the page to increase during play (score, lines, level)" + ).toBe(true); + }); + + // ---- 15. Game over when pieces reach top ---- + test("game over when pieces reach top", async ({ page }) => { + // Stack pieces in the center until the game ends. + // Drop as many pieces as possible straight down. + for (let i = 0; i < 50; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(200); + } + + await page.waitForTimeout(2000); + + // After stacking to overflow, the game should show some game-over indicator: + // - text saying "game over", "you lose", "try again", "restart", "end" + // - or the game stops updating (static screen) + const text = ((await page.evaluate(() => document.body.innerText)) || "").toLowerCase(); + const gameOverText = + text.includes("game over") || + text.includes("gameover") || + text.includes("you lose") || + text.includes("try again") || + text.includes("restart") || + text.includes("play again") || + text.includes("ended"); + + // Check if the game stopped (screen is static) + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + gameOverText || isStatic, + "Expected game-over text or the game to stop after stacking pieces to the top" + ).toBe(true); + }); + + // ---- 16. Game runs for 30 seconds without crashing ---- + test("game runs for 30 seconds without crashing", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Simulate varied gameplay for 30 seconds + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + const start = Date.now(); + + while (Date.now() - start < 30_000) { + const key = keys[Math.floor(Math.random() * keys.length)]; + await page.keyboard.press(key); + await page.waitForTimeout(150 + Math.random() * 200); + } + + // The page should still be alive (not crashed, not blank) + const text = await page.evaluate(() => document.body.innerText); + expect(text, "Page body should not be empty after 30s of play").toBeTruthy(); + expect( + errors.length, + `Expected no console errors during 30s of play, got: ${errors.join("; ")}` + ).toBe(0); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/package-lock.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/package-lock.json @@ -0,0 +1,2270 @@ +{ + "name": "loop-bench-k7ar_jba", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "loop-bench-k7ar_jba", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.4.tgz", + "integrity": "sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.4", + "debug": "^4.3.1", + "minimatch": "^10.2.4" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.4.tgz", + "integrity": "sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.0.tgz", + "integrity": "sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.4.tgz", + "integrity": "sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.0.tgz", + "integrity": "sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.2.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jscpd/badge-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/badge-reporter/-/badge-reporter-4.0.4.tgz", + "integrity": "sha512-I9b4MmLXPM2vo0SxSUWnNGKcA4PjQlD3GzXvFK60z43cN/EIdLbOq3FVwCL+dg2obUqGXKIzAm7EsDFTg0D+mQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "badgen": "^3.2.3", + "colors": "^1.4.0", + "fs-extra": "^11.2.0" + } + }, + "node_modules/@jscpd/core": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/core/-/core-4.0.4.tgz", + "integrity": "sha512-QGMT3iXEX1fI6lgjPH+x8eyJwhwr2KkpSF5uBpjC0Z5Xloj0yFTFLtwJT+RhxP/Ob4WYrtx2jvpKB269oIwgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1" + } + }, + "node_modules/@jscpd/finder": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/finder/-/finder-4.0.4.tgz", + "integrity": "sha512-qVUWY7Nzuvfd5OIk+n7/5CM98LmFroLqblRXAI2gDABwZrc7qS+WH2SNr0qoUq0f4OqwM+piiwKvwL/VDNn/Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "blamer": "^1.0.6", + "bytes": "^3.1.2", + "cli-table3": "^0.6.5", + "colors": "^1.4.0", + "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", + "markdown-table": "^2.0.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/html-reporter": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/html-reporter/-/html-reporter-4.0.4.tgz", + "integrity": "sha512-YiepyeYkeH74Kx59PJRdUdonznct0wHPFkf6FLQN+mCBoy6leAWCcOfHtcexnp+UsBFDlItG5nRdKrDSxSH+Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "1.4.0", + "fs-extra": "^11.2.0", + "pug": "^3.0.3" + } + }, + "node_modules/@jscpd/tokenizer": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@jscpd/tokenizer/-/tokenizer-4.0.4.tgz", + "integrity": "sha512-xxYYY/qaLah/FlwogEbGIxx9CjDO+G9E6qawcy26WwrflzJb6wsnhjwdneN6Wb0RNCDsqvzY+bzG453jsin4UQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/core": "4.0.4", + "reprism": "^0.0.11", + "spark-md5": "^3.0.2" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", + "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert-never": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", + "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-walk": { + "version": "3.0.0-canary-5", + "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", + "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.9.6" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/badgen": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/badgen/-/badgen-3.2.3.tgz", + "integrity": "sha512-svDuwkc63E/z0ky3drpUppB83s/nlgDciH9m+STwwQoWyq7yCgew1qEfJ+9axkKdNq7MskByptWUN9j1PGMwFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/blamer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/blamer/-/blamer-1.0.7.tgz", + "integrity": "sha512-GbBStl/EVlSWkiJQBZps3H1iARBrC7vt++Jb/TTmCNu/jZ04VW7tSN1nScbFXBUy1AN+jzeL7Zep9sbQxLhXKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^4.0.0", + "which": "^2.0.2" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-regex": "^1.0.3" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/constantinople": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", + "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctypes": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", + "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.4", + "@eslint/config-helpers": "^0.5.4", + "@eslint/core": "^1.2.0", + "@eslint/plugin-kit": "^0.7.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.2.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gitignore-to-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gitignore-to-glob/-/gitignore-to-glob-0.3.0.tgz", + "integrity": "sha512-mk74BdnK7lIwDHnotHddx1wsjMOFIThpLY3cPNniJ/2fA/tlLzHnFxIdR+4sLOu5KGgQJdij4kjJ2RoUNnCNMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.4 <5 || >=6.9" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-expression": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", + "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^7.1.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/is-expression/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jscpd": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/jscpd/-/jscpd-4.0.8.tgz", + "integrity": "sha512-d2VNT/2Hv4dxT2/59He8Lyda4DYOxPRyRG9zBaOpTZAqJCVf2xLrBlZkT8Va6Lo9u3X2qz8Bpq4HrDi4JsrQhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jscpd/badge-reporter": "4.0.4", + "@jscpd/core": "4.0.4", + "@jscpd/finder": "4.0.4", + "@jscpd/html-reporter": "4.0.4", + "@jscpd/tokenizer": "4.0.4", + "colors": "^1.4.0", + "commander": "^5.0.0", + "fs-extra": "^11.2.0", + "gitignore-to-glob": "^0.3.0", + "jscpd-sarif-reporter": "4.0.6" + }, + "bin": { + "jscpd": "bin/jscpd" + } + }, + "node_modules/jscpd-sarif-reporter": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/jscpd-sarif-reporter/-/jscpd-sarif-reporter-4.0.6.tgz", + "integrity": "sha512-b9Sm3IPZ3+m8Lwa4gZa+4/LhDhlc/ZLEsLXKSOy1DANQ6kx0ueqZT+fUHWEdQ6m0o3+RIVIa7DmvLSojQD05ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "colors": "^1.4.0", + "fs-extra": "^11.2.0", + "node-sarif-builder": "^3.4.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-promise": "^2.0.0", + "promise": "^7.0.1" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/pug": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.4.tgz", + "integrity": "sha512-kFfq5mMzrS7+wrl5pLJzZEzemx34OQ0w4SARfhy/3yxTlhbstsudDwJzhf1hP02yHzbjoVMSXUj/Sz6RNfMyXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-code-gen": "^3.0.4", + "pug-filters": "^4.0.0", + "pug-lexer": "^5.0.1", + "pug-linker": "^4.0.0", + "pug-load": "^3.0.0", + "pug-parser": "^6.0.0", + "pug-runtime": "^3.0.1", + "pug-strip-comments": "^2.0.0" + } + }, + "node_modules/pug-attrs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", + "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "js-stringify": "^1.0.2", + "pug-runtime": "^3.0.0" + } + }, + "node_modules/pug-code-gen": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.4.tgz", + "integrity": "sha512-6okWYIKdasTyXICyEtvobmTZAVX57JkzgzIi4iRJlin8kmhG+Xry2dsus+Mun/nGCn6F2U49haHI5mkELXB14g==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.2", + "pug-attrs": "^3.0.0", + "pug-error": "^2.1.0", + "pug-runtime": "^3.0.1", + "void-elements": "^3.1.0", + "with": "^7.0.0" + } + }, + "node_modules/pug-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", + "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", + "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "constantinople": "^4.0.1", + "jstransformer": "1.0.0", + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0", + "resolve": "^1.15.1" + } + }, + "node_modules/pug-lexer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", + "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-parser": "^2.2.0", + "is-expression": "^4.0.0", + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-linker": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", + "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-load": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", + "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "pug-walk": "^2.0.0" + } + }, + "node_modules/pug-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", + "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0", + "token-stream": "1.0.0" + } + }, + "node_modules/pug-runtime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pug-strip-comments": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", + "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pug-error": "^2.0.0" + } + }, + "node_modules/pug-walk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/reprism": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/reprism/-/reprism-0.0.11.tgz", + "integrity": "sha512-VsxDR5QxZo08M/3nRypNlScw5r3rKeSOPdU/QhDmu3Ai3BJxHn/qgfXGWQp/tAxUtzwYNo9W6997JZR0tPLZsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/spark-md5": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.2.tgz", + "integrity": "sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz", + "integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/with": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", + "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", + "assert-never": "^1.2.1", + "babel-walk": "3.0.0-canary-5" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/package.json b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/package.json @@ -0,0 +1,20 @@ +{ + "name": "loop-bench-k7ar_jba", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "devDependencies": { + "@eslint/js": "^10.0.1", + "@types/node": "^25.5.2", + "eslint": "^10.2.0", + "jscpd": "^4.0.8", + "typescript": "^6.0.2" + } +} diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-few/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-few/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 30_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-few/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-few/tetris.spec.ts @@ -0,0 +1,96 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + }); + + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Give the page a moment to finish initializing + await page.waitForTimeout(2000); + + expect(errors).toEqual([]); + }); + + test("game board is visible", async ({ page }) => { + // A Tetris game should render either a <canvas> or a grid of DOM elements + const canvas = page.locator("canvas"); + const gridContainer = page.locator( + [ + '[class*="board"]', + '[class*="grid"]', + '[class*="game"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); + + const canvasCount = await canvas.count(); + const gridCount = await gridContainer.count(); + + expect( + canvasCount + gridCount, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + }); + + test("keyboard input does not crash the game", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Press every key a Tetris game should handle + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + for (const key of keys) { + await page.keyboard.press(key); + await page.waitForTimeout(150); + } + + expect(errors).toEqual([]); + }); + + test("game state changes over time", async ({ page }) => { + // If the game is running, the visual output should change as pieces fall + const shot1 = await page.screenshot(); + await page.waitForTimeout(3000); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the page to visually change over 3 seconds (pieces should be falling)" + ).toBe(false); + }); +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-full/playwright.config.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-full/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "@playwright/test"; + +export default defineConfig({ + testDir: ".", + timeout: 60_000, + retries: 0, + workers: 1, + use: { + baseURL: "http://localhost:3000", + headless: true, + viewport: { width: 1280, height: 720 }, + }, +}); diff --git a/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-full/tetris.spec.ts b/artifacts/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/tests-full/tetris.spec.ts @@ -0,0 +1,474 @@ +import { test, expect, type Page } from "@playwright/test"; + +// Try common entry points until one loads successfully. +async function loadGame(page: Page) { + const candidates = [ + "/", + "/index.html", + "/dist/index.html", + "/public/index.html", + "/build/index.html", + ]; + + for (const path of candidates) { + try { + const resp = await page.goto(path, { timeout: 5000 }); + if (resp?.ok()) return; + } catch { + continue; + } + } +} + +// Find the game surface: canvas or a grid-like DOM container. +function gameBoard(page: Page) { + return page.locator( + [ + "canvas", + '[class*="board"]', + '[class*="grid"]', + '[class*="game-area"]', + '[class*="field"]', + '[id*="board"]', + '[id*="grid"]', + '[id*="game"]', + '[id*="field"]', + "table", + ].join(", ") + ); +} + +// Click the board area to make sure it has focus, then try common +// start interactions in case the game waits for user action. +async function ensureGameStarted(page: Page) { + const board = gameBoard(page); + const count = await board.count(); + if (count > 0) { + try { + await board.first().click({ timeout: 2000 }); + } catch { + // click failed, continue anyway + } + } + + // Some games need a key press or button click to start + const startButton = page.locator( + 'button:has-text("start"), button:has-text("Start"), button:has-text("play"), button:has-text("Play"), [class*="start"], [id*="start"]' + ); + if ((await startButton.count()) > 0) { + try { + await startButton.first().click({ timeout: 2000 }); + } catch { + // ignore + } + } + + // Press Enter/Space as a fallback start trigger + await page.keyboard.press("Enter"); + await page.waitForTimeout(300); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); +} + +test.describe("Tetris Game", () => { + test.beforeEach(async ({ page }) => { + await loadGame(page); + await page.waitForLoadState("domcontentloaded"); + await page.waitForTimeout(1000); + await ensureGameStarted(page); + }); + + // ---- 1. Page loads without errors ---- + test("page loads without console errors", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + await page.waitForTimeout(2000); + expect(errors).toEqual([]); + }); + + // ---- 2. Game board is visible ---- + test("game board is visible", async ({ page }) => { + const board = gameBoard(page); + const count = await board.count(); + + expect( + count, + "Expected a <canvas> or a container with board/grid/game/field in its class or id" + ).toBeGreaterThan(0); + + // The board element should have meaningful dimensions + const box = await board.first().boundingBox(); + expect(box, "Game board should be visible on screen").not.toBeNull(); + expect(box!.width).toBeGreaterThan(50); + expect(box!.height).toBeGreaterThan(50); + }); + + // ---- 3. Game starts automatically or via interaction ---- + test("game starts", async ({ page }) => { + // After beforeEach, the game should be running. Verify by checking that + // the page is not static: take two screenshots separated by time. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected the game to show visual activity after starting" + ).toBe(false); + }); + + // ---- 4. Piece falls automatically (auto-drop) ---- + test("piece falls automatically", async ({ page }) => { + // Take screenshots at intervals without pressing any keys. + // A falling piece should cause visual changes. + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot3 = await page.screenshot(); + + const buf1 = Buffer.from(shot1); + const buf2 = Buffer.from(shot2); + const buf3 = Buffer.from(shot3); + + // At least one pair should differ (piece is moving down) + const changed = !buf1.equals(buf2) || !buf2.equals(buf3); + expect(changed, "Expected piece to fall over time without input").toBe( + true + ); + }); + + // ---- 5. Left arrow moves piece left ---- + test("left arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + // The piece should have moved, so the screenshots should differ + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing left arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 6. Right arrow moves piece right ---- + test("right arrow moves piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(200); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing right arrow" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 7. Down arrow moves piece down faster ---- + test("down arrow accelerates piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + for (let i = 0; i < 10; i++) { + await page.keyboard.press("ArrowDown"); + await page.waitForTimeout(50); + } + await page.waitForTimeout(200); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing down arrow repeatedly" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 8. Up arrow (or Z) rotates piece ---- + test("rotation changes the piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("ArrowUp"); + await page.waitForTimeout(300); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing rotate key" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 9. Space bar hard-drops piece ---- + test("space bar hard-drops piece", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + const shot1 = await page.screenshot(); + await page.keyboard.press("Space"); + await page.waitForTimeout(500); + const shot2 = await page.screenshot(); + + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected visual change after pressing space (hard drop)" + ).toBe(false); + expect(errors).toEqual([]); + }); + + // ---- 10. Pieces lock at the bottom ---- + test("pieces lock at the bottom", async ({ page }) => { + // Hard-drop several pieces and check that the bottom of the board + // accumulates filled cells (the visual should change cumulatively). + const shots: Buffer[] = []; + + shots.push(Buffer.from(await page.screenshot())); + + for (let i = 0; i < 3; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(800); + } + + shots.push(Buffer.from(await page.screenshot())); + + // After 3 hard drops, the board should look different from the start + // because pieces have stacked up at the bottom. + expect( + shots[0].equals(shots[1]), + "Expected pieces to stack up at the bottom after hard drops" + ).toBe(false); + }); + + // ---- 11. New piece spawns after lock ---- + test("new piece spawns after locking", async ({ page }) => { + // Hard-drop to lock a piece, then wait and verify the game is still + // showing activity (a new piece should be falling). + await page.keyboard.press("Space"); + await page.waitForTimeout(1000); + + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + + // If a new piece spawned and is falling, the screen should change + expect( + Buffer.from(shot1).equals(Buffer.from(shot2)), + "Expected a new piece to spawn and fall after the previous one locked" + ).toBe(false); + }); + + // ---- 12. Multiple different pieces appear ---- + test("multiple different pieces appear", async ({ page }) => { + // Play through several pieces and capture screenshots. Different piece + // shapes should produce visually distinct patterns. + const shots: Buffer[] = []; + + for (let i = 0; i < 6; i++) { + // Move each piece to a different column so they don't overlap identically + if (i % 2 === 0) { + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowLeft"); + await page.waitForTimeout(100); + } else { + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + await page.keyboard.press("ArrowRight"); + await page.waitForTimeout(100); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(600); + shots.push(Buffer.from(await page.screenshot())); + } + + // At least some consecutive screenshots should differ (different piece shapes) + let differences = 0; + for (let i = 1; i < shots.length; i++) { + if (!shots[i - 1].equals(shots[i])) differences++; + } + + expect( + differences, + "Expected to see visual differences between consecutive pieces (different shapes)" + ).toBeGreaterThanOrEqual(2); + }); + + // ---- 13. Completed line clears ---- + test("completed line clears", async ({ page }) => { + // Fill a row by dropping many pieces. Observe whether any row disappears. + // We can detect this by tracking the total filled area -- after a line clear, + // the board should have less filled content than just before the clear. + const pageText = async () => + (await page.evaluate(() => document.body.innerText)) || ""; + + // Drop many pieces rapidly to fill rows + for (let i = 0; i < 30; i++) { + // Vary positions to try to complete a row + const moves = (i % 5) - 2; // -2, -1, 0, 1, 2 + for (let m = 0; m < Math.abs(moves); m++) { + await page.keyboard.press( + moves < 0 ? "ArrowLeft" : "ArrowRight" + ); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + // Check if a score or lines counter changed (common indicators of line clears) + const text = await pageText(); + const numbers = (text.match(/\d+/g) || []).map(Number); + const hasNonZero = numbers.some((n) => n > 0); + + // Also check visual: the board should not be completely static + const shot1 = await page.screenshot(); + await page.waitForTimeout(1000); + const shot2 = await page.screenshot(); + + // Either: score/lines increased, or game is still active (meaning lines cleared + // and made room for more pieces instead of game over) + const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + hasNonZero || stillActive, + "Expected evidence of line clearing (score > 0 or game still active after many drops)" + ).toBe(true); + }); + + // ---- 14. Score increases during play ---- + test("score increases during play", async ({ page }) => { + // Look for a score display on the page + const getNumbers = async () => { + const text = (await page.evaluate(() => document.body.innerText)) || ""; + return (text.match(/\d+/g) || []).map(Number); + }; + + const numbersBefore = await getNumbers(); + + // Play for a while: drop several pieces + for (let i = 0; i < 15; i++) { + const offset = (i % 5) - 2; + for (let m = 0; m < Math.abs(offset); m++) { + await page.keyboard.press(offset < 0 ? "ArrowLeft" : "ArrowRight"); + await page.waitForTimeout(50); + } + await page.keyboard.press("Space"); + await page.waitForTimeout(300); + } + + const numbersAfter = await getNumbers(); + + // At least one number on the page should have increased + // (score, lines counter, level, etc.) + let anyIncreased = false; + const maxLen = Math.min(numbersBefore.length, numbersAfter.length); + for (let i = 0; i < maxLen; i++) { + if (numbersAfter[i] > numbersBefore[i]) { + anyIncreased = true; + break; + } + } + + // Also accept if new numbers appeared + if (!anyIncreased && numbersAfter.length > numbersBefore.length) { + anyIncreased = true; + } + + // Also accept if the max number increased + if (!anyIncreased) { + const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0; + const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0; + if (maxAfter > maxBefore) anyIncreased = true; + } + + expect( + anyIncreased, + "Expected at least one numeric value on the page to increase during play (score, lines, level)" + ).toBe(true); + }); + + // ---- 15. Game over when pieces reach top ---- + test("game over when pieces reach top", async ({ page }) => { + // Stack pieces in the center until the game ends. + // Drop as many pieces as possible straight down. + for (let i = 0; i < 50; i++) { + await page.keyboard.press("Space"); + await page.waitForTimeout(200); + } + + await page.waitForTimeout(2000); + + // After stacking to overflow, the game should show some game-over indicator: + // - text saying "game over", "you lose", "try again", "restart", "end" + // - or the game stops updating (static screen) + const text = ((await page.evaluate(() => document.body.innerText)) || "").toLowerCase(); + const gameOverText = + text.includes("game over") || + text.includes("gameover") || + text.includes("you lose") || + text.includes("try again") || + text.includes("restart") || + text.includes("play again") || + text.includes("ended"); + + // Check if the game stopped (screen is static) + const shot1 = await page.screenshot(); + await page.waitForTimeout(2000); + const shot2 = await page.screenshot(); + const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2)); + + expect( + gameOverText || isStatic, + "Expected game-over text or the game to stop after stacking pieces to the top" + ).toBe(true); + }); + + // ---- 16. Game runs for 30 seconds without crashing ---- + test("game runs for 30 seconds without crashing", async ({ page }) => { + const errors: string[] = []; + page.on("pageerror", (err) => errors.push(err.message)); + + // Simulate varied gameplay for 30 seconds + const keys = [ + "ArrowLeft", + "ArrowRight", + "ArrowDown", + "ArrowUp", + "Space", + ]; + const start = Date.now(); + + while (Date.now() - start < 30_000) { + const key = keys[Math.floor(Math.random() * keys.length)]; + await page.keyboard.press(key); + await page.waitForTimeout(150 + Math.random() * 200); + } + + // The page should still be alive (not crashed, not blank) + const text = await page.evaluate(() => document.body.innerText); + expect(text, "Page body should not be empty after 30s of play").toBeTruthy(); + expect( + errors.length, + `Expected no console errors during 30s of play, got: ${errors.join("; ")}` + ).toBe(0); + }); +}); diff --git a/results/analysis/main_effects_build_quality.json b/results/analysis/main_effects_build_quality.json @@ -3,17 +3,17 @@ "values": { "javascript": { "mean": 1.0, - "effect": 0.2197, + "effect": 0.2195, "n": 18 }, "typescript": { - "mean": 0.7747, - "effect": -0.0056, - "n": 372 + "mean": 0.775, + "effect": -0.0055, + "n": 377 }, "unspecified": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 17 } }, @@ -23,77 +23,77 @@ "values": { "glm-4.5-air": { "mean": 0.7057, - "effect": -0.0746, + "effect": -0.0749, "n": 37 }, "glm-4.7": { "mean": 0.6961, - "effect": -0.0841, + "effect": -0.0844, "n": 101 }, "glm-5.1": { - "mean": 0.6879, - "effect": -0.0923, - "n": 92 + "mean": 0.6938, + "effect": -0.0867, + "n": 97 }, "haiku": { "mean": 0.7993, - "effect": 0.0191, + "effect": 0.0188, "n": 74 }, "opus": { "mean": 0.9676, - "effect": 0.1874, + "effect": 0.1871, "n": 51 }, "sonnet": { "mean": 0.9492, - "effect": 0.169, + "effect": 0.1687, "n": 52 } }, - "spread": 0.2797 + "spread": 0.2738 }, "strategy": { "values": { "creative_validate": { "mean": 0.725, - "effect": -0.0553, + "effect": -0.0555, "n": 6 }, "delegate": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 }, "iterate": { "mean": 0.725, - "effect": -0.0553, + "effect": -0.0555, "n": 6 }, "none": { - "mean": 0.7089, - "effect": -0.0714, - "n": 212 + "mean": 0.7111, + "effect": -0.0695, + "n": 217 }, "plan_first": { "mean": 0.725, - "effect": -0.0553, + "effect": -0.0555, "n": 6 }, "review": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 }, "split_work": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 }, "use_subagents": { "mean": 0.8942, - "effect": 0.1139, + "effect": 0.1136, "n": 159 } }, @@ -103,18 +103,18 @@ "values": { "available": { "mean": 0.8866, - "effect": 0.1064, + "effect": 0.1061, "n": 163 }, "instructed": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 7 }, "off": { - "mean": 0.7104, - "effect": -0.0699, - "n": 237 + "mean": 0.7123, + "effect": -0.0683, + "n": 242 } }, "spread": 0.2166 @@ -123,265 +123,265 @@ "values": { "canvas": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 }, "dom": { - "mean": 0.67, - "effect": -0.1103, - "n": 3 + "mean": 0.802, + "effect": 0.0215, + "n": 5 }, "none": { "mean": 0.7845, - "effect": 0.0042, + "effect": 0.004, "n": 392 }, "svg": { "mean": 0.67, - "effect": -0.1103, - "n": 3 + "effect": -0.1105, + "n": 6 }, "webgl": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 3 } }, - "spread": 0.1145 + "spread": 0.132 }, "architecture": { "values": { "best_practices": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 }, "none": { - "mean": 0.7836, + "mean": 0.7839, "effect": 0.0033, - "n": 395 + "n": 400 }, "separation": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 } }, - "spread": 0.1136 + "spread": 0.1139 }, "design_guidance": { "values": { "none": { - "mean": 0.7836, + "mean": 0.7839, "effect": 0.0033, - "n": 395 + "n": 400 }, "specific": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 }, "vague": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 } }, - "spread": 0.1136 + "spread": 0.1139 }, "error_checking": { "values": { "none": { - "mean": 0.7819, + "mean": 0.7822, "effect": 0.0016, - "n": 401 + "n": 406 }, "self_verify": { "mean": 0.67, - "effect": -0.1103, + "effect": -0.1105, "n": 6 } }, - "spread": 0.1119 + "spread": 0.1122 }, "prompt_style": { "values": { "detailed": { "mean": 0.703, - "effect": -0.0773, + "effect": -0.0775, "n": 30 }, "simple": { - "mean": 0.7864, + "mean": 0.7866, "effect": 0.0061, - "n": 377 + "n": 382 } }, - "spread": 0.0834 + "spread": 0.0836 }, "max_budget": { "values": { "high": { "mean": 0.8278, - "effect": 0.0476, + "effect": 0.0473, "n": 23 }, "low": { - "mean": 0.7774, + "mean": 0.7777, "effect": -0.0028, - "n": 384 + "n": 389 } }, - "spread": 0.0504 + "spread": 0.0501 }, "tool_read": { "values": { "off": { "mean": 0.7497, - "effect": -0.0306, + "effect": -0.0309, "n": 29 }, "on": { - "mean": 0.7826, + "mean": 0.7829, "effect": 0.0023, - "n": 378 + "n": 383 } }, - "spread": 0.0329 + "spread": 0.0332 }, "linter": { "values": { "off": { "mean": 0.7549, - "effect": -0.0254, + "effect": -0.0257, "n": 35 }, "on": { - "mean": 0.7827, + "mean": 0.7829, "effect": 0.0024, - "n": 372 + "n": 377 } }, - "spread": 0.0278 + "spread": 0.028 }, "tool_edit": { "values": { "off": { "mean": 0.7552, - "effect": -0.0251, + "effect": -0.0254, "n": 31 }, "on": { - "mean": 0.7823, + "mean": 0.7826, "effect": 0.0021, - "n": 376 + "n": 381 } }, - "spread": 0.0271 + "spread": 0.0274 }, "context_file": { "values": { "none": { - "mean": 0.7788, + "mean": 0.7791, "effect": -0.0014, - "n": 379 + "n": 384 }, "provided": { "mean": 0.7996, - "effect": 0.0194, + "effect": 0.0191, "n": 28 } }, - "spread": 0.0208 + "spread": 0.0205 }, "effort": { "values": { "high": { - "mean": 0.7794, + "mean": 0.7797, "effect": -0.0008, - "n": 389 + "n": 394 }, "max": { "mean": 0.7983, - "effect": 0.0181, + "effect": 0.0178, "n": 18 } }, - "spread": 0.0189 + "spread": 0.0186 }, "tool_grep": { "values": { "off": { "mean": 0.7643, - "effect": -0.016, + "effect": -0.0162, "n": 28 }, "on": { - "mean": 0.7815, + "mean": 0.7817, "effect": 0.0012, - "n": 379 + "n": 384 } }, - "spread": 0.0172 + "spread": 0.0174 }, "tool_write": { "values": { "off": { "mean": 0.7643, - "effect": -0.016, + "effect": -0.0162, "n": 28 }, "on": { - "mean": 0.7815, + "mean": 0.7817, "effect": 0.0012, - "n": 379 + "n": 384 } }, - "spread": 0.0172 + "spread": 0.0174 }, "human_language": { "values": { "en": { - "mean": 0.7812, + "mean": 0.7814, "effect": 0.0009, - "n": 380 + "n": 385 }, "es": { "mean": 0.7678, - "effect": -0.0125, + "effect": -0.0128, "n": 27 } }, - "spread": 0.0134 + "spread": 0.0136 }, "tool_glob": { "values": { "off": { "mean": 0.7922, - "effect": 0.012, + "effect": 0.0117, "n": 27 }, "on": { - "mean": 0.7794, + "mean": 0.7797, "effect": -0.0008, - "n": 380 + "n": 385 } }, - "spread": 0.0128 + "spread": 0.0125 }, "web_search": { "values": { "off": { "mean": 0.7768, - "effect": -0.0035, + "effect": -0.0038, "n": 34 }, "on": { - "mean": 0.7806, + "mean": 0.7809, "effect": 0.0003, - "n": 373 + "n": 378 } }, - "spread": 0.0038 + "spread": 0.0041 } } \ No newline at end of file diff --git a/results/analysis/main_effects_code_quality.json b/results/analysis/main_effects_code_quality.json @@ -3,53 +3,53 @@ "values": { "glm-4.5-air": { "mean": 0.6592, - "effect": -0.0178, + "effect": -0.0173, "n": 37 }, "glm-4.7": { "mean": 0.5674, - "effect": -0.1096, + "effect": -0.109, "n": 101 }, "glm-5.1": { - "mean": 0.562, - "effect": -0.1151, - "n": 92 + "mean": 0.5655, + "effect": -0.111, + "n": 97 }, "haiku": { "mean": 0.7176, - "effect": 0.0405, + "effect": 0.0411, "n": 74 }, "opus": { "mean": 0.8647, - "effect": 0.1877, + "effect": 0.1882, "n": 51 }, "sonnet": { "mean": 0.8644, - "effect": 0.1874, + "effect": 0.188, "n": 52 } }, - "spread": 0.3027 + "spread": 0.2992 }, "playwright": { "values": { "available": { "mean": 0.7978, - "effect": 0.1208, + "effect": 0.1213, "n": 163 }, "instructed": { "mean": 0.5214, - "effect": -0.1556, + "effect": -0.155, "n": 7 }, "off": { - "mean": 0.5986, - "effect": -0.0785, - "n": 237 + "mean": 0.5992, + "effect": -0.0772, + "n": 242 } }, "spread": 0.2764 @@ -58,42 +58,42 @@ "values": { "creative_validate": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "delegate": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "iterate": { "mean": 0.6267, - "effect": -0.0504, + "effect": -0.0498, "n": 6 }, "none": { - "mean": 0.6025, - "effect": -0.0746, - "n": 212 + "mean": 0.6031, + "effect": -0.0734, + "n": 217 }, "plan_first": { "mean": 0.6, - "effect": -0.077, + "effect": -0.0765, "n": 6 }, "review": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "split_work": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "use_subagents": { "mean": 0.8004, - "effect": 0.1234, + "effect": 0.124, "n": 159 } }, @@ -103,27 +103,27 @@ "values": { "canvas": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "dom": { - "mean": 0.55, - "effect": -0.127, - "n": 3 + "mean": 0.63, + "effect": -0.0465, + "n": 5 }, "none": { "mean": 0.6819, - "effect": 0.0049, + "effect": 0.0054, "n": 392 }, "svg": { "mean": 0.55, - "effect": -0.127, - "n": 3 + "effect": -0.1265, + "n": 6 }, "webgl": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 3 } }, @@ -133,255 +133,255 @@ "values": { "best_practices": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "none": { - "mean": 0.6809, - "effect": 0.0039, - "n": 395 + "mean": 0.6803, + "effect": 0.0038, + "n": 400 }, "separation": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 } }, - "spread": 0.1309 + "spread": 0.1303 }, "design_guidance": { "values": { "none": { - "mean": 0.6809, - "effect": 0.0039, - "n": 395 + "mean": 0.6803, + "effect": 0.0038, + "n": 400 }, "specific": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 }, "vague": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 } }, - "spread": 0.1309 + "spread": 0.1303 }, "error_checking": { "values": { "none": { - "mean": 0.6789, + "mean": 0.6783, "effect": 0.0019, - "n": 401 + "n": 406 }, "self_verify": { "mean": 0.55, - "effect": -0.127, + "effect": -0.1265, "n": 6 } }, - "spread": 0.1289 + "spread": 0.1283 }, "language": { "values": { "javascript": { "mean": 0.7639, - "effect": 0.0869, + "effect": 0.0874, "n": 18 }, "typescript": { - "mean": 0.6687, + "mean": 0.6682, "effect": -0.0083, - "n": 372 + "n": 377 }, "unspecified": { "mean": 0.7676, - "effect": 0.0906, + "effect": 0.0912, "n": 17 } }, - "spread": 0.0989 + "spread": 0.0994 }, "prompt_style": { "values": { "detailed": { "mean": 0.7617, - "effect": 0.0846, + "effect": 0.0852, "n": 30 }, "simple": { - "mean": 0.6703, + "mean": 0.6698, "effect": -0.0067, - "n": 377 + "n": 382 } }, - "spread": 0.0914 + "spread": 0.0919 }, "tool_grep": { "values": { "off": { "mean": 0.7468, - "effect": 0.0698, + "effect": 0.0703, "n": 28 }, "on": { - "mean": 0.6719, - "effect": -0.0052, - "n": 379 + "mean": 0.6713, + "effect": -0.0051, + "n": 384 } }, - "spread": 0.0749 + "spread": 0.0755 }, "linter": { "values": { "off": { "mean": 0.7343, - "effect": 0.0573, + "effect": 0.0578, "n": 35 }, "on": { - "mean": 0.6716, + "mean": 0.6711, "effect": -0.0054, - "n": 372 + "n": 377 } }, - "spread": 0.0627 + "spread": 0.0632 }, "max_budget": { "values": { "high": { "mean": 0.7343, - "effect": 0.0573, + "effect": 0.0579, "n": 23 }, "low": { - "mean": 0.6736, + "mean": 0.673, "effect": -0.0034, - "n": 384 + "n": 389 } }, - "spread": 0.0607 + "spread": 0.0613 }, "web_search": { "values": { "off": { "mean": 0.7288, - "effect": 0.0518, + "effect": 0.0524, "n": 34 }, "on": { - "mean": 0.6723, + "mean": 0.6717, "effect": -0.0047, - "n": 373 + "n": 378 } }, - "spread": 0.0565 + "spread": 0.0571 }, "tool_read": { "values": { "off": { "mean": 0.7293, - "effect": 0.0523, + "effect": 0.0529, "n": 29 }, "on": { - "mean": 0.673, + "mean": 0.6725, "effect": -0.004, - "n": 378 + "n": 383 } }, - "spread": 0.0563 + "spread": 0.0568 }, "tool_write": { "values": { "off": { "mean": 0.7282, - "effect": 0.0512, + "effect": 0.0518, "n": 28 }, "on": { - "mean": 0.6732, + "mean": 0.6727, "effect": -0.0038, - "n": 379 + "n": 384 } }, - "spread": 0.055 + "spread": 0.0555 }, "tool_edit": { "values": { "off": { "mean": 0.7277, - "effect": 0.0507, + "effect": 0.0513, "n": 31 }, "on": { - "mean": 0.6728, + "mean": 0.6723, "effect": -0.0042, - "n": 376 + "n": 381 } }, - "spread": 0.0549 + "spread": 0.0554 }, "context_file": { "values": { "none": { - "mean": 0.6744, + "mean": 0.6738, "effect": -0.0027, - "n": 379 + "n": 384 }, "provided": { "mean": 0.7132, - "effect": 0.0362, + "effect": 0.0368, "n": 28 } }, - "spread": 0.0388 + "spread": 0.0394 }, "tool_glob": { "values": { "off": { "mean": 0.713, - "effect": 0.0359, + "effect": 0.0365, "n": 27 }, "on": { - "mean": 0.6745, + "mean": 0.6739, "effect": -0.0026, - "n": 380 + "n": 385 } }, - "spread": 0.0385 + "spread": 0.0391 }, "human_language": { "values": { "en": { - "mean": 0.6755, + "mean": 0.6749, "effect": -0.0015, - "n": 380 + "n": 385 }, "es": { "mean": 0.6981, - "effect": 0.0211, + "effect": 0.0217, "n": 27 } }, - "spread": 0.0226 + "spread": 0.0232 }, "effort": { "values": { "high": { - "mean": 0.6769, - "effect": -0.0001, - "n": 389 + "mean": 0.6763, + "effect": -0.0002, + "n": 394 }, "max": { "mean": 0.68, - "effect": 0.003, + "effect": 0.0035, "n": 18 } }, - "spread": 0.0031 + "spread": 0.0037 } } \ No newline at end of file diff --git a/results/analysis/main_effects_cost.json b/results/analysis/main_effects_cost.json @@ -3,77 +3,77 @@ "values": { "glm-4.5-air": { "mean": 0.2575, - "effect": -0.0982, + "effect": -0.0955, "n": 37 }, "glm-4.7": { "mean": 0.1132, - "effect": -0.2425, + "effect": -0.2398, "n": 101 }, "glm-5.1": { - "mean": 0.0176, - "effect": -0.3381, - "n": 92 + "mean": 0.0234, + "effect": -0.3295, + "n": 97 }, "haiku": { "mean": 0.266, - "effect": -0.0897, + "effect": -0.087, "n": 74 }, "opus": { "mean": 0.6385, - "effect": 0.2828, + "effect": 0.2855, "n": 51 }, "sonnet": { "mean": 1.3451, - "effect": 0.9894, + "effect": 0.9922, "n": 52 } }, - "spread": 1.3275 + "spread": 1.3217 }, "strategy": { "values": { "creative_validate": { "mean": 0.8985, - "effect": 0.5428, + "effect": 0.5456, "n": 6 }, "delegate": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 }, "iterate": { "mean": 0.4896, - "effect": 0.1339, + "effect": 0.1366, "n": 6 }, "none": { - "mean": 0.1213, - "effect": -0.2344, - "n": 212 + "mean": 0.1215, + "effect": -0.2315, + "n": 217 }, "plan_first": { "mean": 0.2719, - "effect": -0.0838, + "effect": -0.081, "n": 6 }, "review": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 }, "split_work": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 }, "use_subagents": { "mean": 0.6861, - "effect": 0.3305, + "effect": 0.3332, "n": 159 } }, @@ -83,18 +83,18 @@ "values": { "available": { "mean": 0.6817, - "effect": 0.326, + "effect": 0.3288, "n": 163 }, "instructed": { "mean": 0.0038, - "effect": -0.3518, + "effect": -0.3491, "n": 7 }, "off": { - "mean": 0.1418, - "effect": -0.2138, - "n": 237 + "mean": 0.1416, + "effect": -0.2113, + "n": 242 } }, "spread": 0.6779 @@ -103,27 +103,27 @@ "values": { "canvas": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 }, "dom": { - "mean": 0.0, - "effect": -0.3557, - "n": 3 + "mean": 0.1059, + "effect": -0.247, + "n": 5 }, "none": { "mean": 0.3693, - "effect": 0.0136, + "effect": 0.0163, "n": 392 }, "svg": { - "mean": 0.0, - "effect": -0.3557, - "n": 3 + "mean": 0.0208, + "effect": -0.3322, + "n": 6 }, "webgl": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 3 } }, @@ -133,255 +133,255 @@ "values": { "best_practices": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 }, "none": { - "mean": 0.3665, - "effect": 0.0108, - "n": 395 + "mean": 0.3635, + "effect": 0.0106, + "n": 400 }, "separation": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 } }, - "spread": 0.3665 + "spread": 0.3635 }, "design_guidance": { "values": { "none": { - "mean": 0.3665, - "effect": 0.0108, - "n": 395 + "mean": 0.3635, + "effect": 0.0106, + "n": 400 }, "specific": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 }, "vague": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 } }, - "spread": 0.3665 + "spread": 0.3635 }, "error_checking": { "values": { "none": { - "mean": 0.361, - "effect": 0.0053, - "n": 401 + "mean": 0.3582, + "effect": 0.0052, + "n": 406 }, "self_verify": { "mean": 0.0, - "effect": -0.3557, + "effect": -0.353, "n": 6 } }, - "spread": 0.361 + "spread": 0.3582 }, "effort": { "values": { "high": { - "mean": 0.3443, + "mean": 0.3416, "effect": -0.0113, - "n": 389 + "n": 394 }, "max": { "mean": 0.6006, - "effect": 0.2449, + "effect": 0.2477, "n": 18 } }, - "spread": 0.2563 + "spread": 0.259 }, "web_search": { "values": { "off": { "mean": 0.4189, - "effect": 0.0632, + "effect": 0.066, "n": 34 }, "on": { - "mean": 0.3499, - "effect": -0.0058, - "n": 373 + "mean": 0.347, + "effect": -0.0059, + "n": 378 } }, - "spread": 0.069 + "spread": 0.0719 }, "prompt_style": { "values": { "detailed": { "mean": 0.4041, - "effect": 0.0484, + "effect": 0.0511, "n": 30 }, "simple": { - "mean": 0.3518, - "effect": -0.0039, - "n": 377 + "mean": 0.3489, + "effect": -0.004, + "n": 382 } }, - "spread": 0.0523 + "spread": 0.0552 }, "context_file": { "values": { "none": { - "mean": 0.3523, - "effect": -0.0034, - "n": 379 + "mean": 0.3494, + "effect": -0.0036, + "n": 384 }, "provided": { "mean": 0.4019, - "effect": 0.0462, + "effect": 0.049, "n": 28 } }, - "spread": 0.0496 - }, - "tool_edit": { - "values": { - "off": { - "mean": 0.3174, - "effect": -0.0382, - "n": 31 - }, - "on": { - "mean": 0.3588, - "effect": 0.0032, - "n": 376 - } - }, - "spread": 0.0414 + "spread": 0.0525 }, "language": { "values": { "javascript": { "mean": 0.3246, - "effect": -0.0311, + "effect": -0.0284, "n": 18 }, "typescript": { - "mean": 0.3568, - "effect": 0.0011, - "n": 372 + "mean": 0.3538, + "effect": 0.0009, + "n": 377 }, "unspecified": { "mean": 0.3637, - "effect": 0.008, + "effect": 0.0107, "n": 17 } }, "spread": 0.0391 }, + "tool_edit": { + "values": { + "off": { + "mean": 0.3174, + "effect": -0.0355, + "n": 31 + }, + "on": { + "mean": 0.3558, + "effect": 0.0029, + "n": 381 + } + }, + "spread": 0.0384 + }, "human_language": { "values": { "en": { - "mean": 0.3534, - "effect": -0.0023, - "n": 380 + "mean": 0.3505, + "effect": -0.0025, + "n": 385 }, "es": { "mean": 0.3879, - "effect": 0.0323, + "effect": 0.035, "n": 27 } }, - "spread": 0.0345 + "spread": 0.0374 }, "max_budget": { "values": { "high": { "mean": 0.3852, - "effect": 0.0295, + "effect": 0.0323, "n": 23 }, "low": { - "mean": 0.3539, - "effect": -0.0018, - "n": 384 + "mean": 0.351, + "effect": -0.0019, + "n": 389 } }, - "spread": 0.0313 + "spread": 0.0342 }, "tool_read": { "values": { "off": { "mean": 0.375, - "effect": 0.0194, + "effect": 0.0221, "n": 29 }, "on": { - "mean": 0.3542, - "effect": -0.0015, - "n": 378 + "mean": 0.3513, + "effect": -0.0017, + "n": 383 } }, - "spread": 0.0208 + "spread": 0.0237 }, "tool_write": { "values": { "off": { "mean": 0.3718, - "effect": 0.0161, + "effect": 0.0188, "n": 28 }, "on": { - "mean": 0.3545, - "effect": -0.0012, - "n": 379 + "mean": 0.3516, + "effect": -0.0014, + "n": 384 } }, - "spread": 0.0173 + "spread": 0.0202 }, "tool_grep": { "values": { "off": { "mean": 0.3685, - "effect": 0.0129, + "effect": 0.0156, "n": 28 }, "on": { - "mean": 0.3547, - "effect": -0.001, - "n": 379 + "mean": 0.3518, + "effect": -0.0011, + "n": 384 } }, - "spread": 0.0138 + "spread": 0.0167 }, "linter": { "values": { "off": { "mean": 0.3596, - "effect": 0.0039, + "effect": 0.0066, "n": 35 }, "on": { - "mean": 0.3553, - "effect": -0.0004, - "n": 372 + "mean": 0.3523, + "effect": -0.0006, + "n": 377 } }, - "spread": 0.0043 + "spread": 0.0073 }, "tool_glob": { "values": { "off": { "mean": 0.3575, - "effect": 0.0019, + "effect": 0.0046, "n": 27 }, "on": { - "mean": 0.3555, - "effect": -0.0001, - "n": 380 + "mean": 0.3526, + "effect": -0.0003, + "n": 385 } }, - "spread": 0.002 + "spread": 0.0049 } } \ No newline at end of file diff --git a/results/analysis/main_effects_gameplay.json b/results/analysis/main_effects_gameplay.json @@ -3,53 +3,53 @@ "values": { "glm-4.5-air": { "mean": 0.313, - "effect": 0.0256, + "effect": 0.0242, "n": 37 }, "glm-4.7": { "mean": 0.0464, - "effect": -0.241, + "effect": -0.2424, "n": 101 }, "glm-5.1": { - "mean": 0.0292, - "effect": -0.2582, - "n": 92 + "mean": 0.0484, + "effect": -0.2404, + "n": 97 }, "haiku": { "mean": 0.5473, - "effect": 0.2599, + "effect": 0.2585, "n": 74 }, "opus": { "mean": 0.661, - "effect": 0.3736, + "effect": 0.3722, "n": 51 }, "sonnet": { "mean": 0.4579, - "effect": 0.1705, + "effect": 0.1691, "n": 52 } }, - "spread": 0.6318 + "spread": 0.6146 }, "playwright": { "values": { "available": { "mean": 0.5326, - "effect": 0.2452, + "effect": 0.2439, "n": 163 }, "instructed": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 7 }, "off": { - "mean": 0.1273, - "effect": -0.1602, - "n": 237 + "mean": 0.1329, + "effect": -0.1559, + "n": 242 } }, "spread": 0.5326 @@ -58,330 +58,330 @@ "values": { "creative_validate": { "mean": 0.0417, - "effect": -0.2458, + "effect": -0.2471, "n": 6 }, "delegate": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 }, "iterate": { "mean": 0.1883, - "effect": -0.0991, + "effect": -0.1005, "n": 6 }, "none": { - "mean": 0.1473, - "effect": -0.1401, - "n": 212 + "mean": 0.1531, + "effect": -0.1357, + "n": 217 }, "plan_first": { "mean": 0.125, - "effect": -0.1624, + "effect": -0.1638, "n": 6 }, "review": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 }, "split_work": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 }, "use_subagents": { "mean": 0.5259, - "effect": 0.2385, + "effect": 0.2371, "n": 159 } }, "spread": 0.5259 }, - "max_budget": { - "values": { - "high": { - "mean": 0.5691, - "effect": 0.2817, - "n": 23 - }, - "low": { - "mean": 0.2705, - "effect": -0.0169, - "n": 384 - } - }, - "spread": 0.2986 - }, "renderer": { "values": { "canvas": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 }, "dom": { - "mean": 0.0, - "effect": -0.2874, - "n": 3 + "mean": 0.4, + "effect": 0.1112, + "n": 5 }, "none": { "mean": 0.2984, - "effect": 0.011, + "effect": 0.0096, "n": 392 }, "svg": { "mean": 0.0, - "effect": -0.2874, - "n": 3 + "effect": -0.2888, + "n": 6 }, "webgl": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 3 } }, - "spread": 0.2984 + "spread": 0.4 }, "architecture": { "values": { "best_practices": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 }, "none": { - "mean": 0.2962, + "mean": 0.2974, "effect": 0.0087, - "n": 395 + "n": 400 }, "separation": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 } }, - "spread": 0.2962 + "spread": 0.2974 }, "design_guidance": { "values": { "none": { - "mean": 0.2962, + "mean": 0.2974, "effect": 0.0087, - "n": 395 + "n": 400 }, "specific": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 }, "vague": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 } }, - "spread": 0.2962 + "spread": 0.2974 + }, + "max_budget": { + "values": { + "high": { + "mean": 0.5691, + "effect": 0.2803, + "n": 23 + }, + "low": { + "mean": 0.2722, + "effect": -0.0166, + "n": 389 + } + }, + "spread": 0.2969 }, "error_checking": { "values": { "none": { - "mean": 0.2917, + "mean": 0.2931, "effect": 0.0043, - "n": 401 + "n": 406 }, "self_verify": { "mean": 0.0, - "effect": -0.2874, + "effect": -0.2888, "n": 6 } }, - "spread": 0.2917 + "spread": 0.2931 }, "tool_glob": { "values": { "off": { "mean": 0.5585, - "effect": 0.2711, + "effect": 0.2697, "n": 27 }, "on": { - "mean": 0.2682, - "effect": -0.0193, - "n": 380 + "mean": 0.2699, + "effect": -0.0189, + "n": 385 } }, - "spread": 0.2903 + "spread": 0.2886 }, "context_file": { "values": { "none": { - "mean": 0.2677, - "effect": -0.0198, - "n": 379 + "mean": 0.2694, + "effect": -0.0194, + "n": 384 }, "provided": { "mean": 0.555, - "effect": 0.2676, + "effect": 0.2662, "n": 28 } }, - "spread": 0.2873 + "spread": 0.2856 }, "tool_grep": { "values": { "off": { "mean": 0.4943, - "effect": 0.2069, + "effect": 0.2055, "n": 28 }, "on": { - "mean": 0.2721, - "effect": -0.0153, - "n": 379 + "mean": 0.2738, + "effect": -0.015, + "n": 384 } }, - "spread": 0.2222 + "spread": 0.2205 }, "tool_write": { "values": { "off": { "mean": 0.4807, - "effect": 0.1933, + "effect": 0.1919, "n": 28 }, "on": { - "mean": 0.2731, - "effect": -0.0143, - "n": 379 + "mean": 0.2748, + "effect": -0.014, + "n": 384 } }, - "spread": 0.2076 + "spread": 0.2059 }, "tool_edit": { "values": { "off": { "mean": 0.471, - "effect": 0.1835, + "effect": 0.1822, "n": 31 }, "on": { - "mean": 0.2723, - "effect": -0.0151, - "n": 376 + "mean": 0.274, + "effect": -0.0148, + "n": 381 } }, - "spread": 0.1987 + "spread": 0.197 }, "language": { "values": { "javascript": { "mean": 0.2367, - "effect": -0.0508, + "effect": -0.0521, "n": 18 }, "typescript": { - "mean": 0.2983, + "mean": 0.2997, "effect": 0.0109, - "n": 372 + "n": 377 }, "unspecified": { "mean": 0.1029, - "effect": -0.1845, + "effect": -0.1858, "n": 17 } }, - "spread": 0.1954 + "spread": 0.1968 }, "web_search": { "values": { "off": { "mean": 0.4121, - "effect": 0.1246, + "effect": 0.1233, "n": 34 }, "on": { - "mean": 0.2761, - "effect": -0.0114, - "n": 373 + "mean": 0.2777, + "effect": -0.0111, + "n": 378 } }, - "spread": 0.136 + "spread": 0.1344 }, "prompt_style": { "values": { "detailed": { "mean": 0.3693, - "effect": 0.0819, + "effect": 0.0805, "n": 30 }, "simple": { - "mean": 0.2809, - "effect": -0.0065, - "n": 377 + "mean": 0.2825, + "effect": -0.0063, + "n": 382 } }, - "spread": 0.0884 + "spread": 0.0868 }, "linter": { "values": { "off": { "mean": 0.3666, - "effect": 0.0792, + "effect": 0.0778, "n": 35 }, "on": { - "mean": 0.28, - "effect": -0.0074, - "n": 372 + "mean": 0.2816, + "effect": -0.0072, + "n": 377 } }, - "spread": 0.0866 + "spread": 0.085 }, "human_language": { "values": { "en": { - "mean": 0.2827, - "effect": -0.0048, - "n": 380 + "mean": 0.2842, + "effect": -0.0046, + "n": 385 }, "es": { "mean": 0.3544, - "effect": 0.067, + "effect": 0.0657, "n": 27 } }, - "spread": 0.0717 + "spread": 0.0702 }, "tool_read": { "values": { "off": { "mean": 0.3393, - "effect": 0.0519, + "effect": 0.0505, "n": 29 }, "on": { - "mean": 0.2834, - "effect": -0.004, - "n": 378 + "mean": 0.285, + "effect": -0.0038, + "n": 383 } }, - "spread": 0.0559 + "spread": 0.0543 }, "effort": { "values": { "high": { - "mean": 0.2875, - "effect": 0.0001, - "n": 389 + "mean": 0.289, + "effect": 0.0002, + "n": 394 }, "max": { "mean": 0.285, - "effect": -0.0024, + "effect": -0.0038, "n": 18 } }, - "spread": 0.0025 + "spread": 0.004 } } \ No newline at end of file diff --git a/results/analysis/main_effects_score.json b/results/analysis/main_effects_score.json @@ -3,77 +3,77 @@ "values": { "glm-4.5-air": { "mean": 0.4032, - "effect": 0.0988, + "effect": 0.1001, "n": 37 }, "glm-4.7": { "mean": 0.0356, - "effect": -0.2688, + "effect": -0.2676, "n": 101 }, "glm-5.1": { - "mean": 0.0316, - "effect": -0.2728, - "n": 92 + "mean": 0.0403, + "effect": -0.2629, + "n": 97 }, "haiku": { "mean": 0.5502, - "effect": 0.2458, + "effect": 0.247, "n": 74 }, "opus": { "mean": 0.6692, - "effect": 0.3648, + "effect": 0.3661, "n": 51 }, "sonnet": { "mean": 0.5314, - "effect": 0.227, + "effect": 0.2283, "n": 52 } }, - "spread": 0.6376 + "spread": 0.6336 }, "strategy": { "values": { "creative_validate": { "mean": 0.0208, - "effect": -0.2836, + "effect": -0.2823, "n": 6 }, "delegate": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 }, "iterate": { "mean": 0.0942, - "effect": -0.2103, + "effect": -0.209, "n": 6 }, "none": { - "mean": 0.1614, - "effect": -0.143, - "n": 212 + "mean": 0.1623, + "effect": -0.1409, + "n": 217 }, "plan_first": { "mean": 0.0625, - "effect": -0.2419, + "effect": -0.2407, "n": 6 }, "review": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 }, "split_work": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 }, "use_subagents": { "mean": 0.5573, - "effect": 0.2529, + "effect": 0.2542, "n": 159 } }, @@ -83,18 +83,18 @@ "values": { "available": { "mean": 0.5559, - "effect": 0.2514, + "effect": 0.2527, "n": 163 }, "instructed": { "mean": 0.0586, - "effect": -0.2459, + "effect": -0.2446, "n": 7 }, "off": { - "mean": 0.1388, - "effect": -0.1657, - "n": 237 + "mean": 0.14, + "effect": -0.1631, + "n": 242 } }, "spread": 0.4973 @@ -103,27 +103,27 @@ "values": { "canvas": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 }, "dom": { - "mean": 0.0, - "effect": -0.3044, - "n": 3 + "mean": 0.2, + "effect": -0.1032, + "n": 5 }, "none": { "mean": 0.3161, - "effect": 0.0116, + "effect": 0.0129, "n": 392 }, "svg": { "mean": 0.0, - "effect": -0.3044, - "n": 3 + "effect": -0.3032, + "n": 6 }, "webgl": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 3 } }, @@ -133,255 +133,255 @@ "values": { "best_practices": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 }, "none": { - "mean": 0.3137, - "effect": 0.0092, - "n": 395 + "mean": 0.3123, + "effect": 0.0091, + "n": 400 }, "separation": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 } }, - "spread": 0.3137 + "spread": 0.3123 }, "design_guidance": { "values": { "none": { - "mean": 0.3137, - "effect": 0.0092, - "n": 395 + "mean": 0.3123, + "effect": 0.0091, + "n": 400 }, "specific": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 }, "vague": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 } }, - "spread": 0.3137 + "spread": 0.3123 }, "error_checking": { "values": { "none": { - "mean": 0.309, - "effect": 0.0046, - "n": 401 + "mean": 0.3076, + "effect": 0.0045, + "n": 406 }, "self_verify": { "mean": 0.0, - "effect": -0.3044, + "effect": -0.3032, "n": 6 } }, - "spread": 0.309 + "spread": 0.3076 }, "context_file": { "values": { "none": { - "mean": 0.2906, - "effect": -0.0138, - "n": 379 + "mean": 0.2894, + "effect": -0.0137, + "n": 384 }, "provided": { "mean": 0.4914, - "effect": 0.187, + "effect": 0.1883, "n": 28 } }, - "spread": 0.2008 + "spread": 0.202 }, "max_budget": { "values": { "high": { "mean": 0.492, - "effect": 0.1875, + "effect": 0.1888, "n": 23 }, "low": { - "mean": 0.2932, + "mean": 0.292, "effect": -0.0112, - "n": 384 + "n": 389 } }, - "spread": 0.1988 + "spread": 0.2 }, "tool_grep": { "values": { "off": { "mean": 0.4868, - "effect": 0.1824, + "effect": 0.1836, "n": 28 }, "on": { - "mean": 0.2909, - "effect": -0.0135, - "n": 379 + "mean": 0.2898, + "effect": -0.0134, + "n": 384 } }, - "spread": 0.1959 + "spread": 0.197 }, "tool_glob": { "values": { "off": { "mean": 0.4728, - "effect": 0.1684, + "effect": 0.1696, "n": 27 }, "on": { - "mean": 0.2925, - "effect": -0.012, - "n": 380 + "mean": 0.2913, + "effect": -0.0119, + "n": 385 } }, - "spread": 0.1803 + "spread": 0.1815 }, "tool_write": { "values": { "off": { "mean": 0.4539, - "effect": 0.1495, + "effect": 0.1508, "n": 28 }, "on": { - "mean": 0.2934, + "mean": 0.2922, "effect": -0.011, - "n": 379 + "n": 384 } }, - "spread": 0.1605 + "spread": 0.1617 }, "tool_edit": { "values": { "off": { "mean": 0.4523, - "effect": 0.1478, + "effect": 0.1491, "n": 31 }, "on": { - "mean": 0.2922, - "effect": -0.0122, - "n": 376 + "mean": 0.291, + "effect": -0.0121, + "n": 381 } }, - "spread": 0.1601 + "spread": 0.1613 }, "web_search": { "values": { "off": { "mean": 0.4437, - "effect": 0.1393, + "effect": 0.1405, "n": 34 }, "on": { - "mean": 0.2917, - "effect": -0.0127, - "n": 373 + "mean": 0.2905, + "effect": -0.0126, + "n": 378 } }, - "spread": 0.152 + "spread": 0.1532 }, "linter": { "values": { "off": { "mean": 0.4416, - "effect": 0.1371, + "effect": 0.1384, "n": 35 }, "on": { - "mean": 0.2915, + "mean": 0.2903, "effect": -0.0129, - "n": 372 + "n": 377 } }, - "spread": 0.1501 + "spread": 0.1513 }, "prompt_style": { "values": { "detailed": { "mean": 0.4348, - "effect": 0.1304, + "effect": 0.1317, "n": 30 }, "simple": { - "mean": 0.294, - "effect": -0.0104, - "n": 377 + "mean": 0.2928, + "effect": -0.0103, + "n": 382 } }, - "spread": 0.1408 + "spread": 0.142 }, "tool_read": { "values": { "off": { "mean": 0.4043, - "effect": 0.0999, + "effect": 0.1012, "n": 29 }, "on": { - "mean": 0.2968, + "mean": 0.2955, "effect": -0.0077, - "n": 378 + "n": 383 } }, - "spread": 0.1075 + "spread": 0.1088 }, "human_language": { "values": { "en": { - "mean": 0.2983, + "mean": 0.2971, "effect": -0.0061, - "n": 380 + "n": 385 }, "es": { "mean": 0.39, - "effect": 0.0856, + "effect": 0.0868, "n": 27 } }, - "spread": 0.0917 + "spread": 0.0929 }, "language": { "values": { "javascript": { "mean": 0.3767, - "effect": 0.0722, + "effect": 0.0735, "n": 18 }, "typescript": { - "mean": 0.3001, - "effect": -0.0043, - "n": 372 + "mean": 0.2988, + "effect": -0.0044, + "n": 377 }, "unspecified": { "mean": 0.3224, - "effect": 0.0179, + "effect": 0.0192, "n": 17 } }, - "spread": 0.0766 + "spread": 0.0779 }, "effort": { "values": { "high": { - "mean": 0.304, + "mean": 0.3027, "effect": -0.0004, - "n": 389 + "n": 394 }, "max": { "mean": 0.3125, - "effect": 0.0081, + "effect": 0.0093, "n": 18 } }, - "spread": 0.0085 + "spread": 0.0098 } } \ No newline at end of file diff --git a/results/analysis/main_effects_sonarqube.json b/results/analysis/main_effects_sonarqube.json @@ -3,32 +3,32 @@ "values": { "glm-4.5-air": { "mean": 0.4935, - "effect": 0.1721, + "effect": 0.176, "n": 37 }, "glm-4.7": { "mean": 0.0248, - "effect": -0.2967, + "effect": -0.2928, "n": 101 }, "glm-5.1": { - "mean": 0.0339, - "effect": -0.2875, - "n": 92 + "mean": 0.0322, + "effect": -0.2854, + "n": 97 }, "haiku": { "mean": 0.5531, - "effect": 0.2317, + "effect": 0.2356, "n": 74 }, "opus": { "mean": 0.6775, - "effect": 0.356, + "effect": 0.3599, "n": 51 }, "sonnet": { "mean": 0.605, - "effect": 0.2836, + "effect": 0.2875, "n": 52 } }, @@ -38,42 +38,42 @@ "values": { "creative_validate": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "delegate": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "iterate": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "none": { - "mean": 0.1755, - "effect": -0.1459, - "n": 212 + "mean": 0.1715, + "effect": -0.146, + "n": 217 }, "plan_first": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "review": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "split_work": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "use_subagents": { "mean": 0.5887, - "effect": 0.2673, + "effect": 0.2712, "n": 159 } }, @@ -83,18 +83,18 @@ "values": { "available": { "mean": 0.5791, - "effect": 0.2577, + "effect": 0.2616, "n": 163 }, "instructed": { "mean": 0.1171, - "effect": -0.2043, + "effect": -0.2004, "n": 7 }, "off": { - "mean": 0.1503, - "effect": -0.1712, - "n": 237 + "mean": 0.1471, + "effect": -0.1704, + "n": 242 } }, "spread": 0.462 @@ -103,27 +103,27 @@ "values": { "canvas": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "dom": { "mean": 0.0, - "effect": -0.3214, - "n": 3 + "effect": -0.3175, + "n": 5 }, "none": { "mean": 0.3337, - "effect": 0.0123, + "effect": 0.0162, "n": 392 }, "svg": { "mean": 0.0, - "effect": -0.3214, - "n": 3 + "effect": -0.3175, + "n": 6 }, "webgl": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 3 } }, @@ -133,255 +133,255 @@ "values": { "best_practices": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "none": { - "mean": 0.3312, - "effect": 0.0098, - "n": 395 + "mean": 0.3271, + "effect": 0.0095, + "n": 400 }, "separation": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 } }, - "spread": 0.3312 + "spread": 0.3271 }, "design_guidance": { "values": { "none": { - "mean": 0.3312, - "effect": 0.0098, - "n": 395 + "mean": 0.3271, + "effect": 0.0095, + "n": 400 }, "specific": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 }, "vague": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 } }, - "spread": 0.3312 + "spread": 0.3271 }, "error_checking": { "values": { "none": { - "mean": 0.3262, - "effect": 0.0048, - "n": 401 + "mean": 0.3222, + "effect": 0.0047, + "n": 406 }, "self_verify": { "mean": 0.0, - "effect": -0.3214, + "effect": -0.3175, "n": 6 } }, - "spread": 0.3262 + "spread": 0.3222 }, "language": { "values": { "javascript": { "mean": 0.5167, - "effect": 0.1952, + "effect": 0.1991, "n": 18 }, "typescript": { - "mean": 0.3019, - "effect": -0.0195, - "n": 372 + "mean": 0.2979, + "effect": -0.0196, + "n": 377 }, "unspecified": { "mean": 0.5418, - "effect": 0.2203, + "effect": 0.2242, "n": 17 } }, - "spread": 0.2399 + "spread": 0.2439 }, "linter": { "values": { "off": { "mean": 0.5166, - "effect": 0.1951, + "effect": 0.199, "n": 35 }, "on": { - "mean": 0.3031, - "effect": -0.0184, - "n": 372 + "mean": 0.299, + "effect": -0.0185, + "n": 377 } }, - "spread": 0.2135 + "spread": 0.2176 }, "prompt_style": { "values": { "detailed": { "mean": 0.5003, - "effect": 0.1789, + "effect": 0.1828, "n": 30 }, "simple": { - "mean": 0.3072, - "effect": -0.0142, - "n": 377 + "mean": 0.3032, + "effect": -0.0144, + "n": 382 } }, - "spread": 0.1931 + "spread": 0.1971 }, "tool_grep": { "values": { "off": { "mean": 0.4793, - "effect": 0.1579, + "effect": 0.1618, "n": 28 }, "on": { - "mean": 0.3098, - "effect": -0.0117, - "n": 379 + "mean": 0.3057, + "effect": -0.0118, + "n": 384 } }, - "spread": 0.1695 + "spread": 0.1736 }, "web_search": { "values": { "off": { "mean": 0.4753, - "effect": 0.1539, + "effect": 0.1578, "n": 34 }, "on": { - "mean": 0.3074, - "effect": -0.014, - "n": 373 + "mean": 0.3033, + "effect": -0.0142, + "n": 378 } }, - "spread": 0.1679 + "spread": 0.172 }, "tool_read": { "values": { "off": { "mean": 0.4693, - "effect": 0.1479, + "effect": 0.1518, "n": 29 }, "on": { - "mean": 0.3101, - "effect": -0.0113, - "n": 378 + "mean": 0.306, + "effect": -0.0115, + "n": 383 } }, - "spread": 0.1592 + "spread": 0.1633 }, "tool_edit": { "values": { "off": { "mean": 0.4335, - "effect": 0.1121, + "effect": 0.116, "n": 31 }, "on": { - "mean": 0.3122, - "effect": -0.0092, - "n": 376 + "mean": 0.3081, + "effect": -0.0094, + "n": 381 } }, - "spread": 0.1213 + "spread": 0.1254 }, "context_file": { "values": { "none": { - "mean": 0.3136, - "effect": -0.0079, - "n": 379 + "mean": 0.3095, + "effect": -0.008, + "n": 384 }, "provided": { "mean": 0.4279, - "effect": 0.1064, + "effect": 0.1103, "n": 28 } }, - "spread": 0.1143 + "spread": 0.1184 }, "tool_write": { "values": { "off": { "mean": 0.4271, - "effect": 0.1057, + "effect": 0.1096, "n": 28 }, "on": { - "mean": 0.3136, - "effect": -0.0078, - "n": 379 + "mean": 0.3095, + "effect": -0.008, + "n": 384 } }, - "spread": 0.1135 + "spread": 0.1176 }, "human_language": { "values": { "en": { - "mean": 0.314, - "effect": -0.0074, - "n": 380 + "mean": 0.3099, + "effect": -0.0076, + "n": 385 }, "es": { "mean": 0.4256, - "effect": 0.1041, + "effect": 0.108, "n": 27 } }, - "spread": 0.1116 + "spread": 0.1157 }, "max_budget": { "values": { "high": { "mean": 0.4148, - "effect": 0.0934, + "effect": 0.0973, "n": 23 }, "low": { - "mean": 0.3158, - "effect": -0.0056, - "n": 384 + "mean": 0.3118, + "effect": -0.0058, + "n": 389 } }, - "spread": 0.099 + "spread": 0.103 }, "tool_glob": { "values": { "off": { "mean": 0.387, - "effect": 0.0656, + "effect": 0.0695, "n": 27 }, "on": { - "mean": 0.3168, - "effect": -0.0047, - "n": 380 + "mean": 0.3126, + "effect": -0.0049, + "n": 385 } }, - "spread": 0.0702 + "spread": 0.0744 }, "effort": { "values": { "high": { - "mean": 0.3206, - "effect": -0.0009, - "n": 389 + "mean": 0.3165, + "effect": -0.001, + "n": 394 }, "max": { "mean": 0.34, - "effect": 0.0186, + "effect": 0.0225, "n": 18 } }, - "spread": 0.0194 + "spread": 0.0235 } } \ No newline at end of file diff --git a/results/analysis/main_effects_structural.json b/results/analysis/main_effects_structural.json @@ -3,77 +3,77 @@ "values": { "glm-4.5-air": { "mean": 0.5973, - "effect": -0.0907, + "effect": -0.0909, "n": 37 }, "glm-4.7": { "mean": 0.5423, - "effect": -0.1457, + "effect": -0.1459, "n": 101 }, "glm-5.1": { - "mean": 0.5247, - "effect": -0.1633, - "n": 92 + "mean": 0.5337, + "effect": -0.1544, + "n": 97 }, "haiku": { "mean": 0.7865, - "effect": 0.0985, + "effect": 0.0983, "n": 74 }, "opus": { "mean": 0.9739, - "effect": 0.2859, + "effect": 0.2858, "n": 51 }, "sonnet": { "mean": 0.904, - "effect": 0.216, + "effect": 0.2159, "n": 52 } }, - "spread": 0.4492 + "spread": 0.4402 }, "strategy": { "values": { "creative_validate": { "mean": 0.625, - "effect": -0.063, + "effect": -0.0632, "n": 6 }, "delegate": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 }, "iterate": { "mean": 0.625, - "effect": -0.063, + "effect": -0.0632, "n": 6 }, "none": { - "mean": 0.5742, - "effect": -0.1138, - "n": 212 + "mean": 0.5771, + "effect": -0.1111, + "n": 217 }, "plan_first": { "mean": 0.5833, - "effect": -0.1047, + "effect": -0.1048, "n": 6 }, "review": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 }, "split_work": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 }, "use_subagents": { "mean": 0.8697, - "effect": 0.1817, + "effect": 0.1816, "n": 159 } }, @@ -83,18 +83,18 @@ "values": { "available": { "mean": 0.8642, - "effect": 0.1762, + "effect": 0.1761, "n": 163 }, "instructed": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 7 }, "off": { - "mean": 0.5724, - "effect": -0.1156, - "n": 237 + "mean": 0.575, + "effect": -0.1132, + "n": 242 } }, "spread": 0.3642 @@ -103,285 +103,285 @@ "values": { "canvas": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 }, "dom": { - "mean": 0.5, - "effect": -0.188, - "n": 3 + "mean": 0.7, + "effect": 0.0118, + "n": 5 }, "none": { "mean": 0.6952, - "effect": 0.0072, + "effect": 0.007, "n": 392 }, "svg": { "mean": 0.5, - "effect": -0.188, - "n": 3 + "effect": -0.1882, + "n": 6 }, "webgl": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 3 } }, - "spread": 0.1952 + "spread": 0.2 }, "architecture": { "values": { "best_practices": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 }, "none": { - "mean": 0.6937, - "effect": 0.0057, - "n": 395 + "mean": 0.6938, + "effect": 0.0056, + "n": 400 }, "separation": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 } }, - "spread": 0.1937 + "spread": 0.1938 }, "design_guidance": { "values": { "none": { - "mean": 0.6937, - "effect": 0.0057, - "n": 395 + "mean": 0.6938, + "effect": 0.0056, + "n": 400 }, "specific": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 }, "vague": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 } }, - "spread": 0.1937 + "spread": 0.1938 }, "error_checking": { "values": { "none": { - "mean": 0.6908, + "mean": 0.6909, "effect": 0.0028, - "n": 401 + "n": 406 }, "self_verify": { "mean": 0.5, - "effect": -0.188, + "effect": -0.1882, "n": 6 } }, - "spread": 0.1908 + "spread": 0.1909 }, "language": { "values": { "javascript": { "mean": 0.7983, - "effect": 0.1103, + "effect": 0.1102, "n": 18 }, "typescript": { - "mean": 0.6808, - "effect": -0.0072, - "n": 372 + "mean": 0.6811, + "effect": -0.0071, + "n": 377 }, "unspecified": { "mean": 0.7282, - "effect": 0.0402, + "effect": 0.0401, "n": 17 } }, - "spread": 0.1175 + "spread": 0.1172 }, "max_budget": { "values": { "high": { "mean": 0.7865, - "effect": 0.0985, + "effect": 0.0984, "n": 23 }, "low": { - "mean": 0.6821, - "effect": -0.0059, - "n": 384 + "mean": 0.6823, + "effect": -0.0058, + "n": 389 } }, - "spread": 0.1044 + "spread": 0.1042 }, "context_file": { "values": { "none": { - "mean": 0.6823, - "effect": -0.0057, - "n": 379 + "mean": 0.6826, + "effect": -0.0056, + "n": 384 }, "provided": { "mean": 0.765, - "effect": 0.077, + "effect": 0.0768, "n": 28 } }, - "spread": 0.0827 + "spread": 0.0824 }, "tool_write": { "values": { "off": { "mean": 0.7561, - "effect": 0.0681, + "effect": 0.0679, "n": 28 }, "on": { - "mean": 0.683, + "mean": 0.6832, "effect": -0.005, - "n": 379 + "n": 384 } }, - "spread": 0.0731 + "spread": 0.0729 }, "tool_glob": { "values": { "off": { "mean": 0.7378, - "effect": 0.0498, + "effect": 0.0496, "n": 27 }, "on": { - "mean": 0.6845, + "mean": 0.6847, "effect": -0.0035, - "n": 380 + "n": 385 } }, - "spread": 0.0533 + "spread": 0.0531 }, "web_search": { "values": { "off": { "mean": 0.7356, - "effect": 0.0476, + "effect": 0.0474, "n": 34 }, "on": { - "mean": 0.6837, + "mean": 0.6839, "effect": -0.0043, - "n": 373 + "n": 378 } }, - "spread": 0.0519 + "spread": 0.0517 }, "human_language": { "values": { "en": { - "mean": 0.6853, - "effect": -0.0027, - "n": 380 + "mean": 0.6855, + "effect": -0.0026, + "n": 385 }, "es": { "mean": 0.7256, - "effect": 0.0375, + "effect": 0.0374, "n": 27 } }, - "spread": 0.0403 + "spread": 0.0401 }, "tool_edit": { "values": { "off": { "mean": 0.71, - "effect": 0.022, + "effect": 0.0218, "n": 31 }, "on": { - "mean": 0.6862, + "mean": 0.6864, "effect": -0.0018, - "n": 376 + "n": 381 } }, - "spread": 0.0238 + "spread": 0.0236 }, "prompt_style": { "values": { "detailed": { "mean": 0.6673, - "effect": -0.0207, + "effect": -0.0208, "n": 30 }, "simple": { - "mean": 0.6897, + "mean": 0.6898, "effect": 0.0016, - "n": 377 + "n": 382 } }, - "spread": 0.0224 + "spread": 0.0225 }, "effort": { "values": { "high": { - "mean": 0.6871, + "mean": 0.6872, "effect": -0.0009, - "n": 389 + "n": 394 }, "max": { "mean": 0.7083, - "effect": 0.0203, + "effect": 0.0202, "n": 18 } }, - "spread": 0.0212 + "spread": 0.0211 }, "tool_grep": { "values": { "off": { "mean": 0.7057, - "effect": 0.0177, + "effect": 0.0176, "n": 28 }, "on": { - "mean": 0.6867, + "mean": 0.6869, "effect": -0.0013, - "n": 379 + "n": 384 } }, - "spread": 0.019 + "spread": 0.0188 }, "tool_read": { "values": { "off": { "mean": 0.6959, - "effect": 0.0079, + "effect": 0.0077, "n": 29 }, "on": { - "mean": 0.6874, + "mean": 0.6876, "effect": -0.0006, - "n": 378 + "n": 383 } }, - "spread": 0.0085 + "spread": 0.0083 }, "linter": { "values": { "off": { "mean": 0.6909, - "effect": 0.0028, + "effect": 0.0027, "n": 35 }, "on": { - "mean": 0.6877, + "mean": 0.6879, "effect": -0.0003, - "n": 372 + "n": 377 } }, - "spread": 0.0032 + "spread": 0.003 } } \ No newline at end of file diff --git a/results/analysis/main_effects_transcript.json b/results/analysis/main_effects_transcript.json @@ -3,32 +3,32 @@ "values": { "glm-4.5-air": { "mean": 0.9622, - "effect": 0.0102, + "effect": 0.0096, "n": 37 }, "glm-4.7": { "mean": 0.9842, - "effect": 0.0322, + "effect": 0.0316, "n": 101 }, "glm-5.1": { "mean": 1.0, - "effect": 0.048, - "n": 92 + "effect": 0.0475, + "n": 97 }, "haiku": { "mean": 0.7872, - "effect": -0.1648, + "effect": -0.1654, "n": 74 }, "opus": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 51 }, "sonnet": { "mean": 0.9846, - "effect": 0.0326, + "effect": 0.0321, "n": 52 } }, @@ -38,42 +38,42 @@ "values": { "creative_validate": { "mean": 0.975, - "effect": 0.023, + "effect": 0.0225, "n": 6 }, "delegate": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 }, "iterate": { "mean": 0.9333, - "effect": -0.0186, + "effect": -0.0192, "n": 6 }, "none": { - "mean": 0.9731, - "effect": 0.0211, - "n": 212 + "mean": 0.9737, + "effect": 0.0212, + "n": 217 }, "plan_first": { "mean": 0.9083, - "effect": -0.0436, + "effect": -0.0442, "n": 6 }, "review": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 }, "split_work": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 }, "use_subagents": { "mean": 0.9198, - "effect": -0.0322, + "effect": -0.0327, "n": 159 } }, @@ -83,63 +83,63 @@ "values": { "off": { "mean": 0.8694, - "effect": -0.0826, + "effect": -0.0832, "n": 31 }, "on": { - "mean": 0.9588, + "mean": 0.9593, "effect": 0.0068, - "n": 376 + "n": 381 } }, - "spread": 0.0894 + "spread": 0.0899 }, "tool_write": { "values": { "off": { "mean": 0.8732, - "effect": -0.0788, + "effect": -0.0793, "n": 28 }, "on": { - "mean": 0.9578, + "mean": 0.9583, "effect": 0.0058, - "n": 379 + "n": 384 } }, - "spread": 0.0846 + "spread": 0.0851 }, "context_file": { "values": { "none": { - "mean": 0.9577, + "mean": 0.9582, "effect": 0.0057, - "n": 379 + "n": 384 }, "provided": { "mean": 0.875, - "effect": -0.077, + "effect": -0.0775, "n": 28 } }, - "spread": 0.0827 + "spread": 0.0832 }, "playwright": { "values": { "available": { "mean": 0.919, - "effect": -0.0329, + "effect": -0.0335, "n": 163 }, "instructed": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 7 }, "off": { - "mean": 0.9732, + "mean": 0.9738, "effect": 0.0212, - "n": 237 + "n": 242 } }, "spread": 0.081 @@ -148,167 +148,167 @@ "values": { "off": { "mean": 0.8804, - "effect": -0.0716, + "effect": -0.0722, "n": 28 }, "on": { - "mean": 0.9573, + "mean": 0.9578, "effect": 0.0053, - "n": 379 + "n": 384 } }, - "spread": 0.0769 + "spread": 0.0774 }, "tool_glob": { "values": { "off": { "mean": 0.8815, - "effect": -0.0705, + "effect": -0.0711, "n": 27 }, "on": { - "mean": 0.957, + "mean": 0.9575, "effect": 0.005, - "n": 380 + "n": 385 } }, - "spread": 0.0755 + "spread": 0.076 }, "max_budget": { "values": { "high": { "mean": 0.8848, - "effect": -0.0672, + "effect": -0.0678, "n": 23 }, "low": { - "mean": 0.956, + "mean": 0.9566, "effect": 0.004, - "n": 384 + "n": 389 } }, - "spread": 0.0712 + "spread": 0.0718 }, "tool_read": { "values": { "off": { "mean": 0.8879, - "effect": -0.064, + "effect": -0.0646, "n": 29 }, "on": { - "mean": 0.9569, + "mean": 0.9574, "effect": 0.0049, - "n": 378 + "n": 383 } }, - "spread": 0.069 + "spread": 0.0695 }, - "linter": { + "web_search": { "values": { "off": { - "mean": 0.8914, - "effect": -0.0605, - "n": 35 + "mean": 0.8912, + "effect": -0.0614, + "n": 34 }, "on": { - "mean": 0.9577, - "effect": 0.0057, - "n": 372 + "mean": 0.9581, + "effect": 0.0055, + "n": 378 } }, - "spread": 0.0663 + "spread": 0.0669 }, - "web_search": { + "linter": { "values": { "off": { - "mean": 0.8912, - "effect": -0.0608, - "n": 34 + "mean": 0.8914, + "effect": -0.0611, + "n": 35 }, "on": { - "mean": 0.9575, - "effect": 0.0055, - "n": 373 + "mean": 0.9582, + "effect": 0.0057, + "n": 377 } }, - "spread": 0.0663 + "spread": 0.0668 }, "human_language": { "values": { "en": { - "mean": 0.9561, + "mean": 0.9566, "effect": 0.0041, - "n": 380 + "n": 385 }, "es": { "mean": 0.8944, - "effect": -0.0575, + "effect": -0.0581, "n": 27 } }, - "spread": 0.0617 + "spread": 0.0622 + }, + "prompt_style": { + "values": { + "detailed": { + "mean": 0.905, + "effect": -0.0475, + "n": 30 + }, + "simple": { + "mean": 0.9563, + "effect": 0.0037, + "n": 382 + } + }, + "spread": 0.0513 }, "language": { "values": { "javascript": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 18 }, "typescript": { - "mean": 0.9481, - "effect": -0.0038, - "n": 372 + "mean": 0.9488, + "effect": -0.0037, + "n": 377 }, "unspecified": { "mean": 0.9853, - "effect": 0.0333, + "effect": 0.0327, "n": 17 } }, - "spread": 0.0519 - }, - "prompt_style": { - "values": { - "detailed": { - "mean": 0.905, - "effect": -0.047, - "n": 30 - }, - "simple": { - "mean": 0.9557, - "effect": 0.0037, - "n": 377 - } - }, - "spread": 0.0507 + "spread": 0.0512 }, "renderer": { "values": { "canvas": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 }, "dom": { "mean": 1.0, - "effect": 0.048, - "n": 3 + "effect": 0.0475, + "n": 5 }, "none": { "mean": 0.9501, - "effect": -0.0018, + "effect": -0.0024, "n": 392 }, "svg": { "mean": 1.0, - "effect": 0.048, - "n": 3 + "effect": 0.0475, + "n": 6 }, "webgl": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 3 } }, @@ -318,70 +318,70 @@ "values": { "best_practices": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 }, "none": { - "mean": 0.9505, - "effect": -0.0015, - "n": 395 + "mean": 0.9511, + "effect": -0.0014, + "n": 400 }, "separation": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 } }, - "spread": 0.0495 + "spread": 0.0489 }, "design_guidance": { "values": { "none": { - "mean": 0.9505, - "effect": -0.0015, - "n": 395 + "mean": 0.9511, + "effect": -0.0014, + "n": 400 }, "specific": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 }, "vague": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 } }, - "spread": 0.0495 + "spread": 0.0489 }, "error_checking": { "values": { "none": { - "mean": 0.9512, + "mean": 0.9518, "effect": -0.0007, - "n": 401 + "n": 406 }, "self_verify": { "mean": 1.0, - "effect": 0.048, + "effect": 0.0475, "n": 6 } }, - "spread": 0.0488 + "spread": 0.0482 }, "effort": { "values": { "high": { - "mean": 0.9524, + "mean": 0.953, "effect": 0.0005, - "n": 389 + "n": 394 }, "max": { "mean": 0.9417, - "effect": -0.0103, + "effect": -0.0109, "n": 18 } }, - "spread": 0.0107 + "spread": 0.0113 } } \ No newline at end of file diff --git a/results/analysis/main_effects_turns.json b/results/analysis/main_effects_turns.json @@ -3,42 +3,42 @@ "values": { "creative_validate": { "mean": 35.1667, - "effect": 22.8227, + "effect": 22.8511, "n": 6 }, "delegate": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 }, "iterate": { "mean": 1.1667, - "effect": -11.1773, + "effect": -11.1489, "n": 6 }, "none": { - "mean": 6.6274, - "effect": -5.7166, - "n": 212 + "mean": 6.7051, + "effect": -5.6105, + "n": 217 }, "plan_first": { "mean": 1.3333, - "effect": -11.0106, + "effect": -10.9822, "n": 6 }, "review": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 }, "split_work": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 }, "use_subagents": { "mean": 21.2264, - "effect": 8.8824, + "effect": 8.9109, "n": 159 } }, @@ -48,53 +48,53 @@ "values": { "glm-4.5-air": { "mean": 13.2703, - "effect": 0.9263, + "effect": 0.9547, "n": 37 }, "glm-4.7": { "mean": 3.7921, - "effect": -8.5519, + "effect": -8.5235, "n": 101 }, "glm-5.1": { - "mean": 2.0109, - "effect": -10.3331, - "n": 92 + "mean": 2.4227, + "effect": -9.8929, + "n": 97 }, "haiku": { "mean": 26.2838, - "effect": 13.9398, + "effect": 13.9682, "n": 74 }, "opus": { "mean": 19.2549, - "effect": 6.9109, + "effect": 6.9394, "n": 51 }, "sonnet": { "mean": 19.9615, - "effect": 7.6176, + "effect": 7.646, "n": 52 } }, - "spread": 24.2729 + "spread": 23.8611 }, "playwright": { "values": { "available": { "mean": 21.1779, - "effect": 8.8339, + "effect": 8.8624, "n": 163 }, "instructed": { "mean": 1.5714, - "effect": -10.7726, + "effect": -10.7441, "n": 7 }, "off": { - "mean": 6.5865, - "effect": -5.7575, - "n": 237 + "mean": 6.657, + "effect": -5.6585, + "n": 242 } }, "spread": 19.6065 @@ -103,27 +103,27 @@ "values": { "canvas": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 }, "dom": { - "mean": 1.0, - "effect": -11.344, - "n": 3 + "mean": 10.0, + "effect": -2.3155, + "n": 5 }, "none": { "mean": 12.7781, - "effect": 0.4341, + "effect": 0.4625, "n": 392 }, "svg": { "mean": 1.0, - "effect": -11.344, - "n": 3 + "effect": -11.3155, + "n": 6 }, "webgl": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 3 } }, @@ -133,255 +133,255 @@ "values": { "best_practices": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 }, "none": { - "mean": 12.6886, - "effect": 0.3446, - "n": 395 + "mean": 12.655, + "effect": 0.3395, + "n": 400 }, "separation": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 } }, - "spread": 11.6886 + "spread": 11.655 }, "design_guidance": { "values": { "none": { - "mean": 12.6886, - "effect": 0.3446, - "n": 395 + "mean": 12.655, + "effect": 0.3395, + "n": 400 }, "specific": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 }, "vague": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 } }, - "spread": 11.6886 + "spread": 11.655 }, "error_checking": { "values": { "none": { - "mean": 12.5137, - "effect": 0.1697, - "n": 401 + "mean": 12.4828, + "effect": 0.1672, + "n": 406 }, "self_verify": { "mean": 1.0, - "effect": -11.344, + "effect": -11.3155, "n": 6 } }, - "spread": 11.5137 + "spread": 11.4828 }, "tool_write": { "values": { "off": { "mean": 20.5, - "effect": 8.156, + "effect": 8.1845, "n": 28 }, "on": { - "mean": 11.7414, - "effect": -0.6026, - "n": 379 + "mean": 11.7188, + "effect": -0.5968, + "n": 384 } }, - "spread": 8.7586 + "spread": 8.7812 }, "web_search": { "values": { "off": { "mean": 20.3529, - "effect": 8.009, + "effect": 8.0374, "n": 34 }, "on": { - "mean": 11.6139, - "effect": -0.73, - "n": 373 + "mean": 11.5926, + "effect": -0.7229, + "n": 378 } }, - "spread": 8.739 + "spread": 8.7603 }, "context_file": { "values": { "none": { - "mean": 11.7625, - "effect": -0.5814, - "n": 379 + "mean": 11.7396, + "effect": -0.576, + "n": 384 }, "provided": { "mean": 20.2143, - "effect": 7.8703, + "effect": 7.8988, "n": 28 } }, - "spread": 8.4518 + "spread": 8.4747 }, "human_language": { "values": { "en": { - "mean": 11.8368, - "effect": -0.5071, - "n": 380 + "mean": 11.813, + "effect": -0.5025, + "n": 385 }, "es": { "mean": 19.4815, - "effect": 7.1375, + "effect": 7.1659, "n": 27 } }, - "spread": 7.6447 + "spread": 7.6685 }, "max_budget": { "values": { "high": { "mean": 19.5217, - "effect": 7.1778, + "effect": 7.2062, "n": 23 }, "low": { - "mean": 11.9141, - "effect": -0.4299, - "n": 384 + "mean": 11.8895, + "effect": -0.4261, + "n": 389 } }, - "spread": 7.6076 + "spread": 7.6322 }, "effort": { "values": { "high": { - "mean": 12.0231, - "effect": -0.3208, - "n": 389 + "mean": 11.9975, + "effect": -0.3181, + "n": 394 }, "max": { "mean": 19.2778, - "effect": 6.9338, + "effect": 6.9622, "n": 18 } }, - "spread": 7.2547 + "spread": 7.2803 + }, + "tool_read": { + "values": { + "off": { + "mean": 18.9655, + "effect": 6.65, + "n": 29 + }, + "on": { + "mean": 11.812, + "effect": -0.5035, + "n": 383 + } + }, + "spread": 7.1535 }, "language": { "values": { "javascript": { "mean": 5.7778, - "effect": -6.5662, + "effect": -6.5378, "n": 18 }, "typescript": { - "mean": 12.9409, - "effect": 0.5969, - "n": 372 + "mean": 12.9019, + "effect": 0.5863, + "n": 377 }, "unspecified": { "mean": 6.2353, - "effect": -6.1087, + "effect": -6.0802, "n": 17 } }, - "spread": 7.1631 - }, - "tool_read": { - "values": { - "off": { - "mean": 18.9655, - "effect": 6.6215, - "n": 29 - }, - "on": { - "mean": 11.836, - "effect": -0.508, - "n": 378 - } - }, - "spread": 7.1295 + "spread": 7.1241 }, "tool_glob": { "values": { "off": { "mean": 18.5926, - "effect": 6.2486, + "effect": 6.2771, "n": 27 }, "on": { - "mean": 11.9, - "effect": -0.444, - "n": 380 + "mean": 11.8753, + "effect": -0.4402, + "n": 385 } }, - "spread": 6.6926 + "spread": 6.7173 }, "tool_edit": { "values": { "off": { "mean": 18.2903, - "effect": 5.9463, + "effect": 5.9748, "n": 31 }, "on": { - "mean": 11.8537, - "effect": -0.4903, - "n": 376 + "mean": 11.8294, + "effect": -0.4861, + "n": 381 } }, - "spread": 6.4366 + "spread": 6.4609 }, "tool_grep": { "values": { "off": { "mean": 18.2143, - "effect": 5.8703, + "effect": 5.8988, "n": 28 }, "on": { - "mean": 11.9103, - "effect": -0.4337, - "n": 379 + "mean": 11.8854, + "effect": -0.4301, + "n": 384 } }, - "spread": 6.304 + "spread": 6.3289 }, "linter": { "values": { "off": { "mean": 17.6, - "effect": 5.256, + "effect": 5.2845, "n": 35 }, "on": { - "mean": 11.8495, - "effect": -0.4945, - "n": 372 + "mean": 11.8249, + "effect": -0.4906, + "n": 377 } }, - "spread": 5.7505 + "spread": 5.7751 }, "prompt_style": { "values": { "detailed": { "mean": 14.9, - "effect": 2.556, + "effect": 2.5845, "n": 30 }, "simple": { - "mean": 12.1406, - "effect": -0.2034, - "n": 377 + "mean": 12.1126, + "effect": -0.203, + "n": 382 } }, - "spread": 2.7594 + "spread": 2.7874 } } \ No newline at end of file diff --git a/results/analysis/main_effects_wall_time.json b/results/analysis/main_effects_wall_time.json @@ -3,77 +3,77 @@ "values": { "glm-4.5-air": { "mean": 386.3784, - "effect": 68.9066, + "effect": 68.9463, "n": 37 }, "glm-4.7": { "mean": 251.4455, - "effect": -66.0262, + "effect": -65.9865, "n": 101 }, "glm-5.1": { - "mean": 215.2283, - "effect": -102.2435, - "n": 92 + "mean": 220.3299, + "effect": -97.1021, + "n": 97 }, "haiku": { "mean": 219.973, - "effect": -97.4988, + "effect": -97.4591, "n": 74 }, "opus": { "mean": 224.3529, - "effect": -93.1188, + "effect": -93.0791, "n": 51 }, "sonnet": { "mean": 807.6538, - "effect": 490.1821, + "effect": 490.2218, "n": 52 } }, - "spread": 592.4255 + "spread": 587.6808 }, "strategy": { "values": { "creative_validate": { "mean": 470.0, - "effect": 152.5283, + "effect": 152.568, "n": 6 }, "delegate": { "mean": 201.3333, - "effect": -116.1384, + "effect": -116.0987, "n": 6 }, "iterate": { "mean": 415.8333, - "effect": 98.3616, + "effect": 98.4013, "n": 6 }, "none": { - "mean": 253.3396, - "effect": -64.1321, - "n": 212 + "mean": 254.7419, + "effect": -62.6901, + "n": 217 }, "plan_first": { "mean": 561.6667, - "effect": 244.1949, + "effect": 244.2346, "n": 6 }, "review": { "mean": 198.5, - "effect": -118.9717, + "effect": -118.932, "n": 6 }, "split_work": { "mean": 200.5, - "effect": -116.9717, + "effect": -116.932, "n": 6 }, "use_subagents": { "mean": 397.5849, - "effect": 80.1132, + "effect": 80.1529, "n": 159 } }, @@ -83,18 +83,18 @@ "values": { "available": { "mean": 394.1288, - "effect": 76.6571, + "effect": 76.6968, "n": 163 }, "instructed": { "mean": 209.1429, - "effect": -108.3289, + "effect": -108.2892, "n": 7 }, "off": { - "mean": 267.9494, - "effect": -49.5224, - "n": 237 + "mean": 268.905, + "effect": -48.5271, + "n": 242 } }, "spread": 184.9859 @@ -102,63 +102,63 @@ "effort": { "values": { "high": { - "mean": 310.437, - "effect": -7.0347, - "n": 389 + "mean": 310.4848, + "effect": -6.9473, + "n": 394 }, "max": { "mean": 469.5, - "effect": 152.0283, + "effect": 152.068, "n": 18 } }, - "spread": 159.063 + "spread": 159.0152 }, "design_guidance": { "values": { "none": { - "mean": 321.1367, - "effect": 3.665, - "n": 395 + "mean": 321.05, + "effect": 3.618, + "n": 400 }, "specific": { "mean": 199.0, - "effect": -118.4717, + "effect": -118.432, "n": 6 }, "vague": { "mean": 194.6667, - "effect": -122.8051, + "effect": -122.7654, "n": 6 } }, - "spread": 126.47 + "spread": 126.3833 }, "renderer": { "values": { "canvas": { "mean": 198.1667, - "effect": -119.3051, + "effect": -119.2654, "n": 6 }, "dom": { - "mean": 203.3333, - "effect": -114.1384, - "n": 3 + "mean": 303.0, + "effect": -14.432, + "n": 5 }, "none": { "mean": 321.9974, - "effect": 4.5257, + "effect": 4.5654, "n": 392 }, "svg": { - "mean": 198.3333, - "effect": -119.1384, - "n": 3 + "mean": 210.1667, + "effect": -107.2654, + "n": 6 }, "webgl": { "mean": 198.0, - "effect": -119.4717, + "effect": -119.432, "n": 3 } }, @@ -168,220 +168,220 @@ "values": { "best_practices": { "mean": 202.5, - "effect": -114.9717, + "effect": -114.932, "n": 6 }, "none": { - "mean": 321.043, - "effect": 3.5713, - "n": 395 + "mean": 320.9575, + "effect": 3.5255, + "n": 400 }, "separation": { "mean": 197.3333, - "effect": -120.1384, + "effect": -120.0987, "n": 6 } }, - "spread": 123.7097 + "spread": 123.6242 }, "error_checking": { "values": { "none": { - "mean": 319.2319, - "effect": 1.7602, - "n": 401 + "mean": 319.17, + "effect": 1.7379, + "n": 406 }, "self_verify": { "mean": 199.8333, - "effect": -117.6384, + "effect": -117.5987, "n": 6 } }, - "spread": 119.3986 + "spread": 119.3367 }, "tool_edit": { "values": { "off": { "mean": 275.2581, - "effect": -42.2137, + "effect": -42.174, "n": 31 }, "on": { - "mean": 320.9521, - "effect": 3.4804, - "n": 376 + "mean": 320.8635, + "effect": 3.4315, + "n": 381 } }, - "spread": 45.694 + "spread": 45.6054 }, "web_search": { "values": { "off": { "mean": 354.0, - "effect": 36.5283, + "effect": 36.568, "n": 34 }, "on": { - "mean": 314.1421, - "effect": -3.3297, - "n": 373 + "mean": 314.1429, + "effect": -3.2892, + "n": 378 } }, - "spread": 39.8579 + "spread": 39.8571 }, "context_file": { "values": { "none": { - "mean": 320.1372, - "effect": 2.6655, - "n": 379 + "mean": 320.0599, + "effect": 2.6279, + "n": 384 }, "provided": { "mean": 281.3929, - "effect": -36.0789, + "effect": -36.0392, "n": 28 } }, - "spread": 38.7443 + "spread": 38.667 }, "max_budget": { "values": { "high": { "mean": 281.7826, - "effect": -35.6891, + "effect": -35.6494, "n": 23 }, "low": { - "mean": 319.6094, - "effect": 2.1376, - "n": 384 + "mean": 319.5398, + "effect": 2.1078, + "n": 389 } }, - "spread": 37.8268 + "spread": 37.7572 }, "tool_write": { "values": { "off": { "mean": 285.3571, - "effect": -32.1146, + "effect": -32.0749, "n": 28 }, "on": { - "mean": 319.8443, - "effect": 2.3726, - "n": 379 + "mean": 319.7708, + "effect": 2.3388, + "n": 384 } }, - "spread": 34.4872 + "spread": 34.4137 }, "tool_glob": { "values": { "off": { "mean": 288.7037, - "effect": -28.768, + "effect": -28.7283, "n": 27 }, "on": { - "mean": 319.5158, - "effect": 2.044, - "n": 380 + "mean": 319.4468, + "effect": 2.0147, + "n": 385 } }, - "spread": 30.8121 + "spread": 30.7431 }, "tool_grep": { "values": { "off": { "mean": 290.8214, - "effect": -26.6503, + "effect": -26.6106, "n": 28 }, "on": { - "mean": 319.4406, - "effect": 1.9689, - "n": 379 + "mean": 319.3724, + "effect": 1.9404, + "n": 384 } }, - "spread": 28.6192 + "spread": 28.551 }, "language": { "values": { "javascript": { "mean": 291.6667, - "effect": -25.8051, + "effect": -25.7654, "n": 18 }, "typescript": { - "mean": 319.1478, - "effect": 1.6761, - "n": 372 + "mean": 319.0822, + "effect": 1.6502, + "n": 377 }, "unspecified": { "mean": 308.1176, - "effect": -9.3541, + "effect": -9.3144, "n": 17 } }, - "spread": 27.4811 + "spread": 27.4155 }, "prompt_style": { "values": { "detailed": { "mean": 297.6667, - "effect": -19.8051, + "effect": -19.7654, "n": 30 }, "simple": { - "mean": 319.0477, - "effect": 1.576, - "n": 377 + "mean": 318.9843, + "effect": 1.5523, + "n": 382 } }, - "spread": 21.381 + "spread": 21.3176 }, "linter": { "values": { "off": { "mean": 326.6, - "effect": 9.1283, + "effect": 9.168, "n": 35 }, "on": { - "mean": 316.6129, - "effect": -0.8588, - "n": 372 + "mean": 316.5809, + "effect": -0.8511, + "n": 377 } }, - "spread": 9.9871 + "spread": 10.0191 }, "tool_read": { "values": { "off": { "mean": 324.1034, - "effect": 6.6317, + "effect": 6.6714, "n": 29 }, "on": { - "mean": 316.963, - "effect": -0.5088, - "n": 378 + "mean": 316.9269, + "effect": -0.5051, + "n": 383 } }, - "spread": 7.1404 + "spread": 7.1765 }, "human_language": { "values": { "en": { - "mean": 317.1816, - "effect": -0.2902, - "n": 380 + "mean": 317.1429, + "effect": -0.2892, + "n": 385 }, "es": { "mean": 321.5556, - "effect": 4.0838, + "effect": 4.1235, "n": 27 } }, - "spread": 4.374 + "spread": 4.4127 } } \ No newline at end of file diff --git a/results/index.jsonl b/results/index.jsonl @@ -413,3 +413,8 @@ {"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=canvas_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=canvas_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "30531578", "short_cell_id": "9e8c7e48", "completed_at": "2026-04-07T01:31:45.369802+00:00"} {"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=canvas_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=canvas_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "d8fc25ba", "short_cell_id": "9e8c7e48", "completed_at": "2026-04-07T01:34:51.144052+00:00"} {"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=canvas_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=canvas_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "aa3d18d8", "short_cell_id": "9e8c7e48", "completed_at": "2026-04-07T01:35:07.769014+00:00"} +{"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "f3626e24", "short_cell_id": "a4c12deb", "completed_at": "2026-04-07T01:38:20.329385+00:00"} +{"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "5411d5ce", "short_cell_id": "a4c12deb", "completed_at": "2026-04-07T01:38:22.673272+00:00"} +{"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "8cf0fbde", "short_cell_id": "a4c12deb", "completed_at": "2026-04-07T01:42:57.035119+00:00"} +{"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "11b37482", "short_cell_id": "86ee3001", "completed_at": "2026-04-07T01:48:05.623201+00:00"} +{"run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2", "task": "tetris", "model": "glm-5.1", "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", "short_id": "63c0c2ab", "short_cell_id": "86ee3001", "completed_at": "2026-04-07T01:48:29.575707+00:00"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/claude_output.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/claude_output.json @@ -0,0 +1 @@ +{"type":"result","subtype":"success","is_error":false,"duration_ms":578799,"duration_api_ms":441396,"num_turns":28,"result":"All 16 tests pass. Here's a summary of what was built:\n\n## Tetris Game — DOM-based, TypeScript\n\n### Files\n- **`index.html`** — Main page with game board, side panel (next piece, score, lines, level, controls)\n- **`src/tetris.ts`** — Complete game logic in TypeScript (compiled to `dist/tetris.js`)\n- **`src/styles.css`** — Dark-themed CSS styling with neon glow effects\n\n### Mechanics implemented\n| Feature | Details |\n|---|---|\n| **7 Tetrominoes** | I, O, T, S, Z, J, L with correct shapes |\n| **7-bag randomizer** | Fair piece distribution — all 7 pieces appear before any repeats |\n| **Rotation** | Clockwise rotation with wall-kick offsets (8 kick positions tried) |\n| **Ghost piece** | Dashed outline showing where the piece will land |\n| **Line clearing** | Flash animation on full rows, then collapse |\n| **Scoring** | 1-line: 100×level, 2: 300×, 3: 500×, 4: 800×; soft drop +1, hard drop +2/row |\n| **Levels** | Every 10 lines cleared; speed increases from 800ms down to 80ms across 15 levels |\n| **Controls** | ←/→ move, ↑ rotate, ↓ soft drop, Space hard drop, P pause, R restart |\n| **Game over** | Detected when a piece locks above the visible board |\n| **Auto-repeat** | Custom key repeat (170ms delay, 50ms rate) for held movement keys |\n\n### Rendering\n- Pure DOM: a CSS Grid of `<div>` cells with `data-color` attributes for piece colors\n- No Canvas or SVG used\n- Side panel shows next piece preview, score, lines, level, and keyboard controls","stop_reason":"end_turn","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","total_cost_usd":0.3079764,"usage":{"input_tokens":20950,"cache_creation_input_tokens":0,"cache_read_input_tokens":303232,"output_tokens":9157,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"glm-5.1":{"inputTokens":24810,"outputTokens":9500,"cacheReadInputTokens":303488,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.3079764,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"710c4202-a204-42fd-a8b2-1ce7707b4ce8"} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/claude_stderr.log b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/claude_stderr.log diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/eval_results.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/eval_results.json @@ -0,0 +1,273 @@ +{ + "structural": { + "pass": true, + "checks": [ + { + "name": "entry_point_exists", + "pass": true, + "detail": "index.html found" + }, + { + "name": "package_json_exists", + "pass": true, + "detail": "package.json found" + }, + { + "name": "build_succeeds", + "pass": true, + "detail": "no build script defined (static project)" + }, + { + "name": "typescript_compiles", + "pass": true, + "detail": "tsc --noEmit passed" + } + ], + "score": 1.0 + }, + "quality": { + "lint": { + "pass": true, + "errors": 0, + "warnings": 0 + }, + "typecheck": { + "pass": true + }, + "performance": { + "pass": true, + "bundle_size_bytes": 15061, + "size_under_512kb": true + }, + "score": 1.0 + }, + "code_analysis": { + "files": { + "total": 12, + "code": 8, + "docs": 0, + "unnecessary": 0, + "unnecessary_list": [] + }, + "lines_of_code": 1949, + "dependencies": { + "production": 0, + "dev": 6, + "total": 6 + }, + "complexity": "over-engineered", + "console_logs": 0, + "magic_numbers": { + "count": 55, + "excessive": true + }, + "function_length": { + "count": 92, + "average": 6.8, + "max": 31, + "long_functions": 0 + }, + "max_nesting_depth": 10, + "global_declarations": 58, + "naming": { + "dominant_style": "camelCase", + "consistency_pct": 100.0, + "camel_case": 695, + "snake_case": 0 + }, + "error_handling": { + "try_catch_blocks": 4, + "has_error_handling": true + }, + "comments": { + "comment_lines": 151, + "source_lines": 1391, + "ratio_pct": 10.9 + }, + "separation_of_concerns": { + "verdict": "mixed", + "files_with_rendering": 4, + "files_with_logic": 3, + "files_with_both": 3 + }, + "html_validation": { + "valid": false, + "errors": 8 + }, + "duplication_percentage": 0.0, + "score": 0.75 + }, + "transcript_analysis": { + "total_events": 78, + "tool_calls": { + "total": 27, + "bash": 17, + "write": 0, + "edit": 3, + "read": 7 + }, + "wasted_turns": { + "total": 1, + "docs": 0, + "ascii_art": 0, + "server_starts": 1 + }, + "errors_encountered": 0, + "thinking_blocks": 6, + "text_blocks": 8, + "productivity_ratio": 0.96, + "self_tested": true, + "score": 1.0 + }, + "gameplay_bot": { + "pass": true, + "score": 1, + "total": 16, + "passed": 16, + "failed": 0, + "report": { + "implementation": { + "renderer": "dom", + "grid_detected": true, + "grid_bounds": { + "x": 388, + "y": 50.5, + "width": 300, + "height": 600 + }, + "controls": { + "left": "ArrowLeft", + "right": "ArrowRight", + "down": "ArrowDown", + "rotate": "ArrowUp", + "drop": "Space" + }, + "start_mechanism": "auto", + "score_element_found": true, + "grid_confidence": 1 + }, + "tests": [ + { + "name": "game_loads", + "pass": true, + "detail": "no console errors" + }, + { + "name": "game_starts", + "pass": true, + "detail": "started via auto" + }, + { + "name": "auto_drop", + "pass": true, + "detail": "grid state changed after 5s with no input (grid-verified)" + }, + { + "name": "move_left", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_right", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_down", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "rotate", + "pass": true, + "detail": "piece shape changed after rotate key (grid-verified, 1 rotation(s))" + }, + { + "name": "all_pieces_rotate", + "pass": true, + "detail": "rotation confirmed but could not identify individual piece types" + }, + { + "name": "hard_drop", + "pass": true, + "detail": "piece immediately dropped to bottom (grid-verified)" + }, + { + "name": "piece_locks", + "pass": true, + "detail": "filled cells persist at bottom (grid-verified, 2 lock event(s))" + }, + { + "name": "new_piece_spawns", + "pass": true, + "detail": "1 new piece(s) detected at top of grid" + }, + { + "name": "multiple_pieces", + "pass": true, + "detail": "6 pieces placed during play session" + }, + { + "name": "line_clear", + "pass": true, + "detail": "1 line(s) cleared (grid-verified)" + }, + { + "name": "score_changes", + "pass": true, + "detail": "score changed from 0 to 272" + }, + { + "name": "game_over", + "pass": true, + "detail": "game stopped after stacking to top" + }, + { + "name": "playable_30s", + "pass": true, + "detail": "played for 30s, placed 21 pieces, no crashes" + } + ], + "summary": { + "total": 16, + "passed": 16, + "failed": 0, + "score": 1 + }, + "gameplay": { + "pieces_placed": 21, + "lines_cleared": 1, + "max_score_observed": 272, + "play_duration_seconds": 30, + "errors_during_play": 0 + }, + "session": { + "frames": 1114, + "events_count": 11, + "pieces_spawned": 1, + "pieces_locked": 6, + "lines_cleared": 1, + "piece_types_seen": [ + "unknown" + ], + "grid_read_success_rate": 1 + }, + "performance": { + "load_time_ms": 36 + }, + "accessibility": { + "issues": [ + "no focusable elements" + ], + "issue_count": 1, + "pass": false + } + } + }, + "outcome_score": 0.5, + "score": 0.5, + "sonarqube": { + "error": "SonarQube not running at localhost:9000", + "score": 0 + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/gameplay-bot-report.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/gameplay-bot-report.json @@ -0,0 +1,138 @@ +{ + "implementation": { + "renderer": "dom", + "grid_detected": true, + "grid_bounds": { + "x": 388, + "y": 50.5, + "width": 300, + "height": 600 + }, + "controls": { + "left": "ArrowLeft", + "right": "ArrowRight", + "down": "ArrowDown", + "rotate": "ArrowUp", + "drop": "Space" + }, + "start_mechanism": "auto", + "score_element_found": true, + "grid_confidence": 1 + }, + "tests": [ + { + "name": "game_loads", + "pass": true, + "detail": "no console errors" + }, + { + "name": "game_starts", + "pass": true, + "detail": "started via auto" + }, + { + "name": "auto_drop", + "pass": true, + "detail": "grid state changed after 5s with no input (grid-verified)" + }, + { + "name": "move_left", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_right", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_down", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "rotate", + "pass": true, + "detail": "piece shape changed after rotate key (grid-verified, 1 rotation(s))" + }, + { + "name": "all_pieces_rotate", + "pass": true, + "detail": "rotation confirmed but could not identify individual piece types" + }, + { + "name": "hard_drop", + "pass": true, + "detail": "piece immediately dropped to bottom (grid-verified)" + }, + { + "name": "piece_locks", + "pass": true, + "detail": "filled cells persist at bottom (grid-verified, 2 lock event(s))" + }, + { + "name": "new_piece_spawns", + "pass": true, + "detail": "1 new piece(s) detected at top of grid" + }, + { + "name": "multiple_pieces", + "pass": true, + "detail": "6 pieces placed during play session" + }, + { + "name": "line_clear", + "pass": true, + "detail": "1 line(s) cleared (grid-verified)" + }, + { + "name": "score_changes", + "pass": true, + "detail": "score changed from 0 to 272" + }, + { + "name": "game_over", + "pass": true, + "detail": "game stopped after stacking to top" + }, + { + "name": "playable_30s", + "pass": true, + "detail": "played for 30s, placed 21 pieces, no crashes" + } + ], + "summary": { + "total": 16, + "passed": 16, + "failed": 0, + "score": 1 + }, + "gameplay": { + "pieces_placed": 21, + "lines_cleared": 1, + "max_score_observed": 272, + "play_duration_seconds": 30, + "errors_during_play": 0 + }, + "session": { + "frames": 1114, + "events_count": 11, + "pieces_spawned": 1, + "pieces_locked": 6, + "lines_cleared": 1, + "piece_types_seen": [ + "unknown" + ], + "grid_read_success_rate": 1 + }, + "performance": { + "load_time_ms": 36 + }, + "accessibility": { + "issues": [ + "no focusable elements" + ], + "issue_count": 1, + "pass": false + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/meta.json @@ -0,0 +1,40 @@ +{ + "model": "glm-5.1", + "effort": "high", + "prompt_style": "simple", + "language": "typescript", + "human_language": "en", + "tool_read": "on", + "tool_write": "on", + "tool_edit": "on", + "tool_glob": "on", + "tool_grep": "on", + "linter": "on", + "playwright": "off", + "context_file": "none", + "web_search": "on", + "max_budget": "low", + "tests_provided": "none", + "strategy": "none", + "design_guidance": "none", + "architecture": "none", + "error_checking": "none", + "context_noise": "clean", + "renderer": "dom", + "provider": "zai", + "task": "tetris", + "actual_model": "glm-5.1", + "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", + "runs_per_cell": 3, + "timeout_seconds": 1200, + "max_budget_usd": 2.0, + "run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1", + "short_id": "11b37482", + "short_cell_id": "86ee3001", + "run_number": 1, + "claude_version": "2.1.92 (Claude Code)", + "started_at": "2026-04-07T01:38:24.826400+00:00", + "wall_time_seconds": 579, + "exit_code": 0, + "completed_at": "2026-04-07T01:48:05.623201+00:00" +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/transcript.jsonl b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/transcript.jsonl @@ -0,0 +1,78 @@ +{"type": "harness", "subtype": "config", "model": "glm-5.1", "effort": "high", "tools": ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "WebSearch", "WebFetch"], "max_budget_usd": 2.0, "timeout_seconds": 1200, "task": "tetris", "language": "typescript", "prompt_style": "simple"} +{"type": "user", "subtype": "prompt", "message": {"role": "user", "content": "Build a playable Tetris game that runs in a browser. It should have all the standard mechanics: piece rotation, line clearing, scoring, and increasing speed. Use keyboard controls for movement and rotation.\n\n\nUse TypeScript.\n\nRender the game using DOM elements (divs/tables) with CSS for styling. Do not use Canvas or SVG."}} +{"type":"system","subtype":"init","cwd":"/tmp/loop-bench-50cbv41e","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","tools":["Bash","Edit","Read"],"mcp_servers":[],"model":"glm-5.1","permissionMode":"dontAsk","slash_commands":["update-config","debug","simplify","batch","loop","schedule","claude-api","compact","context","cost","heapdump","init","review","security-review","insights"],"apiKeySource":"apiKeyHelper","claude_code_version":"2.1.92","output_style":"default","agents":["general-purpose","statusline-setup","Explore","Plan"],"skills":["update-config","debug","simplify","batch","loop","schedule","claude-api"],"plugins":[{"name":"claude-hud","path":"/root/.claude/plugins/marketplaces/claude-hud/","source":"claude-hud@claude-hud"},{"name":"rust-analyzer-lsp","path":"/root/.claude/plugins/marketplaces/claude-plugins-official/plugins/rust-analyzer-lsp","source":"rust-analyzer-lsp@claude-plugins-official"}],"uuid":"4e81bd81-d482-401b-b5a7-f2d6a8c938c4","fast_mode_state":"off"} +{"type":"system","subtype":"api_retry","attempt":1,"max_retries":10,"retry_delay_ms":596.3340671886898,"error_status":429,"error":"rate_limit","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"3f8993c0-7a35-45fe-9517-880bb800b4f3"} +{"type":"system","subtype":"api_retry","attempt":2,"max_retries":10,"retry_delay_ms":1141.6796125544925,"error_status":429,"error":"rate_limit","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"45dfc0c8-ecfb-4049-abe6-3eae3ca901a7"} +{"type":"system","subtype":"api_retry","attempt":3,"max_retries":10,"retry_delay_ms":2014.1703972970365,"error_status":429,"error":"rate_limit","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"6e9be356-a523-4cf7-83a7-270ce9b631ec"} +{"type":"system","subtype":"api_retry","attempt":4,"max_retries":10,"retry_delay_ms":4353.390165790498,"error_status":429,"error":"rate_limit","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"e1664760-e097-44ec-b878-e6ea0eb2b57b"} +{"type":"system","subtype":"api_retry","attempt":5,"max_retries":10,"retry_delay_ms":8979.19119412997,"error_status":429,"error":"rate_limit","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"1882ba7f-5705-4315-921d-c04360374479"} +{"type":"system","subtype":"api_retry","attempt":6,"max_retries":10,"retry_delay_ms":19574.547821229506,"error_status":429,"error":"rate_limit","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"9aaba029-b6e6-4c69-89e2-f6ffa2a6cb58"} +{"type":"assistant","message":{"id":"msg_20260407093919158387fa71b04a39","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The user wants me to build a playable Tetris game that runs in a browser using TypeScript, rendered with DOM elements (no Canvas/SVG). Let me plan this out:\n\n1. I'll need an HTML file, a TypeScript file, and CSS\n2. Standard Tetris mechanics: piece rotation, line clearing, scoring, increasing speed\n3. Keyboard controls for movement and rotation\n4. DOM-based rendering with divs/CSS\n\nLet me create a well-structured project:\n- `index.html` - main page\n- `tetris.ts` - game logic in TypeScript\n- `styles.css` - styling\n\nI'll need to compile the TypeScript, so I should set up a simple project with a tsconfig.\n\nLet me think about the game architecture:\n- Game board: 10 columns × 20 rows (standard Tetris)\n- 7 standard tetrominoes (I, O, T, S, Z, J, L)\n- Rotation using SRS (Super Rotation System) or simplified\n- Line clearing with scoring\n- Speed increases with level (based on lines cleared)\n- Keyboard controls: Left/Right arrows for movement, Up arrow for rotation, Down arrow for soft drop, Space for hard drop\n\nLet me write this step by step.\n\nFirst, let me check what's available in the working directory.","signature":"a8b226575bb940e0b3fb9aa4"}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":3860,"output_tokens":343,"cache_read_input_tokens":256,"server_tool_use":{"web_search_requests":0},"service_tier":"standard"},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"f45668e4-4700-443f-87a1-000000000000"} +{"type":"assistant","message":{"id":"msg_20260407093919158387fa71b04a39","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_52d83ce41ba54c09aed6f026","name":"Bash","input":{"command":"ls /tmp/loop-bench-50cbv41e/","description":"Check working directory contents"}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":3860,"output_tokens":343,"cache_read_input_tokens":256,"server_tool_use":{"web_search_requests":0},"service_tier":"standard"},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"f45668e4-4700-443f-87a1-000000000001"} +{"type":"assistant","message":{"id":"msg_20260407093919158387fa71b04a39","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_02d49958bb254460a5b389ea","name":"Bash","input":{"command":"which tsc npx 2>/dev/null; node --version 2>/dev/null","description":"Check available tools"}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":3860,"output_tokens":343,"cache_read_input_tokens":256,"server_tool_use":{"web_search_requests":0},"service_tier":"standard"},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"f45668e4-4700-443f-87a1-000000000002"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_52d83ce41ba54c09aed6f026","type":"tool_result","content":"node_modules\npackage.json\npackage-lock.json\ntests-few\ntests-full\n[rerun: b1]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"f1943d1c-6898-45ad-bdff-f441669a2742","timestamp":"2026-04-07T01:39:36.713Z","tool_use_result":{"stdout":"node_modules\npackage.json\npackage-lock.json\ntests-few\ntests-full","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_02d49958bb254460a5b389ea","type":"tool_result","content":"/usr/bin/tsc\n/usr/bin/npx\nv22.22.0\n[rerun: b2]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"7530e213-d044-4872-987b-52faa7d5c420","timestamp":"2026-04-07T01:39:36.716Z","tool_use_result":{"stdout":"/usr/bin/tsc\n/usr/bin/npx\nv22.22.0","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_2026040709393778fcac6cee6244e3","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"Good, TypeScript compiler and Node.js are available. Let me create the Tetris game. I'll structure it as:\n\n1. `index.html` - Main HTML page\n2. `src/tetris.ts` - Game logic in TypeScript\n3. `src/styles.css` - CSS styling\n4. `tsconfig.json` - TypeScript config\n\nLet me build a complete, polished Tetris game.\n\nLet me think about the game design carefully:\n\n**Board**: 10×20 grid\n\n**Pieces** (7 tetrominoes):\n- I: [[1,1,1,1]]\n- O: [[1,1],[1,1]]\n- T: [[0,1,0],[1,1,1]]\n- S: [[0,1,1],[1,1,0]]\n- Z: [[1,1,0],[0,1,1]]\n- J: [[1,0,0],[1,1,1]]\n- L: [[0,0,1],[1,1,1]]\n\n**Rotation**: I'll implement rotation by transposing and reversing rows (clockwise rotation)\n\n**Scoring**:\n- 1 line: 100 × level\n- 2 lines: 300 × level\n- 3 lines: 500 × level\n- 4 lines: 800 × level\n\n**Speed**: Start at 800ms, decrease as level increases\n\n**Controls**:\n- Left/Right: Move piece\n- Up: Rotate\n- Down: Soft drop\n- Space: Hard drop\n- P: Pause\n\nLet me write the code now.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"7e151e44-e8f2-4f82-83b0-4189b0ff4cea"} +{"type":"assistant","message":{"id":"msg_2026040709393778fcac6cee6244e3","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_16865db4c1574ee485e360ba","name":"Bash","input":{"command":"mkdir -p /tmp/loop-bench-50cbv41e/src","description":"Create src directory"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d6ca3cc7-c7a6-4c60-91a6-54f9d84fa62a"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_16865db4c1574ee485e360ba","type":"tool_result","content":"[rerun: b3]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"cfef9ac4-9d63-47e1-a771-2830013fb118","timestamp":"2026-04-07T01:39:55.555Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":true}} +{"type":"assistant","message":{"id":"msg_202604070939567579657df65f4781","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now I'll create all the project files."}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"b57179a9-39e8-4e1c-a9db-a47e07987392"} +{"type":"assistant","message":{"id":"msg_202604070939567579657df65f4781","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_ce773333824942f4b5105ae0","name":"Bash","input":{"command":"cat > /tmp/loop-bench-50cbv41e/tsconfig.json << 'TSEOF'\n{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ES2020\",\n \"outDir\": \"./dist\",\n \"rootDir\": \"./src\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"sourceMap\": false,\n \"lib\": [\"ES2020\", \"DOM\", \"DOM.Iterable\"]\n },\n \"include\": [\"src/**/*.ts\"],\n \"exclude\": [\"node_modules\"]\n}\nTSEOF\necho \"tsconfig.json created\"","description":"Create tsconfig.json"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d71cd48b-9ae5-497b-b144-bd82cfc5ce43"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_ce773333824942f4b5105ae0","type":"tool_result","content":"tsconfig.json created\n[rerun: b4]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"88ff828f-648a-4068-829c-4ae44a8d46dc","timestamp":"2026-04-07T01:40:05.772Z","tool_use_result":{"stdout":"tsconfig.json created","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_20260407094007fb2997b8ba6f427c","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_c110799dec444e87878bc03f","name":"Bash","input":{"command":"cat > /tmp/loop-bench-50cbv41e/src/styles.css << 'CSSEOF'\n*, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\n:root {\n --bg: #0f0f1a;\n --fg: #e0e0f0;\n --accent: #6c5ce7;\n --board-bg: #1a1a2e;\n --grid-line: rgba(255,255,255,0.04);\n --cell-size: 30px;\n --border-color: #2d2d5e;\n}\n\nbody {\n font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;\n background: var(--bg);\n color: var(--fg);\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n overflow: hidden;\n user-select: none;\n}\n\n#game-container {\n display: flex;\n gap: 24px;\n align-items: flex-start;\n}\n\n/* ---- Game Board ---- */\n\n#board-wrapper {\n position: relative;\n background: var(--board-bg);\n border: 2px solid var(--border-color);\n border-radius: 6px;\n padding: 2px;\n box-shadow: 0 0 40px rgba(108, 92, 231, 0.15), inset 0 0 30px rgba(0,0,0,0.3);\n}\n\n#board {\n display: grid;\n grid-template-columns: repeat(10, var(--cell-size));\n grid-template-rows: repeat(20, var(--cell-size));\n gap: 0;\n}\n\n.cell {\n width: var(--cell-size);\n height: var(--cell-size);\n border: 1px solid var(--grid-line);\n transition: background-color 0.05s ease;\n border-radius: 2px;\n}\n\n/* ---- Cell Colors (Tetrominoes) ---- */\n\n.cell[data-color=\"I\"] { background: #00e5ff; box-shadow: inset 0 0 8px rgba(0,229,255,0.4); }\n.cell[data-color=\"O\"] { background: #ffea00; box-shadow: inset 0 0 8px rgba(255,234,0,0.4); }\n.cell[data-color=\"T\"] { background: #d500f9; box-shadow: inset 0 0 8px rgba(213,0,249,0.4); }\n.cell[data-color=\"S\"] { background: #00e676; box-shadow: inset 0 0 8px rgba(0,230,118,0.4); }\n.cell[data-color=\"Z\"] { background: #ff1744; box-shadow: inset 0 0 8px rgba(255,23,68,0.4); }\n.cell[data-color=\"J\"] { background: #2979ff; box-shadow: inset 0 0 8px rgba(41,121,255,0.4); }\n.cell[data-color=\"L\"] { background: #ff9100; box-shadow: inset 0 0 8px rgba(255,145,0,0.4); }\n\n.cell[data-ghost] {\n background: transparent !important;\n box-shadow: none !important;\n border: 2px dashed rgba(255,255,255,0.25) !important;\n}\n\n/* ---- Side Panel ---- */\n\n#side-panel {\n display: flex;\n flex-direction: column;\n gap: 16px;\n width: 180px;\n}\n\n.panel-box {\n background: var(--board-bg);\n border: 2px solid var(--border-color);\n border-radius: 6px;\n padding: 14px;\n box-shadow: 0 0 20px rgba(108, 92, 231, 0.08);\n}\n\n.panel-box h3 {\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 2px;\n color: #8888aa;\n margin-bottom: 8px;\n font-weight: 600;\n}\n\n.panel-box .value {\n font-size: 28px;\n font-weight: 700;\n color: var(--fg);\n font-variant-numeric: tabular-nums;\n}\n\n/* ---- Next Piece Preview ---- */\n\n#next-preview {\n display: grid;\n grid-template-columns: repeat(4, 20px);\n grid-template-rows: repeat(4, 20px);\n gap: 0;\n justify-content: center;\n}\n\n.preview-cell {\n width: 20px;\n height: 20px;\n border-radius: 2px;\n}\n\n/* ---- Overlay ---- */\n\n#overlay {\n position: absolute;\n inset: 0;\n background: rgba(15, 15, 26, 0.85);\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n z-index: 10;\n border-radius: 6px;\n backdrop-filter: blur(4px);\n}\n\n#overlay.hidden {\n display: none;\n}\n\n#overlay h2 {\n font-size: 28px;\n margin-bottom: 8px;\n color: var(--accent);\n font-weight: 800;\n letter-spacing: 1px;\n}\n\n#overlay p {\n font-size: 14px;\n color: #9999bb;\n margin-bottom: 4px;\n}\n\n#overlay .score-line {\n font-size: 22px;\n font-weight: 700;\n color: var(--fg);\n margin: 8px 0;\n}\n\n/* ---- Controls Help ---- */\n\n#controls {\n font-size: 12px;\n line-height: 1.8;\n color: #7777aa;\n}\n\n#controls kbd {\n display: inline-block;\n background: #252545;\n border: 1px solid #3a3a6e;\n border-radius: 3px;\n padding: 1px 6px;\n font-family: inherit;\n font-size: 11px;\n color: #bbbbdd;\n min-width: 22px;\n text-align: center;\n}\n\n/* ---- Line clear flash ---- */\n\n@keyframes line-clear-flash {\n 0% { background: #ffffff !important; box-shadow: 0 0 12px #ffffff !important; }\n 50% { background: #ffffff !important; box-shadow: 0 0 20px #ffffff !important; }\n 100% { background: transparent !important; box-shadow: none !important; }\n}\n\n.cell.clearing {\n animation: line-clear-flash 0.3s ease-out;\n}\nCSSEOF\necho \"styles.css created\"","description":"Create CSS styles for Tetris game"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d9088a0c-c121-4b08-8f10-d344cd00ef53"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_c110799dec444e87878bc03f","type":"tool_result","content":"styles.css created\n[rerun: b5]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"9bca6516-a17e-4719-87ca-34aca36ee8de","timestamp":"2026-04-07T01:40:49.075Z","tool_use_result":{"stdout":"styles.css created","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070940496e2f15f1153c4d59","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_1f4cc326998d4d7c84bead0e","name":"Bash","input":{"command":"cat > /tmp/loop-bench-50cbv41e/src/tetris.ts << 'TSEOF'\n// ============================================================\n// Tetris – full DOM-based implementation in TypeScript\n// ============================================================\n\n// ---- Types ----\n\ntype Color = \"I\" | \"O\" | \"T\" | \"S\" | \"Z\" | \"J\" | \"L\";\n\ninterface Piece {\n shape: number[][];\n color: Color;\n x: number;\n y: number;\n}\n\ntype Board = (Color | null)[][];\n\n// ---- Constants ----\n\nconst COLS = 10;\nconst ROWS = 20;\n\nconst SHAPES: Record<Color, number[][]> = {\n I: [[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]],\n O: [[1,1],[1,1]],\n T: [[0,1,0],[1,1,1],[0,0,0]],\n S: [[0,1,1],[1,1,0],[0,0,0]],\n Z: [[1,1,0],[0,1,1],[0,0,0]],\n J: [[1,0,0],[1,1,1],[0,0,0]],\n L: [[0,0,1],[1,1,1],[0,0,0]],\n};\n\nconst PIECE_COLORS: Color[] = [\"I\",\"O\",\"T\",\"S\",\"Z\",\"J\",\"L\"];\n\n// Scoring: index = number of lines cleared\nconst LINE_SCORES = [0, 100, 300, 500, 800];\n\nconst LEVEL_SPEEDS: Record<number, number> = {};\nfor (let lvl = 1; lvl <= 15; lvl++) {\n LEVEL_SPEEDS[lvl] = Math.max(80, 800 - (lvl - 1) * 55);\n}\n\n// ---- Game State ----\n\nlet board: Board;\nlet currentPiece: Piece | null;\nlet nextPiece: Piece | null;\nlet score: number;\nlet lines: number;\nlet level: number;\nlet gameOver: boolean;\nlet paused: boolean;\nlet dropTimer: number | null;\nlet lastDropTime: number;\nlet bag: Color[];\n\n// ---- DOM refs ----\n\nlet boardCells: HTMLDivElement[][] = [];\nlet previewCells: HTMLDivElement[][] = [];\nlet scoreEl!: HTMLElement;\nlet linesEl!: HTMLElement;\nlet levelEl!: HTMLElement;\nlet overlayEl!: HTMLElement;\nlet overlayTitleEl!: HTMLElement;\nlet overlayBodyEl!: HTMLElement;\n\n// ---- Initialization ----\n\nfunction createBoardDOM(): void {\n const boardEl = document.getElementById(\"board\")!;\n boardEl.innerHTML = \"\";\n boardCells = [];\n for (let r = 0; r < ROWS; r++) {\n boardCells[r] = [];\n for (let c = 0; c < COLS; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"cell\";\n boardEl.appendChild(cell);\n boardCells[r][c] = cell;\n }\n }\n}\n\nfunction createPreviewDOM(): void {\n const previewEl = document.getElementById(\"next-preview\")!;\n previewEl.innerHTML = \"\";\n previewCells = [];\n for (let r = 0; r < 4; r++) {\n previewCells[r] = [];\n for (let c = 0; c < 4; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"preview-cell\";\n previewEl.appendChild(cell);\n previewCells[r][c] = cell;\n }\n }\n}\n\nfunction initDOMRefs(): void {\n scoreEl = document.getElementById(\"score-value\")!;\n linesEl = document.getElementById(\"lines-value\")!;\n levelEl = document.getElementById(\"level-value\")!;\n overlayEl = document.getElementById(\"overlay\")!;\n overlayTitleEl = document.getElementById(\"overlay-title\")!;\n overlayBodyEl = document.getElementById(\"overlay-body\")!;\n}\n\n// ---- Board helpers ----\n\nfunction emptyBoard(): Board {\n return Array.from({ length: ROWS }, () => Array<Color | null>(COLS).fill(null));\n}\n\n// ---- 7-bag randomizer ----\n\nfunction shuffleArray<T>(arr: T[]): T[] {\n const a = [...arr];\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [a[i], a[j]] = [a[j], a[i]];\n }\n return a;\n}\n\nfunction pullFromBag(): Color {\n if (bag.length === 0) {\n bag = shuffleArray([...PIECE_COLORS]);\n }\n return bag.pop()!;\n}\n\nfunction spawnPiece(color?: Color): Piece {\n const c = color ?? pullFromBag();\n const shape = SHAPES[c].map(row => [...row]);\n return {\n shape,\n color: c,\n x: Math.floor((COLS - shape[0].length) / 2),\n y: c === \"I\" ? -1 : 0,\n };\n}\n\n// ---- Collision ----\n\nfunction collides(shape: number[][], px: number, py: number): boolean {\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const bx = px + c;\n const by = py + r;\n if (bx < 0 || bx >= COLS || by >= ROWS) return true;\n if (by >= 0 && board[by][bx] !== null) return true;\n }\n }\n return false;\n}\n\n// ---- Rotation (clockwise) ----\n\nfunction rotateCW(shape: number[][]): number[][] {\n const rows = shape.length;\n const cols = shape[0].length;\n const result: number[][] = Array.from({ length: cols }, () => Array(rows).fill(0));\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n result[c][rows - 1 - r] = shape[r][c];\n }\n }\n return result;\n}\n\n// Wall kick offsets to try on rotation\nconst KICK_OFFSETS: [number, number][] = [\n [0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1], [-2, 0], [2, 0],\n];\n\nfunction tryRotate(): boolean {\n if (!currentPiece || currentPiece.color === \"O\") return false;\n const rotated = rotateCW(currentPiece.shape);\n for (const [dx, dy] of KICK_OFFSETS) {\n if (!collides(rotated, currentPiece.x + dx, currentPiece.y + dy)) {\n currentPiece.shape = rotated;\n currentPiece.x += dx;\n currentPiece.y += dy;\n return true;\n }\n }\n return false;\n}\n\n// ---- Ghost piece ----\n\nfunction ghostY(): number {\n if (!currentPiece) return 0;\n let gy = currentPiece.y;\n while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) {\n gy++;\n }\n return gy;\n}\n\n// ---- Lock piece ----\n\nfunction lockPiece(): void {\n if (!currentPiece) return;\n const { shape, color, x, y } = currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = y + r;\n const bx = x + c;\n if (by < 0) {\n // piece locked above the board → game over\n endGame();\n return;\n }\n board[by][bx] = color;\n }\n }\n checkLines();\n spawnNext();\n}\n\n// ---- Line clearing ----\n\nfunction checkLines(): void {\n const fullRows: number[] = [];\n for (let r = 0; r < ROWS; r++) {\n if (board[r].every(cell => cell !== null)) {\n fullRows.push(r);\n }\n }\n if (fullRows.length === 0) return;\n\n // Flash animation\n for (const r of fullRows) {\n for (let c = 0; c < COLS; c++) {\n boardCells[r][c].classList.add(\"clearing\");\n }\n }\n\n // After animation, actually clear the rows\n setTimeout(() => {\n // Remove rows from top to bottom (sort descending so indices don't shift)\n const sorted = [...fullRows].sort((a, b) => b - a);\n for (const r of sorted) {\n board.splice(r, 1);\n board.unshift(Array<Color | null>(COLS).fill(null));\n }\n // Update scoring\n const cleared = fullRows.length;\n lines += cleared;\n const newLevel = Math.floor(lines / 10) + 1;\n if (newLevel > level) {\n level = newLevel;\n }\n score += LINE_SCORES[cleared] * level;\n updateStats();\n render();\n }, 300);\n}\n\n// ---- Spawn next ----\n\nfunction spawnNext(): void {\n currentPiece = nextPiece ? { ...nextPiece, shape: nextPiece.shape.map(r => [...r]) } : spawnPiece();\n // Reset position\n currentPiece.x = Math.floor((COLS - currentPiece.shape[0].length) / 2);\n currentPiece.y = currentPiece.color === \"I\" ? -1 : 0;\n nextPiece = spawnPiece();\n\n if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) {\n endGame();\n }\n renderPreview();\n}\n\n// ---- Movement ----\n\nfunction moveLeft(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) {\n currentPiece.x--;\n return true;\n }\n return false;\n}\n\nfunction moveRight(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) {\n currentPiece.x++;\n return true;\n }\n return false;\n}\n\nfunction moveDown(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n return true;\n }\n lockPiece();\n return false;\n}\n\nfunction hardDrop(): void {\n if (!currentPiece || gameOver || paused) return;\n let dropped = 0;\n while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n dropped++;\n }\n score += dropped * 2;\n updateStats();\n lockPiece();\n}\n\nfunction softDrop(): void {\n if (moveDown()) {\n score += 1;\n updateStats();\n }\n}\n\n// ---- Rendering ----\n\nfunction render(): void {\n // Clear board\n for (let r = 0; r < ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = boardCells[r][c];\n const val = board[r][c];\n if (val) {\n cell.setAttribute(\"data-color\", val);\n cell.removeAttribute(\"data-ghost\");\n } else {\n cell.removeAttribute(\"data-color\");\n cell.removeAttribute(\"data-ghost\");\n }\n cell.classList.remove(\"clearing\");\n }\n }\n\n if (!currentPiece || gameOver) return;\n\n // Draw ghost\n const gy = ghostY();\n const { shape, color, x } = currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = gy + r;\n const bx = x + c;\n if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n const cell = boardCells[by][bx];\n // Only draw ghost if no locked piece there\n if (!board[by][bx]) {\n cell.setAttribute(\"data-ghost\", \"\");\n cell.setAttribute(\"data-color\", color);\n }\n }\n }\n }\n\n // Draw current piece (overwrites ghost cells if overlap)\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = currentPiece.y + r;\n const bx = x + c;\n if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n const cell = boardCells[by][bx];\n cell.setAttribute(\"data-color\", color);\n cell.removeAttribute(\"data-ghost\");\n }\n }\n }\n}\n\nfunction renderPreview(): void {\n if (!nextPiece) return;\n // Clear preview\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n previewCells[r][c].removeAttribute(\"data-color\");\n }\n }\n const { shape, color } = nextPiece;\n // Center in 4×4 preview\n const offsetR = Math.floor((4 - shape.length) / 2);\n const offsetC = Math.floor((4 - shape[0].length) / 2);\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const pr = r + offsetR;\n const pc = c + offsetC;\n if (pr < 4 && pc < 4) {\n previewCells[pr][pc].setAttribute(\"data-color\", color);\n }\n }\n }\n}\n\nfunction updateStats(): void {\n scoreEl.textContent = score.toLocaleString();\n linesEl.textContent = lines.toString();\n levelEl.textContent = level.toString();\n}\n\n// ---- Game loop ----\n\nfunction getSpeed(): number {\n return LEVEL_SPEEDS[level] ?? 80;\n}\n\nfunction gameLoop(timestamp: number): void {\n if (gameOver) return;\n if (paused) {\n dropTimer = requestAnimationFrame(gameLoop);\n return;\n }\n const elapsed = timestamp - lastDropTime;\n if (elapsed >= getSpeed()) {\n moveDown();\n lastDropTime = timestamp;\n render();\n }\n dropTimer = requestAnimationFrame(gameLoop);\n}\n\n// ---- Game lifecycle ----\n\nfunction startGame(): void {\n board = emptyBoard();\n score = 0;\n lines = 0;\n level = 1;\n gameOver = false;\n paused = false;\n bag = [];\n currentPiece = null;\n nextPiece = null;\n\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n updateStats();\n\n overlayEl.classList.add(\"hidden\");\n\n spawnNext();\n render();\n lastDropTime = performance.now();\n if (dropTimer !== null) cancelAnimationFrame(dropTimer);\n dropTimer = requestAnimationFrame(gameLoop);\n}\n\nfunction endGame(): void {\n gameOver = true;\n currentPiece = null;\n if (dropTimer !== null) {\n cancelAnimationFrame(dropTimer);\n dropTimer = null;\n }\n render();\n\n overlayTitleEl.textContent = \"Game Over\";\n overlayBodyEl.innerHTML = `\n <p class=\"score-line\">Score: ${score.toLocaleString()}</p>\n <p>Level ${level} · ${lines} lines</p>\n <p style=\"margin-top:16px;color:#8888bb\">Press <kbd>R</kbd> to restart</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n}\n\nfunction togglePause(): void {\n if (gameOver) return;\n paused = !paused;\n if (paused) {\n overlayTitleEl.textContent = \"Paused\";\n overlayBodyEl.innerHTML = `<p>Press <kbd>P</kbd> to resume</p>`;\n overlayEl.classList.remove(\"hidden\");\n } else {\n overlayEl.classList.add(\"hidden\");\n lastDropTime = performance.now();\n }\n}\n\n// ---- Input ----\n\n// Repeat tracking for held keys\nlet keyRepeatTimers: Record<string, number | null> = {};\nconst REPEAT_DELAY = 170; // initial delay (ms)\nconst REPEAT_RATE = 50; // repeat interval (ms)\n\nfunction handleKeyAction(key: string): void {\n switch (key) {\n case \"ArrowLeft\":\n if (moveLeft()) render();\n break;\n case \"ArrowRight\":\n if (moveRight()) render();\n break;\n case \"ArrowDown\":\n softDrop();\n render();\n break;\n case \"ArrowUp\":\n if (tryRotate()) render();\n break;\n case \" \":\n hardDrop();\n render();\n break;\n case \"p\":\n case \"P\":\n togglePause();\n break;\n case \"r\":\n case \"R\":\n if (gameOver) startGame();\n break;\n }\n}\n\nfunction startRepeat(key: string): void {\n clearRepeat(key);\n // First action already happened in keydown; set delayed repeat\n keyRepeatTimers[key] = window.setTimeout(() => {\n keyRepeatTimers[key] = window.setInterval(() => {\n handleKeyAction(key);\n }, REPEAT_RATE);\n }, REPEAT_DELAY);\n}\n\nfunction clearRepeat(key: string): void {\n if (keyRepeatTimers[key] !== null) {\n clearTimeout(keyRepeatTimers[key]);\n clearInterval(keyRepeatTimers[key]);\n keyRepeatTimers[key] = null;\n }\n}\n\nfunction clearAllRepeats(): void {\n for (const key of Object.keys(keyRepeatTimers)) {\n clearRepeat(key);\n }\n}\n\ndocument.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n // Prevent page scrolling for game keys\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n }\n\n if (e.repeat) return; // We handle repeat ourselves\n\n handleKeyAction(e.key);\n\n // Set up repeat for movement keys\n if ([\"ArrowLeft\",\"ArrowRight\",\"ArrowDown\"].includes(e.key)) {\n startRepeat(e.key);\n }\n});\n\ndocument.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n clearRepeat(e.key);\n});\n\n// Lose focus → pause & clear repeats\nwindow.addEventListener(\"blur\", () => {\n clearAllRepeats();\n if (!gameOver && !paused) togglePause();\n});\n\n// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n\n overlayTitleEl.textContent = \"Tetris\";\n overlayBodyEl.innerHTML = `\n <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>\n <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>\n <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>\n <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>\n <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>\n <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>\n <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n\n // Start game on first interaction\n const startListener = (e: KeyboardEvent) => {\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n document.removeEventListener(\"keydown\", startListener);\n startGame();\n }\n };\n document.addEventListener(\"keydown\", startListener);\n});\nTSEOF\necho \"tetris.ts created\"","description":"Create main Tetris game TypeScript source"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"4a237f91-3e8d-46e5-992f-eabfcbe1667c"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_1f4cc326998d4d7c84bead0e","type":"tool_result","content":"tetris.ts created\n[rerun: b6]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"1d5d4e81-fd71-481b-9852-15d633deff7d","timestamp":"2026-04-07T01:42:29.182Z","tool_use_result":{"stdout":"tetris.ts created","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_20260407094229e88c05158d4b4f5a","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_c31059efcc4248718b56a16f","name":"Bash","input":{"command":"cat > /tmp/loop-bench-50cbv41e/index.html << 'HTMLEOF'\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Tetris</title>\n <link rel=\"stylesheet\" href=\"src/styles.css\" />\n</head>\n<body>\n <div id=\"game-container\">\n <div id=\"board-wrapper\">\n <div id=\"board\"></div>\n <div id=\"overlay\">\n <h2 id=\"overlay-title\"></h2>\n <div id=\"overlay-body\"></div>\n </div>\n </div>\n <div id=\"side-panel\">\n <div class=\"panel-box\">\n <h3>Next</h3>\n <div id=\"next-preview\"></div>\n </div>\n <div class=\"panel-box\">\n <h3>Score</h3>\n <div class=\"value\" id=\"score-value\">0</div>\n </div>\n <div class=\"panel-box\">\n <h3>Lines</h3>\n <div class=\"value\" id=\"lines-value\">0</div>\n </div>\n <div class=\"panel-box\">\n <h3>Level</h3>\n <div class=\"value\" id=\"level-value\">1</div>\n </div>\n <div class=\"panel-box\">\n <h3>Controls</h3>\n <div id=\"controls\">\n <kbd>←</kbd> <kbd>→</kbd> Move<br />\n <kbd>↑</kbd> Rotate<br />\n <kbd>↓</kbd> Soft drop<br />\n <kbd>Space</kbd> Hard drop<br />\n <kbd>P</kbd> Pause\n </div>\n </div>\n </div>\n </div>\n <script src=\"src/tetris.js\"></script>\n</body>\n</html>\nHTMLEOF\necho \"index.html created\"","description":"Create index.html"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"e1d0d4f5-1fbb-4c60-8aab-c324b73aed4f"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_c31059efcc4248718b56a16f","type":"tool_result","content":"index.html created\n[rerun: b7]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"cd371576-26b8-4d3e-9de5-c33cbb43a602","timestamp":"2026-04-07T01:42:46.676Z","tool_use_result":{"stdout":"index.html created","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_20260407094249328f56cc1c814b7d","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_d5f1b377c2554bceb1b4dfff","name":"Bash","input":{"command":"npx tsc","description":"Compile TypeScript to JavaScript"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"7a7475fd-64f0-4c75-8477-65a5c819e8a0"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_d5f1b377c2554bceb1b4dfff","type":"tool_result","content":"[rerun: b8]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"b3a19ccc-808b-42b8-b85d-a2bd10f8a9db","timestamp":"2026-04-07T01:42:56.417Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070942570d316560be704f2d","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The TypeScript compiled successfully. But wait - the tsconfig outputs to `./dist/`, but the HTML references `src/tetris.js`. Let me check what happened and fix the tsconfig or move the output.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"a234ac7f-dd20-4c1a-97e5-b4460aaaf66f"} +{"type":"assistant","message":{"id":"msg_202604070942570d316560be704f2d","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_248ca33d732c4b028883c6e3","name":"Bash","input":{"command":"ls /tmp/loop-bench-50cbv41e/dist/ /tmp/loop-bench-50cbv41e/src/","description":"Check where compiled output ended up"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"89cd33a0-e9d8-49e1-8733-8034735fb9f4"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_248ca33d732c4b028883c6e3","type":"tool_result","content":"/tmp/loop-bench-50cbv41e/dist/:\ntetris.js\n\n/tmp/loop-bench-50cbv41e/src/:\nstyles.css\ntetris.ts\n[rerun: b9]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d9178aa5-c416-4156-ade5-2abc22f89009","timestamp":"2026-04-07T01:43:04.303Z","tool_use_result":{"stdout":"/tmp/loop-bench-50cbv41e/dist/:\ntetris.js\n\n/tmp/loop-bench-50cbv41e/src/:\nstyles.css\ntetris.ts","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_20260407094305ce4443ac26ba4d68","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"The compiled JS went to `dist/`. Let me update the HTML to reference the correct path, or simply copy the JS alongside the TS source:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"9a2f6924-3756-4b65-a667-5dbd955d88b1"} +{"type":"assistant","message":{"id":"msg_20260407094305ce4443ac26ba4d68","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_d126ea3dba264e54a5211acf","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-50cbv41e/index.html","old_string":" <script src=\"src/tetris.js\"></script>","new_string":" <script src=\"dist/tetris.js\"></script>"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"7e61286d-e1a8-48e1-b505-79a59ba6c59d"} +{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"<tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>","is_error":true,"tool_use_id":"call_d126ea3dba264e54a5211acf"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"593b772d-e273-44c3-aba3-92e0333d9c90","timestamp":"2026-04-07T01:43:14.187Z","tool_use_result":"Error: File has not been read yet. Read it first before writing to it."} +{"type":"assistant","message":{"id":"msg_20260407094315493de77c87914a3a","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_75a18530f5a5493493c9e50f","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/index.html"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"1119c9b2-9d26-4723-b5d3-670afca1a011"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_75a18530f5a5493493c9e50f","type":"tool_result","content":"1\t<!DOCTYPE html>\n2\t<html lang=\"en\">\n3\t<head>\n4\t <meta charset=\"UTF-8\" />\n5\t <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n6\t <title>Tetris</title>\n7\t <link rel=\"stylesheet\" href=\"src/styles.css\" />\n8\t</head>\n9\t<body>\n10\t <div id=\"game-container\">\n11\t <div id=\"board-wrapper\">\n12\t <div id=\"board\"></div>\n13\t <div id=\"overlay\">\n14\t <h2 id=\"overlay-title\"></h2>\n15\t <div id=\"overlay-body\"></div>\n16\t </div>\n17\t </div>\n18\t <div id=\"side-panel\">\n19\t <div class=\"panel-box\">\n20\t <h3>Next</h3>\n21\t <div id=\"next-preview\"></div>\n22\t </div>\n23\t <div class=\"panel-box\">\n24\t <h3>Score</h3>\n25\t <div class=\"value\" id=\"score-value\">0</div>\n26\t </div>\n27\t <div class=\"panel-box\">\n28\t <h3>Lines</h3>\n29\t <div class=\"value\" id=\"lines-value\">0</div>\n30\t </div>\n31\t <div class=\"panel-box\">\n32\t <h3>Level</h3>\n33\t <div class=\"value\" id=\"level-value\">1</div>\n34\t </div>\n35\t <div class=\"panel-box\">\n36\t <h3>Controls</h3>\n37\t <div id=\"controls\">\n38\t <kbd>←</kbd> <kbd>→</kbd> Move<br />\n39\t <kbd>↑</kbd> Rotate<br />\n40\t <kbd>↓</kbd> Soft drop<br />\n41\t <kbd>Space</kbd> Hard drop<br />\n42\t <kbd>P</kbd> Pause\n43\t </div>\n44\t </div>\n45\t </div>\n46\t </div>\n47\t <script src=\"src/tetris.js\"></script>\n48\t</body>\n49\t</html>\n50\t"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"ab1666f3-61b2-416d-a5c9-0693813495f7","timestamp":"2026-04-07T01:43:20.231Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/index.html","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Tetris</title>\n <link rel=\"stylesheet\" href=\"src/styles.css\" />\n</head>\n<body>\n <div id=\"game-container\">\n <div id=\"board-wrapper\">\n <div id=\"board\"></div>\n <div id=\"overlay\">\n <h2 id=\"overlay-title\"></h2>\n <div id=\"overlay-body\"></div>\n </div>\n </div>\n <div id=\"side-panel\">\n <div class=\"panel-box\">\n <h3>Next</h3>\n <div id=\"next-preview\"></div>\n </div>\n <div class=\"panel-box\">\n <h3>Score</h3>\n <div class=\"value\" id=\"score-value\">0</div>\n </div>\n <div class=\"panel-box\">\n <h3>Lines</h3>\n <div class=\"value\" id=\"lines-value\">0</div>\n </div>\n <div class=\"panel-box\">\n <h3>Level</h3>\n <div class=\"value\" id=\"level-value\">1</div>\n </div>\n <div class=\"panel-box\">\n <h3>Controls</h3>\n <div id=\"controls\">\n <kbd>←</kbd> <kbd>→</kbd> Move<br />\n <kbd>↑</kbd> Rotate<br />\n <kbd>↓</kbd> Soft drop<br />\n <kbd>Space</kbd> Hard drop<br />\n <kbd>P</kbd> Pause\n </div>\n </div>\n </div>\n </div>\n <script src=\"src/tetris.js\"></script>\n</body>\n</html>\n","numLines":50,"startLine":1,"totalLines":50}}} +{"type":"assistant","message":{"id":"msg_202604070943210533812f05a84873","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_dbe0d441a01b416380c546b3","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-50cbv41e/index.html","old_string":" <script src=\"src/tetris.js\"></script>","new_string":" <script src=\"dist/tetris.js\"></script>"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"ef2a766e-97d1-4a5c-808f-05d28aa4dc7c"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_dbe0d441a01b416380c546b3","type":"tool_result","content":"The file /tmp/loop-bench-50cbv41e/index.html has been updated successfully."}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"87b3f35d-9478-4d88-96ca-33b05a27b2be","timestamp":"2026-04-07T01:43:25.386Z","tool_use_result":{"filePath":"/tmp/loop-bench-50cbv41e/index.html","oldString":" <script src=\"src/tetris.js\"></script>","newString":" <script src=\"dist/tetris.js\"></script>","originalFile":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Tetris</title>\n <link rel=\"stylesheet\" href=\"src/styles.css\" />\n</head>\n<body>\n <div id=\"game-container\">\n <div id=\"board-wrapper\">\n <div id=\"board\"></div>\n <div id=\"overlay\">\n <h2 id=\"overlay-title\"></h2>\n <div id=\"overlay-body\"></div>\n </div>\n </div>\n <div id=\"side-panel\">\n <div class=\"panel-box\">\n <h3>Next</h3>\n <div id=\"next-preview\"></div>\n </div>\n <div class=\"panel-box\">\n <h3>Score</h3>\n <div class=\"value\" id=\"score-value\">0</div>\n </div>\n <div class=\"panel-box\">\n <h3>Lines</h3>\n <div class=\"value\" id=\"lines-value\">0</div>\n </div>\n <div class=\"panel-box\">\n <h3>Level</h3>\n <div class=\"value\" id=\"level-value\">1</div>\n </div>\n <div class=\"panel-box\">\n <h3>Controls</h3>\n <div id=\"controls\">\n <kbd>←</kbd> <kbd>→</kbd> Move<br />\n <kbd>↑</kbd> Rotate<br />\n <kbd>↓</kbd> Soft drop<br />\n <kbd>Space</kbd> Hard drop<br />\n <kbd>P</kbd> Pause\n </div>\n </div>\n </div>\n </div>\n <script src=\"src/tetris.js\"></script>\n</body>\n</html>\n","structuredPatch":[{"oldStart":44,"oldLines":6,"newStart":44,"newLines":6,"lines":[" </div>"," </div>"," </div>","- <script src=\"src/tetris.js\"></script>","+ <script src=\"dist/tetris.js\"></script>"," </body>"," </html>"]}],"userModified":false,"replaceAll":false}} +{"type":"assistant","message":{"id":"msg_202604070943260f5245e983c94b1b","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now let me verify the compiled JS looks correct and run the tests:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"2c4e4c83-6f6f-4ba1-b91c-65e6bd3b18f5"} +{"type":"assistant","message":{"id":"msg_202604070943260f5245e983c94b1b","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_9cba9f75960a44e8b129f405","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/dist/tetris.js","limit":20}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"96a2d5ac-b129-46d4-b163-da9fe861511d"} +{"type":"assistant","message":{"id":"msg_202604070943260f5245e983c94b1b","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_112e48c140f9472e9900a815","name":"Bash","input":{"command":"ls /tmp/loop-bench-50cbv41e/tests-few/ /tmp/loop-bench-50cbv41e/tests-full/","description":"Check test directories"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"ab63b0c7-875e-442a-8972-103d8bd5082a"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_9cba9f75960a44e8b129f405","type":"tool_result","content":"1\t\"use strict\";\n2\t// ============================================================\n3\t// Tetris – full DOM-based implementation in TypeScript\n4\t// ============================================================\n5\t// ---- Constants ----\n6\tconst COLS = 10;\n7\tconst ROWS = 20;\n8\tconst SHAPES = {\n9\t I: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],\n10\t O: [[1, 1], [1, 1]],\n11\t T: [[0, 1, 0], [1, 1, 1], [0, 0, 0]],\n12\t S: [[0, 1, 1], [1, 1, 0], [0, 0, 0]],\n13\t Z: [[1, 1, 0], [0, 1, 1], [0, 0, 0]],\n14\t J: [[1, 0, 0], [1, 1, 1], [0, 0, 0]],\n15\t L: [[0, 0, 1], [1, 1, 1], [0, 0, 0]],\n16\t};\n17\tconst PIECE_COLORS = [\"I\", \"O\", \"T\", \"S\", \"Z\", \"J\", \"L\"];\n18\t// Scoring: index = number of lines cleared\n19\tconst LINE_SCORES = [0, 100, 300, 500, 800];\n20\tconst LEVEL_SPEEDS = {};"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"3a53d6ac-9280-46a5-a785-b42403cd6df5","timestamp":"2026-04-07T01:43:36.509Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/dist/tetris.js","content":"\"use strict\";\n// ============================================================\n// Tetris – full DOM-based implementation in TypeScript\n// ============================================================\n// ---- Constants ----\nconst COLS = 10;\nconst ROWS = 20;\nconst SHAPES = {\n I: [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]],\n O: [[1, 1], [1, 1]],\n T: [[0, 1, 0], [1, 1, 1], [0, 0, 0]],\n S: [[0, 1, 1], [1, 1, 0], [0, 0, 0]],\n Z: [[1, 1, 0], [0, 1, 1], [0, 0, 0]],\n J: [[1, 0, 0], [1, 1, 1], [0, 0, 0]],\n L: [[0, 0, 1], [1, 1, 1], [0, 0, 0]],\n};\nconst PIECE_COLORS = [\"I\", \"O\", \"T\", \"S\", \"Z\", \"J\", \"L\"];\n// Scoring: index = number of lines cleared\nconst LINE_SCORES = [0, 100, 300, 500, 800];\nconst LEVEL_SPEEDS = {};","numLines":20,"startLine":1,"totalLines":547}}} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_112e48c140f9472e9900a815","type":"tool_result","content":"/tmp/loop-bench-50cbv41e/tests-few/:\nplaywright.config.ts\ntetris.spec.ts\n\n/tmp/loop-bench-50cbv41e/tests-full/:\nplaywright.config.ts\ntetris.spec.ts\n[rerun: b10]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"c445f8e7-458d-488d-8715-548f90287dfe","timestamp":"2026-04-07T01:43:36.517Z","tool_use_result":{"stdout":"/tmp/loop-bench-50cbv41e/tests-few/:\nplaywright.config.ts\ntetris.spec.ts\n\n/tmp/loop-bench-50cbv41e/tests-full/:\nplaywright.config.ts\ntetris.spec.ts","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_2026040709433817026115783a4add","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_938b10312d724b2d929e9369","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/tests-few/tetris.spec.ts"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"08a1e936-c7ff-461e-bde1-8801bce8518d"} +{"type":"assistant","message":{"id":"msg_2026040709433817026115783a4add","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_44276110f78749de8c9f63c6","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/tests-few/playwright.config.ts"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"39ece8a4-2837-4c8e-ac47-aba920bd8800"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_938b10312d724b2d929e9369","type":"tool_result","content":"1\timport { test, expect, type Page } from \"@playwright/test\";\n2\t\n3\t// Try common entry points until one loads successfully.\n4\tasync function loadGame(page: Page) {\n5\t const candidates = [\n6\t \"/\",\n7\t \"/index.html\",\n8\t \"/dist/index.html\",\n9\t \"/public/index.html\",\n10\t \"/build/index.html\",\n11\t ];\n12\t\n13\t for (const path of candidates) {\n14\t try {\n15\t const resp = await page.goto(path, { timeout: 5000 });\n16\t if (resp?.ok()) return;\n17\t } catch {\n18\t continue;\n19\t }\n20\t }\n21\t}\n22\t\n23\ttest.describe(\"Tetris Game\", () => {\n24\t test.beforeEach(async ({ page }) => {\n25\t await loadGame(page);\n26\t await page.waitForLoadState(\"domcontentloaded\");\n27\t });\n28\t\n29\t test(\"page loads without console errors\", async ({ page }) => {\n30\t const errors: string[] = [];\n31\t page.on(\"pageerror\", (err) => errors.push(err.message));\n32\t\n33\t // Give the page a moment to finish initializing\n34\t await page.waitForTimeout(2000);\n35\t\n36\t expect(errors).toEqual([]);\n37\t });\n38\t\n39\t test(\"game board is visible\", async ({ page }) => {\n40\t // A Tetris game should render either a <canvas> or a grid of DOM elements\n41\t const canvas = page.locator(\"canvas\");\n42\t const gridContainer = page.locator(\n43\t [\n44\t '[class*=\"board\"]',\n45\t '[class*=\"grid\"]',\n46\t '[class*=\"game\"]',\n47\t '[class*=\"field\"]',\n48\t '[id*=\"board\"]',\n49\t '[id*=\"grid\"]',\n50\t '[id*=\"game\"]',\n51\t '[id*=\"field\"]',\n52\t \"table\",\n53\t ].join(\", \")\n54\t );\n55\t\n56\t const canvasCount = await canvas.count();\n57\t const gridCount = await gridContainer.count();\n58\t\n59\t expect(\n60\t canvasCount + gridCount,\n61\t \"Expected a <canvas> or a container with board/grid/game/field in its class or id\"\n62\t ).toBeGreaterThan(0);\n63\t });\n64\t\n65\t test(\"keyboard input does not crash the game\", async ({ page }) => {\n66\t const errors: string[] = [];\n67\t page.on(\"pageerror\", (err) => errors.push(err.message));\n68\t\n69\t // Press every key a Tetris game should handle\n70\t const keys = [\n71\t \"ArrowLeft\",\n72\t \"ArrowRight\",\n73\t \"ArrowDown\",\n74\t \"ArrowUp\",\n75\t \"Space\",\n76\t ];\n77\t for (const key of keys) {\n78\t await page.keyboard.press(key);\n79\t await page.waitForTimeout(150);\n80\t }\n81\t\n82\t expect(errors).toEqual([]);\n83\t });\n84\t\n85\t test(\"game state changes over time\", async ({ page }) => {\n86\t // If the game is running, the visual output should change as pieces fall\n87\t const shot1 = await page.screenshot();\n88\t await page.waitForTimeout(3000);\n89\t const shot2 = await page.screenshot();\n90\t\n91\t expect(\n92\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n93\t \"Expected the page to visually change over 3 seconds (pieces should be falling)\"\n94\t ).toBe(false);\n95\t });\n96\t});\n97\t"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"ebc42b8a-74d4-42d0-9e3e-95e5922bb07e","timestamp":"2026-04-07T01:43:47.049Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/tests-few/tetris.spec.ts","content":"import { test, expect, type Page } from \"@playwright/test\";\n\n// Try common entry points until one loads successfully.\nasync function loadGame(page: Page) {\n const candidates = [\n \"/\",\n \"/index.html\",\n \"/dist/index.html\",\n \"/public/index.html\",\n \"/build/index.html\",\n ];\n\n for (const path of candidates) {\n try {\n const resp = await page.goto(path, { timeout: 5000 });\n if (resp?.ok()) return;\n } catch {\n continue;\n }\n }\n}\n\ntest.describe(\"Tetris Game\", () => {\n test.beforeEach(async ({ page }) => {\n await loadGame(page);\n await page.waitForLoadState(\"domcontentloaded\");\n });\n\n test(\"page loads without console errors\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n // Give the page a moment to finish initializing\n await page.waitForTimeout(2000);\n\n expect(errors).toEqual([]);\n });\n\n test(\"game board is visible\", async ({ page }) => {\n // A Tetris game should render either a <canvas> or a grid of DOM elements\n const canvas = page.locator(\"canvas\");\n const gridContainer = page.locator(\n [\n '[class*=\"board\"]',\n '[class*=\"grid\"]',\n '[class*=\"game\"]',\n '[class*=\"field\"]',\n '[id*=\"board\"]',\n '[id*=\"grid\"]',\n '[id*=\"game\"]',\n '[id*=\"field\"]',\n \"table\",\n ].join(\", \")\n );\n\n const canvasCount = await canvas.count();\n const gridCount = await gridContainer.count();\n\n expect(\n canvasCount + gridCount,\n \"Expected a <canvas> or a container with board/grid/game/field in its class or id\"\n ).toBeGreaterThan(0);\n });\n\n test(\"keyboard input does not crash the game\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n // Press every key a Tetris game should handle\n const keys = [\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowDown\",\n \"ArrowUp\",\n \"Space\",\n ];\n for (const key of keys) {\n await page.keyboard.press(key);\n await page.waitForTimeout(150);\n }\n\n expect(errors).toEqual([]);\n });\n\n test(\"game state changes over time\", async ({ page }) => {\n // If the game is running, the visual output should change as pieces fall\n const shot1 = await page.screenshot();\n await page.waitForTimeout(3000);\n const shot2 = await page.screenshot();\n\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected the page to visually change over 3 seconds (pieces should be falling)\"\n ).toBe(false);\n });\n});\n","numLines":97,"startLine":1,"totalLines":97}}} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_44276110f78749de8c9f63c6","type":"tool_result","content":"1\timport { defineConfig } from \"@playwright/test\";\n2\t\n3\texport default defineConfig({\n4\t testDir: \".\",\n5\t timeout: 30_000,\n6\t retries: 0,\n7\t workers: 1,\n8\t use: {\n9\t baseURL: \"http://localhost:3000\",\n10\t headless: true,\n11\t viewport: { width: 1280, height: 720 },\n12\t },\n13\t});\n14\t"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"356b9594-2073-4d19-915d-1b09d340ed6d","timestamp":"2026-04-07T01:43:47.049Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/tests-few/playwright.config.ts","content":"import { defineConfig } from \"@playwright/test\";\n\nexport default defineConfig({\n testDir: \".\",\n timeout: 30_000,\n retries: 0,\n workers: 1,\n use: {\n baseURL: \"http://localhost:3000\",\n headless: true,\n viewport: { width: 1280, height: 720 },\n },\n});\n","numLines":14,"startLine":1,"totalLines":14}}} +{"type":"assistant","message":{"id":"msg_20260407094348f92cf6ccbd3e4e98","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"I need to set up a simple static file server to serve the game. The tests expect a server at localhost:3000. Let me check what's available. I need to:\n\n1. Install Playwright and its dependencies\n2. Start a static file server at port 3000\n3. Run the tests\n\nLet me first check the package.json to see what's already configured.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"5abc007a-a3fe-40b4-aa8f-4c2da0a30dfb"} +{"type":"assistant","message":{"id":"msg_20260407094348f92cf6ccbd3e4e98","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_2f6c63c2860c4ba3876aec05","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/package.json"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"576e7e50-9c4a-4f7e-804c-c0c6d81aa6e9"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_2f6c63c2860c4ba3876aec05","type":"tool_result","content":"1\t{\n2\t \"name\": \"loop-bench-50cbv41e\",\n3\t \"version\": \"1.0.0\",\n4\t \"description\": \"\",\n5\t \"main\": \"index.js\",\n6\t \"scripts\": {\n7\t \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n8\t },\n9\t \"keywords\": [],\n10\t \"author\": \"\",\n11\t \"license\": \"ISC\",\n12\t \"type\": \"commonjs\",\n13\t \"devDependencies\": {\n14\t \"@eslint/js\": \"^10.0.1\",\n15\t \"@types/node\": \"^25.5.2\",\n16\t \"eslint\": \"^10.2.0\",\n17\t \"typescript\": \"^6.0.2\"\n18\t }\n19\t}\n20\t"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"13ce9dfd-98a1-4712-bb8a-0c77adeef055","timestamp":"2026-04-07T01:43:58.777Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/package.json","content":"{\n \"name\": \"loop-bench-50cbv41e\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"type\": \"commonjs\",\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@types/node\": \"^25.5.2\",\n \"eslint\": \"^10.2.0\",\n \"typescript\": \"^6.0.2\"\n }\n}\n","numLines":20,"startLine":1,"totalLines":20}}} +{"type":"assistant","message":{"id":"msg_202604070944006d34beb6b05d4f1b","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_a063ed2799954dfe9f85875f","name":"Bash","input":{"command":"npm install --save-dev @playwright/test serve 2>&1 | tail -5","description":"Install Playwright and serve packages","timeout":60000}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"44622776-9e09-4763-86e5-50d0cb976b64"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_a063ed2799954dfe9f85875f","type":"tool_result","content":"43 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities\n[rerun: b11]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"bf10d48b-4da5-4017-a328-70e17b75e7f6","timestamp":"2026-04-07T01:44:09.721Z","tool_use_result":{"stdout":"43 packages are looking for funding\n run `npm fund` for details\n\nfound 0 vulnerabilities","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_2026040709441067150397b9ee4154","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_86a0d60ae59a47e79a7a4f14","name":"Bash","input":{"command":"npx playwright install chromium 2>&1 | tail -5","description":"Install Playwright Chromium browser","timeout":120000}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"507d477e-778d-4212-b974-c8e2d4219611"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_86a0d60ae59a47e79a7a4f14","type":"tool_result","content":"[rerun: b12]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"da48059f-3c9c-445c-8fd4-1d4485368404","timestamp":"2026-04-07T01:44:20.425Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070944219641c0384fb14dcb","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_ef802181e2ee496cade8d278","name":"Bash","input":{"command":"npx serve -l 3000 . &>/tmp/serve.log &\necho \"Server PID: $!\"\nsleep 2\ncat /tmp/serve.log","description":"Start static file server on port 3000"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"24b930bb-b406-40ab-bdf0-39128a290efc"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_ef802181e2ee496cade8d278","type":"tool_result","content":"Server PID: 1851693\n INFO Accepting connections at http://localhost:3000\n[rerun: b13]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"acc1f93c-c455-4489-a68a-73641264e1cc","timestamp":"2026-04-07T01:44:28.060Z","tool_use_result":{"stdout":"Server PID: 1851693\n INFO Accepting connections at http://localhost:3000","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070944296df7aba62cd34877","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_89912b98c2024885890d1579","name":"Bash","input":{"command":"npx playwright test --config tests-few/playwright.config.ts 2>&1","description":"Run Playwright tests (few)","timeout":120000}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d16daf71-e87d-4f59-8bc8-97a279fe7023"} +{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"Exit code 1\n\nRunning 4 tests using 1 worker\n\n ✓ 1 tests-few/tetris.spec.ts:29:7 › Tetris Game › page loads without console errors (2.1s)\n ✓ 2 tests-few/tetris.spec.ts:39:7 › Tetris Game › game board is visible (67ms)\n ✓ 3 tests-few/tetris.spec.ts:65:7 › Tetris Game › keyboard input does not crash the game (802ms)\n ✘ 4 tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time (3.1s)\n\n\n 1) tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time ────────────────────\n\n Error: Expected the page to visually change over 3 seconds (pieces should be falling)\n\n \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\n Expected: \u001b[32mfalse\u001b[39m\n Received: \u001b[31mtrue\u001b[39m\n\n 92 | Buffer.from(shot1).equals(Buffer.from(shot2)),\n 93 | \"Expected the page to visually change over 3 seconds (pieces should be falling)\"\n > 94 | ).toBe(false);\n | ^\n 95 | });\n 96 | });\n 97 |\n at /tmp/loop-bench-50cbv41e/tests-few/tetris.spec.ts:94:7\n\n Error Context: test-results/tetris-Tetris-Game-game-state-changes-over-time/error-context.md\n\n 1 failed\n tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time ─────────────────────\n 3 passed (6.5s)\n[rerun: b14]","is_error":true,"tool_use_id":"call_89912b98c2024885890d1579"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"927d128a-a55d-4430-b3d4-0a1c8d0b8886","timestamp":"2026-04-07T01:44:41.031Z","tool_use_result":"Error: Exit code 1\n\nRunning 4 tests using 1 worker\n\n ✓ 1 tests-few/tetris.spec.ts:29:7 › Tetris Game › page loads without console errors (2.1s)\n ✓ 2 tests-few/tetris.spec.ts:39:7 › Tetris Game › game board is visible (67ms)\n ✓ 3 tests-few/tetris.spec.ts:65:7 › Tetris Game › keyboard input does not crash the game (802ms)\n ✘ 4 tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time (3.1s)\n\n\n 1) tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time ────────────────────\n\n Error: Expected the page to visually change over 3 seconds (pieces should be falling)\n\n \u001b[2mexpect(\u001b[22m\u001b[31mreceived\u001b[39m\u001b[2m).\u001b[22mtoBe\u001b[2m(\u001b[22m\u001b[32mexpected\u001b[39m\u001b[2m) // Object.is equality\u001b[22m\n\n Expected: \u001b[32mfalse\u001b[39m\n Received: \u001b[31mtrue\u001b[39m\n\n 92 | Buffer.from(shot1).equals(Buffer.from(shot2)),\n 93 | \"Expected the page to visually change over 3 seconds (pieces should be falling)\"\n > 94 | ).toBe(false);\n | ^\n 95 | });\n 96 | });\n 97 |\n at /tmp/loop-bench-50cbv41e/tests-few/tetris.spec.ts:94:7\n\n Error Context: test-results/tetris-Tetris-Game-game-state-changes-over-time/error-context.md\n\n 1 failed\n tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time ─────────────────────\n 3 passed (6.5s)\n[rerun: b14]"} +{"type":"assistant","message":{"id":"msg_202604070944434184464544b24812","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The test \"game state changes over time\" is failing. The issue is that the game shows an overlay initially and doesn't start until the user presses an arrow key or space. The test just loads the page and waits 3 seconds, but the game isn't running because no key was pressed to start it.\n\nLooking at the test, it doesn't press any keys before taking screenshots. The game shows the start screen overlay and waits for input. I need to make the game auto-start, or I need to look at the test more carefully.\n\nThe test does this:\n1. Load the page\n2. Take screenshot 1\n3. Wait 3 seconds\n4. Take screenshot 2\n5. Expect them to be different\n\nBut since the game hasn't started (it's showing the overlay), nothing changes. I should either:\n1. Auto-start the game on load\n2. Make the overlay have some animation that changes\n\nActually, let me look at the test flow again. The test in \"keyboard input does not crash the game\" presses keys but that's a different test. Each test runs with `beforeEach` which loads the page fresh.\n\nThe simplest fix is to just start the game automatically when the page loads, rather than waiting for a keypress. Or I can add a CSS animation to the start screen so it changes visually.\n\nActually, the cleanest approach is to just auto-start the game. The welcome overlay with \"press any key to start\" is nice but the tests expect the game to be running. Let me auto-start the game on load instead.\n\nWait, actually let me re-read the test. It loads the page, takes a screenshot immediately, waits 3s, takes another screenshot. The game needs to visually change in those 3 seconds. Since the game is showing a static overlay, nothing changes.\n\nThe fix: I'll just start the game immediately on DOMContentLoaded instead of waiting for a keypress. If the user wants to restart, they press R.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"b292d446-aaa2-4d88-94d7-f7a94215a129"} +{"type":"assistant","message":{"id":"msg_202604070944434184464544b24812","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"The last test expects the game to visually change over time, but the game shows a start overlay waiting for input. I need to auto-start the game instead of waiting for a keypress."}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"ea65d0c5-c8c7-4838-b200-291c9ec4c47d"} +{"type":"assistant","message":{"id":"msg_202604070944434184464544b24812","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_0e0acb6823b548deb086d0db","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/src/tetris.ts","offset":280}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"9b1040f4-2e56-475e-afe3-4b8113d9ae8a"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_0e0acb6823b548deb086d0db","type":"tool_result","content":"280\t\n281\tfunction moveLeft(): boolean {\n282\t if (!currentPiece || gameOver || paused) return false;\n283\t if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) {\n284\t currentPiece.x--;\n285\t return true;\n286\t }\n287\t return false;\n288\t}\n289\t\n290\tfunction moveRight(): boolean {\n291\t if (!currentPiece || gameOver || paused) return false;\n292\t if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) {\n293\t currentPiece.x++;\n294\t return true;\n295\t }\n296\t return false;\n297\t}\n298\t\n299\tfunction moveDown(): boolean {\n300\t if (!currentPiece || gameOver || paused) return false;\n301\t if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n302\t currentPiece.y++;\n303\t return true;\n304\t }\n305\t lockPiece();\n306\t return false;\n307\t}\n308\t\n309\tfunction hardDrop(): void {\n310\t if (!currentPiece || gameOver || paused) return;\n311\t let dropped = 0;\n312\t while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n313\t currentPiece.y++;\n314\t dropped++;\n315\t }\n316\t score += dropped * 2;\n317\t updateStats();\n318\t lockPiece();\n319\t}\n320\t\n321\tfunction softDrop(): void {\n322\t if (moveDown()) {\n323\t score += 1;\n324\t updateStats();\n325\t }\n326\t}\n327\t\n328\t// ---- Rendering ----\n329\t\n330\tfunction render(): void {\n331\t // Clear board\n332\t for (let r = 0; r < ROWS; r++) {\n333\t for (let c = 0; c < COLS; c++) {\n334\t const cell = boardCells[r][c];\n335\t const val = board[r][c];\n336\t if (val) {\n337\t cell.setAttribute(\"data-color\", val);\n338\t cell.removeAttribute(\"data-ghost\");\n339\t } else {\n340\t cell.removeAttribute(\"data-color\");\n341\t cell.removeAttribute(\"data-ghost\");\n342\t }\n343\t cell.classList.remove(\"clearing\");\n344\t }\n345\t }\n346\t\n347\t if (!currentPiece || gameOver) return;\n348\t\n349\t // Draw ghost\n350\t const gy = ghostY();\n351\t const { shape, color, x } = currentPiece;\n352\t for (let r = 0; r < shape.length; r++) {\n353\t for (let c = 0; c < shape[r].length; c++) {\n354\t if (!shape[r][c]) continue;\n355\t const by = gy + r;\n356\t const bx = x + c;\n357\t if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n358\t const cell = boardCells[by][bx];\n359\t // Only draw ghost if no locked piece there\n360\t if (!board[by][bx]) {\n361\t cell.setAttribute(\"data-ghost\", \"\");\n362\t cell.setAttribute(\"data-color\", color);\n363\t }\n364\t }\n365\t }\n366\t }\n367\t\n368\t // Draw current piece (overwrites ghost cells if overlap)\n369\t for (let r = 0; r < shape.length; r++) {\n370\t for (let c = 0; c < shape[r].length; c++) {\n371\t if (!shape[r][c]) continue;\n372\t const by = currentPiece.y + r;\n373\t const bx = x + c;\n374\t if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n375\t const cell = boardCells[by][bx];\n376\t cell.setAttribute(\"data-color\", color);\n377\t cell.removeAttribute(\"data-ghost\");\n378\t }\n379\t }\n380\t }\n381\t}\n382\t\n383\tfunction renderPreview(): void {\n384\t if (!nextPiece) return;\n385\t // Clear preview\n386\t for (let r = 0; r < 4; r++) {\n387\t for (let c = 0; c < 4; c++) {\n388\t previewCells[r][c].removeAttribute(\"data-color\");\n389\t }\n390\t }\n391\t const { shape, color } = nextPiece;\n392\t // Center in 4×4 preview\n393\t const offsetR = Math.floor((4 - shape.length) / 2);\n394\t const offsetC = Math.floor((4 - shape[0].length) / 2);\n395\t for (let r = 0; r < shape.length; r++) {\n396\t for (let c = 0; c < shape[r].length; c++) {\n397\t if (!shape[r][c]) continue;\n398\t const pr = r + offsetR;\n399\t const pc = c + offsetC;\n400\t if (pr < 4 && pc < 4) {\n401\t previewCells[pr][pc].setAttribute(\"data-color\", color);\n402\t }\n403\t }\n404\t }\n405\t}\n406\t\n407\tfunction updateStats(): void {\n408\t scoreEl.textContent = score.toLocaleString();\n409\t linesEl.textContent = lines.toString();\n410\t levelEl.textContent = level.toString();\n411\t}\n412\t\n413\t// ---- Game loop ----\n414\t\n415\tfunction getSpeed(): number {\n416\t return LEVEL_SPEEDS[level] ?? 80;\n417\t}\n418\t\n419\tfunction gameLoop(timestamp: number): void {\n420\t if (gameOver) return;\n421\t if (paused) {\n422\t dropTimer = requestAnimationFrame(gameLoop);\n423\t return;\n424\t }\n425\t const elapsed = timestamp - lastDropTime;\n426\t if (elapsed >= getSpeed()) {\n427\t moveDown();\n428\t lastDropTime = timestamp;\n429\t render();\n430\t }\n431\t dropTimer = requestAnimationFrame(gameLoop);\n432\t}\n433\t\n434\t// ---- Game lifecycle ----\n435\t\n436\tfunction startGame(): void {\n437\t board = emptyBoard();\n438\t score = 0;\n439\t lines = 0;\n440\t level = 1;\n441\t gameOver = false;\n442\t paused = false;\n443\t bag = [];\n444\t currentPiece = null;\n445\t nextPiece = null;\n446\t\n447\t initDOMRefs();\n448\t createBoardDOM();\n449\t createPreviewDOM();\n450\t updateStats();\n451\t\n452\t overlayEl.classList.add(\"hidden\");\n453\t\n454\t spawnNext();\n455\t render();\n456\t lastDropTime = performance.now();\n457\t if (dropTimer !== null) cancelAnimationFrame(dropTimer);\n458\t dropTimer = requestAnimationFrame(gameLoop);\n459\t}\n460\t\n461\tfunction endGame(): void {\n462\t gameOver = true;\n463\t currentPiece = null;\n464\t if (dropTimer !== null) {\n465\t cancelAnimationFrame(dropTimer);\n466\t dropTimer = null;\n467\t }\n468\t render();\n469\t\n470\t overlayTitleEl.textContent = \"Game Over\";\n471\t overlayBodyEl.innerHTML = `\n472\t <p class=\"score-line\">Score: ${score.toLocaleString()}</p>\n473\t <p>Level ${level} · ${lines} lines</p>\n474\t <p style=\"margin-top:16px;color:#8888bb\">Press <kbd>R</kbd> to restart</p>\n475\t `;\n476\t overlayEl.classList.remove(\"hidden\");\n477\t}\n478\t\n479\tfunction togglePause(): void {\n480\t if (gameOver) return;\n481\t paused = !paused;\n482\t if (paused) {\n483\t overlayTitleEl.textContent = \"Paused\";\n484\t overlayBodyEl.innerHTML = `<p>Press <kbd>P</kbd> to resume</p>`;\n485\t overlayEl.classList.remove(\"hidden\");\n486\t } else {\n487\t overlayEl.classList.add(\"hidden\");\n488\t lastDropTime = performance.now();\n489\t }\n490\t}\n491\t\n492\t// ---- Input ----\n493\t\n494\t// Repeat tracking for held keys\n495\tlet keyRepeatTimers: Record<string, number | null> = {};\n496\tconst REPEAT_DELAY = 170; // initial delay (ms)\n497\tconst REPEAT_RATE = 50; // repeat interval (ms)\n498\t\n499\tfunction handleKeyAction(key: string): void {\n500\t switch (key) {\n501\t case \"ArrowLeft\":\n502\t if (moveLeft()) render();\n503\t break;\n504\t case \"ArrowRight\":\n505\t if (moveRight()) render();\n506\t break;\n507\t case \"ArrowDown\":\n508\t softDrop();\n509\t render();\n510\t break;\n511\t case \"ArrowUp\":\n512\t if (tryRotate()) render();\n513\t break;\n514\t case \" \":\n515\t hardDrop();\n516\t render();\n517\t break;\n518\t case \"p\":\n519\t case \"P\":\n520\t togglePause();\n521\t break;\n522\t case \"r\":\n523\t case \"R\":\n524\t if (gameOver) startGame();\n525\t break;\n526\t }\n527\t}\n528\t\n529\tfunction startRepeat(key: string): void {\n530\t clearRepeat(key);\n531\t // First action already happened in keydown; set delayed repeat\n532\t keyRepeatTimers[key] = window.setTimeout(() => {\n533\t keyRepeatTimers[key] = window.setInterval(() => {\n534\t handleKeyAction(key);\n535\t }, REPEAT_RATE);\n536\t }, REPEAT_DELAY);\n537\t}\n538\t\n539\tfunction clearRepeat(key: string): void {\n540\t if (keyRepeatTimers[key] !== null) {\n541\t clearTimeout(keyRepeatTimers[key]);\n542\t clearInterval(keyRepeatTimers[key]);\n543\t keyRepeatTimers[key] = null;\n544\t }\n545\t}\n546\t\n547\tfunction clearAllRepeats(): void {\n548\t for (const key of Object.keys(keyRepeatTimers)) {\n549\t clearRepeat(key);\n550\t }\n551\t}\n552\t\n553\tdocument.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n554\t // Prevent page scrolling for game keys\n555\t if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n556\t e.preventDefault();\n557\t }\n558\t\n559\t if (e.repeat) return; // We handle repeat ourselves\n560\t\n561\t handleKeyAction(e.key);\n562\t\n563\t // Set up repeat for movement keys\n564\t if ([\"ArrowLeft\",\"ArrowRight\",\"ArrowDown\"].includes(e.key)) {\n565\t startRepeat(e.key);\n566\t }\n567\t});\n568\t\n569\tdocument.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n570\t clearRepeat(e.key);\n571\t});\n572\t\n573\t// Lose focus → pause & clear repeats\n574\twindow.addEventListener(\"blur\", () => {\n575\t clearAllRepeats();\n576\t if (!gameOver && !paused) togglePause();\n577\t});\n578\t\n579\t// ---- Bootstrap ----\n580\t\n581\twindow.addEventListener(\"DOMContentLoaded\", () => {\n582\t initDOMRefs();\n583\t createBoardDOM();\n584\t createPreviewDOM();\n585\t\n586\t overlayTitleEl.textContent = \"Tetris\";\n587\t overlayBodyEl.innerHTML = `\n588\t <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>\n589\t <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>\n590\t <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>\n591\t <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>\n592\t <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>\n593\t <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>\n594\t <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>\n595\t `;\n596\t overlayEl.classList.remove(\"hidden\");\n597\t\n598\t // Start game on first interaction\n599\t const startListener = (e: KeyboardEvent) => {\n600\t if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n601\t e.preventDefault();\n602\t document.removeEventListener(\"keydown\", startListener);\n603\t startGame();\n604\t }\n605\t };\n606\t document.addEventListener(\"keydown\", startListener);\n607\t});\n608\t"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"52ae11da-ba3c-43d9-b671-43b9d47711d3","timestamp":"2026-04-07T01:45:00.829Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/src/tetris.ts","content":"\nfunction moveLeft(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) {\n currentPiece.x--;\n return true;\n }\n return false;\n}\n\nfunction moveRight(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) {\n currentPiece.x++;\n return true;\n }\n return false;\n}\n\nfunction moveDown(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n return true;\n }\n lockPiece();\n return false;\n}\n\nfunction hardDrop(): void {\n if (!currentPiece || gameOver || paused) return;\n let dropped = 0;\n while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n dropped++;\n }\n score += dropped * 2;\n updateStats();\n lockPiece();\n}\n\nfunction softDrop(): void {\n if (moveDown()) {\n score += 1;\n updateStats();\n }\n}\n\n// ---- Rendering ----\n\nfunction render(): void {\n // Clear board\n for (let r = 0; r < ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = boardCells[r][c];\n const val = board[r][c];\n if (val) {\n cell.setAttribute(\"data-color\", val);\n cell.removeAttribute(\"data-ghost\");\n } else {\n cell.removeAttribute(\"data-color\");\n cell.removeAttribute(\"data-ghost\");\n }\n cell.classList.remove(\"clearing\");\n }\n }\n\n if (!currentPiece || gameOver) return;\n\n // Draw ghost\n const gy = ghostY();\n const { shape, color, x } = currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = gy + r;\n const bx = x + c;\n if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n const cell = boardCells[by][bx];\n // Only draw ghost if no locked piece there\n if (!board[by][bx]) {\n cell.setAttribute(\"data-ghost\", \"\");\n cell.setAttribute(\"data-color\", color);\n }\n }\n }\n }\n\n // Draw current piece (overwrites ghost cells if overlap)\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = currentPiece.y + r;\n const bx = x + c;\n if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n const cell = boardCells[by][bx];\n cell.setAttribute(\"data-color\", color);\n cell.removeAttribute(\"data-ghost\");\n }\n }\n }\n}\n\nfunction renderPreview(): void {\n if (!nextPiece) return;\n // Clear preview\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n previewCells[r][c].removeAttribute(\"data-color\");\n }\n }\n const { shape, color } = nextPiece;\n // Center in 4×4 preview\n const offsetR = Math.floor((4 - shape.length) / 2);\n const offsetC = Math.floor((4 - shape[0].length) / 2);\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const pr = r + offsetR;\n const pc = c + offsetC;\n if (pr < 4 && pc < 4) {\n previewCells[pr][pc].setAttribute(\"data-color\", color);\n }\n }\n }\n}\n\nfunction updateStats(): void {\n scoreEl.textContent = score.toLocaleString();\n linesEl.textContent = lines.toString();\n levelEl.textContent = level.toString();\n}\n\n// ---- Game loop ----\n\nfunction getSpeed(): number {\n return LEVEL_SPEEDS[level] ?? 80;\n}\n\nfunction gameLoop(timestamp: number): void {\n if (gameOver) return;\n if (paused) {\n dropTimer = requestAnimationFrame(gameLoop);\n return;\n }\n const elapsed = timestamp - lastDropTime;\n if (elapsed >= getSpeed()) {\n moveDown();\n lastDropTime = timestamp;\n render();\n }\n dropTimer = requestAnimationFrame(gameLoop);\n}\n\n// ---- Game lifecycle ----\n\nfunction startGame(): void {\n board = emptyBoard();\n score = 0;\n lines = 0;\n level = 1;\n gameOver = false;\n paused = false;\n bag = [];\n currentPiece = null;\n nextPiece = null;\n\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n updateStats();\n\n overlayEl.classList.add(\"hidden\");\n\n spawnNext();\n render();\n lastDropTime = performance.now();\n if (dropTimer !== null) cancelAnimationFrame(dropTimer);\n dropTimer = requestAnimationFrame(gameLoop);\n}\n\nfunction endGame(): void {\n gameOver = true;\n currentPiece = null;\n if (dropTimer !== null) {\n cancelAnimationFrame(dropTimer);\n dropTimer = null;\n }\n render();\n\n overlayTitleEl.textContent = \"Game Over\";\n overlayBodyEl.innerHTML = `\n <p class=\"score-line\">Score: ${score.toLocaleString()}</p>\n <p>Level ${level} · ${lines} lines</p>\n <p style=\"margin-top:16px;color:#8888bb\">Press <kbd>R</kbd> to restart</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n}\n\nfunction togglePause(): void {\n if (gameOver) return;\n paused = !paused;\n if (paused) {\n overlayTitleEl.textContent = \"Paused\";\n overlayBodyEl.innerHTML = `<p>Press <kbd>P</kbd> to resume</p>`;\n overlayEl.classList.remove(\"hidden\");\n } else {\n overlayEl.classList.add(\"hidden\");\n lastDropTime = performance.now();\n }\n}\n\n// ---- Input ----\n\n// Repeat tracking for held keys\nlet keyRepeatTimers: Record<string, number | null> = {};\nconst REPEAT_DELAY = 170; // initial delay (ms)\nconst REPEAT_RATE = 50; // repeat interval (ms)\n\nfunction handleKeyAction(key: string): void {\n switch (key) {\n case \"ArrowLeft\":\n if (moveLeft()) render();\n break;\n case \"ArrowRight\":\n if (moveRight()) render();\n break;\n case \"ArrowDown\":\n softDrop();\n render();\n break;\n case \"ArrowUp\":\n if (tryRotate()) render();\n break;\n case \" \":\n hardDrop();\n render();\n break;\n case \"p\":\n case \"P\":\n togglePause();\n break;\n case \"r\":\n case \"R\":\n if (gameOver) startGame();\n break;\n }\n}\n\nfunction startRepeat(key: string): void {\n clearRepeat(key);\n // First action already happened in keydown; set delayed repeat\n keyRepeatTimers[key] = window.setTimeout(() => {\n keyRepeatTimers[key] = window.setInterval(() => {\n handleKeyAction(key);\n }, REPEAT_RATE);\n }, REPEAT_DELAY);\n}\n\nfunction clearRepeat(key: string): void {\n if (keyRepeatTimers[key] !== null) {\n clearTimeout(keyRepeatTimers[key]);\n clearInterval(keyRepeatTimers[key]);\n keyRepeatTimers[key] = null;\n }\n}\n\nfunction clearAllRepeats(): void {\n for (const key of Object.keys(keyRepeatTimers)) {\n clearRepeat(key);\n }\n}\n\ndocument.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n // Prevent page scrolling for game keys\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n }\n\n if (e.repeat) return; // We handle repeat ourselves\n\n handleKeyAction(e.key);\n\n // Set up repeat for movement keys\n if ([\"ArrowLeft\",\"ArrowRight\",\"ArrowDown\"].includes(e.key)) {\n startRepeat(e.key);\n }\n});\n\ndocument.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n clearRepeat(e.key);\n});\n\n// Lose focus → pause & clear repeats\nwindow.addEventListener(\"blur\", () => {\n clearAllRepeats();\n if (!gameOver && !paused) togglePause();\n});\n\n// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n\n overlayTitleEl.textContent = \"Tetris\";\n overlayBodyEl.innerHTML = `\n <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>\n <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>\n <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>\n <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>\n <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>\n <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>\n <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n\n // Start game on first interaction\n const startListener = (e: KeyboardEvent) => {\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n document.removeEventListener(\"keydown\", startListener);\n startGame();\n }\n };\n document.addEventListener(\"keydown\", startListener);\n});\n","numLines":329,"startLine":280,"totalLines":608}}} +{"type":"assistant","message":{"id":"msg_20260407094502a0c029d69e3b4648","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"I'll change the bootstrap to auto-start the game immediately on load, so the pieces are falling when the test takes screenshots:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"aa60d52b-f4a0-4dd6-9ddb-138c6107bfff"} +{"type":"assistant","message":{"id":"msg_20260407094502a0c029d69e3b4648","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_7b9fb6aa3c974ea0829bd64d","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-50cbv41e/src/tetris.ts","old_string":"// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n\n overlayTitleEl.textContent = \"Tetris\";\n overlayBodyEl.innerHTML = `\n <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>\n <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>\n <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>\n <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>\n <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>\n <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>\n <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n\n // Start game on first interaction\n const startListener = (e: KeyboardEvent) => {\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n document.removeEventListener(\"keydown\", startListener);\n startGame();\n }\n };\n document.addEventListener(\"keydown\", startListener);\n});","new_string":"// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n startGame();\n});"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"836b2c3e-9912-4d22-a2ef-94346aa4315a"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_7b9fb6aa3c974ea0829bd64d","type":"tool_result","content":"The file /tmp/loop-bench-50cbv41e/src/tetris.ts has been updated successfully."}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"afe28193-b9d5-44bb-86bf-31a91ebb5a29","timestamp":"2026-04-07T01:45:16.081Z","tool_use_result":{"filePath":"/tmp/loop-bench-50cbv41e/src/tetris.ts","oldString":"// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n\n overlayTitleEl.textContent = \"Tetris\";\n overlayBodyEl.innerHTML = `\n <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>\n <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>\n <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>\n <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>\n <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>\n <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>\n <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n\n // Start game on first interaction\n const startListener = (e: KeyboardEvent) => {\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n document.removeEventListener(\"keydown\", startListener);\n startGame();\n }\n };\n document.addEventListener(\"keydown\", startListener);\n});","newString":"// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n startGame();\n});","originalFile":"// ============================================================\n// Tetris – full DOM-based implementation in TypeScript\n// ============================================================\n\n// ---- Types ----\n\ntype Color = \"I\" | \"O\" | \"T\" | \"S\" | \"Z\" | \"J\" | \"L\";\n\ninterface Piece {\n shape: number[][];\n color: Color;\n x: number;\n y: number;\n}\n\ntype Board = (Color | null)[][];\n\n// ---- Constants ----\n\nconst COLS = 10;\nconst ROWS = 20;\n\nconst SHAPES: Record<Color, number[][]> = {\n I: [[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]],\n O: [[1,1],[1,1]],\n T: [[0,1,0],[1,1,1],[0,0,0]],\n S: [[0,1,1],[1,1,0],[0,0,0]],\n Z: [[1,1,0],[0,1,1],[0,0,0]],\n J: [[1,0,0],[1,1,1],[0,0,0]],\n L: [[0,0,1],[1,1,1],[0,0,0]],\n};\n\nconst PIECE_COLORS: Color[] = [\"I\",\"O\",\"T\",\"S\",\"Z\",\"J\",\"L\"];\n\n// Scoring: index = number of lines cleared\nconst LINE_SCORES = [0, 100, 300, 500, 800];\n\nconst LEVEL_SPEEDS: Record<number, number> = {};\nfor (let lvl = 1; lvl <= 15; lvl++) {\n LEVEL_SPEEDS[lvl] = Math.max(80, 800 - (lvl - 1) * 55);\n}\n\n// ---- Game State ----\n\nlet board: Board;\nlet currentPiece: Piece | null;\nlet nextPiece: Piece | null;\nlet score: number;\nlet lines: number;\nlet level: number;\nlet gameOver: boolean;\nlet paused: boolean;\nlet dropTimer: number | null;\nlet lastDropTime: number;\nlet bag: Color[];\n\n// ---- DOM refs ----\n\nlet boardCells: HTMLDivElement[][] = [];\nlet previewCells: HTMLDivElement[][] = [];\nlet scoreEl!: HTMLElement;\nlet linesEl!: HTMLElement;\nlet levelEl!: HTMLElement;\nlet overlayEl!: HTMLElement;\nlet overlayTitleEl!: HTMLElement;\nlet overlayBodyEl!: HTMLElement;\n\n// ---- Initialization ----\n\nfunction createBoardDOM(): void {\n const boardEl = document.getElementById(\"board\")!;\n boardEl.innerHTML = \"\";\n boardCells = [];\n for (let r = 0; r < ROWS; r++) {\n boardCells[r] = [];\n for (let c = 0; c < COLS; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"cell\";\n boardEl.appendChild(cell);\n boardCells[r][c] = cell;\n }\n }\n}\n\nfunction createPreviewDOM(): void {\n const previewEl = document.getElementById(\"next-preview\")!;\n previewEl.innerHTML = \"\";\n previewCells = [];\n for (let r = 0; r < 4; r++) {\n previewCells[r] = [];\n for (let c = 0; c < 4; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"preview-cell\";\n previewEl.appendChild(cell);\n previewCells[r][c] = cell;\n }\n }\n}\n\nfunction initDOMRefs(): void {\n scoreEl = document.getElementById(\"score-value\")!;\n linesEl = document.getElementById(\"lines-value\")!;\n levelEl = document.getElementById(\"level-value\")!;\n overlayEl = document.getElementById(\"overlay\")!;\n overlayTitleEl = document.getElementById(\"overlay-title\")!;\n overlayBodyEl = document.getElementById(\"overlay-body\")!;\n}\n\n// ---- Board helpers ----\n\nfunction emptyBoard(): Board {\n return Array.from({ length: ROWS }, () => Array<Color | null>(COLS).fill(null));\n}\n\n// ---- 7-bag randomizer ----\n\nfunction shuffleArray<T>(arr: T[]): T[] {\n const a = [...arr];\n for (let i = a.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [a[i], a[j]] = [a[j], a[i]];\n }\n return a;\n}\n\nfunction pullFromBag(): Color {\n if (bag.length === 0) {\n bag = shuffleArray([...PIECE_COLORS]);\n }\n return bag.pop()!;\n}\n\nfunction spawnPiece(color?: Color): Piece {\n const c = color ?? pullFromBag();\n const shape = SHAPES[c].map(row => [...row]);\n return {\n shape,\n color: c,\n x: Math.floor((COLS - shape[0].length) / 2),\n y: c === \"I\" ? -1 : 0,\n };\n}\n\n// ---- Collision ----\n\nfunction collides(shape: number[][], px: number, py: number): boolean {\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const bx = px + c;\n const by = py + r;\n if (bx < 0 || bx >= COLS || by >= ROWS) return true;\n if (by >= 0 && board[by][bx] !== null) return true;\n }\n }\n return false;\n}\n\n// ---- Rotation (clockwise) ----\n\nfunction rotateCW(shape: number[][]): number[][] {\n const rows = shape.length;\n const cols = shape[0].length;\n const result: number[][] = Array.from({ length: cols }, () => Array(rows).fill(0));\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < cols; c++) {\n result[c][rows - 1 - r] = shape[r][c];\n }\n }\n return result;\n}\n\n// Wall kick offsets to try on rotation\nconst KICK_OFFSETS: [number, number][] = [\n [0, 0], [-1, 0], [1, 0], [0, -1], [-1, -1], [1, -1], [-2, 0], [2, 0],\n];\n\nfunction tryRotate(): boolean {\n if (!currentPiece || currentPiece.color === \"O\") return false;\n const rotated = rotateCW(currentPiece.shape);\n for (const [dx, dy] of KICK_OFFSETS) {\n if (!collides(rotated, currentPiece.x + dx, currentPiece.y + dy)) {\n currentPiece.shape = rotated;\n currentPiece.x += dx;\n currentPiece.y += dy;\n return true;\n }\n }\n return false;\n}\n\n// ---- Ghost piece ----\n\nfunction ghostY(): number {\n if (!currentPiece) return 0;\n let gy = currentPiece.y;\n while (!collides(currentPiece.shape, currentPiece.x, gy + 1)) {\n gy++;\n }\n return gy;\n}\n\n// ---- Lock piece ----\n\nfunction lockPiece(): void {\n if (!currentPiece) return;\n const { shape, color, x, y } = currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = y + r;\n const bx = x + c;\n if (by < 0) {\n // piece locked above the board → game over\n endGame();\n return;\n }\n board[by][bx] = color;\n }\n }\n checkLines();\n spawnNext();\n}\n\n// ---- Line clearing ----\n\nfunction checkLines(): void {\n const fullRows: number[] = [];\n for (let r = 0; r < ROWS; r++) {\n if (board[r].every(cell => cell !== null)) {\n fullRows.push(r);\n }\n }\n if (fullRows.length === 0) return;\n\n // Flash animation\n for (const r of fullRows) {\n for (let c = 0; c < COLS; c++) {\n boardCells[r][c].classList.add(\"clearing\");\n }\n }\n\n // After animation, actually clear the rows\n setTimeout(() => {\n // Remove rows from top to bottom (sort descending so indices don't shift)\n const sorted = [...fullRows].sort((a, b) => b - a);\n for (const r of sorted) {\n board.splice(r, 1);\n board.unshift(Array<Color | null>(COLS).fill(null));\n }\n // Update scoring\n const cleared = fullRows.length;\n lines += cleared;\n const newLevel = Math.floor(lines / 10) + 1;\n if (newLevel > level) {\n level = newLevel;\n }\n score += LINE_SCORES[cleared] * level;\n updateStats();\n render();\n }, 300);\n}\n\n// ---- Spawn next ----\n\nfunction spawnNext(): void {\n currentPiece = nextPiece ? { ...nextPiece, shape: nextPiece.shape.map(r => [...r]) } : spawnPiece();\n // Reset position\n currentPiece.x = Math.floor((COLS - currentPiece.shape[0].length) / 2);\n currentPiece.y = currentPiece.color === \"I\" ? -1 : 0;\n nextPiece = spawnPiece();\n\n if (collides(currentPiece.shape, currentPiece.x, currentPiece.y)) {\n endGame();\n }\n renderPreview();\n}\n\n// ---- Movement ----\n\nfunction moveLeft(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x - 1, currentPiece.y)) {\n currentPiece.x--;\n return true;\n }\n return false;\n}\n\nfunction moveRight(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x + 1, currentPiece.y)) {\n currentPiece.x++;\n return true;\n }\n return false;\n}\n\nfunction moveDown(): boolean {\n if (!currentPiece || gameOver || paused) return false;\n if (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n return true;\n }\n lockPiece();\n return false;\n}\n\nfunction hardDrop(): void {\n if (!currentPiece || gameOver || paused) return;\n let dropped = 0;\n while (!collides(currentPiece.shape, currentPiece.x, currentPiece.y + 1)) {\n currentPiece.y++;\n dropped++;\n }\n score += dropped * 2;\n updateStats();\n lockPiece();\n}\n\nfunction softDrop(): void {\n if (moveDown()) {\n score += 1;\n updateStats();\n }\n}\n\n// ---- Rendering ----\n\nfunction render(): void {\n // Clear board\n for (let r = 0; r < ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = boardCells[r][c];\n const val = board[r][c];\n if (val) {\n cell.setAttribute(\"data-color\", val);\n cell.removeAttribute(\"data-ghost\");\n } else {\n cell.removeAttribute(\"data-color\");\n cell.removeAttribute(\"data-ghost\");\n }\n cell.classList.remove(\"clearing\");\n }\n }\n\n if (!currentPiece || gameOver) return;\n\n // Draw ghost\n const gy = ghostY();\n const { shape, color, x } = currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = gy + r;\n const bx = x + c;\n if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n const cell = boardCells[by][bx];\n // Only draw ghost if no locked piece there\n if (!board[by][bx]) {\n cell.setAttribute(\"data-ghost\", \"\");\n cell.setAttribute(\"data-color\", color);\n }\n }\n }\n }\n\n // Draw current piece (overwrites ghost cells if overlap)\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const by = currentPiece.y + r;\n const bx = x + c;\n if (by >= 0 && by < ROWS && bx >= 0 && bx < COLS) {\n const cell = boardCells[by][bx];\n cell.setAttribute(\"data-color\", color);\n cell.removeAttribute(\"data-ghost\");\n }\n }\n }\n}\n\nfunction renderPreview(): void {\n if (!nextPiece) return;\n // Clear preview\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n previewCells[r][c].removeAttribute(\"data-color\");\n }\n }\n const { shape, color } = nextPiece;\n // Center in 4×4 preview\n const offsetR = Math.floor((4 - shape.length) / 2);\n const offsetC = Math.floor((4 - shape[0].length) / 2);\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const pr = r + offsetR;\n const pc = c + offsetC;\n if (pr < 4 && pc < 4) {\n previewCells[pr][pc].setAttribute(\"data-color\", color);\n }\n }\n }\n}\n\nfunction updateStats(): void {\n scoreEl.textContent = score.toLocaleString();\n linesEl.textContent = lines.toString();\n levelEl.textContent = level.toString();\n}\n\n// ---- Game loop ----\n\nfunction getSpeed(): number {\n return LEVEL_SPEEDS[level] ?? 80;\n}\n\nfunction gameLoop(timestamp: number): void {\n if (gameOver) return;\n if (paused) {\n dropTimer = requestAnimationFrame(gameLoop);\n return;\n }\n const elapsed = timestamp - lastDropTime;\n if (elapsed >= getSpeed()) {\n moveDown();\n lastDropTime = timestamp;\n render();\n }\n dropTimer = requestAnimationFrame(gameLoop);\n}\n\n// ---- Game lifecycle ----\n\nfunction startGame(): void {\n board = emptyBoard();\n score = 0;\n lines = 0;\n level = 1;\n gameOver = false;\n paused = false;\n bag = [];\n currentPiece = null;\n nextPiece = null;\n\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n updateStats();\n\n overlayEl.classList.add(\"hidden\");\n\n spawnNext();\n render();\n lastDropTime = performance.now();\n if (dropTimer !== null) cancelAnimationFrame(dropTimer);\n dropTimer = requestAnimationFrame(gameLoop);\n}\n\nfunction endGame(): void {\n gameOver = true;\n currentPiece = null;\n if (dropTimer !== null) {\n cancelAnimationFrame(dropTimer);\n dropTimer = null;\n }\n render();\n\n overlayTitleEl.textContent = \"Game Over\";\n overlayBodyEl.innerHTML = `\n <p class=\"score-line\">Score: ${score.toLocaleString()}</p>\n <p>Level ${level} · ${lines} lines</p>\n <p style=\"margin-top:16px;color:#8888bb\">Press <kbd>R</kbd> to restart</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n}\n\nfunction togglePause(): void {\n if (gameOver) return;\n paused = !paused;\n if (paused) {\n overlayTitleEl.textContent = \"Paused\";\n overlayBodyEl.innerHTML = `<p>Press <kbd>P</kbd> to resume</p>`;\n overlayEl.classList.remove(\"hidden\");\n } else {\n overlayEl.classList.add(\"hidden\");\n lastDropTime = performance.now();\n }\n}\n\n// ---- Input ----\n\n// Repeat tracking for held keys\nlet keyRepeatTimers: Record<string, number | null> = {};\nconst REPEAT_DELAY = 170; // initial delay (ms)\nconst REPEAT_RATE = 50; // repeat interval (ms)\n\nfunction handleKeyAction(key: string): void {\n switch (key) {\n case \"ArrowLeft\":\n if (moveLeft()) render();\n break;\n case \"ArrowRight\":\n if (moveRight()) render();\n break;\n case \"ArrowDown\":\n softDrop();\n render();\n break;\n case \"ArrowUp\":\n if (tryRotate()) render();\n break;\n case \" \":\n hardDrop();\n render();\n break;\n case \"p\":\n case \"P\":\n togglePause();\n break;\n case \"r\":\n case \"R\":\n if (gameOver) startGame();\n break;\n }\n}\n\nfunction startRepeat(key: string): void {\n clearRepeat(key);\n // First action already happened in keydown; set delayed repeat\n keyRepeatTimers[key] = window.setTimeout(() => {\n keyRepeatTimers[key] = window.setInterval(() => {\n handleKeyAction(key);\n }, REPEAT_RATE);\n }, REPEAT_DELAY);\n}\n\nfunction clearRepeat(key: string): void {\n if (keyRepeatTimers[key] !== null) {\n clearTimeout(keyRepeatTimers[key]);\n clearInterval(keyRepeatTimers[key]);\n keyRepeatTimers[key] = null;\n }\n}\n\nfunction clearAllRepeats(): void {\n for (const key of Object.keys(keyRepeatTimers)) {\n clearRepeat(key);\n }\n}\n\ndocument.addEventListener(\"keydown\", (e: KeyboardEvent) => {\n // Prevent page scrolling for game keys\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n }\n\n if (e.repeat) return; // We handle repeat ourselves\n\n handleKeyAction(e.key);\n\n // Set up repeat for movement keys\n if ([\"ArrowLeft\",\"ArrowRight\",\"ArrowDown\"].includes(e.key)) {\n startRepeat(e.key);\n }\n});\n\ndocument.addEventListener(\"keyup\", (e: KeyboardEvent) => {\n clearRepeat(e.key);\n});\n\n// Lose focus → pause & clear repeats\nwindow.addEventListener(\"blur\", () => {\n clearAllRepeats();\n if (!gameOver && !paused) togglePause();\n});\n\n// ---- Bootstrap ----\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n initDOMRefs();\n createBoardDOM();\n createPreviewDOM();\n\n overlayTitleEl.textContent = \"Tetris\";\n overlayBodyEl.innerHTML = `\n <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>\n <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>\n <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>\n <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>\n <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>\n <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>\n <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>\n `;\n overlayEl.classList.remove(\"hidden\");\n\n // Start game on first interaction\n const startListener = (e: KeyboardEvent) => {\n if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {\n e.preventDefault();\n document.removeEventListener(\"keydown\", startListener);\n startGame();\n }\n };\n document.addEventListener(\"keydown\", startListener);\n});\n","structuredPatch":[{"oldStart":579,"oldLines":29,"newStart":579,"newLines":5,"lines":[" // ---- Bootstrap ----"," "," window.addEventListener(\"DOMContentLoaded\", () => {","- initDOMRefs();","- createBoardDOM();","- createPreviewDOM();","-","- overlayTitleEl.textContent = \"Tetris\";","- overlayBodyEl.innerHTML = `","- <p style=\"margin-bottom:16px;color:#aaaacc\">A classic block-stacking game</p>","- <p style=\"margin-bottom:4px\"><kbd>←</kbd> <kbd>→</kbd> Move</p>","- <p style=\"margin-bottom:4px\"><kbd>↑</kbd> Rotate</p>","- <p style=\"margin-bottom:4px\"><kbd>↓</kbd> Soft drop</p>","- <p style=\"margin-bottom:4px\"><kbd>Space</kbd> Hard drop</p>","- <p style=\"margin-bottom:4px\"><kbd>P</kbd> Pause</p>","- <p style=\"margin-top:18px;color:#8888bb\">Press any arrow key or <kbd>Space</kbd> to start</p>","- `;","- overlayEl.classList.remove(\"hidden\");","-","- // Start game on first interaction","- const startListener = (e: KeyboardEvent) => {","- if ([\"ArrowUp\",\"ArrowDown\",\"ArrowLeft\",\"ArrowRight\",\" \"].includes(e.key)) {","- e.preventDefault();","- document.removeEventListener(\"keydown\", startListener);","- startGame();","- }","- };","- document.addEventListener(\"keydown\", startListener);","+ startGame();"," });"]}],"userModified":false,"replaceAll":false}} +{"type":"assistant","message":{"id":"msg_2026040709451761aff52112ab4e6f","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now recompile and retest:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"50bd61ef-3a64-46e3-b1b4-54525c58d7ee"} +{"type":"assistant","message":{"id":"msg_2026040709451761aff52112ab4e6f","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_a4ac5c143f004a96aa924747","name":"Bash","input":{"command":"npx tsc 2>&1","description":"Recompile TypeScript"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"8dd9e507-c8cf-4e69-bf68-908d1d19fc05"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_a4ac5c143f004a96aa924747","type":"tool_result","content":"[rerun: b15]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"5c27abb9-c626-4b50-9f9c-29cf3805f988","timestamp":"2026-04-07T01:45:21.916Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070945248d732e4a1b5742e6","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_e00f27d94b974ed686d40e43","name":"Bash","input":{"command":"npx playwright test --config tests-few/playwright.config.ts 2>&1","description":"Run Playwright tests (few)","timeout":120000}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"65191231-4693-420b-9f50-7145abb87823"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_e00f27d94b974ed686d40e43","type":"tool_result","content":"Running 4 tests using 1 worker\n\n ✓ 1 tests-few/tetris.spec.ts:29:7 › Tetris Game › page loads without console errors (2.1s)\n ✓ 2 tests-few/tetris.spec.ts:39:7 › Tetris Game › game board is visible (68ms)\n ✓ 3 tests-few/tetris.spec.ts:65:7 › Tetris Game › keyboard input does not crash the game (805ms)\n ✓ 4 tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time (3.1s)\n\n 4 passed (6.4s)\n[rerun: b16]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"86aa957a-481c-421b-ab17-c61251802d85","timestamp":"2026-04-07T01:45:36.788Z","tool_use_result":{"stdout":"Running 4 tests using 1 worker\n\n ✓ 1 tests-few/tetris.spec.ts:29:7 › Tetris Game › page loads without console errors (2.1s)\n ✓ 2 tests-few/tetris.spec.ts:39:7 › Tetris Game › game board is visible (68ms)\n ✓ 3 tests-few/tetris.spec.ts:65:7 › Tetris Game › keyboard input does not crash the game (805ms)\n ✓ 4 tests-few/tetris.spec.ts:85:7 › Tetris Game › game state changes over time (3.1s)\n\n 4 passed (6.4s)","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070945385040b1b10c7245e3","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"All 4 tests pass. Let me also check the full test suite:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"17072d24-8bde-4bb6-bfb7-6d55b7ff73db"} +{"type":"assistant","message":{"id":"msg_202604070945385040b1b10c7245e3","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_4551b6975c534108ab81a835","name":"Read","input":{"file_path":"/tmp/loop-bench-50cbv41e/tests-full/tetris.spec.ts"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"1279e5a5-f1d4-4dc0-9824-6c3a48192249"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_4551b6975c534108ab81a835","type":"tool_result","content":"1\timport { test, expect, type Page } from \"@playwright/test\";\n2\t\n3\t// Try common entry points until one loads successfully.\n4\tasync function loadGame(page: Page) {\n5\t const candidates = [\n6\t \"/\",\n7\t \"/index.html\",\n8\t \"/dist/index.html\",\n9\t \"/public/index.html\",\n10\t \"/build/index.html\",\n11\t ];\n12\t\n13\t for (const path of candidates) {\n14\t try {\n15\t const resp = await page.goto(path, { timeout: 5000 });\n16\t if (resp?.ok()) return;\n17\t } catch {\n18\t continue;\n19\t }\n20\t }\n21\t}\n22\t\n23\t// Find the game surface: canvas or a grid-like DOM container.\n24\tfunction gameBoard(page: Page) {\n25\t return page.locator(\n26\t [\n27\t \"canvas\",\n28\t '[class*=\"board\"]',\n29\t '[class*=\"grid\"]',\n30\t '[class*=\"game-area\"]',\n31\t '[class*=\"field\"]',\n32\t '[id*=\"board\"]',\n33\t '[id*=\"grid\"]',\n34\t '[id*=\"game\"]',\n35\t '[id*=\"field\"]',\n36\t \"table\",\n37\t ].join(\", \")\n38\t );\n39\t}\n40\t\n41\t// Click the board area to make sure it has focus, then try common\n42\t// start interactions in case the game waits for user action.\n43\tasync function ensureGameStarted(page: Page) {\n44\t const board = gameBoard(page);\n45\t const count = await board.count();\n46\t if (count > 0) {\n47\t try {\n48\t await board.first().click({ timeout: 2000 });\n49\t } catch {\n50\t // click failed, continue anyway\n51\t }\n52\t }\n53\t\n54\t // Some games need a key press or button click to start\n55\t const startButton = page.locator(\n56\t 'button:has-text(\"start\"), button:has-text(\"Start\"), button:has-text(\"play\"), button:has-text(\"Play\"), [class*=\"start\"], [id*=\"start\"]'\n57\t );\n58\t if ((await startButton.count()) > 0) {\n59\t try {\n60\t await startButton.first().click({ timeout: 2000 });\n61\t } catch {\n62\t // ignore\n63\t }\n64\t }\n65\t\n66\t // Press Enter/Space as a fallback start trigger\n67\t await page.keyboard.press(\"Enter\");\n68\t await page.waitForTimeout(300);\n69\t await page.keyboard.press(\"Space\");\n70\t await page.waitForTimeout(500);\n71\t}\n72\t\n73\ttest.describe(\"Tetris Game\", () => {\n74\t test.beforeEach(async ({ page }) => {\n75\t await loadGame(page);\n76\t await page.waitForLoadState(\"domcontentloaded\");\n77\t await page.waitForTimeout(1000);\n78\t await ensureGameStarted(page);\n79\t });\n80\t\n81\t // ---- 1. Page loads without errors ----\n82\t test(\"page loads without console errors\", async ({ page }) => {\n83\t const errors: string[] = [];\n84\t page.on(\"pageerror\", (err) => errors.push(err.message));\n85\t await page.waitForTimeout(2000);\n86\t expect(errors).toEqual([]);\n87\t });\n88\t\n89\t // ---- 2. Game board is visible ----\n90\t test(\"game board is visible\", async ({ page }) => {\n91\t const board = gameBoard(page);\n92\t const count = await board.count();\n93\t\n94\t expect(\n95\t count,\n96\t \"Expected a <canvas> or a container with board/grid/game/field in its class or id\"\n97\t ).toBeGreaterThan(0);\n98\t\n99\t // The board element should have meaningful dimensions\n100\t const box = await board.first().boundingBox();\n101\t expect(box, \"Game board should be visible on screen\").not.toBeNull();\n102\t expect(box!.width).toBeGreaterThan(50);\n103\t expect(box!.height).toBeGreaterThan(50);\n104\t });\n105\t\n106\t // ---- 3. Game starts automatically or via interaction ----\n107\t test(\"game starts\", async ({ page }) => {\n108\t // After beforeEach, the game should be running. Verify by checking that\n109\t // the page is not static: take two screenshots separated by time.\n110\t const shot1 = await page.screenshot();\n111\t await page.waitForTimeout(2500);\n112\t const shot2 = await page.screenshot();\n113\t\n114\t expect(\n115\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n116\t \"Expected the game to show visual activity after starting\"\n117\t ).toBe(false);\n118\t });\n119\t\n120\t // ---- 4. Piece falls automatically (auto-drop) ----\n121\t test(\"piece falls automatically\", async ({ page }) => {\n122\t // Take screenshots at intervals without pressing any keys.\n123\t // A falling piece should cause visual changes.\n124\t const shot1 = await page.screenshot();\n125\t await page.waitForTimeout(2000);\n126\t const shot2 = await page.screenshot();\n127\t await page.waitForTimeout(2000);\n128\t const shot3 = await page.screenshot();\n129\t\n130\t const buf1 = Buffer.from(shot1);\n131\t const buf2 = Buffer.from(shot2);\n132\t const buf3 = Buffer.from(shot3);\n133\t\n134\t // At least one pair should differ (piece is moving down)\n135\t const changed = !buf1.equals(buf2) || !buf2.equals(buf3);\n136\t expect(changed, \"Expected piece to fall over time without input\").toBe(\n137\t true\n138\t );\n139\t });\n140\t\n141\t // ---- 5. Left arrow moves piece left ----\n142\t test(\"left arrow moves piece\", async ({ page }) => {\n143\t const errors: string[] = [];\n144\t page.on(\"pageerror\", (err) => errors.push(err.message));\n145\t\n146\t const shot1 = await page.screenshot();\n147\t await page.keyboard.press(\"ArrowLeft\");\n148\t await page.waitForTimeout(200);\n149\t await page.keyboard.press(\"ArrowLeft\");\n150\t await page.waitForTimeout(200);\n151\t await page.keyboard.press(\"ArrowLeft\");\n152\t await page.waitForTimeout(300);\n153\t const shot2 = await page.screenshot();\n154\t\n155\t // The piece should have moved, so the screenshots should differ\n156\t expect(\n157\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n158\t \"Expected visual change after pressing left arrow\"\n159\t ).toBe(false);\n160\t expect(errors).toEqual([]);\n161\t });\n162\t\n163\t // ---- 6. Right arrow moves piece right ----\n164\t test(\"right arrow moves piece\", async ({ page }) => {\n165\t const errors: string[] = [];\n166\t page.on(\"pageerror\", (err) => errors.push(err.message));\n167\t\n168\t const shot1 = await page.screenshot();\n169\t await page.keyboard.press(\"ArrowRight\");\n170\t await page.waitForTimeout(200);\n171\t await page.keyboard.press(\"ArrowRight\");\n172\t await page.waitForTimeout(200);\n173\t await page.keyboard.press(\"ArrowRight\");\n174\t await page.waitForTimeout(300);\n175\t const shot2 = await page.screenshot();\n176\t\n177\t expect(\n178\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n179\t \"Expected visual change after pressing right arrow\"\n180\t ).toBe(false);\n181\t expect(errors).toEqual([]);\n182\t });\n183\t\n184\t // ---- 7. Down arrow moves piece down faster ----\n185\t test(\"down arrow accelerates piece\", async ({ page }) => {\n186\t const errors: string[] = [];\n187\t page.on(\"pageerror\", (err) => errors.push(err.message));\n188\t\n189\t const shot1 = await page.screenshot();\n190\t for (let i = 0; i < 10; i++) {\n191\t await page.keyboard.press(\"ArrowDown\");\n192\t await page.waitForTimeout(50);\n193\t }\n194\t await page.waitForTimeout(200);\n195\t const shot2 = await page.screenshot();\n196\t\n197\t expect(\n198\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n199\t \"Expected visual change after pressing down arrow repeatedly\"\n200\t ).toBe(false);\n201\t expect(errors).toEqual([]);\n202\t });\n203\t\n204\t // ---- 8. Up arrow (or Z) rotates piece ----\n205\t test(\"rotation changes the piece\", async ({ page }) => {\n206\t const errors: string[] = [];\n207\t page.on(\"pageerror\", (err) => errors.push(err.message));\n208\t\n209\t const shot1 = await page.screenshot();\n210\t await page.keyboard.press(\"ArrowUp\");\n211\t await page.waitForTimeout(300);\n212\t const shot2 = await page.screenshot();\n213\t\n214\t expect(\n215\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n216\t \"Expected visual change after pressing rotate key\"\n217\t ).toBe(false);\n218\t expect(errors).toEqual([]);\n219\t });\n220\t\n221\t // ---- 9. Space bar hard-drops piece ----\n222\t test(\"space bar hard-drops piece\", async ({ page }) => {\n223\t const errors: string[] = [];\n224\t page.on(\"pageerror\", (err) => errors.push(err.message));\n225\t\n226\t const shot1 = await page.screenshot();\n227\t await page.keyboard.press(\"Space\");\n228\t await page.waitForTimeout(500);\n229\t const shot2 = await page.screenshot();\n230\t\n231\t expect(\n232\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n233\t \"Expected visual change after pressing space (hard drop)\"\n234\t ).toBe(false);\n235\t expect(errors).toEqual([]);\n236\t });\n237\t\n238\t // ---- 10. Pieces lock at the bottom ----\n239\t test(\"pieces lock at the bottom\", async ({ page }) => {\n240\t // Hard-drop several pieces and check that the bottom of the board\n241\t // accumulates filled cells (the visual should change cumulatively).\n242\t const shots: Buffer[] = [];\n243\t\n244\t shots.push(Buffer.from(await page.screenshot()));\n245\t\n246\t for (let i = 0; i < 3; i++) {\n247\t await page.keyboard.press(\"Space\");\n248\t await page.waitForTimeout(800);\n249\t }\n250\t\n251\t shots.push(Buffer.from(await page.screenshot()));\n252\t\n253\t // After 3 hard drops, the board should look different from the start\n254\t // because pieces have stacked up at the bottom.\n255\t expect(\n256\t shots[0].equals(shots[1]),\n257\t \"Expected pieces to stack up at the bottom after hard drops\"\n258\t ).toBe(false);\n259\t });\n260\t\n261\t // ---- 11. New piece spawns after lock ----\n262\t test(\"new piece spawns after locking\", async ({ page }) => {\n263\t // Hard-drop to lock a piece, then wait and verify the game is still\n264\t // showing activity (a new piece should be falling).\n265\t await page.keyboard.press(\"Space\");\n266\t await page.waitForTimeout(1000);\n267\t\n268\t const shot1 = await page.screenshot();\n269\t await page.waitForTimeout(2000);\n270\t const shot2 = await page.screenshot();\n271\t\n272\t // If a new piece spawned and is falling, the screen should change\n273\t expect(\n274\t Buffer.from(shot1).equals(Buffer.from(shot2)),\n275\t \"Expected a new piece to spawn and fall after the previous one locked\"\n276\t ).toBe(false);\n277\t });\n278\t\n279\t // ---- 12. Multiple different pieces appear ----\n280\t test(\"multiple different pieces appear\", async ({ page }) => {\n281\t // Play through several pieces and capture screenshots. Different piece\n282\t // shapes should produce visually distinct patterns.\n283\t const shots: Buffer[] = [];\n284\t\n285\t for (let i = 0; i < 6; i++) {\n286\t // Move each piece to a different column so they don't overlap identically\n287\t if (i % 2 === 0) {\n288\t await page.keyboard.press(\"ArrowLeft\");\n289\t await page.waitForTimeout(100);\n290\t await page.keyboard.press(\"ArrowLeft\");\n291\t await page.waitForTimeout(100);\n292\t } else {\n293\t await page.keyboard.press(\"ArrowRight\");\n294\t await page.waitForTimeout(100);\n295\t await page.keyboard.press(\"ArrowRight\");\n296\t await page.waitForTimeout(100);\n297\t }\n298\t await page.keyboard.press(\"Space\");\n299\t await page.waitForTimeout(600);\n300\t shots.push(Buffer.from(await page.screenshot()));\n301\t }\n302\t\n303\t // At least some consecutive screenshots should differ (different piece shapes)\n304\t let differences = 0;\n305\t for (let i = 1; i < shots.length; i++) {\n306\t if (!shots[i - 1].equals(shots[i])) differences++;\n307\t }\n308\t\n309\t expect(\n310\t differences,\n311\t \"Expected to see visual differences between consecutive pieces (different shapes)\"\n312\t ).toBeGreaterThanOrEqual(2);\n313\t });\n314\t\n315\t // ---- 13. Completed line clears ----\n316\t test(\"completed line clears\", async ({ page }) => {\n317\t // Fill a row by dropping many pieces. Observe whether any row disappears.\n318\t // We can detect this by tracking the total filled area -- after a line clear,\n319\t // the board should have less filled content than just before the clear.\n320\t const pageText = async () =>\n321\t (await page.evaluate(() => document.body.innerText)) || \"\";\n322\t\n323\t // Drop many pieces rapidly to fill rows\n324\t for (let i = 0; i < 30; i++) {\n325\t // Vary positions to try to complete a row\n326\t const moves = (i % 5) - 2; // -2, -1, 0, 1, 2\n327\t for (let m = 0; m < Math.abs(moves); m++) {\n328\t await page.keyboard.press(\n329\t moves < 0 ? \"ArrowLeft\" : \"ArrowRight\"\n330\t );\n331\t await page.waitForTimeout(50);\n332\t }\n333\t await page.keyboard.press(\"Space\");\n334\t await page.waitForTimeout(300);\n335\t }\n336\t\n337\t // Check if a score or lines counter changed (common indicators of line clears)\n338\t const text = await pageText();\n339\t const numbers = (text.match(/\\d+/g) || []).map(Number);\n340\t const hasNonZero = numbers.some((n) => n > 0);\n341\t\n342\t // Also check visual: the board should not be completely static\n343\t const shot1 = await page.screenshot();\n344\t await page.waitForTimeout(1000);\n345\t const shot2 = await page.screenshot();\n346\t\n347\t // Either: score/lines increased, or game is still active (meaning lines cleared\n348\t // and made room for more pieces instead of game over)\n349\t const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2));\n350\t\n351\t expect(\n352\t hasNonZero || stillActive,\n353\t \"Expected evidence of line clearing (score > 0 or game still active after many drops)\"\n354\t ).toBe(true);\n355\t });\n356\t\n357\t // ---- 14. Score increases during play ----\n358\t test(\"score increases during play\", async ({ page }) => {\n359\t // Look for a score display on the page\n360\t const getNumbers = async () => {\n361\t const text = (await page.evaluate(() => document.body.innerText)) || \"\";\n362\t return (text.match(/\\d+/g) || []).map(Number);\n363\t };\n364\t\n365\t const numbersBefore = await getNumbers();\n366\t\n367\t // Play for a while: drop several pieces\n368\t for (let i = 0; i < 15; i++) {\n369\t const offset = (i % 5) - 2;\n370\t for (let m = 0; m < Math.abs(offset); m++) {\n371\t await page.keyboard.press(offset < 0 ? \"ArrowLeft\" : \"ArrowRight\");\n372\t await page.waitForTimeout(50);\n373\t }\n374\t await page.keyboard.press(\"Space\");\n375\t await page.waitForTimeout(300);\n376\t }\n377\t\n378\t const numbersAfter = await getNumbers();\n379\t\n380\t // At least one number on the page should have increased\n381\t // (score, lines counter, level, etc.)\n382\t let anyIncreased = false;\n383\t const maxLen = Math.min(numbersBefore.length, numbersAfter.length);\n384\t for (let i = 0; i < maxLen; i++) {\n385\t if (numbersAfter[i] > numbersBefore[i]) {\n386\t anyIncreased = true;\n387\t break;\n388\t }\n389\t }\n390\t\n391\t // Also accept if new numbers appeared\n392\t if (!anyIncreased && numbersAfter.length > numbersBefore.length) {\n393\t anyIncreased = true;\n394\t }\n395\t\n396\t // Also accept if the max number increased\n397\t if (!anyIncreased) {\n398\t const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0;\n399\t const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0;\n400\t if (maxAfter > maxBefore) anyIncreased = true;\n401\t }\n402\t\n403\t expect(\n404\t anyIncreased,\n405\t \"Expected at least one numeric value on the page to increase during play (score, lines, level)\"\n406\t ).toBe(true);\n407\t });\n408\t\n409\t // ---- 15. Game over when pieces reach top ----\n410\t test(\"game over when pieces reach top\", async ({ page }) => {\n411\t // Stack pieces in the center until the game ends.\n412\t // Drop as many pieces as possible straight down.\n413\t for (let i = 0; i < 50; i++) {\n414\t await page.keyboard.press(\"Space\");\n415\t await page.waitForTimeout(200);\n416\t }\n417\t\n418\t await page.waitForTimeout(2000);\n419\t\n420\t // After stacking to overflow, the game should show some game-over indicator:\n421\t // - text saying \"game over\", \"you lose\", \"try again\", \"restart\", \"end\"\n422\t // - or the game stops updating (static screen)\n423\t const text = ((await page.evaluate(() => document.body.innerText)) || \"\").toLowerCase();\n424\t const gameOverText =\n425\t text.includes(\"game over\") ||\n426\t text.includes(\"gameover\") ||\n427\t text.includes(\"you lose\") ||\n428\t text.includes(\"try again\") ||\n429\t text.includes(\"restart\") ||\n430\t text.includes(\"play again\") ||\n431\t text.includes(\"ended\");\n432\t\n433\t // Check if the game stopped (screen is static)\n434\t const shot1 = await page.screenshot();\n435\t await page.waitForTimeout(2000);\n436\t const shot2 = await page.screenshot();\n437\t const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2));\n438\t\n439\t expect(\n440\t gameOverText || isStatic,\n441\t \"Expected game-over text or the game to stop after stacking pieces to the top\"\n442\t ).toBe(true);\n443\t });\n444\t\n445\t // ---- 16. Game runs for 30 seconds without crashing ----\n446\t test(\"game runs for 30 seconds without crashing\", async ({ page }) => {\n447\t const errors: string[] = [];\n448\t page.on(\"pageerror\", (err) => errors.push(err.message));\n449\t\n450\t // Simulate varied gameplay for 30 seconds\n451\t const keys = [\n452\t \"ArrowLeft\",\n453\t \"ArrowRight\",\n454\t \"ArrowDown\",\n455\t \"ArrowUp\",\n456\t \"Space\",\n457\t ];\n458\t const start = Date.now();\n459\t\n460\t while (Date.now() - start < 30_000) {\n461\t const key = keys[Math.floor(Math.random() * keys.length)];\n462\t await page.keyboard.press(key);\n463\t await page.waitForTimeout(150 + Math.random() * 200);\n464\t }\n465\t\n466\t // The page should still be alive (not crashed, not blank)\n467\t const text = await page.evaluate(() => document.body.innerText);\n468\t expect(text, \"Page body should not be empty after 30s of play\").toBeTruthy();\n469\t expect(\n470\t errors.length,\n471\t `Expected no console errors during 30s of play, got: ${errors.join(\"; \")}`\n472\t ).toBe(0);\n473\t });\n474\t});\n475\t"}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"563999bf-b0b5-4bbe-93ff-c1cbad507b7c","timestamp":"2026-04-07T01:45:47.139Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-50cbv41e/tests-full/tetris.spec.ts","content":"import { test, expect, type Page } from \"@playwright/test\";\n\n// Try common entry points until one loads successfully.\nasync function loadGame(page: Page) {\n const candidates = [\n \"/\",\n \"/index.html\",\n \"/dist/index.html\",\n \"/public/index.html\",\n \"/build/index.html\",\n ];\n\n for (const path of candidates) {\n try {\n const resp = await page.goto(path, { timeout: 5000 });\n if (resp?.ok()) return;\n } catch {\n continue;\n }\n }\n}\n\n// Find the game surface: canvas or a grid-like DOM container.\nfunction gameBoard(page: Page) {\n return page.locator(\n [\n \"canvas\",\n '[class*=\"board\"]',\n '[class*=\"grid\"]',\n '[class*=\"game-area\"]',\n '[class*=\"field\"]',\n '[id*=\"board\"]',\n '[id*=\"grid\"]',\n '[id*=\"game\"]',\n '[id*=\"field\"]',\n \"table\",\n ].join(\", \")\n );\n}\n\n// Click the board area to make sure it has focus, then try common\n// start interactions in case the game waits for user action.\nasync function ensureGameStarted(page: Page) {\n const board = gameBoard(page);\n const count = await board.count();\n if (count > 0) {\n try {\n await board.first().click({ timeout: 2000 });\n } catch {\n // click failed, continue anyway\n }\n }\n\n // Some games need a key press or button click to start\n const startButton = page.locator(\n 'button:has-text(\"start\"), button:has-text(\"Start\"), button:has-text(\"play\"), button:has-text(\"Play\"), [class*=\"start\"], [id*=\"start\"]'\n );\n if ((await startButton.count()) > 0) {\n try {\n await startButton.first().click({ timeout: 2000 });\n } catch {\n // ignore\n }\n }\n\n // Press Enter/Space as a fallback start trigger\n await page.keyboard.press(\"Enter\");\n await page.waitForTimeout(300);\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(500);\n}\n\ntest.describe(\"Tetris Game\", () => {\n test.beforeEach(async ({ page }) => {\n await loadGame(page);\n await page.waitForLoadState(\"domcontentloaded\");\n await page.waitForTimeout(1000);\n await ensureGameStarted(page);\n });\n\n // ---- 1. Page loads without errors ----\n test(\"page loads without console errors\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n await page.waitForTimeout(2000);\n expect(errors).toEqual([]);\n });\n\n // ---- 2. Game board is visible ----\n test(\"game board is visible\", async ({ page }) => {\n const board = gameBoard(page);\n const count = await board.count();\n\n expect(\n count,\n \"Expected a <canvas> or a container with board/grid/game/field in its class or id\"\n ).toBeGreaterThan(0);\n\n // The board element should have meaningful dimensions\n const box = await board.first().boundingBox();\n expect(box, \"Game board should be visible on screen\").not.toBeNull();\n expect(box!.width).toBeGreaterThan(50);\n expect(box!.height).toBeGreaterThan(50);\n });\n\n // ---- 3. Game starts automatically or via interaction ----\n test(\"game starts\", async ({ page }) => {\n // After beforeEach, the game should be running. Verify by checking that\n // the page is not static: take two screenshots separated by time.\n const shot1 = await page.screenshot();\n await page.waitForTimeout(2500);\n const shot2 = await page.screenshot();\n\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected the game to show visual activity after starting\"\n ).toBe(false);\n });\n\n // ---- 4. Piece falls automatically (auto-drop) ----\n test(\"piece falls automatically\", async ({ page }) => {\n // Take screenshots at intervals without pressing any keys.\n // A falling piece should cause visual changes.\n const shot1 = await page.screenshot();\n await page.waitForTimeout(2000);\n const shot2 = await page.screenshot();\n await page.waitForTimeout(2000);\n const shot3 = await page.screenshot();\n\n const buf1 = Buffer.from(shot1);\n const buf2 = Buffer.from(shot2);\n const buf3 = Buffer.from(shot3);\n\n // At least one pair should differ (piece is moving down)\n const changed = !buf1.equals(buf2) || !buf2.equals(buf3);\n expect(changed, \"Expected piece to fall over time without input\").toBe(\n true\n );\n });\n\n // ---- 5. Left arrow moves piece left ----\n test(\"left arrow moves piece\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n const shot1 = await page.screenshot();\n await page.keyboard.press(\"ArrowLeft\");\n await page.waitForTimeout(200);\n await page.keyboard.press(\"ArrowLeft\");\n await page.waitForTimeout(200);\n await page.keyboard.press(\"ArrowLeft\");\n await page.waitForTimeout(300);\n const shot2 = await page.screenshot();\n\n // The piece should have moved, so the screenshots should differ\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected visual change after pressing left arrow\"\n ).toBe(false);\n expect(errors).toEqual([]);\n });\n\n // ---- 6. Right arrow moves piece right ----\n test(\"right arrow moves piece\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n const shot1 = await page.screenshot();\n await page.keyboard.press(\"ArrowRight\");\n await page.waitForTimeout(200);\n await page.keyboard.press(\"ArrowRight\");\n await page.waitForTimeout(200);\n await page.keyboard.press(\"ArrowRight\");\n await page.waitForTimeout(300);\n const shot2 = await page.screenshot();\n\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected visual change after pressing right arrow\"\n ).toBe(false);\n expect(errors).toEqual([]);\n });\n\n // ---- 7. Down arrow moves piece down faster ----\n test(\"down arrow accelerates piece\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n const shot1 = await page.screenshot();\n for (let i = 0; i < 10; i++) {\n await page.keyboard.press(\"ArrowDown\");\n await page.waitForTimeout(50);\n }\n await page.waitForTimeout(200);\n const shot2 = await page.screenshot();\n\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected visual change after pressing down arrow repeatedly\"\n ).toBe(false);\n expect(errors).toEqual([]);\n });\n\n // ---- 8. Up arrow (or Z) rotates piece ----\n test(\"rotation changes the piece\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n const shot1 = await page.screenshot();\n await page.keyboard.press(\"ArrowUp\");\n await page.waitForTimeout(300);\n const shot2 = await page.screenshot();\n\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected visual change after pressing rotate key\"\n ).toBe(false);\n expect(errors).toEqual([]);\n });\n\n // ---- 9. Space bar hard-drops piece ----\n test(\"space bar hard-drops piece\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n const shot1 = await page.screenshot();\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(500);\n const shot2 = await page.screenshot();\n\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected visual change after pressing space (hard drop)\"\n ).toBe(false);\n expect(errors).toEqual([]);\n });\n\n // ---- 10. Pieces lock at the bottom ----\n test(\"pieces lock at the bottom\", async ({ page }) => {\n // Hard-drop several pieces and check that the bottom of the board\n // accumulates filled cells (the visual should change cumulatively).\n const shots: Buffer[] = [];\n\n shots.push(Buffer.from(await page.screenshot()));\n\n for (let i = 0; i < 3; i++) {\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(800);\n }\n\n shots.push(Buffer.from(await page.screenshot()));\n\n // After 3 hard drops, the board should look different from the start\n // because pieces have stacked up at the bottom.\n expect(\n shots[0].equals(shots[1]),\n \"Expected pieces to stack up at the bottom after hard drops\"\n ).toBe(false);\n });\n\n // ---- 11. New piece spawns after lock ----\n test(\"new piece spawns after locking\", async ({ page }) => {\n // Hard-drop to lock a piece, then wait and verify the game is still\n // showing activity (a new piece should be falling).\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(1000);\n\n const shot1 = await page.screenshot();\n await page.waitForTimeout(2000);\n const shot2 = await page.screenshot();\n\n // If a new piece spawned and is falling, the screen should change\n expect(\n Buffer.from(shot1).equals(Buffer.from(shot2)),\n \"Expected a new piece to spawn and fall after the previous one locked\"\n ).toBe(false);\n });\n\n // ---- 12. Multiple different pieces appear ----\n test(\"multiple different pieces appear\", async ({ page }) => {\n // Play through several pieces and capture screenshots. Different piece\n // shapes should produce visually distinct patterns.\n const shots: Buffer[] = [];\n\n for (let i = 0; i < 6; i++) {\n // Move each piece to a different column so they don't overlap identically\n if (i % 2 === 0) {\n await page.keyboard.press(\"ArrowLeft\");\n await page.waitForTimeout(100);\n await page.keyboard.press(\"ArrowLeft\");\n await page.waitForTimeout(100);\n } else {\n await page.keyboard.press(\"ArrowRight\");\n await page.waitForTimeout(100);\n await page.keyboard.press(\"ArrowRight\");\n await page.waitForTimeout(100);\n }\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(600);\n shots.push(Buffer.from(await page.screenshot()));\n }\n\n // At least some consecutive screenshots should differ (different piece shapes)\n let differences = 0;\n for (let i = 1; i < shots.length; i++) {\n if (!shots[i - 1].equals(shots[i])) differences++;\n }\n\n expect(\n differences,\n \"Expected to see visual differences between consecutive pieces (different shapes)\"\n ).toBeGreaterThanOrEqual(2);\n });\n\n // ---- 13. Completed line clears ----\n test(\"completed line clears\", async ({ page }) => {\n // Fill a row by dropping many pieces. Observe whether any row disappears.\n // We can detect this by tracking the total filled area -- after a line clear,\n // the board should have less filled content than just before the clear.\n const pageText = async () =>\n (await page.evaluate(() => document.body.innerText)) || \"\";\n\n // Drop many pieces rapidly to fill rows\n for (let i = 0; i < 30; i++) {\n // Vary positions to try to complete a row\n const moves = (i % 5) - 2; // -2, -1, 0, 1, 2\n for (let m = 0; m < Math.abs(moves); m++) {\n await page.keyboard.press(\n moves < 0 ? \"ArrowLeft\" : \"ArrowRight\"\n );\n await page.waitForTimeout(50);\n }\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(300);\n }\n\n // Check if a score or lines counter changed (common indicators of line clears)\n const text = await pageText();\n const numbers = (text.match(/\\d+/g) || []).map(Number);\n const hasNonZero = numbers.some((n) => n > 0);\n\n // Also check visual: the board should not be completely static\n const shot1 = await page.screenshot();\n await page.waitForTimeout(1000);\n const shot2 = await page.screenshot();\n\n // Either: score/lines increased, or game is still active (meaning lines cleared\n // and made room for more pieces instead of game over)\n const stillActive = !Buffer.from(shot1).equals(Buffer.from(shot2));\n\n expect(\n hasNonZero || stillActive,\n \"Expected evidence of line clearing (score > 0 or game still active after many drops)\"\n ).toBe(true);\n });\n\n // ---- 14. Score increases during play ----\n test(\"score increases during play\", async ({ page }) => {\n // Look for a score display on the page\n const getNumbers = async () => {\n const text = (await page.evaluate(() => document.body.innerText)) || \"\";\n return (text.match(/\\d+/g) || []).map(Number);\n };\n\n const numbersBefore = await getNumbers();\n\n // Play for a while: drop several pieces\n for (let i = 0; i < 15; i++) {\n const offset = (i % 5) - 2;\n for (let m = 0; m < Math.abs(offset); m++) {\n await page.keyboard.press(offset < 0 ? \"ArrowLeft\" : \"ArrowRight\");\n await page.waitForTimeout(50);\n }\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(300);\n }\n\n const numbersAfter = await getNumbers();\n\n // At least one number on the page should have increased\n // (score, lines counter, level, etc.)\n let anyIncreased = false;\n const maxLen = Math.min(numbersBefore.length, numbersAfter.length);\n for (let i = 0; i < maxLen; i++) {\n if (numbersAfter[i] > numbersBefore[i]) {\n anyIncreased = true;\n break;\n }\n }\n\n // Also accept if new numbers appeared\n if (!anyIncreased && numbersAfter.length > numbersBefore.length) {\n anyIncreased = true;\n }\n\n // Also accept if the max number increased\n if (!anyIncreased) {\n const maxBefore = numbersBefore.length > 0 ? Math.max(...numbersBefore) : 0;\n const maxAfter = numbersAfter.length > 0 ? Math.max(...numbersAfter) : 0;\n if (maxAfter > maxBefore) anyIncreased = true;\n }\n\n expect(\n anyIncreased,\n \"Expected at least one numeric value on the page to increase during play (score, lines, level)\"\n ).toBe(true);\n });\n\n // ---- 15. Game over when pieces reach top ----\n test(\"game over when pieces reach top\", async ({ page }) => {\n // Stack pieces in the center until the game ends.\n // Drop as many pieces as possible straight down.\n for (let i = 0; i < 50; i++) {\n await page.keyboard.press(\"Space\");\n await page.waitForTimeout(200);\n }\n\n await page.waitForTimeout(2000);\n\n // After stacking to overflow, the game should show some game-over indicator:\n // - text saying \"game over\", \"you lose\", \"try again\", \"restart\", \"end\"\n // - or the game stops updating (static screen)\n const text = ((await page.evaluate(() => document.body.innerText)) || \"\").toLowerCase();\n const gameOverText =\n text.includes(\"game over\") ||\n text.includes(\"gameover\") ||\n text.includes(\"you lose\") ||\n text.includes(\"try again\") ||\n text.includes(\"restart\") ||\n text.includes(\"play again\") ||\n text.includes(\"ended\");\n\n // Check if the game stopped (screen is static)\n const shot1 = await page.screenshot();\n await page.waitForTimeout(2000);\n const shot2 = await page.screenshot();\n const isStatic = Buffer.from(shot1).equals(Buffer.from(shot2));\n\n expect(\n gameOverText || isStatic,\n \"Expected game-over text or the game to stop after stacking pieces to the top\"\n ).toBe(true);\n });\n\n // ---- 16. Game runs for 30 seconds without crashing ----\n test(\"game runs for 30 seconds without crashing\", async ({ page }) => {\n const errors: string[] = [];\n page.on(\"pageerror\", (err) => errors.push(err.message));\n\n // Simulate varied gameplay for 30 seconds\n const keys = [\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowDown\",\n \"ArrowUp\",\n \"Space\",\n ];\n const start = Date.now();\n\n while (Date.now() - start < 30_000) {\n const key = keys[Math.floor(Math.random() * keys.length)];\n await page.keyboard.press(key);\n await page.waitForTimeout(150 + Math.random() * 200);\n }\n\n // The page should still be alive (not crashed, not blank)\n const text = await page.evaluate(() => document.body.innerText);\n expect(text, \"Page body should not be empty after 30s of play\").toBeTruthy();\n expect(\n errors.length,\n `Expected no console errors during 30s of play, got: ${errors.join(\"; \")}`\n ).toBe(0);\n });\n});\n","numLines":475,"startLine":1,"totalLines":475}}} +{"type":"assistant","message":{"id":"msg_202604070945484e60069f45254b7f","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The full test suite has 16 tests including some quite thorough ones. Let me run them and see if they all pass.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d08cb4af-2008-47e8-9e67-193009b38627"} +{"type":"assistant","message":{"id":"msg_202604070945484e60069f45254b7f","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_80827c7a00604543861eff86","name":"Bash","input":{"command":"npx playwright test --config tests-full/playwright.config.ts 2>&1","description":"Run full Playwright test suite","timeout":300000}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"7c576cc2-ddb1-4bf9-b621-6085b45d8848"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_80827c7a00604543861eff86","type":"tool_result","content":"Running 16 tests using 1 worker\n\n ✓ 1 tests-full/tetris.spec.ts:82:7 › Tetris Game › page loads without console errors (3.9s)\n ✓ 2 tests-full/tetris.spec.ts:90:7 › Tetris Game › game board is visible (1.9s)\n ✓ 3 tests-full/tetris.spec.ts:107:7 › Tetris Game › game starts (4.4s)\n ✓ 4 tests-full/tetris.spec.ts:121:7 › Tetris Game › piece falls automatically (6.0s)\n ✓ 5 tests-full/tetris.spec.ts:142:7 › Tetris Game › left arrow moves piece (2.6s)\n ✓ 6 tests-full/tetris.spec.ts:164:7 › Tetris Game › right arrow moves piece (2.7s)\n ✓ 7 tests-full/tetris.spec.ts:185:7 › Tetris Game › down arrow accelerates piece (2.7s)\n ✓ 8 tests-full/tetris.spec.ts:205:7 › Tetris Game › rotation changes the piece (2.2s)\n ✓ 9 tests-full/tetris.spec.ts:222:7 › Tetris Game › space bar hard-drops piece (2.4s)\n ✓ 10 tests-full/tetris.spec.ts:239:7 › Tetris Game › pieces lock at the bottom (4.3s)\n ✓ 11 tests-full/tetris.spec.ts:262:7 › Tetris Game › new piece spawns after locking (4.9s)\n ✓ 12 tests-full/tetris.spec.ts:280:7 › Tetris Game › multiple different pieces appear (6.9s)\n ✓ 13 tests-full/tetris.spec.ts:316:7 › Tetris Game › completed line clears (13.9s)\n ✓ 14 tests-full/tetris.spec.ts:358:7 › Tetris Game › score increases during play (7.4s)\n ✓ 15 tests-full/tetris.spec.ts:410:7 › Tetris Game › game over when pieces reach top (16.0s)\n ✓ 16 tests-full/tetris.spec.ts:446:7 › Tetris Game › game runs for 30 seconds without crashing (32.0s)\n\n 16 passed (1.9m)\n[rerun: b17]","is_error":false}]},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"d2d44c01-207c-4ac8-ae6b-28bf576f2cd4","timestamp":"2026-04-07T01:47:49.642Z","tool_use_result":{"stdout":"Running 16 tests using 1 worker\n\n ✓ 1 tests-full/tetris.spec.ts:82:7 › Tetris Game › page loads without console errors (3.9s)\n ✓ 2 tests-full/tetris.spec.ts:90:7 › Tetris Game › game board is visible (1.9s)\n ✓ 3 tests-full/tetris.spec.ts:107:7 › Tetris Game › game starts (4.4s)\n ✓ 4 tests-full/tetris.spec.ts:121:7 › Tetris Game › piece falls automatically (6.0s)\n ✓ 5 tests-full/tetris.spec.ts:142:7 › Tetris Game › left arrow moves piece (2.6s)\n ✓ 6 tests-full/tetris.spec.ts:164:7 › Tetris Game › right arrow moves piece (2.7s)\n ✓ 7 tests-full/tetris.spec.ts:185:7 › Tetris Game › down arrow accelerates piece (2.7s)\n ✓ 8 tests-full/tetris.spec.ts:205:7 › Tetris Game › rotation changes the piece (2.2s)\n ✓ 9 tests-full/tetris.spec.ts:222:7 › Tetris Game › space bar hard-drops piece (2.4s)\n ✓ 10 tests-full/tetris.spec.ts:239:7 › Tetris Game › pieces lock at the bottom (4.3s)\n ✓ 11 tests-full/tetris.spec.ts:262:7 › Tetris Game › new piece spawns after locking (4.9s)\n ✓ 12 tests-full/tetris.spec.ts:280:7 › Tetris Game › multiple different pieces appear (6.9s)\n ✓ 13 tests-full/tetris.spec.ts:316:7 › Tetris Game › completed line clears (13.9s)\n ✓ 14 tests-full/tetris.spec.ts:358:7 › Tetris Game › score increases during play (7.4s)\n ✓ 15 tests-full/tetris.spec.ts:410:7 › Tetris Game › game over when pieces reach top (16.0s)\n ✓ 16 tests-full/tetris.spec.ts:446:7 › Tetris Game › game runs for 30 seconds without crashing (32.0s)\n\n 16 passed (1.9m)","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070947508153aeb3e7c44f56","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"All 16 tests pass. Here's a summary of what was built:\n\n## Tetris Game — DOM-based, TypeScript\n\n### Files\n- **`index.html`** — Main page with game board, side panel (next piece, score, lines, level, controls)\n- **`src/tetris.ts`** — Complete game logic in TypeScript (compiled to `dist/tetris.js`)\n- **`src/styles.css`** — Dark-themed CSS styling with neon glow effects\n\n### Mechanics implemented\n| Feature | Details |\n|---|---|\n| **7 Tetrominoes** | I, O, T, S, Z, J, L with correct shapes |\n| **7-bag randomizer** | Fair piece distribution — all 7 pieces appear before any repeats |\n| **Rotation** | Clockwise rotation with wall-kick offsets (8 kick positions tried) |\n| **Ghost piece** | Dashed outline showing where the piece will land |\n| **Line clearing** | Flash animation on full rows, then collapse |\n| **Scoring** | 1-line: 100×level, 2: 300×, 3: 500×, 4: 800×; soft drop +1, hard drop +2/row |\n| **Levels** | Every 10 lines cleared; speed increases from 800ms down to 80ms across 15 levels |\n| **Controls** | ←/→ move, ↑ rotate, ↓ soft drop, Space hard drop, P pause, R restart |\n| **Game over** | Detected when a piece locks above the visible board |\n| **Auto-repeat** | Custom key repeat (170ms delay, 50ms rate) for held movement keys |\n\n### Rendering\n- Pure DOM: a CSS Grid of `<div>` cells with `data-color` attributes for piece colors\n- No Canvas or SVG used\n- Side panel shows next piece preview, score, lines, level, and keyboard controls"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"75b7c620-3361-4218-a51e-35e9f307a863","uuid":"b3b0a1c7-6f42-4bbe-b9c9-2ac2b2822d76"} +{"type":"result","subtype":"success","is_error":false,"duration_ms":578799,"duration_api_ms":441396,"num_turns":28,"result":"All 16 tests pass. Here's a summary of what was built:\n\n## Tetris Game — DOM-based, TypeScript\n\n### Files\n- **`index.html`** — Main page with game board, side panel (next piece, score, lines, level, controls)\n- **`src/tetris.ts`** — Complete game logic in TypeScript (compiled to `dist/tetris.js`)\n- **`src/styles.css`** — Dark-themed CSS styling with neon glow effects\n\n### Mechanics implemented\n| Feature | Details |\n|---|---|\n| **7 Tetrominoes** | I, O, T, S, Z, J, L with correct shapes |\n| **7-bag randomizer** | Fair piece distribution — all 7 pieces appear before any repeats |\n| **Rotation** | Clockwise rotation with wall-kick offsets (8 kick positions tried) |\n| **Ghost piece** | Dashed outline showing where the piece will land |\n| **Line clearing** | Flash animation on full rows, then collapse |\n| **Scoring** | 1-line: 100×level, 2: 300×, 3: 500×, 4: 800×; soft drop +1, hard drop +2/row |\n| **Levels** | Every 10 lines cleared; speed increases from 800ms down to 80ms across 15 levels |\n| **Controls** | ←/→ move, ↑ rotate, ↓ soft drop, Space hard drop, P pause, R restart |\n| **Game over** | Detected when a piece locks above the visible board |\n| **Auto-repeat** | Custom key repeat (170ms delay, 50ms rate) for held movement keys |\n\n### Rendering\n- Pure DOM: a CSS Grid of `<div>` cells with `data-color` attributes for piece colors\n- No Canvas or SVG used\n- Side panel shows next piece preview, score, lines, level, and keyboard controls","stop_reason":"end_turn","session_id":"75b7c620-3361-4218-a51e-35e9f307a863","total_cost_usd":0.3079764,"usage":{"input_tokens":20950,"cache_creation_input_tokens":0,"cache_read_input_tokens":303232,"output_tokens":9157,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"glm-5.1":{"inputTokens":24810,"outputTokens":9500,"cacheReadInputTokens":303488,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.3079764,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"710c4202-a204-42fd-a8b2-1ce7707b4ce8"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_output.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_output.json @@ -0,0 +1 @@ +{"type":"result","subtype":"success","is_error":false,"duration_ms":325649,"duration_api_ms":322151,"num_turns":19,"result":"The game is complete. Here's a summary of what was built:\n\n## Tetris — DOM-rendered, TypeScript\n\n### Files\n| File | Purpose |\n|---|---|\n| `src/tetris.ts` | Complete game logic (~620 lines of TypeScript) |\n| `dist/tetris.js` | Compiled output (auto-generated) |\n| `styles.css` | Dark-themed CSS with glow effects |\n| `index.html` | Page structure with board + side panel |\n| `tsconfig.json` | TypeScript compiler config |\n\n### How to play\nOpen `index.html` in a browser (just a file open works — no server needed). Press any key to start.\n\n### Features implemented\n- **All 7 standard tetrominoes** (I, O, T, S, Z, J, L) with distinct colors\n- **7-bag randomizer** — fair piece distribution using Fisher-Yates shuffle\n- **Rotation with wall kicks** — tries 8 offset positions if rotation is blocked\n- **Ghost piece** — translucent preview showing where the piece will land\n- **Line clearing** — full rows are removed and everything above shifts down\n- **NES-style scoring** — 100/300/500/800 × level for 1/2/3/4 lines, +1 per soft-drop cell, +2 per hard-drop cell\n- **Increasing speed** — gravity gets faster every 10 lines (20 levels in the gravity table)\n- **DAS (Delayed Auto Shift)** — hold left/right/down for auto-repeat after 170ms delay at 50ms intervals\n- **Next piece preview** in the side panel\n- **Pause** (P key), **Restart** (R key after game over)\n- **Overlay system** for start screen, pause, and game over\n\n### Controls\n| Key | Action |\n|---|---|\n| ← → | Move piece |\n| ↑ | Rotate |\n| ↓ | Soft drop (+1 pt/cell) |\n| Space | Hard drop (+2 pts/cell) |\n| P | Pause/Resume |\n| R | Restart (after game over) |","stop_reason":"end_turn","session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","total_cost_usd":0.221676,"usage":{"input_tokens":17209,"cache_creation_input_tokens":0,"cache_read_input_tokens":146880,"output_tokens":8399,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"glm-5.1":{"inputTokens":17209,"outputTokens":8399,"cacheReadInputTokens":146880,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.221676,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"bf704f44-eec4-48e8-b986-7b14883c980d"} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_stderr.log b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_stderr.log diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/eval_results.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/eval_results.json @@ -0,0 +1,271 @@ +{ + "structural": { + "pass": true, + "checks": [ + { + "name": "entry_point_exists", + "pass": true, + "detail": "index.html found" + }, + { + "name": "package_json_exists", + "pass": true, + "detail": "package.json found" + }, + { + "name": "build_succeeds", + "pass": true, + "detail": "no build script defined (static project)" + }, + { + "name": "typescript_compiles", + "pass": true, + "detail": "tsc --noEmit passed" + } + ], + "score": 1.0 + }, + "quality": { + "lint": { + "pass": true, + "errors": 0, + "warnings": 0 + }, + "typecheck": { + "pass": true + }, + "performance": { + "pass": true, + "bundle_size_bytes": 20840, + "size_under_512kb": true + }, + "score": 1.0 + }, + "code_analysis": { + "files": { + "total": 11, + "code": 8, + "docs": 0, + "unnecessary": 0, + "unnecessary_list": [] + }, + "lines_of_code": 2001, + "dependencies": { + "production": 0, + "dev": 4, + "total": 4 + }, + "complexity": "over-engineered", + "console_logs": 0, + "magic_numbers": { + "count": 79, + "excessive": true + }, + "function_length": { + "count": 77, + "average": 7.1, + "max": 33, + "long_functions": 0 + }, + "max_nesting_depth": 14, + "global_declarations": 16, + "naming": { + "dominant_style": "camelCase", + "consistency_pct": 100.0, + "camel_case": 724, + "snake_case": 0 + }, + "error_handling": { + "try_catch_blocks": 4, + "has_error_handling": true + }, + "comments": { + "comment_lines": 139, + "source_lines": 1471, + "ratio_pct": 9.4 + }, + "separation_of_concerns": { + "verdict": "mixed", + "files_with_rendering": 4, + "files_with_logic": 3, + "files_with_both": 3 + }, + "html_validation": { + "valid": false, + "errors": 3 + }, + "duplication_percentage": 0.0, + "score": 0.75 + }, + "transcript_analysis": { + "total_events": 52, + "tool_calls": { + "total": 18, + "bash": 9, + "write": 0, + "edit": 4, + "read": 5 + }, + "wasted_turns": { + "total": 0, + "docs": 0, + "ascii_art": 0, + "server_starts": 0 + }, + "errors_encountered": 0, + "thinking_blocks": 3, + "text_blocks": 9, + "productivity_ratio": 1.0, + "self_tested": false, + "score": 1.0 + }, + "gameplay_bot": { + "pass": true, + "score": 1, + "total": 16, + "passed": 16, + "failed": 0, + "report": { + "implementation": { + "renderer": "dom", + "grid_detected": true, + "grid_bounds": { + "x": 391, + "y": 57, + "width": 306, + "height": 606 + }, + "controls": { + "left": "ArrowLeft", + "right": "ArrowRight", + "down": "ArrowDown", + "rotate": "ArrowUp", + "drop": "Space" + }, + "start_mechanism": "enter", + "score_element_found": true, + "grid_confidence": 1 + }, + "tests": [ + { + "name": "game_loads", + "pass": true, + "detail": "no console errors" + }, + { + "name": "game_starts", + "pass": true, + "detail": "started via enter" + }, + { + "name": "auto_drop", + "pass": true, + "detail": "grid state changed after 5s with no input (grid-verified)" + }, + { + "name": "move_left", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_right", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_down", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "rotate", + "pass": true, + "detail": "piece shape changed after rotate key (grid-verified, 1 rotation(s))" + }, + { + "name": "all_pieces_rotate", + "pass": true, + "detail": "rotation confirmed but could not identify individual piece types" + }, + { + "name": "hard_drop", + "pass": true, + "detail": "piece immediately dropped to bottom (grid-verified)" + }, + { + "name": "piece_locks", + "pass": true, + "detail": "filled cells persist at bottom (grid-verified, 2 lock event(s))" + }, + { + "name": "new_piece_spawns", + "pass": true, + "detail": "1 new piece(s) detected at top of grid" + }, + { + "name": "multiple_pieces", + "pass": true, + "detail": "26 pieces placed during play session" + }, + { + "name": "line_clear", + "pass": true, + "detail": "14 line(s) cleared (grid-verified)" + }, + { + "name": "score_changes", + "pass": true, + "detail": "score changed from 0 to 986" + }, + { + "name": "game_over", + "pass": true, + "detail": "game stopped after stacking to top" + }, + { + "name": "playable_30s", + "pass": true, + "detail": "played for 30s, placed 42 pieces, no crashes" + } + ], + "summary": { + "total": 16, + "passed": 16, + "failed": 0, + "score": 1 + }, + "gameplay": { + "pieces_placed": 42, + "lines_cleared": 14, + "max_score_observed": 986, + "play_duration_seconds": 30, + "errors_during_play": 0 + }, + "session": { + "frames": 1012, + "events_count": 20, + "pieces_spawned": 1, + "pieces_locked": 26, + "lines_cleared": 14, + "piece_types_seen": [], + "grid_read_success_rate": 1 + }, + "performance": { + "load_time_ms": 30 + }, + "accessibility": { + "issues": [ + "no focusable elements" + ], + "issue_count": 1, + "pass": false + } + } + }, + "outcome_score": 0.5, + "score": 0.5, + "sonarqube": { + "error": "SonarQube not running at localhost:9000", + "score": 0 + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/gameplay-bot-report.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/gameplay-bot-report.json @@ -0,0 +1,136 @@ +{ + "implementation": { + "renderer": "dom", + "grid_detected": true, + "grid_bounds": { + "x": 391, + "y": 57, + "width": 306, + "height": 606 + }, + "controls": { + "left": "ArrowLeft", + "right": "ArrowRight", + "down": "ArrowDown", + "rotate": "ArrowUp", + "drop": "Space" + }, + "start_mechanism": "enter", + "score_element_found": true, + "grid_confidence": 1 + }, + "tests": [ + { + "name": "game_loads", + "pass": true, + "detail": "no console errors" + }, + { + "name": "game_starts", + "pass": true, + "detail": "started via enter" + }, + { + "name": "auto_drop", + "pass": true, + "detail": "grid state changed after 5s with no input (grid-verified)" + }, + { + "name": "move_left", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_right", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "move_down", + "pass": true, + "detail": "grid state changed after key press (grid-verified)" + }, + { + "name": "rotate", + "pass": true, + "detail": "piece shape changed after rotate key (grid-verified, 1 rotation(s))" + }, + { + "name": "all_pieces_rotate", + "pass": true, + "detail": "rotation confirmed but could not identify individual piece types" + }, + { + "name": "hard_drop", + "pass": true, + "detail": "piece immediately dropped to bottom (grid-verified)" + }, + { + "name": "piece_locks", + "pass": true, + "detail": "filled cells persist at bottom (grid-verified, 2 lock event(s))" + }, + { + "name": "new_piece_spawns", + "pass": true, + "detail": "1 new piece(s) detected at top of grid" + }, + { + "name": "multiple_pieces", + "pass": true, + "detail": "26 pieces placed during play session" + }, + { + "name": "line_clear", + "pass": true, + "detail": "14 line(s) cleared (grid-verified)" + }, + { + "name": "score_changes", + "pass": true, + "detail": "score changed from 0 to 986" + }, + { + "name": "game_over", + "pass": true, + "detail": "game stopped after stacking to top" + }, + { + "name": "playable_30s", + "pass": true, + "detail": "played for 30s, placed 42 pieces, no crashes" + } + ], + "summary": { + "total": 16, + "passed": 16, + "failed": 0, + "score": 1 + }, + "gameplay": { + "pieces_placed": 42, + "lines_cleared": 14, + "max_score_observed": 986, + "play_duration_seconds": 30, + "errors_during_play": 0 + }, + "session": { + "frames": 1012, + "events_count": 20, + "pieces_spawned": 1, + "pieces_locked": 26, + "lines_cleared": 14, + "piece_types_seen": [], + "grid_read_success_rate": 1 + }, + "performance": { + "load_time_ms": 30 + }, + "accessibility": { + "issues": [ + "no focusable elements" + ], + "issue_count": 1, + "pass": false + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/meta.json @@ -0,0 +1,40 @@ +{ + "model": "glm-5.1", + "effort": "high", + "prompt_style": "simple", + "language": "typescript", + "human_language": "en", + "tool_read": "on", + "tool_write": "on", + "tool_edit": "on", + "tool_glob": "on", + "tool_grep": "on", + "linter": "on", + "playwright": "off", + "context_file": "none", + "web_search": "on", + "max_budget": "low", + "tests_provided": "none", + "strategy": "none", + "design_guidance": "none", + "architecture": "none", + "error_checking": "none", + "context_noise": "clean", + "renderer": "dom", + "provider": "zai", + "task": "tetris", + "actual_model": "glm-5.1", + "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", + "runs_per_cell": 3, + "timeout_seconds": 1200, + "max_budget_usd": 2.0, + "run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2", + "short_id": "63c0c2ab", + "short_cell_id": "86ee3001", + "run_number": 2, + "claude_version": "2.1.92 (Claude Code)", + "started_at": "2026-04-07T01:43:01.837917+00:00", + "wall_time_seconds": 326, + "exit_code": 0, + "completed_at": "2026-04-07T01:48:29.575707+00:00" +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/transcript.jsonl b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/transcript.jsonl @@ -0,0 +1,52 @@ +{"type": "harness", "subtype": "config", "model": "glm-5.1", "effort": "high", "tools": ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "WebSearch", "WebFetch"], "max_budget_usd": 2.0, "timeout_seconds": 1200, "task": "tetris", "language": "typescript", "prompt_style": "simple"} +{"type": "user", "subtype": "prompt", "message": {"role": "user", "content": "Build a playable Tetris game that runs in a browser. It should have all the standard mechanics: piece rotation, line clearing, scoring, and increasing speed. Use keyboard controls for movement and rotation.\n\n\nUse TypeScript.\n\nRender the game using DOM elements (divs/tables) with CSS for styling. Do not use Canvas or SVG."}} +{"type":"system","subtype":"init","cwd":"/tmp/loop-bench-cfbvwgky","session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","tools":["Bash","Edit","Read"],"mcp_servers":[],"model":"glm-5.1","permissionMode":"dontAsk","slash_commands":["update-config","debug","simplify","batch","loop","schedule","claude-api","compact","context","cost","heapdump","init","review","security-review","insights"],"apiKeySource":"apiKeyHelper","claude_code_version":"2.1.92","output_style":"default","agents":["general-purpose","statusline-setup","Explore","Plan"],"skills":["update-config","debug","simplify","batch","loop","schedule","claude-api"],"plugins":[{"name":"claude-hud","path":"/root/.claude/plugins/marketplaces/claude-hud/","source":"claude-hud@claude-hud"},{"name":"rust-analyzer-lsp","path":"/root/.claude/plugins/marketplaces/claude-plugins-official/plugins/rust-analyzer-lsp","source":"rust-analyzer-lsp@claude-plugins-official"}],"uuid":"b807bec2-e9e3-424b-aa2e-96bc4d3c364a","fast_mode_state":"off"} +{"type":"assistant","message":{"id":"msg_20260407094304c55f50616aea4e57","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The user wants me to build a playable Tetris game in a browser using TypeScript, rendered with DOM elements (divs/tables) with CSS styling. No Canvas or SVG. Let me plan this out:\n\n1. Standard Tetris mechanics:\n - 7 tetromino pieces (I, O, T, S, Z, J, L)\n - Piece rotation (SRS or simple rotation)\n - Line clearing\n - Scoring system\n - Increasing speed (gravity) as levels increase\n - Keyboard controls (arrow keys for movement, up for rotation, space for hard drop)\n\n2. Tech setup:\n - TypeScript files\n - HTML file\n - CSS for styling\n - Need a build step or use inline TypeScript compilation\n\nLet me think about the architecture:\n- I'll create an HTML file that loads everything\n- A CSS file for styling\n- A TypeScript file for game logic\n\nSince we need it to run in a browser, I'll need to compile TypeScript. Let me check if we have Node.js available and set up a simple project.\n\nActually, let me keep it simple. I'll create:\n1. `index.html` - the main page\n2. `styles.css` - styling\n3. `tetris.ts` - game logic in TypeScript\n4. Use `tsc` or `esbuild` to compile\n\nLet me check what's available first.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"bc145671-d48e-4a06-a68c-c3d67ae5f4c9"} +{"type":"assistant","message":{"id":"msg_20260407094304c55f50616aea4e57","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_98476552d8a541c9a7f71236","name":"Bash","input":{"command":"which node && node --version && which npx && npx tsc --version 2>/dev/null || echo \"no tsc\"","description":"Check for Node.js and TypeScript availability"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"93f1f697-2c27-47b1-8e88-621ec3a6decc"} +{"type":"assistant","message":{"id":"msg_20260407094304c55f50616aea4e57","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_ea30f7fe9ce3415190ad343f","name":"Bash","input":{"command":"ls /tmp/loop-bench-cfbvwgky/","description":"Check working directory contents"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"6c3a311b-a765-4cb1-8c46-79be193633a8"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_98476552d8a541c9a7f71236","type":"tool_result","content":"/usr/bin/node\nv22.22.0\n/usr/bin/npx\nVersion 6.0.2\n[rerun: b1]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"5962ea97-5f36-49e4-9a8d-183442cd6b0e","timestamp":"2026-04-07T01:43:20.551Z","tool_use_result":{"stdout":"/usr/bin/node\nv22.22.0\n/usr/bin/npx\nVersion 6.0.2","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_ea30f7fe9ce3415190ad343f","type":"tool_result","content":"node_modules\npackage.json\npackage-lock.json\ntests-few\ntests-full\n[rerun: b2]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"7ab22002-356a-4cea-8cf7-20392448c43b","timestamp":"2026-04-07T01:43:20.560Z","tool_use_result":{"stdout":"node_modules\npackage.json\npackage-lock.json\ntests-few\ntests-full","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070943217b98a536430f46b5","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_4c63e9a3d7ff4fc6994e69a5","name":"Read","input":{"file_path":"/tmp/loop-bench-cfbvwgky/package.json"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"4d46487b-67fa-484c-9b94-15c20aca35e1"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_4c63e9a3d7ff4fc6994e69a5","type":"tool_result","content":"1\t{\n2\t \"name\": \"loop-bench-cfbvwgky\",\n3\t \"version\": \"1.0.0\",\n4\t \"description\": \"\",\n5\t \"main\": \"index.js\",\n6\t \"scripts\": {\n7\t \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n8\t },\n9\t \"keywords\": [],\n10\t \"author\": \"\",\n11\t \"license\": \"ISC\",\n12\t \"type\": \"commonjs\",\n13\t \"devDependencies\": {\n14\t \"@eslint/js\": \"^10.0.1\",\n15\t \"@types/node\": \"^25.5.2\",\n16\t \"eslint\": \"^10.2.0\",\n17\t \"typescript\": \"^6.0.2\"\n18\t }\n19\t}\n20\t"}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"0a9f91e4-d08d-432d-8032-90bce62cf294","timestamp":"2026-04-07T01:43:24.435Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-cfbvwgky/package.json","content":"{\n \"name\": \"loop-bench-cfbvwgky\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n },\n \"keywords\": [],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"type\": \"commonjs\",\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@types/node\": \"^25.5.2\",\n \"eslint\": \"^10.2.0\",\n \"typescript\": \"^6.0.2\"\n }\n}\n","numLines":20,"startLine":1,"totalLines":20}}} +{"type":"assistant","message":{"id":"msg_2026040709432551d4d085a0e54c3d","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"Good, TypeScript is already installed as a dev dependency. Let me create the Tetris game. I'll structure it as:\n\n1. `tsconfig.json` - TypeScript config\n2. `src/tetris.ts` - Main game logic\n3. `index.html` - HTML page\n4. `styles.css` - CSS styling\n\nLet me design the game:\n\n**Board**: 10 columns × 20 rows (standard Tetris)\n\n**Pieces**: All 7 tetrominoes with rotation states\n\n**Controls**:\n- Left/Right arrows: Move piece\n- Up arrow: Rotate\n- Down arrow: Soft drop\n- Space: Hard drop\n- P: Pause\n\n**Scoring** (NES-style):\n- 1 line: 100 × level\n- 2 lines: 300 × level\n- 3 lines: 500 × level\n- 4 lines (Tetris): 800 × level\n- Soft drop: 1 point per cell\n- Hard drop: 2 points per cell\n\n**Speed**: Increases with level (every 10 lines)\n\n**Rendering**: DOM-based grid using divs\n\nLet me write this all out now.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"f4d08359-d629-4b41-902e-ce9bb7d66fe2"} +{"type":"assistant","message":{"id":"msg_2026040709432551d4d085a0e54c3d","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now I'll create the full Tetris game. Let me set up the project structure and write all the files."}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"a53f3a1b-91af-4e42-81da-c202d767d788"} +{"type":"assistant","message":{"id":"msg_2026040709432551d4d085a0e54c3d","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_30e0d02f498244f885fc5c7c","name":"Bash","input":{"command":"mkdir -p /tmp/loop-bench-cfbvwgky/src","description":"Create src directory"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"0da1c0c9-209f-4855-b4fc-106fe8c9e26c"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_30e0d02f498244f885fc5c7c","type":"tool_result","content":"[rerun: b3]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"df1c8c12-50be-476a-8c3f-2f33c06c51bf","timestamp":"2026-04-07T01:43:38.033Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":true}} +{"type":"assistant","message":{"id":"msg_20260407094339da59a55332f24354","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_5adeefa201af416fafff6209","name":"Bash","input":{"command":"cat > tsconfig.json << 'TSEOF'\n{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ES2020\",\n \"outDir\": \"./dist\",\n \"rootDir\": \"./src\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"moduleResolution\": \"node\",\n \"declaration\": false,\n \"sourceMap\": false\n },\n \"include\": [\"src/**/*\"],\n \"exclude\": [\"node_modules\", \"dist\"]\n}\nTSEOF","description":"Create tsconfig.json"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"eb564c25-50ad-4f46-bebb-403112e022bf"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_5adeefa201af416fafff6209","type":"tool_result","content":"[rerun: b4]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"5fa55be3-ef96-4753-928a-af77f4972001","timestamp":"2026-04-07T01:43:47.755Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_20260407094348d4e8db00510342f4","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_de05f94fd6ad4010a6a6e63d","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-cfbvwgky/src/tetris.ts","old_string":"","new_string":"// ─── Types & Constants ────────────────────────────────────────────────\n\nconst COLS = 10;\nconst ROWS = 20;\nconst HIDDEN_ROWS = 2; // buffer rows above visible area\n\ntype CellColor = string | null;\ntype Board = CellColor[][];\n\ninterface Position {\n x: number;\n y: number;\n}\n\ninterface Piece {\n shape: number[][];\n color: string;\n pos: Position;\n}\n\n// Standard NES-style scoring\nconst LINE_SCORES = [0, 100, 300, 500, 800];\n\n// Gravity intervals in ms per level (index = level, faster as level increases)\nconst GRAVITY_TABLE = [\n 800, 720, 630, 550, 470, 380, 300, 220, 150, 100,\n 80, 80, 80, 70, 70, 70, 50, 50, 50, 30,\n];\n\nfunction getGravity(level: number): number {\n if (level < GRAVITY_TABLE.length) return GRAVITY_TABLE[level];\n return 20; // cap\n}\n\n// Tetromino definitions (shapes in their spawn orientation)\nconst TETROMINOES: { shape: number[][]; color: string }[] = [\n { shape: [[1, 1, 1, 1]], color: \"#00f0f0\" }, // I - cyan\n { shape: [[1, 1], [1, 1]], color: \"#f0f000\" }, // O - yellow\n { shape: [[0, 1, 0], [1, 1, 1]], color: \"#a000f0\" }, // T - purple\n { shape: [[0, 1, 1], [1, 1, 0]], color: \"#00f000\" }, // S - green\n { shape: [[1, 1, 0], [0, 1, 1]], color: \"#f00000\" }, // Z - red\n { shape: [[1, 0, 0], [1, 1, 1]], color: \"#0000f0\" }, // J - blue\n { shape: [[0, 0, 1], [1, 1, 1]], color: \"#f0a000\" }, // L - orange\n];\n\n// ─── Utility ──────────────────────────────────────────────────────────\n\nfunction createBoard(): Board {\n const rows = ROWS + HIDDEN_ROWS;\n const board: Board = [];\n for (let r = 0; r < rows; r++) {\n board.push(new Array<string | null>(COLS).fill(null));\n }\n return board;\n}\n\nfunction rotateMatrix(matrix: number[][]): number[][] {\n const rows = matrix.length;\n const cols = matrix[0].length;\n const result: number[][] = [];\n for (let c = 0; c < cols; c++) {\n const newRow: number[] = [];\n for (let r = rows - 1; r >= 0; r--) {\n newRow.push(matrix[r][c]);\n }\n result.push(newRow);\n }\n return result;\n}\n\n// Wall-kick offsets to try when rotation is blocked\nconst WALL_KICKS: Position[] = [\n { x: 0, y: 0 },\n { x: -1, y: 0 },\n { x: 1, y: 0 },\n { x: -2, y: 0 },\n { x: 2, y: 0 },\n { x: 0, y: -1 },\n { x: -1, y: -1 },\n { x: 1, y: -1 },\n];\n\n// ─── Bag Randomiser (7-bag) ───────────────────────────────────────────\n\nclass Bag {\n private bag: number[] = [];\n\n next(): number {\n if (this.bag.length === 0) {\n this.bag = [0, 1, 2, 3, 4, 5, 6];\n // Fisher-Yates shuffle\n for (let i = this.bag.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];\n }\n }\n return this.bag.pop()!;\n }\n}\n\n// ─── Game ─────────────────────────────────────────────────────────────\n\nclass TetrisGame {\n board: Board = createBoard();\n currentPiece: Piece | null = null;\n nextPieceIndex: number;\n bag = new Bag();\n score = 0;\n level = 0;\n linesCleared = 0;\n gameOver = false;\n paused = false;\n\n // Timing\n private lastTick = 0;\n private gravityInterval = getGravity(0);\n private animFrameId = 0;\n\n // DAS (Delayed Auto Shift) for held keys\n private dasDirection: \"left\" | \"right\" | \"down\" | null = null;\n private dasTimer = 0;\n private dasDelay = 170; // ms before auto-repeat starts\n private dasRate = 50; // ms between auto-repeats\n private dasActive = false;\n private keysDown = new Set<string>();\n\n // DOM references\n private boardEl: HTMLElement;\n private scoreEl: HTMLElement;\n private levelEl: HTMLElement;\n private linesEl: HTMLElement;\n private nextPieceEl: HTMLElement;\n private overlayEl: HTMLElement;\n private overlayTitleEl: HTMLElement;\n private overlaySubEl: HTMLElement;\n private cells: (HTMLElement | null)[][] = [];\n private nextCells: (HTMLElement | null)[][] = [];\n\n constructor() {\n this.nextPieceIndex = this.bag.next();\n\n // Grab DOM elements\n this.boardEl = document.getElementById(\"board\")!;\n this.scoreEl = document.getElementById(\"score\")!;\n this.levelEl = document.getElementById(\"level\")!;\n this.linesEl = document.getElementById(\"lines\")!;\n this.nextPieceEl = document.getElementById(\"next-piece\")!;\n this.overlayEl = document.getElementById(\"overlay\")!;\n this.overlayTitleEl = document.getElementById(\"overlay-title\")!;\n this.overlaySubEl = document.getElementById(\"overlay-sub\")!;\n\n this.buildBoardDOM();\n this.buildNextPieceDOM();\n\n // Input\n window.addEventListener(\"keydown\", (e) => this.onKeyDown(e));\n window.addEventListener(\"keyup\", (e) => this.onKeyUp(e));\n\n // Start\n this.spawnPiece();\n this.showOverlay(\"TETRIS\", \"Press any key to start\");\n this.draw();\n }\n\n // ── DOM Construction ──────────────────────────────────────────────\n\n private buildBoardDOM(): void {\n this.boardEl.innerHTML = \"\";\n this.cells = [];\n for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) {\n const rowCells: (HTMLElement | null)[] = [];\n const rowDiv = document.createElement(\"div\");\n rowDiv.className = \"board-row\";\n for (let c = 0; c < COLS; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"cell\";\n rowDiv.appendChild(cell);\n rowCells.push(cell);\n }\n this.boardEl.appendChild(rowDiv);\n this.cells.push(rowCells);\n }\n }\n\n private buildNextPieceDOM(): void {\n this.nextPieceEl.innerHTML = \"\";\n this.nextCells = [];\n for (let r = 0; r < 4; r++) {\n const rowCells: (HTMLElement | null)[] = [];\n const rowDiv = document.createElement(\"div\");\n rowDiv.className = \"next-row\";\n for (let c = 0; c < 4; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"next-cell\";\n rowDiv.appendChild(cell);\n rowCells.push(cell);\n }\n this.nextPieceEl.appendChild(rowDiv);\n this.nextCells.push(rowCells);\n }\n }\n\n // ── Overlay ───────────────────────────────────────────────────────\n\n private showOverlay(title: string, sub: string): void {\n this.overlayTitleEl.textContent = title;\n this.overlaySubEl.textContent = sub;\n this.overlayEl.classList.remove(\"hidden\");\n }\n\n private hideOverlay(): void {\n this.overlayEl.classList.add(\"hidden\");\n }\n\n // ── Game Loop ─────────────────────────────────────────────────────\n\n start(): void {\n this.hideOverlay();\n this.lastTick = performance.now();\n this.loop(this.lastTick);\n }\n\n private loop = (now: number): void => {\n if (this.gameOver) return;\n if (this.paused) {\n this.animFrameId = requestAnimationFrame(this.loop);\n return;\n }\n\n const dt = now - this.lastTick;\n\n // DAS handling\n this.handleDAS(now);\n\n // Gravity\n if (dt >= this.gravityInterval) {\n this.tick();\n this.lastTick = now;\n }\n\n this.draw();\n this.animFrameId = requestAnimationFrame(this.loop);\n };\n\n private tick(): void {\n if (!this.currentPiece || this.gameOver) return;\n if (!this.movePiece(0, 1)) {\n this.lockPiece();\n const cleared = this.clearLines();\n if (cleared > 0) {\n this.score += LINE_SCORES[cleared] * (this.level + 1);\n this.linesCleared += cleared;\n const newLevel = Math.floor(this.linesCleared / 10);\n if (newLevel > this.level) {\n this.level = newLevel;\n this.gravityInterval = getGravity(this.level);\n }\n }\n if (!this.spawnPiece()) {\n this.endGame();\n return;\n }\n }\n }\n\n // ── Piece Management ──────────────────────────────────────────────\n\n private spawnPiece(): boolean {\n const idx = this.nextPieceIndex;\n this.nextPieceIndex = this.bag.next();\n const t = TETROMINOES[idx];\n const shape = t.shape.map((row) => [...row]);\n const piece: Piece = {\n shape,\n color: t.color,\n pos: {\n x: Math.floor((COLS - shape[0].length) / 2),\n y: 0,\n },\n };\n this.currentPiece = piece;\n if (!this.isValid(piece.shape, piece.pos)) {\n return false;\n }\n return true;\n }\n\n private lockPiece(): void {\n if (!this.currentPiece) return;\n const { shape, pos, color } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (shape[r][c]) {\n const br = pos.y + r;\n const bc = pos.x + c;\n if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) {\n this.board[br][bc] = color;\n }\n }\n }\n }\n }\n\n private clearLines(): number {\n let cleared = 0;\n for (let r = this.board.length - 1; r >= 0; r--) {\n if (this.board[r].every((cell) => cell !== null)) {\n this.board.splice(r, 1);\n this.board.unshift(new Array<string | null>(COLS).fill(null));\n cleared++;\n r++; // recheck same index\n }\n }\n return cleared;\n }\n\n // ── Collision ─────────────────────────────────────────────────────\n\n private isValid(shape: number[][], pos: Position): boolean {\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = pos.y + r;\n const bc = pos.x + c;\n if (bc < 0 || bc >= COLS || br >= this.board.length) return false;\n if (br < 0) continue; // above board is OK\n if (this.board[br][bc] !== null) return false;\n }\n }\n return true;\n }\n\n // ── Movement ──────────────────────────────────────────────────────\n\n movePiece(dx: number, dy: number): boolean {\n if (!this.currentPiece) return false;\n const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy };\n if (this.isValid(this.currentPiece.shape, newPos)) {\n this.currentPiece.pos = newPos;\n return true;\n }\n return false;\n }\n\n private rotatePiece(): void {\n if (!this.currentPiece) return;\n const rotated = rotateMatrix(this.currentPiece.shape);\n // Try wall kicks\n for (const kick of WALL_KICKS) {\n const testPos = {\n x: this.currentPiece.pos.x + kick.x,\n y: this.currentPiece.pos.y + kick.y,\n };\n if (this.isValid(rotated, testPos)) {\n this.currentPiece.shape = rotated;\n this.currentPiece.pos = testPos;\n return;\n }\n }\n }\n\n private hardDrop(): void {\n if (!this.currentPiece) return;\n let dropped = 0;\n while (this.movePiece(0, 1)) dropped++;\n this.score += dropped * 2;\n this.lockPiece();\n const cleared = this.clearLines();\n if (cleared > 0) {\n this.score += LINE_SCORES[cleared] * (this.level + 1);\n this.linesCleared += cleared;\n const newLevel = Math.floor(this.linesCleared / 10);\n if (newLevel > this.level) {\n this.level = newLevel;\n this.gravityInterval = getGravity(this.level);\n }\n }\n if (!this.spawnPiece()) {\n this.endGame();\n return;\n }\n this.lastTick = performance.now();\n this.draw();\n }\n\n private getGhostPosition(): Position | null {\n if (!this.currentPiece) return null;\n let ghostY = this.currentPiece.pos.y;\n while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) {\n ghostY++;\n }\n return { x: this.currentPiece.pos.x, y: ghostY };\n }\n\n // ── Input Handling ────────────────────────────────────────────────\n\n private started = false;\n\n private onKeyDown(e: KeyboardEvent): void {\n if (!this.started) {\n this.started = true;\n this.start();\n return;\n }\n\n if (this.gameOver) return;\n\n if (e.code === \"KeyP\") {\n this.paused = !this.paused;\n if (this.paused) {\n this.showOverlay(\"PAUSED\", \"Press P to resume\");\n } else {\n this.hideOverlay();\n this.lastTick = performance.now();\n }\n return;\n }\n\n if (this.paused) return;\n\n this.keysDown.add(e.code);\n\n switch (e.code) {\n case \"ArrowLeft\":\n e.preventDefault();\n this.movePiece(-1, 0);\n this.dasDirection = \"left\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowRight\":\n e.preventDefault();\n this.movePiece(1, 0);\n this.dasDirection = \"right\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowDown\":\n e.preventDefault();\n if (this.movePiece(0, 1)) this.score += 1;\n this.dasDirection = \"down\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowUp\":\n case \"KeyX\":\n e.preventDefault();\n this.rotatePiece();\n break;\n case \"Space\":\n e.preventDefault();\n this.hardDrop();\n break;\n }\n }\n\n private onKeyUp(e: KeyboardEvent): void {\n this.keysDown.delete(e.code);\n // If the key released matches current DAS direction, stop DAS\n if (\n (e.code === \"ArrowLeft\" && this.dasDirection === \"left\") ||\n (e.code === \"ArrowRight\" && this.dasDirection === \"right\") ||\n (e.code === \"ArrowDown\" && this.dasDirection === \"down\")\n ) {\n this.dasDirection = null;\n }\n }\n\n private handleDAS(now: number): void {\n if (!this.dasDirection) return;\n // Check if the key is still held\n const codeMap = { left: \"ArrowLeft\", right: \"ArrowRight\", down: \"ArrowDown\" };\n if (!this.keysDown.has(codeMap[this.dasDirection])) {\n this.dasDirection = null;\n return;\n }\n\n const elapsed = now - this.dasTimer;\n if (!this.dasActive) {\n if (elapsed >= this.dasDelay) {\n this.dasActive = true;\n this.dasTimer = now;\n this.dasRepeat();\n }\n } else {\n if (elapsed >= this.dasRate) {\n this.dasTimer = now;\n this.dasRepeat();\n }\n }\n }\n\n private dasRepeat(): void {\n switch (this.dasDirection) {\n case \"left\":\n this.movePiece(-1, 0);\n break;\n case \"right\":\n this.movePiece(1, 0);\n break;\n case \"down\":\n if (this.movePiece(0, 1)) this.score += 1;\n break;\n }\n }\n\n // ── End Game ──────────────────────────────────────────────────────\n\n private endGame(): void {\n this.gameOver = true;\n cancelAnimationFrame(this.animFrameId);\n this.draw();\n this.showOverlay(\"GAME OVER\", `Final score: ${this.score.toLocaleString()}\\nPress R to restart`);\n }\n\n restart(): void {\n this.board = createBoard();\n this.score = 0;\n this.level = 0;\n this.linesCleared = 0;\n this.gameOver = false;\n this.paused = false;\n this.currentPiece = null;\n this.bag = new Bag();\n this.nextPieceIndex = this.bag.next();\n this.gravityInterval = getGravity(0);\n this.dasDirection = null;\n this.keysDown.clear();\n this.spawnPiece();\n this.hideOverlay();\n this.lastTick = performance.now();\n this.draw();\n this.loop(this.lastTick);\n }\n\n // ── Rendering ─────────────────────────────────────────────────────\n\n private draw(): void {\n // Draw board\n for (let r = 0; r < ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = this.cells[r][c];\n if (!cell) continue;\n const boardColor = this.board[r + HIDDEN_ROWS][c];\n cell.style.backgroundColor = boardColor ?? \"\";\n cell.className = \"cell\" + (boardColor ? \" filled\" : \"\");\n }\n }\n\n // Draw ghost piece\n const ghost = this.getGhostPosition();\n if (this.currentPiece && ghost && !this.gameOver) {\n const { shape } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = ghost.y + r - HIDDEN_ROWS;\n const bc = ghost.x + c;\n if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n const cell = this.cells[br][bc];\n if (cell && !this.board[br + HIDDEN_ROWS][bc]) {\n cell.style.backgroundColor = this.currentPiece.color;\n cell.className = \"cell ghost\";\n }\n }\n }\n }\n }\n\n // Draw current piece\n if (this.currentPiece && !this.gameOver) {\n const { shape, pos, color } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = pos.y + r - HIDDEN_ROWS;\n const bc = pos.x + c;\n if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n const cell = this.cells[br][bc];\n if (cell) {\n cell.style.backgroundColor = color;\n cell.className = \"cell active\";\n }\n }\n }\n }\n }\n\n // Draw next piece preview\n const nextT = TETROMINOES[this.nextPieceIndex];\n const nextShape = nextT.shape;\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n const cell = this.nextCells[r][c];\n if (!cell) continue;\n const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1;\n cell.style.backgroundColor = filled ? nextT.color : \"\";\n cell.className = \"next-cell\" + (filled ? \" filled\" : \"\");\n }\n }\n\n // Update HUD\n this.scoreEl.textContent = this.score.toLocaleString();\n this.levelEl.textContent = String(this.level);\n this.linesEl.textContent = String(this.linesCleared);\n }\n}\n\n// ─── Bootstrap ────────────────────────────────────────────────────────\n\nlet game: TetrisGame;\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n game = new TetrisGame();\n\n window.addEventListener(\"keydown\", (e) => {\n if (e.code === \"KeyR\" && game.gameOver) {\n game.restart();\n }\n });\n});"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"807f9363-547a-440e-a1b0-e64108e122a3"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_de05f94fd6ad4010a6a6e63d","type":"tool_result","content":"The file /tmp/loop-bench-cfbvwgky/src/tetris.ts has been updated successfully."}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"16ea2487-120b-4c06-83ae-b30856575e51","timestamp":"2026-04-07T01:46:34.123Z","tool_use_result":{"filePath":"/tmp/loop-bench-cfbvwgky/src/tetris.ts","oldString":"","newString":"// ─── Types & Constants ────────────────────────────────────────────────\n\nconst COLS = 10;\nconst ROWS = 20;\nconst HIDDEN_ROWS = 2; // buffer rows above visible area\n\ntype CellColor = string | null;\ntype Board = CellColor[][];\n\ninterface Position {\n x: number;\n y: number;\n}\n\ninterface Piece {\n shape: number[][];\n color: string;\n pos: Position;\n}\n\n// Standard NES-style scoring\nconst LINE_SCORES = [0, 100, 300, 500, 800];\n\n// Gravity intervals in ms per level (index = level, faster as level increases)\nconst GRAVITY_TABLE = [\n 800, 720, 630, 550, 470, 380, 300, 220, 150, 100,\n 80, 80, 80, 70, 70, 70, 50, 50, 50, 30,\n];\n\nfunction getGravity(level: number): number {\n if (level < GRAVITY_TABLE.length) return GRAVITY_TABLE[level];\n return 20; // cap\n}\n\n// Tetromino definitions (shapes in their spawn orientation)\nconst TETROMINOES: { shape: number[][]; color: string }[] = [\n { shape: [[1, 1, 1, 1]], color: \"#00f0f0\" }, // I - cyan\n { shape: [[1, 1], [1, 1]], color: \"#f0f000\" }, // O - yellow\n { shape: [[0, 1, 0], [1, 1, 1]], color: \"#a000f0\" }, // T - purple\n { shape: [[0, 1, 1], [1, 1, 0]], color: \"#00f000\" }, // S - green\n { shape: [[1, 1, 0], [0, 1, 1]], color: \"#f00000\" }, // Z - red\n { shape: [[1, 0, 0], [1, 1, 1]], color: \"#0000f0\" }, // J - blue\n { shape: [[0, 0, 1], [1, 1, 1]], color: \"#f0a000\" }, // L - orange\n];\n\n// ─── Utility ──────────────────────────────────────────────────────────\n\nfunction createBoard(): Board {\n const rows = ROWS + HIDDEN_ROWS;\n const board: Board = [];\n for (let r = 0; r < rows; r++) {\n board.push(new Array<string | null>(COLS).fill(null));\n }\n return board;\n}\n\nfunction rotateMatrix(matrix: number[][]): number[][] {\n const rows = matrix.length;\n const cols = matrix[0].length;\n const result: number[][] = [];\n for (let c = 0; c < cols; c++) {\n const newRow: number[] = [];\n for (let r = rows - 1; r >= 0; r--) {\n newRow.push(matrix[r][c]);\n }\n result.push(newRow);\n }\n return result;\n}\n\n// Wall-kick offsets to try when rotation is blocked\nconst WALL_KICKS: Position[] = [\n { x: 0, y: 0 },\n { x: -1, y: 0 },\n { x: 1, y: 0 },\n { x: -2, y: 0 },\n { x: 2, y: 0 },\n { x: 0, y: -1 },\n { x: -1, y: -1 },\n { x: 1, y: -1 },\n];\n\n// ─── Bag Randomiser (7-bag) ───────────────────────────────────────────\n\nclass Bag {\n private bag: number[] = [];\n\n next(): number {\n if (this.bag.length === 0) {\n this.bag = [0, 1, 2, 3, 4, 5, 6];\n // Fisher-Yates shuffle\n for (let i = this.bag.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];\n }\n }\n return this.bag.pop()!;\n }\n}\n\n// ─── Game ─────────────────────────────────────────────────────────────\n\nclass TetrisGame {\n board: Board = createBoard();\n currentPiece: Piece | null = null;\n nextPieceIndex: number;\n bag = new Bag();\n score = 0;\n level = 0;\n linesCleared = 0;\n gameOver = false;\n paused = false;\n\n // Timing\n private lastTick = 0;\n private gravityInterval = getGravity(0);\n private animFrameId = 0;\n\n // DAS (Delayed Auto Shift) for held keys\n private dasDirection: \"left\" | \"right\" | \"down\" | null = null;\n private dasTimer = 0;\n private dasDelay = 170; // ms before auto-repeat starts\n private dasRate = 50; // ms between auto-repeats\n private dasActive = false;\n private keysDown = new Set<string>();\n\n // DOM references\n private boardEl: HTMLElement;\n private scoreEl: HTMLElement;\n private levelEl: HTMLElement;\n private linesEl: HTMLElement;\n private nextPieceEl: HTMLElement;\n private overlayEl: HTMLElement;\n private overlayTitleEl: HTMLElement;\n private overlaySubEl: HTMLElement;\n private cells: (HTMLElement | null)[][] = [];\n private nextCells: (HTMLElement | null)[][] = [];\n\n constructor() {\n this.nextPieceIndex = this.bag.next();\n\n // Grab DOM elements\n this.boardEl = document.getElementById(\"board\")!;\n this.scoreEl = document.getElementById(\"score\")!;\n this.levelEl = document.getElementById(\"level\")!;\n this.linesEl = document.getElementById(\"lines\")!;\n this.nextPieceEl = document.getElementById(\"next-piece\")!;\n this.overlayEl = document.getElementById(\"overlay\")!;\n this.overlayTitleEl = document.getElementById(\"overlay-title\")!;\n this.overlaySubEl = document.getElementById(\"overlay-sub\")!;\n\n this.buildBoardDOM();\n this.buildNextPieceDOM();\n\n // Input\n window.addEventListener(\"keydown\", (e) => this.onKeyDown(e));\n window.addEventListener(\"keyup\", (e) => this.onKeyUp(e));\n\n // Start\n this.spawnPiece();\n this.showOverlay(\"TETRIS\", \"Press any key to start\");\n this.draw();\n }\n\n // ── DOM Construction ──────────────────────────────────────────────\n\n private buildBoardDOM(): void {\n this.boardEl.innerHTML = \"\";\n this.cells = [];\n for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) {\n const rowCells: (HTMLElement | null)[] = [];\n const rowDiv = document.createElement(\"div\");\n rowDiv.className = \"board-row\";\n for (let c = 0; c < COLS; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"cell\";\n rowDiv.appendChild(cell);\n rowCells.push(cell);\n }\n this.boardEl.appendChild(rowDiv);\n this.cells.push(rowCells);\n }\n }\n\n private buildNextPieceDOM(): void {\n this.nextPieceEl.innerHTML = \"\";\n this.nextCells = [];\n for (let r = 0; r < 4; r++) {\n const rowCells: (HTMLElement | null)[] = [];\n const rowDiv = document.createElement(\"div\");\n rowDiv.className = \"next-row\";\n for (let c = 0; c < 4; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"next-cell\";\n rowDiv.appendChild(cell);\n rowCells.push(cell);\n }\n this.nextPieceEl.appendChild(rowDiv);\n this.nextCells.push(rowCells);\n }\n }\n\n // ── Overlay ───────────────────────────────────────────────────────\n\n private showOverlay(title: string, sub: string): void {\n this.overlayTitleEl.textContent = title;\n this.overlaySubEl.textContent = sub;\n this.overlayEl.classList.remove(\"hidden\");\n }\n\n private hideOverlay(): void {\n this.overlayEl.classList.add(\"hidden\");\n }\n\n // ── Game Loop ─────────────────────────────────────────────────────\n\n start(): void {\n this.hideOverlay();\n this.lastTick = performance.now();\n this.loop(this.lastTick);\n }\n\n private loop = (now: number): void => {\n if (this.gameOver) return;\n if (this.paused) {\n this.animFrameId = requestAnimationFrame(this.loop);\n return;\n }\n\n const dt = now - this.lastTick;\n\n // DAS handling\n this.handleDAS(now);\n\n // Gravity\n if (dt >= this.gravityInterval) {\n this.tick();\n this.lastTick = now;\n }\n\n this.draw();\n this.animFrameId = requestAnimationFrame(this.loop);\n };\n\n private tick(): void {\n if (!this.currentPiece || this.gameOver) return;\n if (!this.movePiece(0, 1)) {\n this.lockPiece();\n const cleared = this.clearLines();\n if (cleared > 0) {\n this.score += LINE_SCORES[cleared] * (this.level + 1);\n this.linesCleared += cleared;\n const newLevel = Math.floor(this.linesCleared / 10);\n if (newLevel > this.level) {\n this.level = newLevel;\n this.gravityInterval = getGravity(this.level);\n }\n }\n if (!this.spawnPiece()) {\n this.endGame();\n return;\n }\n }\n }\n\n // ── Piece Management ──────────────────────────────────────────────\n\n private spawnPiece(): boolean {\n const idx = this.nextPieceIndex;\n this.nextPieceIndex = this.bag.next();\n const t = TETROMINOES[idx];\n const shape = t.shape.map((row) => [...row]);\n const piece: Piece = {\n shape,\n color: t.color,\n pos: {\n x: Math.floor((COLS - shape[0].length) / 2),\n y: 0,\n },\n };\n this.currentPiece = piece;\n if (!this.isValid(piece.shape, piece.pos)) {\n return false;\n }\n return true;\n }\n\n private lockPiece(): void {\n if (!this.currentPiece) return;\n const { shape, pos, color } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (shape[r][c]) {\n const br = pos.y + r;\n const bc = pos.x + c;\n if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) {\n this.board[br][bc] = color;\n }\n }\n }\n }\n }\n\n private clearLines(): number {\n let cleared = 0;\n for (let r = this.board.length - 1; r >= 0; r--) {\n if (this.board[r].every((cell) => cell !== null)) {\n this.board.splice(r, 1);\n this.board.unshift(new Array<string | null>(COLS).fill(null));\n cleared++;\n r++; // recheck same index\n }\n }\n return cleared;\n }\n\n // ── Collision ─────────────────────────────────────────────────────\n\n private isValid(shape: number[][], pos: Position): boolean {\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = pos.y + r;\n const bc = pos.x + c;\n if (bc < 0 || bc >= COLS || br >= this.board.length) return false;\n if (br < 0) continue; // above board is OK\n if (this.board[br][bc] !== null) return false;\n }\n }\n return true;\n }\n\n // ── Movement ──────────────────────────────────────────────────────\n\n movePiece(dx: number, dy: number): boolean {\n if (!this.currentPiece) return false;\n const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy };\n if (this.isValid(this.currentPiece.shape, newPos)) {\n this.currentPiece.pos = newPos;\n return true;\n }\n return false;\n }\n\n private rotatePiece(): void {\n if (!this.currentPiece) return;\n const rotated = rotateMatrix(this.currentPiece.shape);\n // Try wall kicks\n for (const kick of WALL_KICKS) {\n const testPos = {\n x: this.currentPiece.pos.x + kick.x,\n y: this.currentPiece.pos.y + kick.y,\n };\n if (this.isValid(rotated, testPos)) {\n this.currentPiece.shape = rotated;\n this.currentPiece.pos = testPos;\n return;\n }\n }\n }\n\n private hardDrop(): void {\n if (!this.currentPiece) return;\n let dropped = 0;\n while (this.movePiece(0, 1)) dropped++;\n this.score += dropped * 2;\n this.lockPiece();\n const cleared = this.clearLines();\n if (cleared > 0) {\n this.score += LINE_SCORES[cleared] * (this.level + 1);\n this.linesCleared += cleared;\n const newLevel = Math.floor(this.linesCleared / 10);\n if (newLevel > this.level) {\n this.level = newLevel;\n this.gravityInterval = getGravity(this.level);\n }\n }\n if (!this.spawnPiece()) {\n this.endGame();\n return;\n }\n this.lastTick = performance.now();\n this.draw();\n }\n\n private getGhostPosition(): Position | null {\n if (!this.currentPiece) return null;\n let ghostY = this.currentPiece.pos.y;\n while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) {\n ghostY++;\n }\n return { x: this.currentPiece.pos.x, y: ghostY };\n }\n\n // ── Input Handling ────────────────────────────────────────────────\n\n private started = false;\n\n private onKeyDown(e: KeyboardEvent): void {\n if (!this.started) {\n this.started = true;\n this.start();\n return;\n }\n\n if (this.gameOver) return;\n\n if (e.code === \"KeyP\") {\n this.paused = !this.paused;\n if (this.paused) {\n this.showOverlay(\"PAUSED\", \"Press P to resume\");\n } else {\n this.hideOverlay();\n this.lastTick = performance.now();\n }\n return;\n }\n\n if (this.paused) return;\n\n this.keysDown.add(e.code);\n\n switch (e.code) {\n case \"ArrowLeft\":\n e.preventDefault();\n this.movePiece(-1, 0);\n this.dasDirection = \"left\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowRight\":\n e.preventDefault();\n this.movePiece(1, 0);\n this.dasDirection = \"right\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowDown\":\n e.preventDefault();\n if (this.movePiece(0, 1)) this.score += 1;\n this.dasDirection = \"down\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowUp\":\n case \"KeyX\":\n e.preventDefault();\n this.rotatePiece();\n break;\n case \"Space\":\n e.preventDefault();\n this.hardDrop();\n break;\n }\n }\n\n private onKeyUp(e: KeyboardEvent): void {\n this.keysDown.delete(e.code);\n // If the key released matches current DAS direction, stop DAS\n if (\n (e.code === \"ArrowLeft\" && this.dasDirection === \"left\") ||\n (e.code === \"ArrowRight\" && this.dasDirection === \"right\") ||\n (e.code === \"ArrowDown\" && this.dasDirection === \"down\")\n ) {\n this.dasDirection = null;\n }\n }\n\n private handleDAS(now: number): void {\n if (!this.dasDirection) return;\n // Check if the key is still held\n const codeMap = { left: \"ArrowLeft\", right: \"ArrowRight\", down: \"ArrowDown\" };\n if (!this.keysDown.has(codeMap[this.dasDirection])) {\n this.dasDirection = null;\n return;\n }\n\n const elapsed = now - this.dasTimer;\n if (!this.dasActive) {\n if (elapsed >= this.dasDelay) {\n this.dasActive = true;\n this.dasTimer = now;\n this.dasRepeat();\n }\n } else {\n if (elapsed >= this.dasRate) {\n this.dasTimer = now;\n this.dasRepeat();\n }\n }\n }\n\n private dasRepeat(): void {\n switch (this.dasDirection) {\n case \"left\":\n this.movePiece(-1, 0);\n break;\n case \"right\":\n this.movePiece(1, 0);\n break;\n case \"down\":\n if (this.movePiece(0, 1)) this.score += 1;\n break;\n }\n }\n\n // ── End Game ──────────────────────────────────────────────────────\n\n private endGame(): void {\n this.gameOver = true;\n cancelAnimationFrame(this.animFrameId);\n this.draw();\n this.showOverlay(\"GAME OVER\", `Final score: ${this.score.toLocaleString()}\\nPress R to restart`);\n }\n\n restart(): void {\n this.board = createBoard();\n this.score = 0;\n this.level = 0;\n this.linesCleared = 0;\n this.gameOver = false;\n this.paused = false;\n this.currentPiece = null;\n this.bag = new Bag();\n this.nextPieceIndex = this.bag.next();\n this.gravityInterval = getGravity(0);\n this.dasDirection = null;\n this.keysDown.clear();\n this.spawnPiece();\n this.hideOverlay();\n this.lastTick = performance.now();\n this.draw();\n this.loop(this.lastTick);\n }\n\n // ── Rendering ─────────────────────────────────────────────────────\n\n private draw(): void {\n // Draw board\n for (let r = 0; r < ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = this.cells[r][c];\n if (!cell) continue;\n const boardColor = this.board[r + HIDDEN_ROWS][c];\n cell.style.backgroundColor = boardColor ?? \"\";\n cell.className = \"cell\" + (boardColor ? \" filled\" : \"\");\n }\n }\n\n // Draw ghost piece\n const ghost = this.getGhostPosition();\n if (this.currentPiece && ghost && !this.gameOver) {\n const { shape } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = ghost.y + r - HIDDEN_ROWS;\n const bc = ghost.x + c;\n if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n const cell = this.cells[br][bc];\n if (cell && !this.board[br + HIDDEN_ROWS][bc]) {\n cell.style.backgroundColor = this.currentPiece.color;\n cell.className = \"cell ghost\";\n }\n }\n }\n }\n }\n\n // Draw current piece\n if (this.currentPiece && !this.gameOver) {\n const { shape, pos, color } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = pos.y + r - HIDDEN_ROWS;\n const bc = pos.x + c;\n if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n const cell = this.cells[br][bc];\n if (cell) {\n cell.style.backgroundColor = color;\n cell.className = \"cell active\";\n }\n }\n }\n }\n }\n\n // Draw next piece preview\n const nextT = TETROMINOES[this.nextPieceIndex];\n const nextShape = nextT.shape;\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n const cell = this.nextCells[r][c];\n if (!cell) continue;\n const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1;\n cell.style.backgroundColor = filled ? nextT.color : \"\";\n cell.className = \"next-cell\" + (filled ? \" filled\" : \"\");\n }\n }\n\n // Update HUD\n this.scoreEl.textContent = this.score.toLocaleString();\n this.levelEl.textContent = String(this.level);\n this.linesEl.textContent = String(this.linesCleared);\n }\n}\n\n// ─── Bootstrap ────────────────────────────────────────────────────────\n\nlet game: TetrisGame;\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n game = new TetrisGame();\n\n window.addEventListener(\"keydown\", (e) => {\n if (e.code === \"KeyR\" && game.gameOver) {\n game.restart();\n }\n });\n});","originalFile":"","structuredPatch":[{"oldStart":1,"oldLines":0,"newStart":1,"newLines":621,"lines":["+// ─── Types & Constants ────────────────────────────────────────────────","+","+const COLS = 10;","+const ROWS = 20;","+const HIDDEN_ROWS = 2; // buffer rows above visible area","+","+type CellColor = string | null;","+type Board = CellColor[][];","+","+interface Position {","+ x: number;","+ y: number;","+}","+","+interface Piece {","+ shape: number[][];","+ color: string;","+ pos: Position;","+}","+","+// Standard NES-style scoring","+const LINE_SCORES = [0, 100, 300, 500, 800];","+","+// Gravity intervals in ms per level (index = level, faster as level increases)","+const GRAVITY_TABLE = [","+ 800, 720, 630, 550, 470, 380, 300, 220, 150, 100,","+ 80, 80, 80, 70, 70, 70, 50, 50, 50, 30,","+];","+","+function getGravity(level: number): number {","+ if (level < GRAVITY_TABLE.length) return GRAVITY_TABLE[level];","+ return 20; // cap","+}","+","+// Tetromino definitions (shapes in their spawn orientation)","+const TETROMINOES: { shape: number[][]; color: string }[] = [","+ { shape: [[1, 1, 1, 1]], color: \"#00f0f0\" }, // I - cyan","+ { shape: [[1, 1], [1, 1]], color: \"#f0f000\" }, // O - yellow","+ { shape: [[0, 1, 0], [1, 1, 1]], color: \"#a000f0\" }, // T - purple","+ { shape: [[0, 1, 1], [1, 1, 0]], color: \"#00f000\" }, // S - green","+ { shape: [[1, 1, 0], [0, 1, 1]], color: \"#f00000\" }, // Z - red","+ { shape: [[1, 0, 0], [1, 1, 1]], color: \"#0000f0\" }, // J - blue","+ { shape: [[0, 0, 1], [1, 1, 1]], color: \"#f0a000\" }, // L - orange","+];","+","+// ─── Utility ──────────────────────────────────────────────────────────","+","+function createBoard(): Board {","+ const rows = ROWS + HIDDEN_ROWS;","+ const board: Board = [];","+ for (let r = 0; r < rows; r++) {","+ board.push(new Array<string | null>(COLS).fill(null));","+ }","+ return board;","+}","+","+function rotateMatrix(matrix: number[][]): number[][] {","+ const rows = matrix.length;","+ const cols = matrix[0].length;","+ const result: number[][] = [];","+ for (let c = 0; c < cols; c++) {","+ const newRow: number[] = [];","+ for (let r = rows - 1; r >= 0; r--) {","+ newRow.push(matrix[r][c]);","+ }","+ result.push(newRow);","+ }","+ return result;","+}","+","+// Wall-kick offsets to try when rotation is blocked","+const WALL_KICKS: Position[] = [","+ { x: 0, y: 0 },","+ { x: -1, y: 0 },","+ { x: 1, y: 0 },","+ { x: -2, y: 0 },","+ { x: 2, y: 0 },","+ { x: 0, y: -1 },","+ { x: -1, y: -1 },","+ { x: 1, y: -1 },","+];","+","+// ─── Bag Randomiser (7-bag) ───────────────────────────────────────────","+","+class Bag {","+ private bag: number[] = [];","+","+ next(): number {","+ if (this.bag.length === 0) {","+ this.bag = [0, 1, 2, 3, 4, 5, 6];","+ // Fisher-Yates shuffle","+ for (let i = this.bag.length - 1; i > 0; i--) {","+ const j = Math.floor(Math.random() * (i + 1));","+ [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];","+ }","+ }","+ return this.bag.pop()!;","+ }","+}","+","+// ─── Game ─────────────────────────────────────────────────────────────","+","+class TetrisGame {","+ board: Board = createBoard();","+ currentPiece: Piece | null = null;","+ nextPieceIndex: number;","+ bag = new Bag();","+ score = 0;","+ level = 0;","+ linesCleared = 0;","+ gameOver = false;","+ paused = false;","+","+ // Timing","+ private lastTick = 0;","+ private gravityInterval = getGravity(0);","+ private animFrameId = 0;","+","+ // DAS (Delayed Auto Shift) for held keys","+ private dasDirection: \"left\" | \"right\" | \"down\" | null = null;","+ private dasTimer = 0;","+ private dasDelay = 170; // ms before auto-repeat starts","+ private dasRate = 50; // ms between auto-repeats","+ private dasActive = false;","+ private keysDown = new Set<string>();","+","+ // DOM references","+ private boardEl: HTMLElement;","+ private scoreEl: HTMLElement;","+ private levelEl: HTMLElement;","+ private linesEl: HTMLElement;","+ private nextPieceEl: HTMLElement;","+ private overlayEl: HTMLElement;","+ private overlayTitleEl: HTMLElement;","+ private overlaySubEl: HTMLElement;","+ private cells: (HTMLElement | null)[][] = [];","+ private nextCells: (HTMLElement | null)[][] = [];","+","+ constructor() {","+ this.nextPieceIndex = this.bag.next();","+","+ // Grab DOM elements","+ this.boardEl = document.getElementById(\"board\")!;","+ this.scoreEl = document.getElementById(\"score\")!;","+ this.levelEl = document.getElementById(\"level\")!;","+ this.linesEl = document.getElementById(\"lines\")!;","+ this.nextPieceEl = document.getElementById(\"next-piece\")!;","+ this.overlayEl = document.getElementById(\"overlay\")!;","+ this.overlayTitleEl = document.getElementById(\"overlay-title\")!;","+ this.overlaySubEl = document.getElementById(\"overlay-sub\")!;","+","+ this.buildBoardDOM();","+ this.buildNextPieceDOM();","+","+ // Input","+ window.addEventListener(\"keydown\", (e) => this.onKeyDown(e));","+ window.addEventListener(\"keyup\", (e) => this.onKeyUp(e));","+","+ // Start","+ this.spawnPiece();","+ this.showOverlay(\"TETRIS\", \"Press any key to start\");","+ this.draw();","+ }","+","+ // ── DOM Construction ──────────────────────────────────────────────","+","+ private buildBoardDOM(): void {","+ this.boardEl.innerHTML = \"\";","+ this.cells = [];","+ for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) {","+ const rowCells: (HTMLElement | null)[] = [];","+ const rowDiv = document.createElement(\"div\");","+ rowDiv.className = \"board-row\";","+ for (let c = 0; c < COLS; c++) {","+ const cell = document.createElement(\"div\");","+ cell.className = \"cell\";","+ rowDiv.appendChild(cell);","+ rowCells.push(cell);","+ }","+ this.boardEl.appendChild(rowDiv);","+ this.cells.push(rowCells);","+ }","+ }","+","+ private buildNextPieceDOM(): void {","+ this.nextPieceEl.innerHTML = \"\";","+ this.nextCells = [];","+ for (let r = 0; r < 4; r++) {","+ const rowCells: (HTMLElement | null)[] = [];","+ const rowDiv = document.createElement(\"div\");","+ rowDiv.className = \"next-row\";","+ for (let c = 0; c < 4; c++) {","+ const cell = document.createElement(\"div\");","+ cell.className = \"next-cell\";","+ rowDiv.appendChild(cell);","+ rowCells.push(cell);","+ }","+ this.nextPieceEl.appendChild(rowDiv);","+ this.nextCells.push(rowCells);","+ }","+ }","+","+ // ── Overlay ───────────────────────────────────────────────────────","+","+ private showOverlay(title: string, sub: string): void {","+ this.overlayTitleEl.textContent = title;","+ this.overlaySubEl.textContent = sub;","+ this.overlayEl.classList.remove(\"hidden\");","+ }","+","+ private hideOverlay(): void {","+ this.overlayEl.classList.add(\"hidden\");","+ }","+","+ // ── Game Loop ─────────────────────────────────────────────────────","+","+ start(): void {","+ this.hideOverlay();","+ this.lastTick = performance.now();","+ this.loop(this.lastTick);","+ }","+","+ private loop = (now: number): void => {","+ if (this.gameOver) return;","+ if (this.paused) {","+ this.animFrameId = requestAnimationFrame(this.loop);","+ return;","+ }","+","+ const dt = now - this.lastTick;","+","+ // DAS handling","+ this.handleDAS(now);","+","+ // Gravity","+ if (dt >= this.gravityInterval) {","+ this.tick();","+ this.lastTick = now;","+ }","+","+ this.draw();","+ this.animFrameId = requestAnimationFrame(this.loop);","+ };","+","+ private tick(): void {","+ if (!this.currentPiece || this.gameOver) return;","+ if (!this.movePiece(0, 1)) {","+ this.lockPiece();","+ const cleared = this.clearLines();","+ if (cleared > 0) {","+ this.score += LINE_SCORES[cleared] * (this.level + 1);","+ this.linesCleared += cleared;","+ const newLevel = Math.floor(this.linesCleared / 10);","+ if (newLevel > this.level) {","+ this.level = newLevel;","+ this.gravityInterval = getGravity(this.level);","+ }","+ }","+ if (!this.spawnPiece()) {","+ this.endGame();","+ return;","+ }","+ }","+ }","+","+ // ── Piece Management ──────────────────────────────────────────────","+","+ private spawnPiece(): boolean {","+ const idx = this.nextPieceIndex;","+ this.nextPieceIndex = this.bag.next();","+ const t = TETROMINOES[idx];","+ const shape = t.shape.map((row) => [...row]);","+ const piece: Piece = {","+ shape,","+ color: t.color,","+ pos: {","+ x: Math.floor((COLS - shape[0].length) / 2),","+ y: 0,","+ },","+ };","+ this.currentPiece = piece;","+ if (!this.isValid(piece.shape, piece.pos)) {","+ return false;","+ }","+ return true;","+ }","+","+ private lockPiece(): void {","+ if (!this.currentPiece) return;","+ const { shape, pos, color } = this.currentPiece;","+ for (let r = 0; r < shape.length; r++) {","+ for (let c = 0; c < shape[r].length; c++) {","+ if (shape[r][c]) {","+ const br = pos.y + r;","+ const bc = pos.x + c;","+ if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) {","+ this.board[br][bc] = color;","+ }","+ }","+ }","+ }","+ }","+","+ private clearLines(): number {","+ let cleared = 0;","+ for (let r = this.board.length - 1; r >= 0; r--) {","+ if (this.board[r].every((cell) => cell !== null)) {","+ this.board.splice(r, 1);","+ this.board.unshift(new Array<string | null>(COLS).fill(null));","+ cleared++;","+ r++; // recheck same index","+ }","+ }","+ return cleared;","+ }","+","+ // ── Collision ─────────────────────────────────────────────────────","+","+ private isValid(shape: number[][], pos: Position): boolean {","+ for (let r = 0; r < shape.length; r++) {","+ for (let c = 0; c < shape[r].length; c++) {","+ if (!shape[r][c]) continue;","+ const br = pos.y + r;","+ const bc = pos.x + c;","+ if (bc < 0 || bc >= COLS || br >= this.board.length) return false;","+ if (br < 0) continue; // above board is OK","+ if (this.board[br][bc] !== null) return false;","+ }","+ }","+ return true;","+ }","+","+ // ── Movement ──────────────────────────────────────────────────────","+","+ movePiece(dx: number, dy: number): boolean {","+ if (!this.currentPiece) return false;","+ const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy };","+ if (this.isValid(this.currentPiece.shape, newPos)) {","+ this.currentPiece.pos = newPos;","+ return true;","+ }","+ return false;","+ }","+","+ private rotatePiece(): void {","+ if (!this.currentPiece) return;","+ const rotated = rotateMatrix(this.currentPiece.shape);","+ // Try wall kicks","+ for (const kick of WALL_KICKS) {","+ const testPos = {","+ x: this.currentPiece.pos.x + kick.x,","+ y: this.currentPiece.pos.y + kick.y,","+ };","+ if (this.isValid(rotated, testPos)) {","+ this.currentPiece.shape = rotated;","+ this.currentPiece.pos = testPos;","+ return;","+ }","+ }","+ }","+","+ private hardDrop(): void {","+ if (!this.currentPiece) return;","+ let dropped = 0;","+ while (this.movePiece(0, 1)) dropped++;","+ this.score += dropped * 2;","+ this.lockPiece();","+ const cleared = this.clearLines();","+ if (cleared > 0) {","+ this.score += LINE_SCORES[cleared] * (this.level + 1);","+ this.linesCleared += cleared;","+ const newLevel = Math.floor(this.linesCleared / 10);","+ if (newLevel > this.level) {","+ this.level = newLevel;","+ this.gravityInterval = getGravity(this.level);","+ }","+ }","+ if (!this.spawnPiece()) {","+ this.endGame();","+ return;","+ }","+ this.lastTick = performance.now();","+ this.draw();","+ }","+","+ private getGhostPosition(): Position | null {","+ if (!this.currentPiece) return null;","+ let ghostY = this.currentPiece.pos.y;","+ while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) {","+ ghostY++;","+ }","+ return { x: this.currentPiece.pos.x, y: ghostY };","+ }","+","+ // ── Input Handling ────────────────────────────────────────────────","+","+ private started = false;","+","+ private onKeyDown(e: KeyboardEvent): void {","+ if (!this.started) {","+ this.started = true;","+ this.start();","+ return;","+ }","+","+ if (this.gameOver) return;","+","+ if (e.code === \"KeyP\") {","+ this.paused = !this.paused;","+ if (this.paused) {","+ this.showOverlay(\"PAUSED\", \"Press P to resume\");","+ } else {","+ this.hideOverlay();","+ this.lastTick = performance.now();","+ }","+ return;","+ }","+","+ if (this.paused) return;","+","+ this.keysDown.add(e.code);","+","+ switch (e.code) {","+ case \"ArrowLeft\":","+ e.preventDefault();","+ this.movePiece(-1, 0);","+ this.dasDirection = \"left\";","+ this.dasTimer = performance.now();","+ this.dasActive = false;","+ break;","+ case \"ArrowRight\":","+ e.preventDefault();","+ this.movePiece(1, 0);","+ this.dasDirection = \"right\";","+ this.dasTimer = performance.now();","+ this.dasActive = false;","+ break;","+ case \"ArrowDown\":","+ e.preventDefault();","+ if (this.movePiece(0, 1)) this.score += 1;","+ this.dasDirection = \"down\";","+ this.dasTimer = performance.now();","+ this.dasActive = false;","+ break;","+ case \"ArrowUp\":","+ case \"KeyX\":","+ e.preventDefault();","+ this.rotatePiece();","+ break;","+ case \"Space\":","+ e.preventDefault();","+ this.hardDrop();","+ break;","+ }","+ }","+","+ private onKeyUp(e: KeyboardEvent): void {","+ this.keysDown.delete(e.code);","+ // If the key released matches current DAS direction, stop DAS","+ if (","+ (e.code === \"ArrowLeft\" && this.dasDirection === \"left\") ||","+ (e.code === \"ArrowRight\" && this.dasDirection === \"right\") ||","+ (e.code === \"ArrowDown\" && this.dasDirection === \"down\")","+ ) {","+ this.dasDirection = null;","+ }","+ }","+","+ private handleDAS(now: number): void {","+ if (!this.dasDirection) return;","+ // Check if the key is still held","+ const codeMap = { left: \"ArrowLeft\", right: \"ArrowRight\", down: \"ArrowDown\" };","+ if (!this.keysDown.has(codeMap[this.dasDirection])) {","+ this.dasDirection = null;","+ return;","+ }","+","+ const elapsed = now - this.dasTimer;","+ if (!this.dasActive) {","+ if (elapsed >= this.dasDelay) {","+ this.dasActive = true;","+ this.dasTimer = now;","+ this.dasRepeat();","+ }","+ } else {","+ if (elapsed >= this.dasRate) {","+ this.dasTimer = now;","+ this.dasRepeat();","+ }","+ }","+ }","+","+ private dasRepeat(): void {","+ switch (this.dasDirection) {","+ case \"left\":","+ this.movePiece(-1, 0);","+ break;","+ case \"right\":","+ this.movePiece(1, 0);","+ break;","+ case \"down\":","+ if (this.movePiece(0, 1)) this.score += 1;","+ break;","+ }","+ }","+","+ // ── End Game ──────────────────────────────────────────────────────","+","+ private endGame(): void {","+ this.gameOver = true;","+ cancelAnimationFrame(this.animFrameId);","+ this.draw();","+ this.showOverlay(\"GAME OVER\", `Final score: ${this.score.toLocaleString()}\\nPress R to restart`);","+ }","+","+ restart(): void {","+ this.board = createBoard();","+ this.score = 0;","+ this.level = 0;","+ this.linesCleared = 0;","+ this.gameOver = false;","+ this.paused = false;","+ this.currentPiece = null;","+ this.bag = new Bag();","+ this.nextPieceIndex = this.bag.next();","+ this.gravityInterval = getGravity(0);","+ this.dasDirection = null;","+ this.keysDown.clear();","+ this.spawnPiece();","+ this.hideOverlay();","+ this.lastTick = performance.now();","+ this.draw();","+ this.loop(this.lastTick);","+ }","+","+ // ── Rendering ─────────────────────────────────────────────────────","+","+ private draw(): void {","+ // Draw board","+ for (let r = 0; r < ROWS; r++) {","+ for (let c = 0; c < COLS; c++) {","+ const cell = this.cells[r][c];","+ if (!cell) continue;","+ const boardColor = this.board[r + HIDDEN_ROWS][c];","+ cell.style.backgroundColor = boardColor ?? \"\";","+ cell.className = \"cell\" + (boardColor ? \" filled\" : \"\");","+ }","+ }","+","+ // Draw ghost piece","+ const ghost = this.getGhostPosition();","+ if (this.currentPiece && ghost && !this.gameOver) {","+ const { shape } = this.currentPiece;","+ for (let r = 0; r < shape.length; r++) {","+ for (let c = 0; c < shape[r].length; c++) {","+ if (!shape[r][c]) continue;","+ const br = ghost.y + r - HIDDEN_ROWS;","+ const bc = ghost.x + c;","+ if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {","+ const cell = this.cells[br][bc];","+ if (cell && !this.board[br + HIDDEN_ROWS][bc]) {","+ cell.style.backgroundColor = this.currentPiece.color;","+ cell.className = \"cell ghost\";","+ }","+ }","+ }","+ }","+ }","+","+ // Draw current piece","+ if (this.currentPiece && !this.gameOver) {","+ const { shape, pos, color } = this.currentPiece;","+ for (let r = 0; r < shape.length; r++) {","+ for (let c = 0; c < shape[r].length; c++) {","+ if (!shape[r][c]) continue;","+ const br = pos.y + r - HIDDEN_ROWS;","+ const bc = pos.x + c;","+ if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {","+ const cell = this.cells[br][bc];","+ if (cell) {","+ cell.style.backgroundColor = color;","+ cell.className = \"cell active\";","+ }","+ }","+ }","+ }","+ }","+","+ // Draw next piece preview","+ const nextT = TETROMINOES[this.nextPieceIndex];","+ const nextShape = nextT.shape;","+ for (let r = 0; r < 4; r++) {","+ for (let c = 0; c < 4; c++) {","+ const cell = this.nextCells[r][c];","+ if (!cell) continue;","+ const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1;","+ cell.style.backgroundColor = filled ? nextT.color : \"\";","+ cell.className = \"next-cell\" + (filled ? \" filled\" : \"\");","+ }","+ }","+","+ // Update HUD","+ this.scoreEl.textContent = this.score.toLocaleString();","+ this.levelEl.textContent = String(this.level);","+ this.linesEl.textContent = String(this.linesCleared);","+ }","+}","+","+// ─── Bootstrap ────────────────────────────────────────────────────────","+","+let game: TetrisGame;","+","+window.addEventListener(\"DOMContentLoaded\", () => {","+ game = new TetrisGame();","+","+ window.addEventListener(\"keydown\", (e) => {","+ if (e.code === \"KeyR\" && game.gameOver) {","+ game.restart();","+ }","+ });","+});","\\ No newline at end of file"]}],"userModified":false,"replaceAll":false}} +{"type":"assistant","message":{"id":"msg_20260407094635551b682c950b4475","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now the CSS:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"747c13fe-3cc5-4879-9445-edd693502a2d"} +{"type":"assistant","message":{"id":"msg_20260407094635551b682c950b4475","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_cb56772f29044e0faf030357","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-cfbvwgky/styles.css","old_string":"","new_string":"/* ── Reset & Base ──────────────────────────────────────────────────── */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nhtml, body {\n height: 100%;\n background: #0a0a1a;\n color: #ddd;\n font-family: \"Courier New\", Courier, monospace;\n overflow: hidden;\n user-select: none;\n}\n\n/* ── Layout ────────────────────────────────────────────────────────── */\n.game-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n gap: 32px;\n}\n\n.board-container {\n position: relative;\n}\n\n#board {\n display: flex;\n flex-direction: column;\n border: 3px solid #3a3a5c;\n border-radius: 4px;\n background: #111122;\n box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(0, 0, 0, 0.5);\n}\n\n.board-row {\n display: flex;\n}\n\n/* ── Cells ─────────────────────────────────────────────────────────── */\n.cell {\n width: 30px;\n height: 30px;\n border: 1px solid rgba(255, 255, 255, 0.04);\n border-radius: 2px;\n transition: background-color 0.05s;\n}\n\n.cell.filled {\n border-color: rgba(255, 255, 255, 0.18);\n box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n}\n\n.cell.active {\n border-color: rgba(255, 255, 255, 0.35);\n box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.25), 0 0 6px currentColor;\n}\n\n.cell.ghost {\n opacity: 0.2;\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n/* ── Side Panel ────────────────────────────────────────────────────── */\n.side-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n min-width: 160px;\n}\n\n.panel-box {\n background: rgba(255, 255, 255, 0.03);\n border: 2px solid #3a3a5c;\n border-radius: 6px;\n padding: 16px;\n}\n\n.panel-box h3 {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 3px;\n color: #777;\n margin-bottom: 8px;\n border-bottom: 1px solid #333;\n padding-bottom: 6px;\n}\n\n.panel-box .value {\n font-size: 26px;\n font-weight: bold;\n color: #fff;\n text-align: right;\n}\n\n/* ── Next Piece Preview ────────────────────────────────────────────── */\n#next-piece {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 4px;\n}\n\n.next-row {\n display: flex;\n}\n\n.next-cell {\n width: 22px;\n height: 22px;\n border: 1px solid rgba(255, 255, 255, 0.04);\n border-radius: 2px;\n}\n\n.next-cell.filled {\n border-color: rgba(255, 255, 255, 0.18);\n box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n}\n\n/* ── Controls Help ─────────────────────────────────────────────────── */\n.controls {\n font-size: 11px;\n color: #666;\n line-height: 1.8;\n}\n\n.controls kbd {\n display: inline-block;\n background: #222;\n border: 1px solid #444;\n border-radius: 3px;\n padding: 1px 6px;\n font-size: 11px;\n color: #aaa;\n min-width: 24px;\n text-align: center;\n}\n\n/* ── Overlay ───────────────────────────────────────────────────────── */\n.overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.82);\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n border-radius: 4px;\n z-index: 10;\n transition: opacity 0.2s;\n}\n\n.overlay.hidden {\n display: none;\n}\n\n.overlay-title {\n font-size: 28px;\n font-weight: bold;\n letter-spacing: 6px;\n margin-bottom: 12px;\n color: #fff;\n text-shadow: 0 0 20px rgba(100, 100, 255, 0.6);\n}\n\n.overlay-sub {\n font-size: 13px;\n color: #999;\n white-space: pre-line;\n text-align: center;\n line-height: 1.6;\n}"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"350b2ea8-8436-4eb9-9573-6c5d6c2ab2c9"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_cb56772f29044e0faf030357","type":"tool_result","content":"The file /tmp/loop-bench-cfbvwgky/styles.css has been updated successfully."}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"72d75e82-4ae8-49ae-95e7-30bbf5bcb384","timestamp":"2026-04-07T01:47:06.557Z","tool_use_result":{"filePath":"/tmp/loop-bench-cfbvwgky/styles.css","oldString":"","newString":"/* ── Reset & Base ──────────────────────────────────────────────────── */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nhtml, body {\n height: 100%;\n background: #0a0a1a;\n color: #ddd;\n font-family: \"Courier New\", Courier, monospace;\n overflow: hidden;\n user-select: none;\n}\n\n/* ── Layout ────────────────────────────────────────────────────────── */\n.game-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n gap: 32px;\n}\n\n.board-container {\n position: relative;\n}\n\n#board {\n display: flex;\n flex-direction: column;\n border: 3px solid #3a3a5c;\n border-radius: 4px;\n background: #111122;\n box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(0, 0, 0, 0.5);\n}\n\n.board-row {\n display: flex;\n}\n\n/* ── Cells ─────────────────────────────────────────────────────────── */\n.cell {\n width: 30px;\n height: 30px;\n border: 1px solid rgba(255, 255, 255, 0.04);\n border-radius: 2px;\n transition: background-color 0.05s;\n}\n\n.cell.filled {\n border-color: rgba(255, 255, 255, 0.18);\n box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n}\n\n.cell.active {\n border-color: rgba(255, 255, 255, 0.35);\n box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.25), 0 0 6px currentColor;\n}\n\n.cell.ghost {\n opacity: 0.2;\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n/* ── Side Panel ────────────────────────────────────────────────────── */\n.side-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n min-width: 160px;\n}\n\n.panel-box {\n background: rgba(255, 255, 255, 0.03);\n border: 2px solid #3a3a5c;\n border-radius: 6px;\n padding: 16px;\n}\n\n.panel-box h3 {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 3px;\n color: #777;\n margin-bottom: 8px;\n border-bottom: 1px solid #333;\n padding-bottom: 6px;\n}\n\n.panel-box .value {\n font-size: 26px;\n font-weight: bold;\n color: #fff;\n text-align: right;\n}\n\n/* ── Next Piece Preview ────────────────────────────────────────────── */\n#next-piece {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 4px;\n}\n\n.next-row {\n display: flex;\n}\n\n.next-cell {\n width: 22px;\n height: 22px;\n border: 1px solid rgba(255, 255, 255, 0.04);\n border-radius: 2px;\n}\n\n.next-cell.filled {\n border-color: rgba(255, 255, 255, 0.18);\n box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n}\n\n/* ── Controls Help ─────────────────────────────────────────────────── */\n.controls {\n font-size: 11px;\n color: #666;\n line-height: 1.8;\n}\n\n.controls kbd {\n display: inline-block;\n background: #222;\n border: 1px solid #444;\n border-radius: 3px;\n padding: 1px 6px;\n font-size: 11px;\n color: #aaa;\n min-width: 24px;\n text-align: center;\n}\n\n/* ── Overlay ───────────────────────────────────────────────────────── */\n.overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.82);\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n border-radius: 4px;\n z-index: 10;\n transition: opacity 0.2s;\n}\n\n.overlay.hidden {\n display: none;\n}\n\n.overlay-title {\n font-size: 28px;\n font-weight: bold;\n letter-spacing: 6px;\n margin-bottom: 12px;\n color: #fff;\n text-shadow: 0 0 20px rgba(100, 100, 255, 0.6);\n}\n\n.overlay-sub {\n font-size: 13px;\n color: #999;\n white-space: pre-line;\n text-align: center;\n line-height: 1.6;\n}","originalFile":"","structuredPatch":[{"oldStart":1,"oldLines":0,"newStart":1,"newLines":180,"lines":["+/* ── Reset & Base ──────────────────────────────────────────────────── */","+*,","+*::before,","+*::after {","+ box-sizing: border-box;","+ margin: 0;","+ padding: 0;","+}","+","+html, body {","+ height: 100%;","+ background: #0a0a1a;","+ color: #ddd;","+ font-family: \"Courier New\", Courier, monospace;","+ overflow: hidden;","+ user-select: none;","+}","+","+/* ── Layout ────────────────────────────────────────────────────────── */","+.game-wrapper {","+ display: flex;","+ justify-content: center;","+ align-items: center;","+ height: 100vh;","+ gap: 32px;","+}","+","+.board-container {","+ position: relative;","+}","+","+#board {","+ display: flex;","+ flex-direction: column;","+ border: 3px solid #3a3a5c;","+ border-radius: 4px;","+ background: #111122;","+ box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(0, 0, 0, 0.5);","+}","+","+.board-row {","+ display: flex;","+}","+","+/* ── Cells ─────────────────────────────────────────────────────────── */","+.cell {","+ width: 30px;","+ height: 30px;","+ border: 1px solid rgba(255, 255, 255, 0.04);","+ border-radius: 2px;","+ transition: background-color 0.05s;","+}","+","+.cell.filled {","+ border-color: rgba(255, 255, 255, 0.18);","+ box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);","+}","+","+.cell.active {","+ border-color: rgba(255, 255, 255, 0.35);","+ box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.25), 0 0 6px currentColor;","+}","+","+.cell.ghost {","+ opacity: 0.2;","+ border-color: rgba(255, 255, 255, 0.1);","+}","+","+/* ── Side Panel ────────────────────────────────────────────────────── */","+.side-panel {","+ display: flex;","+ flex-direction: column;","+ gap: 24px;","+ min-width: 160px;","+}","+","+.panel-box {","+ background: rgba(255, 255, 255, 0.03);","+ border: 2px solid #3a3a5c;","+ border-radius: 6px;","+ padding: 16px;","+}","+","+.panel-box h3 {","+ font-size: 12px;","+ text-transform: uppercase;","+ letter-spacing: 3px;","+ color: #777;","+ margin-bottom: 8px;","+ border-bottom: 1px solid #333;","+ padding-bottom: 6px;","+}","+","+.panel-box .value {","+ font-size: 26px;","+ font-weight: bold;","+ color: #fff;","+ text-align: right;","+}","+","+/* ── Next Piece Preview ────────────────────────────────────────────── */","+#next-piece {","+ display: flex;","+ flex-direction: column;","+ align-items: center;","+ padding-top: 4px;","+}","+","+.next-row {","+ display: flex;","+}","+","+.next-cell {","+ width: 22px;","+ height: 22px;","+ border: 1px solid rgba(255, 255, 255, 0.04);","+ border-radius: 2px;","+}","+","+.next-cell.filled {","+ border-color: rgba(255, 255, 255, 0.18);","+ box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);","+}","+","+/* ── Controls Help ─────────────────────────────────────────────────── */","+.controls {","+ font-size: 11px;","+ color: #666;","+ line-height: 1.8;","+}","+","+.controls kbd {","+ display: inline-block;","+ background: #222;","+ border: 1px solid #444;","+ border-radius: 3px;","+ padding: 1px 6px;","+ font-size: 11px;","+ color: #aaa;","+ min-width: 24px;","+ text-align: center;","+}","+","+/* ── Overlay ───────────────────────────────────────────────────────── */","+.overlay {","+ position: absolute;","+ top: 0;","+ left: 0;","+ right: 0;","+ bottom: 0;","+ background: rgba(0, 0, 0, 0.82);","+ display: flex;","+ flex-direction: column;","+ justify-content: center;","+ align-items: center;","+ border-radius: 4px;","+ z-index: 10;","+ transition: opacity 0.2s;","+}","+","+.overlay.hidden {","+ display: none;","+}","+","+.overlay-title {","+ font-size: 28px;","+ font-weight: bold;","+ letter-spacing: 6px;","+ margin-bottom: 12px;","+ color: #fff;","+ text-shadow: 0 0 20px rgba(100, 100, 255, 0.6);","+}","+","+.overlay-sub {","+ font-size: 13px;","+ color: #999;","+ white-space: pre-line;","+ text-align: center;","+ line-height: 1.6;","+}","\\ No newline at end of file"]}],"userModified":false,"replaceAll":false}} +{"type":"assistant","message":{"id":"msg_20260407094707b14dbf4f021341b2","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now the HTML:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"6afc0b34-94ec-4a9d-9de3-eb298c8eaca2"} +{"type":"assistant","message":{"id":"msg_20260407094707b14dbf4f021341b2","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_442a859acc5e4b3fbc0e43d8","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-cfbvwgky/index.html","old_string":"","new_string":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Tetris</title>\n <link rel=\"stylesheet\" href=\"styles.css\" />\n</head>\n<body>\n <div class=\"game-wrapper\">\n <div class=\"board-container\">\n <div id=\"board\"></div>\n <div id=\"overlay\" class=\"overlay\">\n <div id=\"overlay-title\" class=\"overlay-title\"></div>\n <div id=\"overlay-sub\" class=\"overlay-sub\"></div>\n </div>\n </div>\n\n <div class=\"side-panel\">\n <div class=\"panel-box\">\n <h3>Next</h3>\n <div id=\"next-piece\"></div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Score</h3>\n <div id=\"score\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Level</h3>\n <div id=\"level\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Lines</h3>\n <div id=\"lines\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box controls\">\n <h3>Controls</h3>\n <div><kbd>←</kbd> <kbd>→</kbd> Move</div>\n <div><kbd>↑</kbd> Rotate</div>\n <div><kbd>↓</kbd> Soft drop</div>\n <div><kbd>Space</kbd> Hard drop</div>\n <div><kbd>P</kbd> Pause</div>\n <div><kbd>R</kbd> Restart</div>\n </div>\n </div>\n </div>\n\n <script src=\"dist/tetris.js\"></script>\n</body>\n</html>"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"ecbf6875-1392-4145-a361-bf9d40ed7d7c"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_442a859acc5e4b3fbc0e43d8","type":"tool_result","content":"The file /tmp/loop-bench-cfbvwgky/index.html has been updated successfully."}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"9c3dbb31-c21d-4a8b-bbdb-d596e5576d62","timestamp":"2026-04-07T01:47:20.901Z","tool_use_result":{"filePath":"/tmp/loop-bench-cfbvwgky/index.html","oldString":"","newString":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Tetris</title>\n <link rel=\"stylesheet\" href=\"styles.css\" />\n</head>\n<body>\n <div class=\"game-wrapper\">\n <div class=\"board-container\">\n <div id=\"board\"></div>\n <div id=\"overlay\" class=\"overlay\">\n <div id=\"overlay-title\" class=\"overlay-title\"></div>\n <div id=\"overlay-sub\" class=\"overlay-sub\"></div>\n </div>\n </div>\n\n <div class=\"side-panel\">\n <div class=\"panel-box\">\n <h3>Next</h3>\n <div id=\"next-piece\"></div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Score</h3>\n <div id=\"score\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Level</h3>\n <div id=\"level\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Lines</h3>\n <div id=\"lines\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box controls\">\n <h3>Controls</h3>\n <div><kbd>←</kbd> <kbd>→</kbd> Move</div>\n <div><kbd>↑</kbd> Rotate</div>\n <div><kbd>↓</kbd> Soft drop</div>\n <div><kbd>Space</kbd> Hard drop</div>\n <div><kbd>P</kbd> Pause</div>\n <div><kbd>R</kbd> Restart</div>\n </div>\n </div>\n </div>\n\n <script src=\"dist/tetris.js\"></script>\n</body>\n</html>","originalFile":"","structuredPatch":[{"oldStart":1,"oldLines":0,"newStart":1,"newLines":54,"lines":["+<!DOCTYPE html>","+<html lang=\"en\">","+<head>","+ <meta charset=\"UTF-8\" />","+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />","+ <title>Tetris</title>","+ <link rel=\"stylesheet\" href=\"styles.css\" />","+</head>","+<body>","+ <div class=\"game-wrapper\">","+ <div class=\"board-container\">","+ <div id=\"board\"></div>","+ <div id=\"overlay\" class=\"overlay\">","+ <div id=\"overlay-title\" class=\"overlay-title\"></div>","+ <div id=\"overlay-sub\" class=\"overlay-sub\"></div>","+ </div>","+ </div>","+","+ <div class=\"side-panel\">","+ <div class=\"panel-box\">","+ <h3>Next</h3>","+ <div id=\"next-piece\"></div>","+ </div>","+","+ <div class=\"panel-box\">","+ <h3>Score</h3>","+ <div id=\"score\" class=\"value\">0</div>","+ </div>","+","+ <div class=\"panel-box\">","+ <h3>Level</h3>","+ <div id=\"level\" class=\"value\">0</div>","+ </div>","+","+ <div class=\"panel-box\">","+ <h3>Lines</h3>","+ <div id=\"lines\" class=\"value\">0</div>","+ </div>","+","+ <div class=\"panel-box controls\">","+ <h3>Controls</h3>","+ <div><kbd>←</kbd> <kbd>→</kbd> Move</div>","+ <div><kbd>↑</kbd> Rotate</div>","+ <div><kbd>↓</kbd> Soft drop</div>","+ <div><kbd>Space</kbd> Hard drop</div>","+ <div><kbd>P</kbd> Pause</div>","+ <div><kbd>R</kbd> Restart</div>","+ </div>","+ </div>","+ </div>","+","+ <script src=\"dist/tetris.js\"></script>","+</body>","+</html>","\\ No newline at end of file"]}],"userModified":false,"replaceAll":false}} +{"type":"assistant","message":{"id":"msg_202604070947220c22194a6cd54673","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Now compile the TypeScript:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"0bb065f1-d3e5-4614-b83e-e780ccf70d2f"} +{"type":"assistant","message":{"id":"msg_202604070947220c22194a6cd54673","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_b70e00acd33d45e6b1486971","name":"Bash","input":{"command":"npx tsc 2>&1","description":"Compile TypeScript to JS"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"eb6bfd1b-592e-487f-8014-a60feeddc76e"} +{"type":"user","message":{"role":"user","content":[{"type":"tool_result","content":"Exit code 2\ntsconfig.json(10,25): error TS5107: Option 'moduleResolution=node10' is deprecated and will stop functioning in TypeScript 7.0. Specify compilerOption '\"ignoreDeprecations\": \"6.0\"' to silence this error.\n Visit https://aka.ms/ts6 for migration information.\n[rerun: b5]","is_error":true,"tool_use_id":"call_b70e00acd33d45e6b1486971"}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"23aba2d6-cda9-4ffa-868d-588f99d0f828","timestamp":"2026-04-07T01:47:26.759Z","tool_use_result":"Error: Exit code 2\ntsconfig.json(10,25): error TS5107: Option 'moduleResolution=node10' is deprecated and will stop functioning in TypeScript 7.0. Specify compilerOption '\"ignoreDeprecations\": \"6.0\"' to silence this error.\n Visit https://aka.ms/ts6 for migration information.\n[rerun: b5]"} +{"type":"assistant","message":{"id":"msg_2026040709472718a077fe29164f99","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_08dddeebbf694534951cfefa","name":"Read","input":{"file_path":"/tmp/loop-bench-cfbvwgky/tsconfig.json"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"3f5c981e-f61f-4ab7-b23f-5244c2b0d51d"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_08dddeebbf694534951cfefa","type":"tool_result","content":"1\t{\n2\t \"compilerOptions\": {\n3\t \"target\": \"ES2020\",\n4\t \"module\": \"ES2020\",\n5\t \"outDir\": \"./dist\",\n6\t \"rootDir\": \"./src\",\n7\t \"strict\": true,\n8\t \"esModuleInterop\": true,\n9\t \"forceConsistentCasingInFileNames\": true,\n10\t \"moduleResolution\": \"node\",\n11\t \"declaration\": false,\n12\t \"sourceMap\": false\n13\t },\n14\t \"include\": [\"src/**/*\"],\n15\t \"exclude\": [\"node_modules\", \"dist\"]\n16\t}\n17\t"}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"0f1c11ec-a4bc-48ca-ae70-97ebe2041399","timestamp":"2026-04-07T01:47:31.453Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-cfbvwgky/tsconfig.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ES2020\",\n \"outDir\": \"./dist\",\n \"rootDir\": \"./src\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"moduleResolution\": \"node\",\n \"declaration\": false,\n \"sourceMap\": false\n },\n \"include\": [\"src/**/*\"],\n \"exclude\": [\"node_modules\", \"dist\"]\n}\n","numLines":17,"startLine":1,"totalLines":17}}} +{"type":"assistant","message":{"id":"msg_202604070947324d03ee91ba4746d2","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_6a9b100bcd1e4ec895ffd9fd","name":"Edit","input":{"replace_all":false,"file_path":"/tmp/loop-bench-cfbvwgky/tsconfig.json","old_string":" \"moduleResolution\": \"node\",","new_string":" \"moduleResolution\": \"bundler\",\n \"ignoreDeprecations\": \"6.0\","}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"7e6ac8a8-f3ff-499f-870b-0ec41f50a6ab"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_6a9b100bcd1e4ec895ffd9fd","type":"tool_result","content":"The file /tmp/loop-bench-cfbvwgky/tsconfig.json has been updated successfully."}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"607a6578-41bd-4b3e-a094-10b78d5d1599","timestamp":"2026-04-07T01:47:37.014Z","tool_use_result":{"filePath":"/tmp/loop-bench-cfbvwgky/tsconfig.json","oldString":" \"moduleResolution\": \"node\",","newString":" \"moduleResolution\": \"bundler\",\n \"ignoreDeprecations\": \"6.0\",","originalFile":"{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"module\": \"ES2020\",\n \"outDir\": \"./dist\",\n \"rootDir\": \"./src\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"forceConsistentCasingInFileNames\": true,\n \"moduleResolution\": \"node\",\n \"declaration\": false,\n \"sourceMap\": false\n },\n \"include\": [\"src/**/*\"],\n \"exclude\": [\"node_modules\", \"dist\"]\n}\n","structuredPatch":[{"oldStart":7,"oldLines":7,"newStart":7,"newLines":8,"lines":[" \"strict\": true,"," \"esModuleInterop\": true,"," \"forceConsistentCasingInFileNames\": true,","- \"moduleResolution\": \"node\",","+ \"moduleResolution\": \"bundler\",","+ \"ignoreDeprecations\": \"6.0\","," \"declaration\": false,"," \"sourceMap\": false"," },"]}],"userModified":false,"replaceAll":false}} +{"type":"assistant","message":{"id":"msg_2026040709473863d354b9c139483f","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_6ca887de43f8450c89501f91","name":"Bash","input":{"command":"npx tsc 2>&1","description":"Compile TypeScript"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"0c303c51-f640-4309-888d-8d6209674cc7"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_6ca887de43f8450c89501f91","type":"tool_result","content":"[rerun: b6]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"f8f021bb-3404-42f3-9ad9-d329424e5bd4","timestamp":"2026-04-07T01:47:42.570Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_2026040709474388e3c062b81847e1","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Let me verify the output:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"eecad5e8-2918-4233-b4e4-f01cf50755d3"} +{"type":"assistant","message":{"id":"msg_2026040709474388e3c062b81847e1","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_5656bc0f5c194103becde1e1","name":"Bash","input":{"command":"ls -la dist/ && head -5 dist/tetris.js && echo \"...\" && wc -l dist/tetris.js","description":"Verify compiled JS output"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"d7b8a4c8-6141-450b-8936-f147962216ec"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_5656bc0f5c194103becde1e1","type":"tool_result","content":"total 32\ndrwxr-xr-x 2 root root 4096 Apr 7 03:47 .\ndrwx------ 7 root root 4096 Apr 7 03:47 ..\n-rw-r--r-- 1 root root 20840 Apr 7 03:47 tetris.js\n\"use strict\";\n// ─── Types & Constants ────────────────────────────────────────────────\nconst COLS = 10;\nconst ROWS = 20;\nconst HIDDEN_ROWS = 2; // buffer rows above visible area\n...\n550 dist/tetris.js\n[rerun: b7]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"79c5d09e-3d50-4b8f-9592-ba1dda08a2ef","timestamp":"2026-04-07T01:47:47.403Z","tool_use_result":{"stdout":"total 32\ndrwxr-xr-x 2 root root 4096 Apr 7 03:47 .\ndrwx------ 7 root root 4096 Apr 7 03:47 ..\n-rw-r--r-- 1 root root 20840 Apr 7 03:47 tetris.js\n\"use strict\";\n// ─── Types & Constants ────────────────────────────────────────────────\nconst COLS = 10;\nconst ROWS = 20;\nconst HIDDEN_ROWS = 2; // buffer rows above visible area\n...\n550 dist/tetris.js","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_2026040709474981321f14ea504e61","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The game compiles fine. Let me verify the HTML script tag matches the output. The HTML loads `dist/tetris.js` which exists. But since it's using `moduleResolution: \"bundler\"` and `module: \"ES2020\"`, I should check if the output uses `import/export` or just plain script format. Let me check.\n\nActually, the TypeScript source doesn't use any `import` or `export` statements, so it should compile to a plain script that runs in the browser. Let me verify.","signature":""}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"31861e6b-8470-4d37-89a5-5a7323d7deb4"} +{"type":"assistant","message":{"id":"msg_2026040709474981321f14ea504e61","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Good — it compiles cleanly. Let me verify the JS doesn't use ES module syntax (no imports/exports in the source, so it should be a plain script):"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"99405c9e-21fb-42d1-97d7-baae9207617e"} +{"type":"assistant","message":{"id":"msg_2026040709474981321f14ea504e61","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_e122726b4160447b95af97f0","name":"Bash","input":{"command":"grep -c 'import\\|export' dist/tetris.js","description":"Check for module syntax in compiled JS"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"820a37ab-87e3-4951-b71a-3b4f60708e25"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_e122726b4160447b95af97f0","type":"tool_result","content":"0\n[rerun: b8]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"a7530c55-e31b-4fc8-879d-1194af4cd019","timestamp":"2026-04-07T01:47:58.162Z","tool_use_result":{"stdout":"0","stderr":"","interrupted":false,"isImage":false,"returnCodeInterpretation":"No matches found","noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_20260407094759a879b3fb7f744f13","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"No module syntax — the plain `<script>` tag in the HTML will work. Let me also quickly verify the JS is valid by doing a syntax check:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"3acc618b-1f08-4462-a0c9-088bc63fdcb2"} +{"type":"assistant","message":{"id":"msg_20260407094759a879b3fb7f744f13","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_5640749e36e44398b71c46a0","name":"Bash","input":{"command":"node --check dist/tetris.js","description":"Verify JS syntax is valid"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"b9f72d6b-46f5-40bb-b678-124688709d67"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_5640749e36e44398b71c46a0","type":"tool_result","content":"[rerun: b9]","is_error":false}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"88e76595-d193-4794-acb6-8c4c27a07b9d","timestamp":"2026-04-07T01:48:03.943Z","tool_use_result":{"stdout":"","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false}} +{"type":"assistant","message":{"id":"msg_202604070948052bdfee9e4f824c30","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"Everything checks out. Let me do a final review of the key files to make sure everything is wired together correctly:"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"70534c24-f80f-478a-8140-de358f5a6d93"} +{"type":"assistant","message":{"id":"msg_202604070948052bdfee9e4f824c30","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_3604e3f2c6384f2786808657","name":"Read","input":{"file_path":"/tmp/loop-bench-cfbvwgky/index.html"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"3b817350-ac7c-44b3-96a3-b2104e84882a"} +{"type":"assistant","message":{"id":"msg_202604070948052bdfee9e4f824c30","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_d62a262cbce34bb495a35e95","name":"Read","input":{"file_path":"/tmp/loop-bench-cfbvwgky/src/tetris.ts"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"4549c9b7-e1e9-4479-8fcb-259608aa44ba"} +{"type":"assistant","message":{"id":"msg_202604070948052bdfee9e4f824c30","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"tool_use","id":"call_e4b147a744b24571af30fe2b","name":"Read","input":{"file_path":"/tmp/loop-bench-cfbvwgky/styles.css"}}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"9849ae4c-1d5b-433e-aa0a-71b5318336b8"} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_3604e3f2c6384f2786808657","type":"tool_result","content":"1\t<!DOCTYPE html>\n2\t<html lang=\"en\">\n3\t<head>\n4\t <meta charset=\"UTF-8\" />\n5\t <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n6\t <title>Tetris</title>\n7\t <link rel=\"stylesheet\" href=\"styles.css\" />\n8\t</head>\n9\t<body>\n10\t <div class=\"game-wrapper\">\n11\t <div class=\"board-container\">\n12\t <div id=\"board\"></div>\n13\t <div id=\"overlay\" class=\"overlay\">\n14\t <div id=\"overlay-title\" class=\"overlay-title\"></div>\n15\t <div id=\"overlay-sub\" class=\"overlay-sub\"></div>\n16\t </div>\n17\t </div>\n18\t\n19\t <div class=\"side-panel\">\n20\t <div class=\"panel-box\">\n21\t <h3>Next</h3>\n22\t <div id=\"next-piece\"></div>\n23\t </div>\n24\t\n25\t <div class=\"panel-box\">\n26\t <h3>Score</h3>\n27\t <div id=\"score\" class=\"value\">0</div>\n28\t </div>\n29\t\n30\t <div class=\"panel-box\">\n31\t <h3>Level</h3>\n32\t <div id=\"level\" class=\"value\">0</div>\n33\t </div>\n34\t\n35\t <div class=\"panel-box\">\n36\t <h3>Lines</h3>\n37\t <div id=\"lines\" class=\"value\">0</div>\n38\t </div>\n39\t\n40\t <div class=\"panel-box controls\">\n41\t <h3>Controls</h3>\n42\t <div><kbd>←</kbd> <kbd>→</kbd> Move</div>\n43\t <div><kbd>↑</kbd> Rotate</div>\n44\t <div><kbd>↓</kbd> Soft drop</div>\n45\t <div><kbd>Space</kbd> Hard drop</div>\n46\t <div><kbd>P</kbd> Pause</div>\n47\t <div><kbd>R</kbd> Restart</div>\n48\t </div>\n49\t </div>\n50\t </div>\n51\t\n52\t <script src=\"dist/tetris.js\"></script>\n53\t</body>\n54\t</html>"}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"63fe549a-3a23-4bf0-971b-e176b53a35ae","timestamp":"2026-04-07T01:48:09.955Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-cfbvwgky/index.html","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>Tetris</title>\n <link rel=\"stylesheet\" href=\"styles.css\" />\n</head>\n<body>\n <div class=\"game-wrapper\">\n <div class=\"board-container\">\n <div id=\"board\"></div>\n <div id=\"overlay\" class=\"overlay\">\n <div id=\"overlay-title\" class=\"overlay-title\"></div>\n <div id=\"overlay-sub\" class=\"overlay-sub\"></div>\n </div>\n </div>\n\n <div class=\"side-panel\">\n <div class=\"panel-box\">\n <h3>Next</h3>\n <div id=\"next-piece\"></div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Score</h3>\n <div id=\"score\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Level</h3>\n <div id=\"level\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box\">\n <h3>Lines</h3>\n <div id=\"lines\" class=\"value\">0</div>\n </div>\n\n <div class=\"panel-box controls\">\n <h3>Controls</h3>\n <div><kbd>←</kbd> <kbd>→</kbd> Move</div>\n <div><kbd>↑</kbd> Rotate</div>\n <div><kbd>↓</kbd> Soft drop</div>\n <div><kbd>Space</kbd> Hard drop</div>\n <div><kbd>P</kbd> Pause</div>\n <div><kbd>R</kbd> Restart</div>\n </div>\n </div>\n </div>\n\n <script src=\"dist/tetris.js\"></script>\n</body>\n</html>","numLines":54,"startLine":1,"totalLines":54}}} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_e4b147a744b24571af30fe2b","type":"tool_result","content":"1\t/* ── Reset & Base ──────────────────────────────────────────────────── */\n2\t*,\n3\t*::before,\n4\t*::after {\n5\t box-sizing: border-box;\n6\t margin: 0;\n7\t padding: 0;\n8\t}\n9\t\n10\thtml, body {\n11\t height: 100%;\n12\t background: #0a0a1a;\n13\t color: #ddd;\n14\t font-family: \"Courier New\", Courier, monospace;\n15\t overflow: hidden;\n16\t user-select: none;\n17\t}\n18\t\n19\t/* ── Layout ────────────────────────────────────────────────────────── */\n20\t.game-wrapper {\n21\t display: flex;\n22\t justify-content: center;\n23\t align-items: center;\n24\t height: 100vh;\n25\t gap: 32px;\n26\t}\n27\t\n28\t.board-container {\n29\t position: relative;\n30\t}\n31\t\n32\t#board {\n33\t display: flex;\n34\t flex-direction: column;\n35\t border: 3px solid #3a3a5c;\n36\t border-radius: 4px;\n37\t background: #111122;\n38\t box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(0, 0, 0, 0.5);\n39\t}\n40\t\n41\t.board-row {\n42\t display: flex;\n43\t}\n44\t\n45\t/* ── Cells ─────────────────────────────────────────────────────────── */\n46\t.cell {\n47\t width: 30px;\n48\t height: 30px;\n49\t border: 1px solid rgba(255, 255, 255, 0.04);\n50\t border-radius: 2px;\n51\t transition: background-color 0.05s;\n52\t}\n53\t\n54\t.cell.filled {\n55\t border-color: rgba(255, 255, 255, 0.18);\n56\t box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n57\t}\n58\t\n59\t.cell.active {\n60\t border-color: rgba(255, 255, 255, 0.35);\n61\t box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.25), 0 0 6px currentColor;\n62\t}\n63\t\n64\t.cell.ghost {\n65\t opacity: 0.2;\n66\t border-color: rgba(255, 255, 255, 0.1);\n67\t}\n68\t\n69\t/* ── Side Panel ────────────────────────────────────────────────────── */\n70\t.side-panel {\n71\t display: flex;\n72\t flex-direction: column;\n73\t gap: 24px;\n74\t min-width: 160px;\n75\t}\n76\t\n77\t.panel-box {\n78\t background: rgba(255, 255, 255, 0.03);\n79\t border: 2px solid #3a3a5c;\n80\t border-radius: 6px;\n81\t padding: 16px;\n82\t}\n83\t\n84\t.panel-box h3 {\n85\t font-size: 12px;\n86\t text-transform: uppercase;\n87\t letter-spacing: 3px;\n88\t color: #777;\n89\t margin-bottom: 8px;\n90\t border-bottom: 1px solid #333;\n91\t padding-bottom: 6px;\n92\t}\n93\t\n94\t.panel-box .value {\n95\t font-size: 26px;\n96\t font-weight: bold;\n97\t color: #fff;\n98\t text-align: right;\n99\t}\n100\t\n101\t/* ── Next Piece Preview ────────────────────────────────────────────── */\n102\t#next-piece {\n103\t display: flex;\n104\t flex-direction: column;\n105\t align-items: center;\n106\t padding-top: 4px;\n107\t}\n108\t\n109\t.next-row {\n110\t display: flex;\n111\t}\n112\t\n113\t.next-cell {\n114\t width: 22px;\n115\t height: 22px;\n116\t border: 1px solid rgba(255, 255, 255, 0.04);\n117\t border-radius: 2px;\n118\t}\n119\t\n120\t.next-cell.filled {\n121\t border-color: rgba(255, 255, 255, 0.18);\n122\t box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n123\t}\n124\t\n125\t/* ── Controls Help ─────────────────────────────────────────────────── */\n126\t.controls {\n127\t font-size: 11px;\n128\t color: #666;\n129\t line-height: 1.8;\n130\t}\n131\t\n132\t.controls kbd {\n133\t display: inline-block;\n134\t background: #222;\n135\t border: 1px solid #444;\n136\t border-radius: 3px;\n137\t padding: 1px 6px;\n138\t font-size: 11px;\n139\t color: #aaa;\n140\t min-width: 24px;\n141\t text-align: center;\n142\t}\n143\t\n144\t/* ── Overlay ───────────────────────────────────────────────────────── */\n145\t.overlay {\n146\t position: absolute;\n147\t top: 0;\n148\t left: 0;\n149\t right: 0;\n150\t bottom: 0;\n151\t background: rgba(0, 0, 0, 0.82);\n152\t display: flex;\n153\t flex-direction: column;\n154\t justify-content: center;\n155\t align-items: center;\n156\t border-radius: 4px;\n157\t z-index: 10;\n158\t transition: opacity 0.2s;\n159\t}\n160\t\n161\t.overlay.hidden {\n162\t display: none;\n163\t}\n164\t\n165\t.overlay-title {\n166\t font-size: 28px;\n167\t font-weight: bold;\n168\t letter-spacing: 6px;\n169\t margin-bottom: 12px;\n170\t color: #fff;\n171\t text-shadow: 0 0 20px rgba(100, 100, 255, 0.6);\n172\t}\n173\t\n174\t.overlay-sub {\n175\t font-size: 13px;\n176\t color: #999;\n177\t white-space: pre-line;\n178\t text-align: center;\n179\t line-height: 1.6;\n180\t}"}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"05f8ad5d-13a7-4d52-9e78-8e741994063d","timestamp":"2026-04-07T01:48:09.955Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-cfbvwgky/styles.css","content":"/* ── Reset & Base ──────────────────────────────────────────────────── */\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nhtml, body {\n height: 100%;\n background: #0a0a1a;\n color: #ddd;\n font-family: \"Courier New\", Courier, monospace;\n overflow: hidden;\n user-select: none;\n}\n\n/* ── Layout ────────────────────────────────────────────────────────── */\n.game-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n gap: 32px;\n}\n\n.board-container {\n position: relative;\n}\n\n#board {\n display: flex;\n flex-direction: column;\n border: 3px solid #3a3a5c;\n border-radius: 4px;\n background: #111122;\n box-shadow: 0 0 30px rgba(0, 0, 0, 0.8), inset 0 0 20px rgba(0, 0, 0, 0.5);\n}\n\n.board-row {\n display: flex;\n}\n\n/* ── Cells ─────────────────────────────────────────────────────────── */\n.cell {\n width: 30px;\n height: 30px;\n border: 1px solid rgba(255, 255, 255, 0.04);\n border-radius: 2px;\n transition: background-color 0.05s;\n}\n\n.cell.filled {\n border-color: rgba(255, 255, 255, 0.18);\n box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n}\n\n.cell.active {\n border-color: rgba(255, 255, 255, 0.35);\n box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.25), 0 0 6px currentColor;\n}\n\n.cell.ghost {\n opacity: 0.2;\n border-color: rgba(255, 255, 255, 0.1);\n}\n\n/* ── Side Panel ────────────────────────────────────────────────────── */\n.side-panel {\n display: flex;\n flex-direction: column;\n gap: 24px;\n min-width: 160px;\n}\n\n.panel-box {\n background: rgba(255, 255, 255, 0.03);\n border: 2px solid #3a3a5c;\n border-radius: 6px;\n padding: 16px;\n}\n\n.panel-box h3 {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 3px;\n color: #777;\n margin-bottom: 8px;\n border-bottom: 1px solid #333;\n padding-bottom: 6px;\n}\n\n.panel-box .value {\n font-size: 26px;\n font-weight: bold;\n color: #fff;\n text-align: right;\n}\n\n/* ── Next Piece Preview ────────────────────────────────────────────── */\n#next-piece {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding-top: 4px;\n}\n\n.next-row {\n display: flex;\n}\n\n.next-cell {\n width: 22px;\n height: 22px;\n border: 1px solid rgba(255, 255, 255, 0.04);\n border-radius: 2px;\n}\n\n.next-cell.filled {\n border-color: rgba(255, 255, 255, 0.18);\n box-shadow: inset 0 0 6px rgba(255, 255, 255, 0.15);\n}\n\n/* ── Controls Help ─────────────────────────────────────────────────── */\n.controls {\n font-size: 11px;\n color: #666;\n line-height: 1.8;\n}\n\n.controls kbd {\n display: inline-block;\n background: #222;\n border: 1px solid #444;\n border-radius: 3px;\n padding: 1px 6px;\n font-size: 11px;\n color: #aaa;\n min-width: 24px;\n text-align: center;\n}\n\n/* ── Overlay ───────────────────────────────────────────────────────── */\n.overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.82);\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n border-radius: 4px;\n z-index: 10;\n transition: opacity 0.2s;\n}\n\n.overlay.hidden {\n display: none;\n}\n\n.overlay-title {\n font-size: 28px;\n font-weight: bold;\n letter-spacing: 6px;\n margin-bottom: 12px;\n color: #fff;\n text-shadow: 0 0 20px rgba(100, 100, 255, 0.6);\n}\n\n.overlay-sub {\n font-size: 13px;\n color: #999;\n white-space: pre-line;\n text-align: center;\n line-height: 1.6;\n}","numLines":180,"startLine":1,"totalLines":180}}} +{"type":"user","message":{"role":"user","content":[{"tool_use_id":"call_d62a262cbce34bb495a35e95","type":"tool_result","content":"1\t// ─── Types & Constants ────────────────────────────────────────────────\n2\t\n3\tconst COLS = 10;\n4\tconst ROWS = 20;\n5\tconst HIDDEN_ROWS = 2; // buffer rows above visible area\n6\t\n7\ttype CellColor = string | null;\n8\ttype Board = CellColor[][];\n9\t\n10\tinterface Position {\n11\t x: number;\n12\t y: number;\n13\t}\n14\t\n15\tinterface Piece {\n16\t shape: number[][];\n17\t color: string;\n18\t pos: Position;\n19\t}\n20\t\n21\t// Standard NES-style scoring\n22\tconst LINE_SCORES = [0, 100, 300, 500, 800];\n23\t\n24\t// Gravity intervals in ms per level (index = level, faster as level increases)\n25\tconst GRAVITY_TABLE = [\n26\t 800, 720, 630, 550, 470, 380, 300, 220, 150, 100,\n27\t 80, 80, 80, 70, 70, 70, 50, 50, 50, 30,\n28\t];\n29\t\n30\tfunction getGravity(level: number): number {\n31\t if (level < GRAVITY_TABLE.length) return GRAVITY_TABLE[level];\n32\t return 20; // cap\n33\t}\n34\t\n35\t// Tetromino definitions (shapes in their spawn orientation)\n36\tconst TETROMINOES: { shape: number[][]; color: string }[] = [\n37\t { shape: [[1, 1, 1, 1]], color: \"#00f0f0\" }, // I - cyan\n38\t { shape: [[1, 1], [1, 1]], color: \"#f0f000\" }, // O - yellow\n39\t { shape: [[0, 1, 0], [1, 1, 1]], color: \"#a000f0\" }, // T - purple\n40\t { shape: [[0, 1, 1], [1, 1, 0]], color: \"#00f000\" }, // S - green\n41\t { shape: [[1, 1, 0], [0, 1, 1]], color: \"#f00000\" }, // Z - red\n42\t { shape: [[1, 0, 0], [1, 1, 1]], color: \"#0000f0\" }, // J - blue\n43\t { shape: [[0, 0, 1], [1, 1, 1]], color: \"#f0a000\" }, // L - orange\n44\t];\n45\t\n46\t// ─── Utility ──────────────────────────────────────────────────────────\n47\t\n48\tfunction createBoard(): Board {\n49\t const rows = ROWS + HIDDEN_ROWS;\n50\t const board: Board = [];\n51\t for (let r = 0; r < rows; r++) {\n52\t board.push(new Array<string | null>(COLS).fill(null));\n53\t }\n54\t return board;\n55\t}\n56\t\n57\tfunction rotateMatrix(matrix: number[][]): number[][] {\n58\t const rows = matrix.length;\n59\t const cols = matrix[0].length;\n60\t const result: number[][] = [];\n61\t for (let c = 0; c < cols; c++) {\n62\t const newRow: number[] = [];\n63\t for (let r = rows - 1; r >= 0; r--) {\n64\t newRow.push(matrix[r][c]);\n65\t }\n66\t result.push(newRow);\n67\t }\n68\t return result;\n69\t}\n70\t\n71\t// Wall-kick offsets to try when rotation is blocked\n72\tconst WALL_KICKS: Position[] = [\n73\t { x: 0, y: 0 },\n74\t { x: -1, y: 0 },\n75\t { x: 1, y: 0 },\n76\t { x: -2, y: 0 },\n77\t { x: 2, y: 0 },\n78\t { x: 0, y: -1 },\n79\t { x: -1, y: -1 },\n80\t { x: 1, y: -1 },\n81\t];\n82\t\n83\t// ─── Bag Randomiser (7-bag) ───────────────────────────────────────────\n84\t\n85\tclass Bag {\n86\t private bag: number[] = [];\n87\t\n88\t next(): number {\n89\t if (this.bag.length === 0) {\n90\t this.bag = [0, 1, 2, 3, 4, 5, 6];\n91\t // Fisher-Yates shuffle\n92\t for (let i = this.bag.length - 1; i > 0; i--) {\n93\t const j = Math.floor(Math.random() * (i + 1));\n94\t [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];\n95\t }\n96\t }\n97\t return this.bag.pop()!;\n98\t }\n99\t}\n100\t\n101\t// ─── Game ─────────────────────────────────────────────────────────────\n102\t\n103\tclass TetrisGame {\n104\t board: Board = createBoard();\n105\t currentPiece: Piece | null = null;\n106\t nextPieceIndex: number;\n107\t bag = new Bag();\n108\t score = 0;\n109\t level = 0;\n110\t linesCleared = 0;\n111\t gameOver = false;\n112\t paused = false;\n113\t\n114\t // Timing\n115\t private lastTick = 0;\n116\t private gravityInterval = getGravity(0);\n117\t private animFrameId = 0;\n118\t\n119\t // DAS (Delayed Auto Shift) for held keys\n120\t private dasDirection: \"left\" | \"right\" | \"down\" | null = null;\n121\t private dasTimer = 0;\n122\t private dasDelay = 170; // ms before auto-repeat starts\n123\t private dasRate = 50; // ms between auto-repeats\n124\t private dasActive = false;\n125\t private keysDown = new Set<string>();\n126\t\n127\t // DOM references\n128\t private boardEl: HTMLElement;\n129\t private scoreEl: HTMLElement;\n130\t private levelEl: HTMLElement;\n131\t private linesEl: HTMLElement;\n132\t private nextPieceEl: HTMLElement;\n133\t private overlayEl: HTMLElement;\n134\t private overlayTitleEl: HTMLElement;\n135\t private overlaySubEl: HTMLElement;\n136\t private cells: (HTMLElement | null)[][] = [];\n137\t private nextCells: (HTMLElement | null)[][] = [];\n138\t\n139\t constructor() {\n140\t this.nextPieceIndex = this.bag.next();\n141\t\n142\t // Grab DOM elements\n143\t this.boardEl = document.getElementById(\"board\")!;\n144\t this.scoreEl = document.getElementById(\"score\")!;\n145\t this.levelEl = document.getElementById(\"level\")!;\n146\t this.linesEl = document.getElementById(\"lines\")!;\n147\t this.nextPieceEl = document.getElementById(\"next-piece\")!;\n148\t this.overlayEl = document.getElementById(\"overlay\")!;\n149\t this.overlayTitleEl = document.getElementById(\"overlay-title\")!;\n150\t this.overlaySubEl = document.getElementById(\"overlay-sub\")!;\n151\t\n152\t this.buildBoardDOM();\n153\t this.buildNextPieceDOM();\n154\t\n155\t // Input\n156\t window.addEventListener(\"keydown\", (e) => this.onKeyDown(e));\n157\t window.addEventListener(\"keyup\", (e) => this.onKeyUp(e));\n158\t\n159\t // Start\n160\t this.spawnPiece();\n161\t this.showOverlay(\"TETRIS\", \"Press any key to start\");\n162\t this.draw();\n163\t }\n164\t\n165\t // ── DOM Construction ──────────────────────────────────────────────\n166\t\n167\t private buildBoardDOM(): void {\n168\t this.boardEl.innerHTML = \"\";\n169\t this.cells = [];\n170\t for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) {\n171\t const rowCells: (HTMLElement | null)[] = [];\n172\t const rowDiv = document.createElement(\"div\");\n173\t rowDiv.className = \"board-row\";\n174\t for (let c = 0; c < COLS; c++) {\n175\t const cell = document.createElement(\"div\");\n176\t cell.className = \"cell\";\n177\t rowDiv.appendChild(cell);\n178\t rowCells.push(cell);\n179\t }\n180\t this.boardEl.appendChild(rowDiv);\n181\t this.cells.push(rowCells);\n182\t }\n183\t }\n184\t\n185\t private buildNextPieceDOM(): void {\n186\t this.nextPieceEl.innerHTML = \"\";\n187\t this.nextCells = [];\n188\t for (let r = 0; r < 4; r++) {\n189\t const rowCells: (HTMLElement | null)[] = [];\n190\t const rowDiv = document.createElement(\"div\");\n191\t rowDiv.className = \"next-row\";\n192\t for (let c = 0; c < 4; c++) {\n193\t const cell = document.createElement(\"div\");\n194\t cell.className = \"next-cell\";\n195\t rowDiv.appendChild(cell);\n196\t rowCells.push(cell);\n197\t }\n198\t this.nextPieceEl.appendChild(rowDiv);\n199\t this.nextCells.push(rowCells);\n200\t }\n201\t }\n202\t\n203\t // ── Overlay ───────────────────────────────────────────────────────\n204\t\n205\t private showOverlay(title: string, sub: string): void {\n206\t this.overlayTitleEl.textContent = title;\n207\t this.overlaySubEl.textContent = sub;\n208\t this.overlayEl.classList.remove(\"hidden\");\n209\t }\n210\t\n211\t private hideOverlay(): void {\n212\t this.overlayEl.classList.add(\"hidden\");\n213\t }\n214\t\n215\t // ── Game Loop ─────────────────────────────────────────────────────\n216\t\n217\t start(): void {\n218\t this.hideOverlay();\n219\t this.lastTick = performance.now();\n220\t this.loop(this.lastTick);\n221\t }\n222\t\n223\t private loop = (now: number): void => {\n224\t if (this.gameOver) return;\n225\t if (this.paused) {\n226\t this.animFrameId = requestAnimationFrame(this.loop);\n227\t return;\n228\t }\n229\t\n230\t const dt = now - this.lastTick;\n231\t\n232\t // DAS handling\n233\t this.handleDAS(now);\n234\t\n235\t // Gravity\n236\t if (dt >= this.gravityInterval) {\n237\t this.tick();\n238\t this.lastTick = now;\n239\t }\n240\t\n241\t this.draw();\n242\t this.animFrameId = requestAnimationFrame(this.loop);\n243\t };\n244\t\n245\t private tick(): void {\n246\t if (!this.currentPiece || this.gameOver) return;\n247\t if (!this.movePiece(0, 1)) {\n248\t this.lockPiece();\n249\t const cleared = this.clearLines();\n250\t if (cleared > 0) {\n251\t this.score += LINE_SCORES[cleared] * (this.level + 1);\n252\t this.linesCleared += cleared;\n253\t const newLevel = Math.floor(this.linesCleared / 10);\n254\t if (newLevel > this.level) {\n255\t this.level = newLevel;\n256\t this.gravityInterval = getGravity(this.level);\n257\t }\n258\t }\n259\t if (!this.spawnPiece()) {\n260\t this.endGame();\n261\t return;\n262\t }\n263\t }\n264\t }\n265\t\n266\t // ── Piece Management ──────────────────────────────────────────────\n267\t\n268\t private spawnPiece(): boolean {\n269\t const idx = this.nextPieceIndex;\n270\t this.nextPieceIndex = this.bag.next();\n271\t const t = TETROMINOES[idx];\n272\t const shape = t.shape.map((row) => [...row]);\n273\t const piece: Piece = {\n274\t shape,\n275\t color: t.color,\n276\t pos: {\n277\t x: Math.floor((COLS - shape[0].length) / 2),\n278\t y: 0,\n279\t },\n280\t };\n281\t this.currentPiece = piece;\n282\t if (!this.isValid(piece.shape, piece.pos)) {\n283\t return false;\n284\t }\n285\t return true;\n286\t }\n287\t\n288\t private lockPiece(): void {\n289\t if (!this.currentPiece) return;\n290\t const { shape, pos, color } = this.currentPiece;\n291\t for (let r = 0; r < shape.length; r++) {\n292\t for (let c = 0; c < shape[r].length; c++) {\n293\t if (shape[r][c]) {\n294\t const br = pos.y + r;\n295\t const bc = pos.x + c;\n296\t if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) {\n297\t this.board[br][bc] = color;\n298\t }\n299\t }\n300\t }\n301\t }\n302\t }\n303\t\n304\t private clearLines(): number {\n305\t let cleared = 0;\n306\t for (let r = this.board.length - 1; r >= 0; r--) {\n307\t if (this.board[r].every((cell) => cell !== null)) {\n308\t this.board.splice(r, 1);\n309\t this.board.unshift(new Array<string | null>(COLS).fill(null));\n310\t cleared++;\n311\t r++; // recheck same index\n312\t }\n313\t }\n314\t return cleared;\n315\t }\n316\t\n317\t // ── Collision ─────────────────────────────────────────────────────\n318\t\n319\t private isValid(shape: number[][], pos: Position): boolean {\n320\t for (let r = 0; r < shape.length; r++) {\n321\t for (let c = 0; c < shape[r].length; c++) {\n322\t if (!shape[r][c]) continue;\n323\t const br = pos.y + r;\n324\t const bc = pos.x + c;\n325\t if (bc < 0 || bc >= COLS || br >= this.board.length) return false;\n326\t if (br < 0) continue; // above board is OK\n327\t if (this.board[br][bc] !== null) return false;\n328\t }\n329\t }\n330\t return true;\n331\t }\n332\t\n333\t // ── Movement ──────────────────────────────────────────────────────\n334\t\n335\t movePiece(dx: number, dy: number): boolean {\n336\t if (!this.currentPiece) return false;\n337\t const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy };\n338\t if (this.isValid(this.currentPiece.shape, newPos)) {\n339\t this.currentPiece.pos = newPos;\n340\t return true;\n341\t }\n342\t return false;\n343\t }\n344\t\n345\t private rotatePiece(): void {\n346\t if (!this.currentPiece) return;\n347\t const rotated = rotateMatrix(this.currentPiece.shape);\n348\t // Try wall kicks\n349\t for (const kick of WALL_KICKS) {\n350\t const testPos = {\n351\t x: this.currentPiece.pos.x + kick.x,\n352\t y: this.currentPiece.pos.y + kick.y,\n353\t };\n354\t if (this.isValid(rotated, testPos)) {\n355\t this.currentPiece.shape = rotated;\n356\t this.currentPiece.pos = testPos;\n357\t return;\n358\t }\n359\t }\n360\t }\n361\t\n362\t private hardDrop(): void {\n363\t if (!this.currentPiece) return;\n364\t let dropped = 0;\n365\t while (this.movePiece(0, 1)) dropped++;\n366\t this.score += dropped * 2;\n367\t this.lockPiece();\n368\t const cleared = this.clearLines();\n369\t if (cleared > 0) {\n370\t this.score += LINE_SCORES[cleared] * (this.level + 1);\n371\t this.linesCleared += cleared;\n372\t const newLevel = Math.floor(this.linesCleared / 10);\n373\t if (newLevel > this.level) {\n374\t this.level = newLevel;\n375\t this.gravityInterval = getGravity(this.level);\n376\t }\n377\t }\n378\t if (!this.spawnPiece()) {\n379\t this.endGame();\n380\t return;\n381\t }\n382\t this.lastTick = performance.now();\n383\t this.draw();\n384\t }\n385\t\n386\t private getGhostPosition(): Position | null {\n387\t if (!this.currentPiece) return null;\n388\t let ghostY = this.currentPiece.pos.y;\n389\t while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) {\n390\t ghostY++;\n391\t }\n392\t return { x: this.currentPiece.pos.x, y: ghostY };\n393\t }\n394\t\n395\t // ── Input Handling ────────────────────────────────────────────────\n396\t\n397\t private started = false;\n398\t\n399\t private onKeyDown(e: KeyboardEvent): void {\n400\t if (!this.started) {\n401\t this.started = true;\n402\t this.start();\n403\t return;\n404\t }\n405\t\n406\t if (this.gameOver) return;\n407\t\n408\t if (e.code === \"KeyP\") {\n409\t this.paused = !this.paused;\n410\t if (this.paused) {\n411\t this.showOverlay(\"PAUSED\", \"Press P to resume\");\n412\t } else {\n413\t this.hideOverlay();\n414\t this.lastTick = performance.now();\n415\t }\n416\t return;\n417\t }\n418\t\n419\t if (this.paused) return;\n420\t\n421\t this.keysDown.add(e.code);\n422\t\n423\t switch (e.code) {\n424\t case \"ArrowLeft\":\n425\t e.preventDefault();\n426\t this.movePiece(-1, 0);\n427\t this.dasDirection = \"left\";\n428\t this.dasTimer = performance.now();\n429\t this.dasActive = false;\n430\t break;\n431\t case \"ArrowRight\":\n432\t e.preventDefault();\n433\t this.movePiece(1, 0);\n434\t this.dasDirection = \"right\";\n435\t this.dasTimer = performance.now();\n436\t this.dasActive = false;\n437\t break;\n438\t case \"ArrowDown\":\n439\t e.preventDefault();\n440\t if (this.movePiece(0, 1)) this.score += 1;\n441\t this.dasDirection = \"down\";\n442\t this.dasTimer = performance.now();\n443\t this.dasActive = false;\n444\t break;\n445\t case \"ArrowUp\":\n446\t case \"KeyX\":\n447\t e.preventDefault();\n448\t this.rotatePiece();\n449\t break;\n450\t case \"Space\":\n451\t e.preventDefault();\n452\t this.hardDrop();\n453\t break;\n454\t }\n455\t }\n456\t\n457\t private onKeyUp(e: KeyboardEvent): void {\n458\t this.keysDown.delete(e.code);\n459\t // If the key released matches current DAS direction, stop DAS\n460\t if (\n461\t (e.code === \"ArrowLeft\" && this.dasDirection === \"left\") ||\n462\t (e.code === \"ArrowRight\" && this.dasDirection === \"right\") ||\n463\t (e.code === \"ArrowDown\" && this.dasDirection === \"down\")\n464\t ) {\n465\t this.dasDirection = null;\n466\t }\n467\t }\n468\t\n469\t private handleDAS(now: number): void {\n470\t if (!this.dasDirection) return;\n471\t // Check if the key is still held\n472\t const codeMap = { left: \"ArrowLeft\", right: \"ArrowRight\", down: \"ArrowDown\" };\n473\t if (!this.keysDown.has(codeMap[this.dasDirection])) {\n474\t this.dasDirection = null;\n475\t return;\n476\t }\n477\t\n478\t const elapsed = now - this.dasTimer;\n479\t if (!this.dasActive) {\n480\t if (elapsed >= this.dasDelay) {\n481\t this.dasActive = true;\n482\t this.dasTimer = now;\n483\t this.dasRepeat();\n484\t }\n485\t } else {\n486\t if (elapsed >= this.dasRate) {\n487\t this.dasTimer = now;\n488\t this.dasRepeat();\n489\t }\n490\t }\n491\t }\n492\t\n493\t private dasRepeat(): void {\n494\t switch (this.dasDirection) {\n495\t case \"left\":\n496\t this.movePiece(-1, 0);\n497\t break;\n498\t case \"right\":\n499\t this.movePiece(1, 0);\n500\t break;\n501\t case \"down\":\n502\t if (this.movePiece(0, 1)) this.score += 1;\n503\t break;\n504\t }\n505\t }\n506\t\n507\t // ── End Game ──────────────────────────────────────────────────────\n508\t\n509\t private endGame(): void {\n510\t this.gameOver = true;\n511\t cancelAnimationFrame(this.animFrameId);\n512\t this.draw();\n513\t this.showOverlay(\"GAME OVER\", `Final score: ${this.score.toLocaleString()}\\nPress R to restart`);\n514\t }\n515\t\n516\t restart(): void {\n517\t this.board = createBoard();\n518\t this.score = 0;\n519\t this.level = 0;\n520\t this.linesCleared = 0;\n521\t this.gameOver = false;\n522\t this.paused = false;\n523\t this.currentPiece = null;\n524\t this.bag = new Bag();\n525\t this.nextPieceIndex = this.bag.next();\n526\t this.gravityInterval = getGravity(0);\n527\t this.dasDirection = null;\n528\t this.keysDown.clear();\n529\t this.spawnPiece();\n530\t this.hideOverlay();\n531\t this.lastTick = performance.now();\n532\t this.draw();\n533\t this.loop(this.lastTick);\n534\t }\n535\t\n536\t // ── Rendering ─────────────────────────────────────────────────────\n537\t\n538\t private draw(): void {\n539\t // Draw board\n540\t for (let r = 0; r < ROWS; r++) {\n541\t for (let c = 0; c < COLS; c++) {\n542\t const cell = this.cells[r][c];\n543\t if (!cell) continue;\n544\t const boardColor = this.board[r + HIDDEN_ROWS][c];\n545\t cell.style.backgroundColor = boardColor ?? \"\";\n546\t cell.className = \"cell\" + (boardColor ? \" filled\" : \"\");\n547\t }\n548\t }\n549\t\n550\t // Draw ghost piece\n551\t const ghost = this.getGhostPosition();\n552\t if (this.currentPiece && ghost && !this.gameOver) {\n553\t const { shape } = this.currentPiece;\n554\t for (let r = 0; r < shape.length; r++) {\n555\t for (let c = 0; c < shape[r].length; c++) {\n556\t if (!shape[r][c]) continue;\n557\t const br = ghost.y + r - HIDDEN_ROWS;\n558\t const bc = ghost.x + c;\n559\t if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n560\t const cell = this.cells[br][bc];\n561\t if (cell && !this.board[br + HIDDEN_ROWS][bc]) {\n562\t cell.style.backgroundColor = this.currentPiece.color;\n563\t cell.className = \"cell ghost\";\n564\t }\n565\t }\n566\t }\n567\t }\n568\t }\n569\t\n570\t // Draw current piece\n571\t if (this.currentPiece && !this.gameOver) {\n572\t const { shape, pos, color } = this.currentPiece;\n573\t for (let r = 0; r < shape.length; r++) {\n574\t for (let c = 0; c < shape[r].length; c++) {\n575\t if (!shape[r][c]) continue;\n576\t const br = pos.y + r - HIDDEN_ROWS;\n577\t const bc = pos.x + c;\n578\t if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n579\t const cell = this.cells[br][bc];\n580\t if (cell) {\n581\t cell.style.backgroundColor = color;\n582\t cell.className = \"cell active\";\n583\t }\n584\t }\n585\t }\n586\t }\n587\t }\n588\t\n589\t // Draw next piece preview\n590\t const nextT = TETROMINOES[this.nextPieceIndex];\n591\t const nextShape = nextT.shape;\n592\t for (let r = 0; r < 4; r++) {\n593\t for (let c = 0; c < 4; c++) {\n594\t const cell = this.nextCells[r][c];\n595\t if (!cell) continue;\n596\t const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1;\n597\t cell.style.backgroundColor = filled ? nextT.color : \"\";\n598\t cell.className = \"next-cell\" + (filled ? \" filled\" : \"\");\n599\t }\n600\t }\n601\t\n602\t // Update HUD\n603\t this.scoreEl.textContent = this.score.toLocaleString();\n604\t this.levelEl.textContent = String(this.level);\n605\t this.linesEl.textContent = String(this.linesCleared);\n606\t }\n607\t}\n608\t\n609\t// ─── Bootstrap ────────────────────────────────────────────────────────\n610\t\n611\tlet game: TetrisGame;\n612\t\n613\twindow.addEventListener(\"DOMContentLoaded\", () => {\n614\t game = new TetrisGame();\n615\t\n616\t window.addEventListener(\"keydown\", (e) => {\n617\t if (e.code === \"KeyR\" && game.gameOver) {\n618\t game.restart();\n619\t }\n620\t });\n621\t});"}]},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"9e8c5eda-4a91-454b-be65-685c85db8442","timestamp":"2026-04-07T01:48:11.161Z","tool_use_result":{"type":"text","file":{"filePath":"/tmp/loop-bench-cfbvwgky/src/tetris.ts","content":"// ─── Types & Constants ────────────────────────────────────────────────\n\nconst COLS = 10;\nconst ROWS = 20;\nconst HIDDEN_ROWS = 2; // buffer rows above visible area\n\ntype CellColor = string | null;\ntype Board = CellColor[][];\n\ninterface Position {\n x: number;\n y: number;\n}\n\ninterface Piece {\n shape: number[][];\n color: string;\n pos: Position;\n}\n\n// Standard NES-style scoring\nconst LINE_SCORES = [0, 100, 300, 500, 800];\n\n// Gravity intervals in ms per level (index = level, faster as level increases)\nconst GRAVITY_TABLE = [\n 800, 720, 630, 550, 470, 380, 300, 220, 150, 100,\n 80, 80, 80, 70, 70, 70, 50, 50, 50, 30,\n];\n\nfunction getGravity(level: number): number {\n if (level < GRAVITY_TABLE.length) return GRAVITY_TABLE[level];\n return 20; // cap\n}\n\n// Tetromino definitions (shapes in their spawn orientation)\nconst TETROMINOES: { shape: number[][]; color: string }[] = [\n { shape: [[1, 1, 1, 1]], color: \"#00f0f0\" }, // I - cyan\n { shape: [[1, 1], [1, 1]], color: \"#f0f000\" }, // O - yellow\n { shape: [[0, 1, 0], [1, 1, 1]], color: \"#a000f0\" }, // T - purple\n { shape: [[0, 1, 1], [1, 1, 0]], color: \"#00f000\" }, // S - green\n { shape: [[1, 1, 0], [0, 1, 1]], color: \"#f00000\" }, // Z - red\n { shape: [[1, 0, 0], [1, 1, 1]], color: \"#0000f0\" }, // J - blue\n { shape: [[0, 0, 1], [1, 1, 1]], color: \"#f0a000\" }, // L - orange\n];\n\n// ─── Utility ──────────────────────────────────────────────────────────\n\nfunction createBoard(): Board {\n const rows = ROWS + HIDDEN_ROWS;\n const board: Board = [];\n for (let r = 0; r < rows; r++) {\n board.push(new Array<string | null>(COLS).fill(null));\n }\n return board;\n}\n\nfunction rotateMatrix(matrix: number[][]): number[][] {\n const rows = matrix.length;\n const cols = matrix[0].length;\n const result: number[][] = [];\n for (let c = 0; c < cols; c++) {\n const newRow: number[] = [];\n for (let r = rows - 1; r >= 0; r--) {\n newRow.push(matrix[r][c]);\n }\n result.push(newRow);\n }\n return result;\n}\n\n// Wall-kick offsets to try when rotation is blocked\nconst WALL_KICKS: Position[] = [\n { x: 0, y: 0 },\n { x: -1, y: 0 },\n { x: 1, y: 0 },\n { x: -2, y: 0 },\n { x: 2, y: 0 },\n { x: 0, y: -1 },\n { x: -1, y: -1 },\n { x: 1, y: -1 },\n];\n\n// ─── Bag Randomiser (7-bag) ───────────────────────────────────────────\n\nclass Bag {\n private bag: number[] = [];\n\n next(): number {\n if (this.bag.length === 0) {\n this.bag = [0, 1, 2, 3, 4, 5, 6];\n // Fisher-Yates shuffle\n for (let i = this.bag.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];\n }\n }\n return this.bag.pop()!;\n }\n}\n\n// ─── Game ─────────────────────────────────────────────────────────────\n\nclass TetrisGame {\n board: Board = createBoard();\n currentPiece: Piece | null = null;\n nextPieceIndex: number;\n bag = new Bag();\n score = 0;\n level = 0;\n linesCleared = 0;\n gameOver = false;\n paused = false;\n\n // Timing\n private lastTick = 0;\n private gravityInterval = getGravity(0);\n private animFrameId = 0;\n\n // DAS (Delayed Auto Shift) for held keys\n private dasDirection: \"left\" | \"right\" | \"down\" | null = null;\n private dasTimer = 0;\n private dasDelay = 170; // ms before auto-repeat starts\n private dasRate = 50; // ms between auto-repeats\n private dasActive = false;\n private keysDown = new Set<string>();\n\n // DOM references\n private boardEl: HTMLElement;\n private scoreEl: HTMLElement;\n private levelEl: HTMLElement;\n private linesEl: HTMLElement;\n private nextPieceEl: HTMLElement;\n private overlayEl: HTMLElement;\n private overlayTitleEl: HTMLElement;\n private overlaySubEl: HTMLElement;\n private cells: (HTMLElement | null)[][] = [];\n private nextCells: (HTMLElement | null)[][] = [];\n\n constructor() {\n this.nextPieceIndex = this.bag.next();\n\n // Grab DOM elements\n this.boardEl = document.getElementById(\"board\")!;\n this.scoreEl = document.getElementById(\"score\")!;\n this.levelEl = document.getElementById(\"level\")!;\n this.linesEl = document.getElementById(\"lines\")!;\n this.nextPieceEl = document.getElementById(\"next-piece\")!;\n this.overlayEl = document.getElementById(\"overlay\")!;\n this.overlayTitleEl = document.getElementById(\"overlay-title\")!;\n this.overlaySubEl = document.getElementById(\"overlay-sub\")!;\n\n this.buildBoardDOM();\n this.buildNextPieceDOM();\n\n // Input\n window.addEventListener(\"keydown\", (e) => this.onKeyDown(e));\n window.addEventListener(\"keyup\", (e) => this.onKeyUp(e));\n\n // Start\n this.spawnPiece();\n this.showOverlay(\"TETRIS\", \"Press any key to start\");\n this.draw();\n }\n\n // ── DOM Construction ──────────────────────────────────────────────\n\n private buildBoardDOM(): void {\n this.boardEl.innerHTML = \"\";\n this.cells = [];\n for (let r = HIDDEN_ROWS; r < ROWS + HIDDEN_ROWS; r++) {\n const rowCells: (HTMLElement | null)[] = [];\n const rowDiv = document.createElement(\"div\");\n rowDiv.className = \"board-row\";\n for (let c = 0; c < COLS; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"cell\";\n rowDiv.appendChild(cell);\n rowCells.push(cell);\n }\n this.boardEl.appendChild(rowDiv);\n this.cells.push(rowCells);\n }\n }\n\n private buildNextPieceDOM(): void {\n this.nextPieceEl.innerHTML = \"\";\n this.nextCells = [];\n for (let r = 0; r < 4; r++) {\n const rowCells: (HTMLElement | null)[] = [];\n const rowDiv = document.createElement(\"div\");\n rowDiv.className = \"next-row\";\n for (let c = 0; c < 4; c++) {\n const cell = document.createElement(\"div\");\n cell.className = \"next-cell\";\n rowDiv.appendChild(cell);\n rowCells.push(cell);\n }\n this.nextPieceEl.appendChild(rowDiv);\n this.nextCells.push(rowCells);\n }\n }\n\n // ── Overlay ───────────────────────────────────────────────────────\n\n private showOverlay(title: string, sub: string): void {\n this.overlayTitleEl.textContent = title;\n this.overlaySubEl.textContent = sub;\n this.overlayEl.classList.remove(\"hidden\");\n }\n\n private hideOverlay(): void {\n this.overlayEl.classList.add(\"hidden\");\n }\n\n // ── Game Loop ─────────────────────────────────────────────────────\n\n start(): void {\n this.hideOverlay();\n this.lastTick = performance.now();\n this.loop(this.lastTick);\n }\n\n private loop = (now: number): void => {\n if (this.gameOver) return;\n if (this.paused) {\n this.animFrameId = requestAnimationFrame(this.loop);\n return;\n }\n\n const dt = now - this.lastTick;\n\n // DAS handling\n this.handleDAS(now);\n\n // Gravity\n if (dt >= this.gravityInterval) {\n this.tick();\n this.lastTick = now;\n }\n\n this.draw();\n this.animFrameId = requestAnimationFrame(this.loop);\n };\n\n private tick(): void {\n if (!this.currentPiece || this.gameOver) return;\n if (!this.movePiece(0, 1)) {\n this.lockPiece();\n const cleared = this.clearLines();\n if (cleared > 0) {\n this.score += LINE_SCORES[cleared] * (this.level + 1);\n this.linesCleared += cleared;\n const newLevel = Math.floor(this.linesCleared / 10);\n if (newLevel > this.level) {\n this.level = newLevel;\n this.gravityInterval = getGravity(this.level);\n }\n }\n if (!this.spawnPiece()) {\n this.endGame();\n return;\n }\n }\n }\n\n // ── Piece Management ──────────────────────────────────────────────\n\n private spawnPiece(): boolean {\n const idx = this.nextPieceIndex;\n this.nextPieceIndex = this.bag.next();\n const t = TETROMINOES[idx];\n const shape = t.shape.map((row) => [...row]);\n const piece: Piece = {\n shape,\n color: t.color,\n pos: {\n x: Math.floor((COLS - shape[0].length) / 2),\n y: 0,\n },\n };\n this.currentPiece = piece;\n if (!this.isValid(piece.shape, piece.pos)) {\n return false;\n }\n return true;\n }\n\n private lockPiece(): void {\n if (!this.currentPiece) return;\n const { shape, pos, color } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (shape[r][c]) {\n const br = pos.y + r;\n const bc = pos.x + c;\n if (br >= 0 && br < this.board.length && bc >= 0 && bc < COLS) {\n this.board[br][bc] = color;\n }\n }\n }\n }\n }\n\n private clearLines(): number {\n let cleared = 0;\n for (let r = this.board.length - 1; r >= 0; r--) {\n if (this.board[r].every((cell) => cell !== null)) {\n this.board.splice(r, 1);\n this.board.unshift(new Array<string | null>(COLS).fill(null));\n cleared++;\n r++; // recheck same index\n }\n }\n return cleared;\n }\n\n // ── Collision ─────────────────────────────────────────────────────\n\n private isValid(shape: number[][], pos: Position): boolean {\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = pos.y + r;\n const bc = pos.x + c;\n if (bc < 0 || bc >= COLS || br >= this.board.length) return false;\n if (br < 0) continue; // above board is OK\n if (this.board[br][bc] !== null) return false;\n }\n }\n return true;\n }\n\n // ── Movement ──────────────────────────────────────────────────────\n\n movePiece(dx: number, dy: number): boolean {\n if (!this.currentPiece) return false;\n const newPos = { x: this.currentPiece.pos.x + dx, y: this.currentPiece.pos.y + dy };\n if (this.isValid(this.currentPiece.shape, newPos)) {\n this.currentPiece.pos = newPos;\n return true;\n }\n return false;\n }\n\n private rotatePiece(): void {\n if (!this.currentPiece) return;\n const rotated = rotateMatrix(this.currentPiece.shape);\n // Try wall kicks\n for (const kick of WALL_KICKS) {\n const testPos = {\n x: this.currentPiece.pos.x + kick.x,\n y: this.currentPiece.pos.y + kick.y,\n };\n if (this.isValid(rotated, testPos)) {\n this.currentPiece.shape = rotated;\n this.currentPiece.pos = testPos;\n return;\n }\n }\n }\n\n private hardDrop(): void {\n if (!this.currentPiece) return;\n let dropped = 0;\n while (this.movePiece(0, 1)) dropped++;\n this.score += dropped * 2;\n this.lockPiece();\n const cleared = this.clearLines();\n if (cleared > 0) {\n this.score += LINE_SCORES[cleared] * (this.level + 1);\n this.linesCleared += cleared;\n const newLevel = Math.floor(this.linesCleared / 10);\n if (newLevel > this.level) {\n this.level = newLevel;\n this.gravityInterval = getGravity(this.level);\n }\n }\n if (!this.spawnPiece()) {\n this.endGame();\n return;\n }\n this.lastTick = performance.now();\n this.draw();\n }\n\n private getGhostPosition(): Position | null {\n if (!this.currentPiece) return null;\n let ghostY = this.currentPiece.pos.y;\n while (this.isValid(this.currentPiece.shape, { x: this.currentPiece.pos.x, y: ghostY + 1 })) {\n ghostY++;\n }\n return { x: this.currentPiece.pos.x, y: ghostY };\n }\n\n // ── Input Handling ────────────────────────────────────────────────\n\n private started = false;\n\n private onKeyDown(e: KeyboardEvent): void {\n if (!this.started) {\n this.started = true;\n this.start();\n return;\n }\n\n if (this.gameOver) return;\n\n if (e.code === \"KeyP\") {\n this.paused = !this.paused;\n if (this.paused) {\n this.showOverlay(\"PAUSED\", \"Press P to resume\");\n } else {\n this.hideOverlay();\n this.lastTick = performance.now();\n }\n return;\n }\n\n if (this.paused) return;\n\n this.keysDown.add(e.code);\n\n switch (e.code) {\n case \"ArrowLeft\":\n e.preventDefault();\n this.movePiece(-1, 0);\n this.dasDirection = \"left\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowRight\":\n e.preventDefault();\n this.movePiece(1, 0);\n this.dasDirection = \"right\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowDown\":\n e.preventDefault();\n if (this.movePiece(0, 1)) this.score += 1;\n this.dasDirection = \"down\";\n this.dasTimer = performance.now();\n this.dasActive = false;\n break;\n case \"ArrowUp\":\n case \"KeyX\":\n e.preventDefault();\n this.rotatePiece();\n break;\n case \"Space\":\n e.preventDefault();\n this.hardDrop();\n break;\n }\n }\n\n private onKeyUp(e: KeyboardEvent): void {\n this.keysDown.delete(e.code);\n // If the key released matches current DAS direction, stop DAS\n if (\n (e.code === \"ArrowLeft\" && this.dasDirection === \"left\") ||\n (e.code === \"ArrowRight\" && this.dasDirection === \"right\") ||\n (e.code === \"ArrowDown\" && this.dasDirection === \"down\")\n ) {\n this.dasDirection = null;\n }\n }\n\n private handleDAS(now: number): void {\n if (!this.dasDirection) return;\n // Check if the key is still held\n const codeMap = { left: \"ArrowLeft\", right: \"ArrowRight\", down: \"ArrowDown\" };\n if (!this.keysDown.has(codeMap[this.dasDirection])) {\n this.dasDirection = null;\n return;\n }\n\n const elapsed = now - this.dasTimer;\n if (!this.dasActive) {\n if (elapsed >= this.dasDelay) {\n this.dasActive = true;\n this.dasTimer = now;\n this.dasRepeat();\n }\n } else {\n if (elapsed >= this.dasRate) {\n this.dasTimer = now;\n this.dasRepeat();\n }\n }\n }\n\n private dasRepeat(): void {\n switch (this.dasDirection) {\n case \"left\":\n this.movePiece(-1, 0);\n break;\n case \"right\":\n this.movePiece(1, 0);\n break;\n case \"down\":\n if (this.movePiece(0, 1)) this.score += 1;\n break;\n }\n }\n\n // ── End Game ──────────────────────────────────────────────────────\n\n private endGame(): void {\n this.gameOver = true;\n cancelAnimationFrame(this.animFrameId);\n this.draw();\n this.showOverlay(\"GAME OVER\", `Final score: ${this.score.toLocaleString()}\\nPress R to restart`);\n }\n\n restart(): void {\n this.board = createBoard();\n this.score = 0;\n this.level = 0;\n this.linesCleared = 0;\n this.gameOver = false;\n this.paused = false;\n this.currentPiece = null;\n this.bag = new Bag();\n this.nextPieceIndex = this.bag.next();\n this.gravityInterval = getGravity(0);\n this.dasDirection = null;\n this.keysDown.clear();\n this.spawnPiece();\n this.hideOverlay();\n this.lastTick = performance.now();\n this.draw();\n this.loop(this.lastTick);\n }\n\n // ── Rendering ─────────────────────────────────────────────────────\n\n private draw(): void {\n // Draw board\n for (let r = 0; r < ROWS; r++) {\n for (let c = 0; c < COLS; c++) {\n const cell = this.cells[r][c];\n if (!cell) continue;\n const boardColor = this.board[r + HIDDEN_ROWS][c];\n cell.style.backgroundColor = boardColor ?? \"\";\n cell.className = \"cell\" + (boardColor ? \" filled\" : \"\");\n }\n }\n\n // Draw ghost piece\n const ghost = this.getGhostPosition();\n if (this.currentPiece && ghost && !this.gameOver) {\n const { shape } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = ghost.y + r - HIDDEN_ROWS;\n const bc = ghost.x + c;\n if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n const cell = this.cells[br][bc];\n if (cell && !this.board[br + HIDDEN_ROWS][bc]) {\n cell.style.backgroundColor = this.currentPiece.color;\n cell.className = \"cell ghost\";\n }\n }\n }\n }\n }\n\n // Draw current piece\n if (this.currentPiece && !this.gameOver) {\n const { shape, pos, color } = this.currentPiece;\n for (let r = 0; r < shape.length; r++) {\n for (let c = 0; c < shape[r].length; c++) {\n if (!shape[r][c]) continue;\n const br = pos.y + r - HIDDEN_ROWS;\n const bc = pos.x + c;\n if (br >= 0 && br < ROWS && bc >= 0 && bc < COLS) {\n const cell = this.cells[br][bc];\n if (cell) {\n cell.style.backgroundColor = color;\n cell.className = \"cell active\";\n }\n }\n }\n }\n }\n\n // Draw next piece preview\n const nextT = TETROMINOES[this.nextPieceIndex];\n const nextShape = nextT.shape;\n for (let r = 0; r < 4; r++) {\n for (let c = 0; c < 4; c++) {\n const cell = this.nextCells[r][c];\n if (!cell) continue;\n const filled = r < nextShape.length && c < nextShape[r].length && nextShape[r][c] === 1;\n cell.style.backgroundColor = filled ? nextT.color : \"\";\n cell.className = \"next-cell\" + (filled ? \" filled\" : \"\");\n }\n }\n\n // Update HUD\n this.scoreEl.textContent = this.score.toLocaleString();\n this.levelEl.textContent = String(this.level);\n this.linesEl.textContent = String(this.linesCleared);\n }\n}\n\n// ─── Bootstrap ────────────────────────────────────────────────────────\n\nlet game: TetrisGame;\n\nwindow.addEventListener(\"DOMContentLoaded\", () => {\n game = new TetrisGame();\n\n window.addEventListener(\"keydown\", (e) => {\n if (e.code === \"KeyR\" && game.gameOver) {\n game.restart();\n }\n });\n});","numLines":621,"startLine":1,"totalLines":621}}} +{"type":"assistant","message":{"id":"msg_202604070948129213be84e19b40ad","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"text","text":"The game is complete. Here's a summary of what was built:\n\n## Tetris — DOM-rendered, TypeScript\n\n### Files\n| File | Purpose |\n|---|---|\n| `src/tetris.ts` | Complete game logic (~620 lines of TypeScript) |\n| `dist/tetris.js` | Compiled output (auto-generated) |\n| `styles.css` | Dark-themed CSS with glow effects |\n| `index.html` | Page structure with board + side panel |\n| `tsconfig.json` | TypeScript compiler config |\n\n### How to play\nOpen `index.html` in a browser (just a file open works — no server needed). Press any key to start.\n\n### Features implemented\n- **All 7 standard tetrominoes** (I, O, T, S, Z, J, L) with distinct colors\n- **7-bag randomizer** — fair piece distribution using Fisher-Yates shuffle\n- **Rotation with wall kicks** — tries 8 offset positions if rotation is blocked\n- **Ghost piece** — translucent preview showing where the piece will land\n- **Line clearing** — full rows are removed and everything above shifts down\n- **NES-style scoring** — 100/300/500/800 × level for 1/2/3/4 lines, +1 per soft-drop cell, +2 per hard-drop cell\n- **Increasing speed** — gravity gets faster every 10 lines (20 levels in the gravity table)\n- **DAS (Delayed Auto Shift)** — hold left/right/down for auto-repeat after 170ms delay at 50ms intervals\n- **Next piece preview** in the side panel\n- **Pause** (P key), **Restart** (R key after game over)\n- **Overlay system** for start screen, pause, and game over\n\n### Controls\n| Key | Action |\n|---|---|\n| ← → | Move piece |\n| ↑ | Rotate |\n| ↓ | Soft drop (+1 pt/cell) |\n| Space | Hard drop (+2 pts/cell) |\n| P | Pause/Resume |\n| R | Restart (after game over) |"}],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0},"context_management":null},"parent_tool_use_id":null,"session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","uuid":"7239a5a5-18f8-463b-ba4e-3f3900840354"} +{"type":"result","subtype":"success","is_error":false,"duration_ms":325649,"duration_api_ms":322151,"num_turns":19,"result":"The game is complete. Here's a summary of what was built:\n\n## Tetris — DOM-rendered, TypeScript\n\n### Files\n| File | Purpose |\n|---|---|\n| `src/tetris.ts` | Complete game logic (~620 lines of TypeScript) |\n| `dist/tetris.js` | Compiled output (auto-generated) |\n| `styles.css` | Dark-themed CSS with glow effects |\n| `index.html` | Page structure with board + side panel |\n| `tsconfig.json` | TypeScript compiler config |\n\n### How to play\nOpen `index.html` in a browser (just a file open works — no server needed). Press any key to start.\n\n### Features implemented\n- **All 7 standard tetrominoes** (I, O, T, S, Z, J, L) with distinct colors\n- **7-bag randomizer** — fair piece distribution using Fisher-Yates shuffle\n- **Rotation with wall kicks** — tries 8 offset positions if rotation is blocked\n- **Ghost piece** — translucent preview showing where the piece will land\n- **Line clearing** — full rows are removed and everything above shifts down\n- **NES-style scoring** — 100/300/500/800 × level for 1/2/3/4 lines, +1 per soft-drop cell, +2 per hard-drop cell\n- **Increasing speed** — gravity gets faster every 10 lines (20 levels in the gravity table)\n- **DAS (Delayed Auto Shift)** — hold left/right/down for auto-repeat after 170ms delay at 50ms intervals\n- **Next piece preview** in the side panel\n- **Pause** (P key), **Restart** (R key after game over)\n- **Overlay system** for start screen, pause, and game over\n\n### Controls\n| Key | Action |\n|---|---|\n| ← → | Move piece |\n| ↑ | Rotate |\n| ↓ | Soft drop (+1 pt/cell) |\n| Space | Hard drop (+2 pts/cell) |\n| P | Pause/Resume |\n| R | Restart (after game over) |","stop_reason":"end_turn","session_id":"0fdf4f8f-a55a-4bf3-bd52-3c8066d052a2","total_cost_usd":0.221676,"usage":{"input_tokens":17209,"cache_creation_input_tokens":0,"cache_read_input_tokens":146880,"output_tokens":8399,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"glm-5.1":{"inputTokens":17209,"outputTokens":8399,"cacheReadInputTokens":146880,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.221676,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"bf704f44-eec4-48e8-b986-7b14883c980d"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/claude_stderr.log b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/claude_stderr.log diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/meta.json @@ -0,0 +1,37 @@ +{ + "model": "glm-5.1", + "effort": "high", + "prompt_style": "simple", + "language": "typescript", + "human_language": "en", + "tool_read": "on", + "tool_write": "on", + "tool_edit": "on", + "tool_glob": "on", + "tool_grep": "on", + "linter": "on", + "playwright": "off", + "context_file": "none", + "web_search": "on", + "max_budget": "low", + "tests_provided": "none", + "strategy": "none", + "design_guidance": "none", + "architecture": "none", + "error_checking": "none", + "context_noise": "clean", + "renderer": "dom", + "provider": "zai", + "task": "tetris", + "actual_model": "glm-5.1", + "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", + "runs_per_cell": 3, + "timeout_seconds": 1200, + "max_budget_usd": 2.0, + "run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3", + "short_id": "5da14018", + "short_cell_id": "86ee3001", + "run_number": 3, + "claude_version": "2.1.92 (Claude Code)", + "started_at": "2026-04-07T01:50:27.346969+00:00" +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/transcript.jsonl b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=dom_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/transcript.jsonl @@ -0,0 +1,3 @@ +{"type": "harness", "subtype": "config", "model": "glm-5.1", "effort": "high", "tools": ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "WebSearch", "WebFetch"], "max_budget_usd": 2.0, "timeout_seconds": 1200, "task": "tetris", "language": "typescript", "prompt_style": "simple"} +{"type": "user", "subtype": "prompt", "message": {"role": "user", "content": "Build a playable Tetris game that runs in a browser. It should have all the standard mechanics: piece rotation, line clearing, scoring, and increasing speed. Use keyboard controls for movement and rotation.\n\n\nUse TypeScript.\n\nRender the game using DOM elements (divs/tables) with CSS for styling. Do not use Canvas or SVG."}} +{"type":"system","subtype":"init","cwd":"/tmp/loop-bench-4v9zg5jy","session_id":"35cf97aa-a5f1-432a-acb7-3e3f74501418","tools":["Bash","Edit","Read"],"mcp_servers":[],"model":"glm-5.1","permissionMode":"dontAsk","slash_commands":["update-config","debug","simplify","batch","loop","schedule","claude-api","compact","context","cost","heapdump","init","review","security-review","insights"],"apiKeySource":"apiKeyHelper","claude_code_version":"2.1.92","output_style":"default","agents":["general-purpose","statusline-setup","Explore","Plan"],"skills":["update-config","debug","simplify","batch","loop","schedule","claude-api"],"plugins":[{"name":"claude-hud","path":"/root/.claude/plugins/marketplaces/claude-hud/","source":"claude-hud@claude-hud"},{"name":"rust-analyzer-lsp","path":"/root/.claude/plugins/marketplaces/claude-plugins-official/plugins/rust-analyzer-lsp","source":"rust-analyzer-lsp@claude-plugins-official"}],"uuid":"bf530bca-ec43-4813-b471-13a6e1530ead","fast_mode_state":"off"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/claude_output.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/claude_output.json @@ -0,0 +1 @@ +{"type":"result","subtype":"success","is_error":true,"duration_ms":202395,"duration_api_ms":0,"num_turns":1,"result":"API Error: 429 {\"error\":{\"code\":\"1308\",\"message\":\"Usage limit reached for 5 hour. Your limit will reset at 2026-04-07 09:39:11\"},\"request_id\":\"20260407093819257b46ae72a14d9a\"}","stop_reason":"stop_sequence","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","total_cost_usd":0,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"5e220c76-d8a3-48ee-a92d-918d0715fbc9"} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/eval_results.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/eval_results.json @@ -0,0 +1,134 @@ +{ + "structural": { + "pass": false, + "checks": [ + { + "name": "entry_point_exists", + "pass": false, + "detail": "no index.html found in workspace root, dist/, or public/" + }, + { + "name": "package_json_exists", + "pass": true, + "detail": "package.json found" + }, + { + "name": "build_succeeds", + "pass": true, + "detail": "no build script defined (static project)" + }, + { + "name": "typescript_compiles", + "pass": false, + "detail": "TypeScript files found but no tsconfig.json" + } + ], + "score": 0.5 + }, + "quality": { + "lint": { + "pass": true, + "errors": 0, + "warnings": 0 + }, + "typecheck": { + "pass": false, + "error": "no tsconfig.json" + }, + "performance": { + "pass": true, + "bundle_size_bytes": 0, + "size_under_512kb": true + }, + "score": 0.67 + }, + "code_analysis": { + "files": { + "total": 6, + "code": 4, + "docs": 0, + "unnecessary": 0, + "unnecessary_list": [] + }, + "lines_of_code": 596, + "dependencies": { + "production": 0, + "dev": 4, + "total": 4 + }, + "complexity": "moderate", + "console_logs": 0, + "magic_numbers": { + "count": 37, + "excessive": true + }, + "function_length": { + "count": 16, + "average": 6.6, + "max": 16, + "long_functions": 0 + }, + "max_nesting_depth": 5, + "global_declarations": 0, + "naming": { + "dominant_style": "camelCase", + "consistency_pct": 100.0, + "camel_case": 141, + "snake_case": 0 + }, + "error_handling": { + "try_catch_blocks": 4, + "has_error_handling": true + }, + "comments": { + "comment_lines": 70, + "source_lines": 444, + "ratio_pct": 15.8 + }, + "separation_of_concerns": { + "verdict": "mixed", + "files_with_rendering": 2, + "files_with_logic": 1, + "files_with_both": 1 + }, + "html_validation": { + "valid": false, + "errors": 0 + }, + "duplication_percentage": 0.0, + "score": 0.55 + }, + "transcript_analysis": { + "total_events": 15, + "tool_calls": { + "total": 0, + "bash": 0, + "write": 0, + "edit": 0, + "read": 0 + }, + "wasted_turns": { + "total": 0, + "docs": 0, + "ascii_art": 0, + "server_starts": 0 + }, + "errors_encountered": 0, + "thinking_blocks": 0, + "text_blocks": 1, + "productivity_ratio": 0, + "self_tested": false, + "score": 1.0 + }, + "gameplay_bot": { + "pass": false, + "score": 0, + "error": "no HTML files in workspace - game was not built" + }, + "outcome_score": 0.0, + "score": 0.0, + "sonarqube": { + "error": "SonarQube not running at localhost:9000", + "score": 0 + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/meta.json @@ -33,5 +33,8 @@ "short_cell_id": "a4c12deb", "run_number": 1, "claude_version": "2.1.92 (Claude Code)", - "started_at": "2026-04-07T01:34:55.542672+00:00" + "started_at": "2026-04-07T01:34:55.542672+00:00", + "wall_time_seconds": 203, + "exit_code": 1, + "completed_at": "2026-04-07T01:38:20.329385+00:00" } \ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/transcript.jsonl b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/transcript.jsonl @@ -5,3 +5,11 @@ {"type":"system","subtype":"api_retry","attempt":2,"max_retries":10,"retry_delay_ms":1004.3837192985903,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"46fd8d54-28dc-4936-9b72-7e0e28f67f62"} {"type":"system","subtype":"api_retry","attempt":3,"max_retries":10,"retry_delay_ms":2369.923199076935,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"8949e1ee-2be2-4cb5-b766-3213849ecb42"} {"type":"system","subtype":"api_retry","attempt":4,"max_retries":10,"retry_delay_ms":4296.742569695087,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"04649a63-e357-4270-a47f-bcc60b3782a7"} +{"type":"system","subtype":"api_retry","attempt":5,"max_retries":10,"retry_delay_ms":9571.92658258702,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"849fdf74-fe57-4b19-9b49-15d902d63f17"} +{"type":"system","subtype":"api_retry","attempt":6,"max_retries":10,"retry_delay_ms":19869.935404167536,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"32b5e649-b52d-4a11-b706-bce64a6882f1"} +{"type":"system","subtype":"api_retry","attempt":7,"max_retries":10,"retry_delay_ms":33505.75481274989,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"a214f5e8-9ee8-41ea-b877-e850ecb66335"} +{"type":"system","subtype":"api_retry","attempt":8,"max_retries":10,"retry_delay_ms":37051.36115930728,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"b0efb6fe-62ba-4c87-bc4e-796bd3473abd"} +{"type":"system","subtype":"api_retry","attempt":9,"max_retries":10,"retry_delay_ms":36415.83544980083,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"48959ea3-210f-46e4-be1e-c3dc74840d6f"} +{"type":"system","subtype":"api_retry","attempt":10,"max_retries":10,"retry_delay_ms":37644.02556006692,"error_status":429,"error":"rate_limit","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"d4f9310e-21fb-4b39-bd9b-e828916da96e"} +{"type":"assistant","message":{"id":"1fcf3b32-85bd-4706-a31a-41e196b9254e","container":null,"model":"<synthetic>","role":"assistant","stop_reason":"stop_sequence","stop_sequence":"","type":"message","usage":{"input_tokens":0,"output_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":null,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":null,"iterations":null,"speed":null},"content":[{"type":"text","text":"API Error: 429 {\"error\":{\"code\":\"1308\",\"message\":\"Usage limit reached for 5 hour. Your limit will reset at 2026-04-07 09:39:11\"},\"request_id\":\"20260407093819257b46ae72a14d9a\"}"}],"context_management":null},"parent_tool_use_id":null,"session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","uuid":"ca3a445a-5cd3-4c69-9b41-0126a2b2486b","error":"unknown"} +{"type":"result","subtype":"success","is_error":true,"duration_ms":202395,"duration_api_ms":0,"num_turns":1,"result":"API Error: 429 {\"error\":{\"code\":\"1308\",\"message\":\"Usage limit reached for 5 hour. Your limit will reset at 2026-04-07 09:39:11\"},\"request_id\":\"20260407093819257b46ae72a14d9a\"}","stop_reason":"stop_sequence","session_id":"b57d61dd-70bf-4815-ab24-9cb6cb44f274","total_cost_usd":0,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"5e220c76-d8a3-48ee-a92d-918d0715fbc9"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_output.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_output.json @@ -0,0 +1 @@ +{"type":"result","subtype":"success","is_error":true,"duration_ms":190558,"duration_api_ms":0,"num_turns":1,"result":"API Error: 429 {\"error\":{\"code\":\"1308\",\"message\":\"Usage limit reached for 5 hour. Your limit will reset at 2026-04-07 09:39:11\"},\"request_id\":\"20260407093821b956be3b4aab45df\"}","stop_reason":"stop_sequence","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","total_cost_usd":0,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"f7e97aa4-0736-4084-8252-f93056ecf7b8"} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_stderr.log b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/claude_stderr.log diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/eval_results.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/eval_results.json @@ -0,0 +1,134 @@ +{ + "structural": { + "pass": false, + "checks": [ + { + "name": "entry_point_exists", + "pass": false, + "detail": "no index.html found in workspace root, dist/, or public/" + }, + { + "name": "package_json_exists", + "pass": true, + "detail": "package.json found" + }, + { + "name": "build_succeeds", + "pass": true, + "detail": "no build script defined (static project)" + }, + { + "name": "typescript_compiles", + "pass": false, + "detail": "TypeScript files found but no tsconfig.json" + } + ], + "score": 0.5 + }, + "quality": { + "lint": { + "pass": true, + "errors": 0, + "warnings": 0 + }, + "typecheck": { + "pass": false, + "error": "no tsconfig.json" + }, + "performance": { + "pass": true, + "bundle_size_bytes": 0, + "size_under_512kb": true + }, + "score": 0.67 + }, + "code_analysis": { + "files": { + "total": 6, + "code": 4, + "docs": 0, + "unnecessary": 0, + "unnecessary_list": [] + }, + "lines_of_code": 596, + "dependencies": { + "production": 0, + "dev": 4, + "total": 4 + }, + "complexity": "moderate", + "console_logs": 0, + "magic_numbers": { + "count": 37, + "excessive": true + }, + "function_length": { + "count": 16, + "average": 6.6, + "max": 16, + "long_functions": 0 + }, + "max_nesting_depth": 5, + "global_declarations": 0, + "naming": { + "dominant_style": "camelCase", + "consistency_pct": 100.0, + "camel_case": 141, + "snake_case": 0 + }, + "error_handling": { + "try_catch_blocks": 4, + "has_error_handling": true + }, + "comments": { + "comment_lines": 70, + "source_lines": 444, + "ratio_pct": 15.8 + }, + "separation_of_concerns": { + "verdict": "mixed", + "files_with_rendering": 2, + "files_with_logic": 1, + "files_with_both": 1 + }, + "html_validation": { + "valid": false, + "errors": 0 + }, + "duplication_percentage": 0.0, + "score": 0.55 + }, + "transcript_analysis": { + "total_events": 15, + "tool_calls": { + "total": 0, + "bash": 0, + "write": 0, + "edit": 0, + "read": 0 + }, + "wasted_turns": { + "total": 0, + "docs": 0, + "ascii_art": 0, + "server_starts": 0 + }, + "errors_encountered": 0, + "thinking_blocks": 0, + "text_blocks": 1, + "productivity_ratio": 0, + "self_tested": false, + "score": 1.0 + }, + "gameplay_bot": { + "pass": false, + "score": 0, + "error": "no HTML files in workspace - game was not built" + }, + "outcome_score": 0.0, + "score": 0.0, + "sonarqube": { + "error": "SonarQube not running at localhost:9000", + "score": 0 + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/meta.json @@ -33,5 +33,8 @@ "short_cell_id": "a4c12deb", "run_number": 2, "claude_version": "2.1.92 (Claude Code)", - "started_at": "2026-04-07T01:35:09.780909+00:00" + "started_at": "2026-04-07T01:35:09.780909+00:00", + "wall_time_seconds": 191, + "exit_code": 1, + "completed_at": "2026-04-07T01:38:22.673272+00:00" } \ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/transcript.jsonl b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run2/transcript.jsonl @@ -0,0 +1,15 @@ +{"type": "harness", "subtype": "config", "model": "glm-5.1", "effort": "high", "tools": ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "WebSearch", "WebFetch"], "max_budget_usd": 2.0, "timeout_seconds": 1200, "task": "tetris", "language": "typescript", "prompt_style": "simple"} +{"type": "user", "subtype": "prompt", "message": {"role": "user", "content": "Build a playable Tetris game that runs in a browser. It should have all the standard mechanics: piece rotation, line clearing, scoring, and increasing speed. Use keyboard controls for movement and rotation.\n\n\nUse TypeScript.\n\nRender the game using SVG elements."}} +{"type":"system","subtype":"init","cwd":"/tmp/loop-bench-e8tgl0pn","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","tools":["Bash","Edit","Read"],"mcp_servers":[],"model":"glm-5.1","permissionMode":"dontAsk","slash_commands":["update-config","debug","simplify","batch","loop","schedule","claude-api","compact","context","cost","heapdump","init","review","security-review","insights"],"apiKeySource":"apiKeyHelper","claude_code_version":"2.1.92","output_style":"default","agents":["general-purpose","statusline-setup","Explore","Plan"],"skills":["update-config","debug","simplify","batch","loop","schedule","claude-api"],"plugins":[{"name":"claude-hud","path":"/root/.claude/plugins/marketplaces/claude-hud/","source":"claude-hud@claude-hud"},{"name":"rust-analyzer-lsp","path":"/root/.claude/plugins/marketplaces/claude-plugins-official/plugins/rust-analyzer-lsp","source":"rust-analyzer-lsp@claude-plugins-official"}],"uuid":"2c1c406b-c52a-4e76-abb0-8dd480e3f991","fast_mode_state":"off"} +{"type":"system","subtype":"api_retry","attempt":1,"max_retries":10,"retry_delay_ms":575.7470263620231,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"37b82182-7c77-43d3-92a7-e2875681cf87"} +{"type":"system","subtype":"api_retry","attempt":2,"max_retries":10,"retry_delay_ms":1068.213808777122,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"7e207d85-4313-43ec-920d-759870cd9f1c"} +{"type":"system","subtype":"api_retry","attempt":3,"max_retries":10,"retry_delay_ms":2301.024069993878,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"4ea4f8f2-83be-4803-b3aa-ec5bcb759118"} +{"type":"system","subtype":"api_retry","attempt":4,"max_retries":10,"retry_delay_ms":4944.876443413669,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"81f8e79a-abdb-47ed-b069-a4ee561f5f96"} +{"type":"system","subtype":"api_retry","attempt":5,"max_retries":10,"retry_delay_ms":9384.604760493407,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"d70e48f1-1711-49d6-8147-67be9cb18fcb"} +{"type":"system","subtype":"api_retry","attempt":6,"max_retries":10,"retry_delay_ms":19918.100086771647,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"ac5ce0c5-6e58-4c51-a727-a8a75bf20950"} +{"type":"system","subtype":"api_retry","attempt":7,"max_retries":10,"retry_delay_ms":33562.10644500833,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"73c861e9-23ea-4a1a-9baa-cf985ef85a41"} +{"type":"system","subtype":"api_retry","attempt":8,"max_retries":10,"retry_delay_ms":32355.149554905638,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"8d1b9120-49d7-4348-b7f6-363b7ed36c67"} +{"type":"system","subtype":"api_retry","attempt":9,"max_retries":10,"retry_delay_ms":32849.60879098822,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"a01e16b1-ab98-45aa-806c-5fc99c7fed73"} +{"type":"system","subtype":"api_retry","attempt":10,"max_retries":10,"retry_delay_ms":39911.5635021247,"error_status":429,"error":"rate_limit","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"4b64aa26-5b99-4f63-802c-971f89eecc5a"} +{"type":"assistant","message":{"id":"291546ff-3282-4884-8f3f-2fadc1215b85","container":null,"model":"<synthetic>","role":"assistant","stop_reason":"stop_sequence","stop_sequence":"","type":"message","usage":{"input_tokens":0,"output_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":null,"cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":null,"iterations":null,"speed":null},"content":[{"type":"text","text":"API Error: 429 {\"error\":{\"code\":\"1308\",\"message\":\"Usage limit reached for 5 hour. Your limit will reset at 2026-04-07 09:39:11\"},\"request_id\":\"20260407093821b956be3b4aab45df\"}"}],"context_management":null},"parent_tool_use_id":null,"session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","uuid":"e69a2e7e-7f59-47e8-9396-21859ad0204a","error":"unknown"} +{"type":"result","subtype":"success","is_error":true,"duration_ms":190558,"duration_api_ms":0,"num_turns":1,"result":"API Error: 429 {\"error\":{\"code\":\"1308\",\"message\":\"Usage limit reached for 5 hour. Your limit will reset at 2026-04-07 09:39:11\"},\"request_id\":\"20260407093821b956be3b4aab45df\"}","stop_reason":"stop_sequence","session_id":"ae51d5a6-b2f5-43ff-8dc1-228a3063cd6d","total_cost_usd":0,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"f7e97aa4-0736-4084-8252-f93056ecf7b8"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/claude_output.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/claude_output.json @@ -0,0 +1 @@ +{"type":"result","subtype":"success","is_error":false,"duration_ms":271402,"duration_api_ms":271327,"num_turns":1,"result":"","stop_reason":"max_tokens","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","total_cost_usd":0.1246908,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"glm-5.1":{"inputTokens":1282,"outputTokens":8000,"cacheReadInputTokens":2816,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.1246908,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"958c84fa-3bbd-4c0b-8304-c8d75bf8abd1"} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/claude_stderr.log b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/claude_stderr.log diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/eval_results.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/eval_results.json @@ -0,0 +1,134 @@ +{ + "structural": { + "pass": false, + "checks": [ + { + "name": "entry_point_exists", + "pass": false, + "detail": "no index.html found in workspace root, dist/, or public/" + }, + { + "name": "package_json_exists", + "pass": true, + "detail": "package.json found" + }, + { + "name": "build_succeeds", + "pass": true, + "detail": "no build script defined (static project)" + }, + { + "name": "typescript_compiles", + "pass": false, + "detail": "TypeScript files found but no tsconfig.json" + } + ], + "score": 0.5 + }, + "quality": { + "lint": { + "pass": true, + "errors": 0, + "warnings": 0 + }, + "typecheck": { + "pass": false, + "error": "no tsconfig.json" + }, + "performance": { + "pass": true, + "bundle_size_bytes": 0, + "size_under_512kb": true + }, + "score": 0.67 + }, + "code_analysis": { + "files": { + "total": 6, + "code": 4, + "docs": 0, + "unnecessary": 0, + "unnecessary_list": [] + }, + "lines_of_code": 596, + "dependencies": { + "production": 0, + "dev": 4, + "total": 4 + }, + "complexity": "moderate", + "console_logs": 0, + "magic_numbers": { + "count": 37, + "excessive": true + }, + "function_length": { + "count": 16, + "average": 6.6, + "max": 16, + "long_functions": 0 + }, + "max_nesting_depth": 5, + "global_declarations": 0, + "naming": { + "dominant_style": "camelCase", + "consistency_pct": 100.0, + "camel_case": 141, + "snake_case": 0 + }, + "error_handling": { + "try_catch_blocks": 4, + "has_error_handling": true + }, + "comments": { + "comment_lines": 70, + "source_lines": 444, + "ratio_pct": 15.8 + }, + "separation_of_concerns": { + "verdict": "mixed", + "files_with_rendering": 2, + "files_with_logic": 1, + "files_with_both": 1 + }, + "html_validation": { + "valid": false, + "errors": 0 + }, + "duplication_percentage": 0.0, + "score": 0.55 + }, + "transcript_analysis": { + "total_events": 11, + "tool_calls": { + "total": 0, + "bash": 0, + "write": 0, + "edit": 0, + "read": 0 + }, + "wasted_turns": { + "total": 0, + "docs": 0, + "ascii_art": 0, + "server_starts": 0 + }, + "errors_encountered": 0, + "thinking_blocks": 1, + "text_blocks": 0, + "productivity_ratio": 0, + "self_tested": false, + "score": 1.0 + }, + "gameplay_bot": { + "pass": false, + "score": 0, + "error": "no HTML files in workspace - game was not built" + }, + "outcome_score": 0.0, + "score": 0.0, + "sonarqube": { + "error": "SonarQube not running at localhost:9000", + "score": 0 + } +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/meta.json @@ -0,0 +1,40 @@ +{ + "model": "glm-5.1", + "effort": "high", + "prompt_style": "simple", + "language": "typescript", + "human_language": "en", + "tool_read": "on", + "tool_write": "on", + "tool_edit": "on", + "tool_glob": "on", + "tool_grep": "on", + "linter": "on", + "playwright": "off", + "context_file": "none", + "web_search": "on", + "max_budget": "low", + "tests_provided": "none", + "strategy": "none", + "design_guidance": "none", + "architecture": "none", + "error_checking": "none", + "context_noise": "clean", + "renderer": "svg", + "provider": "zai", + "task": "tetris", + "actual_model": "glm-5.1", + "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", + "runs_per_cell": 3, + "timeout_seconds": 1200, + "max_budget_usd": 2.0, + "run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3", + "short_id": "8cf0fbde", + "short_cell_id": "a4c12deb", + "run_number": 3, + "claude_version": "2.1.92 (Claude Code)", + "started_at": "2026-04-07T01:38:22.395917+00:00", + "wall_time_seconds": 272, + "exit_code": 0, + "completed_at": "2026-04-07T01:42:57.035119+00:00" +} +\ No newline at end of file diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/transcript.jsonl b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=svg_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run3/transcript.jsonl @@ -0,0 +1,11 @@ +{"type": "harness", "subtype": "config", "model": "glm-5.1", "effort": "high", "tools": ["Bash", "Read", "Write", "Edit", "Glob", "Grep", "WebSearch", "WebFetch"], "max_budget_usd": 2.0, "timeout_seconds": 1200, "task": "tetris", "language": "typescript", "prompt_style": "simple"} +{"type": "user", "subtype": "prompt", "message": {"role": "user", "content": "Build a playable Tetris game that runs in a browser. It should have all the standard mechanics: piece rotation, line clearing, scoring, and increasing speed. Use keyboard controls for movement and rotation.\n\n\nUse TypeScript.\n\nRender the game using SVG elements."}} +{"type":"system","subtype":"init","cwd":"/tmp/loop-bench-k7ar_jba","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","tools":["Bash","Edit","Read"],"mcp_servers":[],"model":"glm-5.1","permissionMode":"dontAsk","slash_commands":["update-config","debug","simplify","batch","loop","schedule","claude-api","compact","context","cost","heapdump","init","review","security-review","insights"],"apiKeySource":"apiKeyHelper","claude_code_version":"2.1.92","output_style":"default","agents":["general-purpose","statusline-setup","Explore","Plan"],"skills":["update-config","debug","simplify","batch","loop","schedule","claude-api"],"plugins":[{"name":"claude-hud","path":"/root/.claude/plugins/marketplaces/claude-hud/","source":"claude-hud@claude-hud"},{"name":"rust-analyzer-lsp","path":"/root/.claude/plugins/marketplaces/claude-plugins-official/plugins/rust-analyzer-lsp","source":"rust-analyzer-lsp@claude-plugins-official"}],"uuid":"f4d1c3e3-812e-4610-8f30-4ae6aa26bf62","fast_mode_state":"off"} +{"type":"system","subtype":"api_retry","attempt":1,"max_retries":10,"retry_delay_ms":602.833641289021,"error_status":429,"error":"rate_limit","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"e9996292-477a-40a9-b7ac-68a45781723c"} +{"type":"system","subtype":"api_retry","attempt":2,"max_retries":10,"retry_delay_ms":1005.5905604517862,"error_status":429,"error":"rate_limit","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"b02892f6-a3d2-4edb-b45f-3c1cf67a2c6b"} +{"type":"system","subtype":"api_retry","attempt":3,"max_retries":10,"retry_delay_ms":2463.7327390230384,"error_status":429,"error":"rate_limit","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"7d3ed793-c0aa-4412-8060-908960b95cce"} +{"type":"system","subtype":"api_retry","attempt":4,"max_retries":10,"retry_delay_ms":4419.611433532665,"error_status":429,"error":"rate_limit","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"f24346e2-71e9-4297-acb0-2ad0aa7f8fd3"} +{"type":"system","subtype":"api_retry","attempt":5,"max_retries":10,"retry_delay_ms":9915.925230621218,"error_status":429,"error":"rate_limit","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"1ab650f1-ca28-411d-b7ed-80c9f278434f"} +{"type":"system","subtype":"api_retry","attempt":6,"max_retries":10,"retry_delay_ms":17355.60566644762,"error_status":429,"error":"rate_limit","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"9855de2e-bfba-4aaa-88b8-b65f9f30c232"} +{"type":"assistant","message":{"id":"msg_20260407093912cf1184f82e144f31","type":"message","role":"assistant","model":"glm-5.1","content":[{"type":"thinking","thinking":"The user wants me to build a playable Tetris game that runs in a browser using TypeScript and SVG rendering. Let me plan out the structure:\n\n1. A single HTML file that loads a TypeScript file (or I can compile TS to JS)\n2. SVG-based rendering for the game board\n3. Standard Tetris mechanics:\n - 7 tetromino pieces (I, O, T, S, Z, J, L)\n - Piece rotation\n - Line clearing\n - Scoring\n - Increasing speed (levels)\n - Keyboard controls (arrow keys for movement, up for rotation)\n\nSince the user wants TypeScript, I'll need to set up a simple project with a build step. Let me create:\n- `index.html` - the main page\n- `tetris.ts` - the game logic and rendering\n- `tsconfig.json` - TypeScript config\n- Use a simple build approach\n\nActually, for simplicity and to make it immediately playable, I could either:\n1. Use a bundler like esbuild or webpack\n2. Just use `tsc` to compile and include the JS in HTML\n\nLet me go with a simple approach: create the TS file, compile it with `tsc`, and serve the HTML. Let me set up the project.\n\nLet me create the project structure:\n- `/tmp/loop-bench-k7ar_jba/tetris/`\n - `index.html`\n - `src/tetris.ts`\n - `tsconfig.json`\n - `package.json`\n\nActually, let me keep it simple. I'll create the files in the current directory.\n\nLet me think about the game architecture:\n\n**Game State:**\n- Board: 10 columns × 20 rows grid\n- Current piece with position and rotation\n- Next piece preview\n- Score, level, lines cleared\n- Game state (playing, paused, game over)\n\n**Tetrominoes:**\n- I, O, T, S, Z, J, L with their rotations\n\n**Rendering with SVG:**\n- SVG element for the board\n- Rect elements for each cell\n- SVG for next piece preview\n- Text elements for score, level, lines\n\n**Controls:**\n- Left/Right arrows: move piece\n- Down arrow: soft drop\n- Up arrow: rotate\n- Space: hard drop\n- P: pause\n\n**Scoring (classic Tetris):**\n- 1 line: 100 × level\n- 2 lines: 300 × level\n- 3 lines: 500 × level\n- 4 lines: 800 × level\n- Soft drop: 1 point per cell\n- Hard drop: 2 points per cell\n\n**Speed:**\n- Increases with level (every 10 lines)\n- Level 0: 800ms, decreasing with each level\n\nLet me code this up.\n\nFor SVG rendering, I'll create the SVG programmatically and update cell rectangles. Each cell will be a rect element with appropriate fill color.\n\nLet me write the TypeScript code:\n\n```typescript\n// Tetromino definitions\n// Board class\n// Piece class\n// Game class with SVG rendering\n// Keyboard input handling\n```\n\nLet me think about the SVG approach more carefully. I'll create:\n- A main SVG for the game board (10×20 grid)\n- Each cell is a rect with a stroke border\n- A separate SVG for the next piece preview\n- Text elements for score/level/lines\n\nFor piece colors, I'll use the classic Tetris colors:\n- I: cyan\n- O: yellow\n- T: purple\n- S: green\n- Z: red\n- J: blue\n- L: orange\n\nLet me write the complete code now.\n\nI'll use cell size of 30px for the board, so the board SVG will be 300×600.\n\nFor the piece rotation, I'll use the Super Rotation System (SRS) or a simpler rotation system. Let me use a basic rotation system where I store all 4 rotation states for each piece.\n\nLet me define the pieces as 2D arrays for each rotation state.\n\nActually, let me use a more efficient approach: store each piece as a list of relative cell positions for each rotation state.\n\nHere's my plan for the piece definitions:\n\n```typescript\nconst PIECES = {\n I: [\n [[0,0],[1,0],[2,0],[3,0]], // rotation 0\n [[0,0],[0,1],[0,2],[0,3]], // rotation 1\n [[0,0],[1,0],[2,0],[3,0]], // rotation 2\n [[0,0],[0,1],[0,2],[0,3]], // rotation 3\n ],\n // etc.\n};\n```\n\nActually, let me use a matrix representation which is easier to reason about for rotation. I'll store each piece as a 2D grid and rotate by transposing and reversing rows.\n\nLet me write the full implementation:\n\n```typescript\ntype PieceType = 'I' | 'O' | 'T' | 'S' | 'Z' | 'J' | 'L';\n\ninterface Position {\n x: number;\n y: number;\n}\n\nconst PIECE_SHAPES: Record<PieceType, number[][]> = {\n I: [\n [0, 0, 0, 0],\n [1, 1, 1, 1],\n [0, 0, 0, 0],\n [0, 0, 0, 0],\n ],\n O: [\n [1, 1],\n [1, 1],\n ],\n T: [\n [0, 1, 0],\n [1, 1, 1],\n [0, 0, 0],\n ],\n S: [\n [0, 1, 1],\n [1, 1, 0],\n [0, 0, 0],\n ],\n Z: [\n [1, 1, 0],\n [0, 1, 1],\n [0, 0, 0],\n ],\n J: [\n [1, 0, 0],\n [1, 1, 1],\n [0, 0, 0],\n ],\n L: [\n [0, 0, 1],\n [1, 1, 1],\n [0, 0, 0],\n ],\n};\n\nconst PIECE_COLORS: Record<PieceType, string> = {\n I: '#00f0f0',\n O: '#f0f000',\n T: '#a000f0',\n S: '#00f000',\n Z: '#f00000',\n J: '#0000f0',\n L: '#f0a000',\n};\n```\n\nFor rotation, I'll implement a clockwise rotation function that transposes and reverses rows:\n\n```typescript\nfunction rotateMatrix(matrix: number[][]): number[][] {\n const n = matrix.length;\n const result: number[][] = [];\n for (let i = 0; i < n; i++) {\n result[i] = [];\n for (let j = 0; j < n; j++) {\n result[i][j] = matrix[n - 1 - j][i];\n }\n }\n return result;\n}\n```\n\nNow let me think about the SVG rendering. I want to create a nice-looking game. I'll use:\n- A dark background\n- Rounded rectangles for cells\n- Gradient effects\n- A panel on the right side for score/next piece\n\nLet me design the layout:\n- Game board: 300×600 (10×20 cells, 30px each)\n- Info panel to the right\n- Total page centered\n\nFor the SVG rendering approach, I have two options:\n1. Create all possible rect elements upfront and just change their fill\n2. Recreate elements each frame\n\nOption 1 is more efficient. Let me create a grid of rect elements for the board, and update their fill colors on each render.\n\nLet me write the complete implementation now. I'll put it all in one TypeScript file.\n\nActually, for the build setup, let me just use `npx tsc` with a tsconfig. Or even simpler, I can use esbuild to bundle it.\n\nLet me go with:\n1. `package.json` with a build script using esbuild\n2. `src/tetris.ts` - the game\n3. `index.html` - the page\n\nOr I could just use `tsc` directly. Let me keep it minimal.\n\nLet me write the code now. I'll create:\n- `index.html`\n- `src/tetris.ts`\n- `tsconfig.json`\n- `package.json`\n\nThen build and the user can open index.html in a browser.\n\nWait, actually if I just use tsc and no modules, the output will be a simple JS file that index.html can load. Let me do that.\n\nLet me write the full game now.\n\nFor the SVG approach, I think the cleanest way is:\n\n1. Create the SVG structure in the HTML\n2. In TypeScript, get references to SVG elements\n3. Update fill attributes on rect elements to render the game state\n\nActually, let me create the entire UI from TypeScript for more control.\n\nHere's my full plan for the game:\n\n```\nBoard: 10×20 grid\nCell size: 30px\nBoard SVG: 300×600\n```\n\nThe game class will:\n1. Initialize the SVG elements\n2. Run a game loop with requestAnimationFrame for rendering and a timer for piece dropping\n3. Handle keyboard input\n4. Manage game state\n\nLet me code it up now. I'll aim for a clean, well-structured implementation.\n\nFor the wall kick system, I'll implement basic wall kicks (try shifting the piece left/right/up if rotation would cause a collision).\n\nLet me also add:\n- Ghost piece (shadow showing where the piece will land)\n- Next piece preview\n- Hold piece feature (optional, let me skip this for simplicity)\n\nActually, let me include a ghost piece since it's a nice visual feature and not too hard to implement.\n\nHere's my full implementation plan:\n\n```typescript\n// Constants\nconst COLS = 10;\nconst ROWS = 20;\nconst CELL_SIZE = 30;\n\n// Piece definitions with colors\n\n// Game class\nclass TetrisGame {\n private board: (string | null)[][];\n private currentPiece: { type: PieceType; shape: number[][]; x: number; y: number } | null;\n private nextPiece: PieceType;\n private score: number;\n private level: number;\n private lines: number;\n private gameOver: boolean;\n private paused: boolean;\n \n // SVG elements\n private boardCells: SVGRectElement[][];\n private nextPieceCells: SVGRectElement[][];\n private scoreText: SVGTextElement;\n private levelText: SVGTextElement;\n private linesText: SVGTextElement;\n \n // Timing\n private lastDrop: number;\n private dropInterval: number;\n private animationId: number;\n \n constructor() {\n // Initialize everything\n }\n \n // Game methods\n}\n```\n\nLet me write the actual code now. I'll make it comprehensive and well-polished.\n\nLet me think about the SVG structure more carefully. I want to create:\n\n1. A main container SVG or a div with SVG elements inside\n2. Board area: 300×600 SVG with a grid of rects\n3. Side panel: next piece, score, level, lines\n\nFor the overall layout, I'll use HTML with inline SVGs rather than one big SVG. This makes layout easier.\n\n```html\n<div id=\"game-container\">\n <div id=\"left-panel\">\n <!-- Hold piece or controls info -->\n </div>\n <div id=\"board-container\">\n <svg id=\"board\" width=\"300\" height=\"600\"></svg>\n </div>\n <div id=\"right-panel\">\n <div id=\"next-piece-container\">\n <svg id=\"next-piece\" width=\"120\" height=\"120\"></svg>\n </div>\n <div id=\"score-panel\">\n <!-- Score, level, lines -->\n </div>\n </div>\n</div>\n```\n\nActually, since the user specifically said \"Render the game using SVG elements,\" I should make the entire game rendering SVG-based. Let me use one large SVG for the game area including the board, side panel, etc. Or I can use multiple SVGs embedded in HTML.\n\nI think using HTML for layout with SVG elements for the actual game rendering is the right approach. The board, pieces, and next piece preview will all be SVG. The score/level display can be HTML text or SVG text.\n\nLet me go with HTML layout + SVG elements for the game parts.\n\nOK let me just write the code now. I've planned enough.\n\nLet me structure the TypeScript file:\n\n```typescript\n// Types and constants\n// Piece definitions\n// Helper functions (rotation, collision detection)\n// Game class\n// Initialization\n```\n\nI'll write it all out now.\n\nFor the ghost piece, I'll render it as semi-transparent rectangles.\n\nFor the visual style, I want:\n- Dark background (#1a1a2e or similar)\n- Grid lines on the board\n- Colorful pieces with slight 3D effect (lighter top/left edges, darker bottom/right edges)\n- Clean sans-serif font for text\n\nLet me use SVG features like gradients and filters for nice visuals.\n\nActually, for each cell, I can create a group with:\n- A filled rect for the main color\n- A lighter rect on top and left edges (highlight)\n- A darker rect on bottom and right edges (shadow)\n\nOr I can use SVG gradients. Let me keep it simpler and just use flat colors with a stroke for now, but make it look good.\n\nLet me just write the code. I'll use:\n- Flat colored rects with a darker stroke for pieces\n- A subtle grid on the board\n- Clean typography\n\nHere's the implementation:\n\nFor the piece shapes, I'll use the standard Tetris definitions where each piece is represented as a matrix. The rotation will be done by rotating the matrix.\n\nFor the SRS wall kick data, I'll include basic wall kick offsets for when a rotation fails.\n\nActually, let me simplify and just try a few offsets (0, -1, +1, 0 up, -1 up, +1 up) for wall kicks rather than the full SRS table. This gives a decent rotation experience without the complexity.\n\nOK here's my final plan. Let me write the code:\n\n```typescript\n// tetris.ts\n\nconst COLS = 10;\nconst ROWS = 20;\nconst CELL = 30;\nconst BOARD_W = COLS * CELL;\nconst BOARD_H = ROWS * CELL;\n\ntype PieceType = 'I' | 'O' | 'T' | 'S' | 'Z' | 'J' | 'L';\n\nconst SHAPES: Record<PieceType, number[][]> = { ... };\nconst COLORS: Record<PieceType, string> = { ... };\nconst LIGHT_COLORS: Record<PieceType, string> = { ... }; // lighter shade\nconst DARK_COLORS: Record<PieceType, string> = { ... }; // darker shade\n\nfunction rotateCW(matrix: number[][]): number[][] { ... }\nfunction rotateCCW(matrix: number[][]): number[][] { ... }\n\nclass Tetris {\n // ... full implementation\n}\n\nwindow.addEventListener('DOMContentLoaded', () => {\n new Tetris();\n});\n```\n\nLet me write the full code now. I'll aim for about 400-500 lines of TypeScript.\n\nLet me think about one more thing: the SVG rendering strategy. I have two approaches:\n\n1. **Pre-create all cells, update attributes**: Create a grid of `<rect>` elements for the board. On each render, update their `fill` attribute based on the game state. Similarly for the next piece preview.\n\n2. **Clear and redraw**: Remove all children and recreate them each frame.\n\nApproach 1 is more performant. Let me use that.\n\nFor the board, I'll create ROWS × COLS rect elements. I'll also create additional rect elements for the current piece and ghost piece that float on top of the board.\n\nActually, let me use a layered approach:\n- Layer 1: Background grid (static)\n- Layer 2: Placed blocks (rects that get updated when lines are cleared)\n- Layer 3: Ghost piece (semi-transparent rects)\n- Layer 4: Current piece (colored rects)\n\nI'll use SVG groups (`<g>`) for each layer.\n\nFor the current piece and ghost piece, since their position changes, I can either:\n- Update the `transform` attribute of a group\n- Update individual rect positions\n\nUsing transform on a group is cleanest. I'll create a group for the current piece and one for the ghost piece, and translate them as the piece moves.\n\nLet me finalize my approach:\n\n**Board SVG structure:**\n```xml\n<svg id=\"board\" width=\"300\" height=\"600\">\n <g id=\"grid-layer\"><!-- grid lines --></g>\n <g id=\"blocks-layer\"><!-- placed blocks, ROWS*COLS rects --></g>\n <g id=\"ghost-layer\"><!-- ghost piece group --></g>\n <g id=\"piece-layer\"><!-- current piece group --></g>\n</svg>\n```\n\nFor the blocks layer, I'll create all cells upfront and update their fill. Empty cells get a dark fill, filled cells get their color.\n\nFor the ghost and piece layers, I'll create groups with rects that match the piece shape. When the piece changes (new piece spawned), I'll update the rects. When the piece moves, I'll update the group transform.\n\nActually, this is getting complex. Let me simplify:\n\nJust have a single grid of rects for the board (including placed blocks), and overlay rects for the current piece and ghost piece. On each render:\n1. Update board cells from the board state array\n2. Clear and redraw the current piece overlay\n3. Clear and redraw the ghost piece overlay\n\nFor the overlay rects, I'll just recreate them each frame since there are at most 4 rects for each.\n\nActually even simpler: just have the board cells array and update everything each frame. With only 200 cells + 8 overlay rects, this is fast enough.\n\nLet me write the code now. No more planning.\n\nI also want to add a nice game over overlay and start screen. Let me add:\n- Start screen: \"Press ENTER to start\"\n- Game over screen: \"GAME OVER\" with final score and \"Press ENTER to restart\"\n- Pause: \"PAUSED\" overlay\n\nThese can be SVG text elements or HTML overlays.\n\nOK, let me code it up now. For real this time.\n\nLet me write a comprehensive implementation. I'll create:\n1. `package.json` - minimal, just for the build\n2. `tsconfig.json` - TypeScript config\n3. `src/tetris.ts` - the game\n4. `index.html` - the page\n\nLet me write each file.\n\nFor the package.json, I'll use esbuild for bundling since it's fast and simple:\n```json\n{\n \"name\": \"tetris\",\n \"scripts\": {\n \"build\": \"esbuild src/tetris.ts --bundle --outfile=dist/tetris.js\"\n },\n \"devDependencies\": {\n \"esbuild\": \"^0.20.0\",\n \"typescript\": \"^5.3.0\"\n }\n}\n```\n\nActually wait, let me check what's available. Let me just create the files and build.\n\nLet me think about the tsconfig. I'll keep it simple:\n```json\n{\n \"compilerOptions\": {\n \"target\": \"ES2020\",\n \"strict\": true,\n \"noEmit\": true\n },\n \"include\": [\"src/**/*\"]\n}\n```\n\nSince I'm using esbuild for the actual compilation, tsc is just for type checking.\n\nActually, I could skip the build step entirely by using `<script type=\"module\">` with a TS-to-ESM transform. But that would require a dev server. Let me just use the build approach.\n\nOr... I could write pure JS with JSDoc type annotations. But the user specifically asked for TypeScript.\n\nLet me just set up esbuild to compile the TS.\n\nHere's my final file structure:\n```\n/tmp/loop-bench-k7ar_jba/\n├── index.html\n├── package.json\n├── tsconfig.json\n└── src/\n └── tetris.ts\n```\n\nAnd I'll build with: `npx esbuild src/tetris.ts --bundle --outfile=dist/tetris.js`\n\nLet me write all the files now.\n\nFor the game implementation, here's the complete structure:\n\n```typescript\n// ============ Constants ============\nconst COLS = 10;\nconst ROWS = 20;\nconst CELL = 30;\n\n// ============ Types ============\ntype PieceType = 'I' | 'O' | 'T' | 'S' | 'Z' | 'J' | 'L';\n\ninterface ActivePiece {\n type: PieceType;\n shape: number[][];\n x: number;\n y: number;\n}\n\n// ============ Piece Definitions ============\nconst SHAPES: Record<PieceType, number[][]> = {\n I: [[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]],\n O: [[1,1],[1,1]],\n T: [[0,1,0],[1,1,1],[0,0,0]],\n S: [[0,1,1],[1,1,0],[0,0,0]],\n Z: [[1,1,0],[0,1,1],[0,0,0]],\n J: [[1,0,0],[1,1,1],[0,0,0]],\n L: [[0,0,1],[1,1,1],[0,0,0]],\n};\n\nconst COLORS: Record<PieceType, string> = {\n I: '#00d4d4',\n O: '#d4d400',\n T: '#9b30ff',\n S: '#00d400',\n Z: '#d40000',\n J: '#0000d4',\n L: '#d47800',\n};\n\nconst PIECE_TYPES: PieceType[] = ['I', 'O', 'T', 'S', 'Z', 'J', 'L'];\n\n// ============ Helper Functions ============\nfunction deepCopy<T>(arr: T[][]): T[][] {\n return arr.map(row => [...row]);\n}\n\nfunction rotateCW(matrix: number[][]): number[][] {\n const n = matrix.length;\n const result: number[][] = [];\n for (let i = 0; i < n; i++) {\n result[i] = [];\n for (let j = 0; j < n; j++) {\n result[i][j] = matrix[n - 1 - j][i];\n }\n }\n return result;\n}\n\nfunction randomPiece(): PieceType {\n return PIECE_TYPES[Math.floor(Math.random() * PIECE_TYPES.length)];\n}\n\n// ============ Tetris Class ============\nclass Tetris {\n private board: (string | null)[][];\n private piece: ActivePiece | null;\n private nextType: PieceType;\n private score: number;\n private level: number;\n private lines: number;\n private state: 'idle' | 'playing' | 'paused' | 'gameover';\n \n // SVG elements\n private svg: SVGSVGElement;\n private boardRects: SVGRectElement[][];\n private nextSvg: SVGSVGElement;\n private nextRects: SVGRectElement[][];\n private scoreText: Element;\n private levelText: Element;\n private linesText: Element;\n private overlayText: SVGTextElement;\n private overlayRect: SVGRectElement;\n \n // Timing\n private lastDrop: number;\n private animFrameId: number;\n \n // 7-bag randomizer\n private bag: PieceType[];\n \n constructor() {\n // Initialize game state\n this.board = this.createBoard();\n this.piece = null;\n this.nextType = this.pullFromBag();\n this.score = 0;\n this.level = 1;\n this.lines = 0;\n this.state = 'idle';\n this.lastDrop = 0;\n this.animFrameId = 0;\n this.bag = [];\n \n // Set up SVG elements\n this.svg = document.getElementById('board-svg') as SVGSVGElement;\n this.nextSvg = document.getElementById('next-svg') as SVGSVGElement;\n \n // ... initialize rects, etc.\n \n // Build the SVG grid\n this.buildBoard();\n this.buildNextPiece();\n \n // Set up event listeners\n document.addEventListener('keydown', this.handleKey.bind(this));\n \n // Start the game loop\n this.gameLoop = this.gameLoop.bind(this);\n this.animFrameId = requestAnimationFrame(this.gameLoop);\n }\n \n private createBoard(): (string | null)[][] {\n return Array.from({ length: ROWS }, () => Array(COLS).fill(null));\n }\n \n private pullFromBag(): PieceType {\n if (this.bag.length === 0) {\n this.bag = [...PIECE_TYPES];\n // Shuffle\n for (let i = this.bag.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [this.bag[i], this.bag[j]] = [this.bag[j], this.bag[i]];\n }\n }\n return this.bag.pop()!;\n }\n \n // ... rest of the implementation\n}\n```\n\nOK let me just write the complete code. I'll create the files now.\n\nLet me think about what I want the final product to look like:\n\nThe page will have a dark background with the Tetris game centered. The layout will be:\n- Left: Controls info\n- Center: Game board (SVG)\n- Right: Next piece preview + Score/Level/Lines\n\nThe SVG board will have a dark grid with colored cells for placed pieces and the current piece. A ghost piece will show where the current piece will land.\n\nColors will be vibrant on a dark background for a classic arcade feel.\n\nLet me write the code now.\n\nI want to create a complete, polished game. Let me write it all out.\n\nActually, I realize I should think about how to handle the SVG rendering more carefully. Let me decide on the exact approach:\n\nFor the board:\n- Create a grid of `<rect>` elements (ROWS × COLS = 200 elements)\n- Store references in a 2D array `boardRects[row][col]`\n- On each render, update the `fill` attribute based on the board state + current piece + ghost piece\n\nFor the next piece:\n- Create a small grid of `<rect>` elements (4×4 = 16 elements)\n- On each render (when next piece changes), update their fills\n\nThis is the simplest and most efficient approach.\n\nFor visual polish, I can add:\n- Inner shadow/3D effect on each cell using SVG gradients or multiple rects\n- A glow effect on active pieces\n- Smooth animations for line clears\n\nBut for a solid first version, let me keep the rendering simple but clean.\n\nLet me write the complete code now. For real. No more planning.\n\nI'll structure the code as follows:\n1. Constants and types\n2. Piece data\n3. Utility functions\n4. Tetris class with all game logic and rendering\n5. Initialization on DOMContentLoaded\n\nHere goes:\n\nActually, for the SVG approach, I want to create rect elements for each cell that have a nice 3D appearance. I'll use:\n- A base rect with the fill color\n- A lighter inner rect on top for highlight\n\nOr I can use SVG linear gradients on each rect. Let me define gradients for each piece color.\n\nActually, the simplest approach for a 3D look: for each filled cell, draw:\n1. The main colored rect\n2. A lighter border on top and left\n3. A darker border on bottom and right\n\nThis gives a nice beveled look. I can do this with SVG `<polygon>` or multiple rects. Or I can just use `stroke` with a lighter color and a slightly different fill.\n\nLet me just use a simple approach: colored rect with a darker stroke, and maybe a small inset highlight.\n\nActually, the simplest nice-looking approach:\n- Each cell is a rect with fill=color and stroke=darkerColor, stroke-width=1\n- This gives a clean grid appearance\n\nLet me go with this. Now let me actually write the code.\n\nFor the HTML, I'll create a nice styled page with the game centered, dark background, and the SVG elements.\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Tetris</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body {\n background: #0f0f1a;\n color: #e0e0e0;\n font-family: 'Segoe UI', system-ui, sans-serif;\n display: flex;\n justify-content: center;\n align-items: center;\n min-height: 100vh;\n overflow: hidden;\n }\n #game-wrapper {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n }\n .panel {\n width: 160px;\n }\n .panel-title {\n font-size: 14px;\n text-transform: uppercase;\n letter-spacing: 2px;\n color: #888;\n margin-bottom: 8px;\n }\n .stat-value {\n font-size: 28px;\n font-weight: bold;\n color: #fff;\n font-variant-numeric: tabular-nums;\n }\n .stat-group {\n margin-bottom: 20px;\n }\n #board-container {\n border: 2px solid #333;\n border-radius: 4px;\n box-shadow: 0 0 30px rgba(0,0,0,0.5);\n }\n .controls {\n font-size: 13px;\n line-height: 1.8;\n color: #777;\n }\n .controls kbd {\n background: #222;\n border: 1px solid #444;\n border-radius: 3px;\n padding: 2px 6px;\n font-size: 12px;\n color: #bbb;\n }\n #next-container {\n background: #111;\n border: 1px solid #333;\n border-radius: 4px;\n padding: 10px;\n display: flex;\n justify-content: center;\n }\n </style>\n</head>\n<body>\n <div id=\"game-wrapper\">\n <div class=\"panel\" id=\"left-panel\">\n <div class=\"stat-group\">\n <div class=\"panel-title\">Score</div>\n <div class=\"stat-value\" id=\"score-display\">0</div>\n </div>\n <div class=\"stat-group\">\n <div class=\"panel-title\">Level</div>\n <div class=\"stat-value\" id=\"level-display\">1</div>\n </div>\n <div class=\"stat-group\">\n <div class=\"panel-title\">Lines</div>\n <div class=\"stat-value\" id=\"lines-display\">0</div>\n </div>\n <div class=\"controls\">\n <div><kbd>←</kbd> <kbd>→</kbd> Move</div>\n <div><kbd>↑</kbd> Rotate</div>\n <div><kbd>↓</kbd> Soft Drop</div>\n <div><kbd>Space</kbd> Hard Drop</div>\n <div><kbd>P</kbd> Pause</div>\n <div><kbd>Enter</kbd> Start</div>\n </div>\n </div>\n <div id=\"board-container\">\n <svg id=\"board-svg\" width=\"300\" height=\"600\" xmlns=\"http://www.w3.org/2000/svg\"></svg>\n </div>\n <div class=\"panel\" id=\"right-panel\">\n <div class=\"panel-title\">Next</div>\n <div id=\"next-container\">\n <svg id=\"next-svg\" width=\"120\" height=\"120\" xmlns=\"http://www.w3.org/2000/svg\"></svg>\n </div>\n </div>\n </div>\n <script src=\"dist/tetris.js\"></script>\n</body>\n</html>\n```\n\nNow for the TypeScript code, let me write the complete game:\n\nI want to implement:\n1. Board with grid lines\n2. All 7 tetrominoes with correct shapes and colors\n3. Rotation (CW with wall kicks)\n4. Movement (left, right, soft drop, hard drop)\n5. Line clearing with animation\n6. Scoring (standard NES-style)\n7. Level progression (speed increases)\n8. 7-bag randomizer\n9. Ghost piece\n10. Next piece preview\n11. Game states: idle, playing, paused, game over\n12. SVG rendering with nice visuals\n\nLet me write it all now.\n\nFor the cell rendering, I want each cell to look nice. Here's my approach:\n- Empty cells: very dark fill (#0a0a15) with a subtle grid line (#1a1a2a)\n- Filled cells: piece color with a beveled 3D look\n\nFor the 3D beveled look, I'll create each cell as a group with:\n```xml\n<g>\n <rect fill=\"color\" x=\"X\" y=\"Y\" width=\"30\" height=\"30\" />\n <rect fill=\"lighterColor\" x=\"X\" y=\"Y\" width=\"30\" height=\"3\" /> <!-- top highlight -->\n <rect fill=\"lighterColor\" x=\"X\" y=\"Y\" width=\"3\" height=\"30\" /> <!-- left highlight -->\n <rect fill=\"darkerColor\" x=\"X\" y=\"Y+27\" width=\"30\" height=\"3\" /> <!-- bottom shadow -->\n <rect fill=\"darkerColor\" x=\"X+27\" y=\"Y\" width=\"3\" height=\"30\" /> <!-- right shadow -->\n</g>\n```\n\nThis creates a nice 3D block appearance. But with 200 cells, each having 5 rects, that's 1000 elements. It's fine for performance.\n\nActually, let me simplify. I'll use SVG `<rect>` with `rx` and `ry` for slightly rounded corners, and use the fill color with a slight stroke for the grid. This is cleaner and simpler.\n\nFor the 3D effect, I can use SVG filters or gradients. Let me define a gradient for each piece color.\n\nOr even simpler: use `<rect>` with the fill color, and overlay a semi-transparent white gradient (lighter at top, transparent at bottom) to give depth.\n\nActually, the simplest nice approach:\n- Define SVG `<linearGradient>` for each piece color that goes from lighter at top to darker at bottom\n- Use these gradients as fills for the rects\n- Add a thin dark stroke\n\nThis gives a clean, polished look without too many elements.\n\nLet me define the gradients programmatically.\n\nOK here's my final approach for cell rendering:\n1. Background: dark rect for each cell (or just the SVG background)\n2. Grid lines: drawn once as static lines\n3. Placed pieces and current piece: colored rects with gradient fills and dark stroke\n4. Ghost piece: same rects but with opacity 0.3\n\nFor the SVG defs, I'll create gradients dynamically:\n```typescript\nconst ns = 'http://www.w3.org/2000/svg';\n\nfunction createGradient(svg: SVGSVGElement, id: string, baseColor: string): SVGLinearGradientElement {\n const defs = svg.querySelector('defs') || (() => {\n const d = document.createElementNS(ns, 'defs');\n svg.prepend(d);\n return d;\n })();\n \n const grad = document.createElementNS(ns, 'linearGradient');\n grad.setAttribute('id', id);\n grad.setAttribute('x1', '0');\n grad.setAttribute('y1', '0');\n grad.setAttribute('x2', '0');\n grad.setAttribute('y2', '1');\n \n const stop1 = document.createElementNS(ns, 'stop');\n stop1.setAttribute('offset', '0%');\n stop1.setAttribute('stop-color', lighten(baseColor));\n \n const stop2 = document.createElementNS(ns, 'stop');\n stop2.setAttribute('offset', '100%');\n stop2.setAttribute('stop-color', darken(baseColor));\n \n grad.appendChild(stop1);\n grad.appendChild(stop2);\n defs.appendChild(grad);\n \n return grad;\n}\n```\n\nActually, this is getting complicated. Let me just use flat colors with a stroke. The game will still look great. I can always add visual polish later.\n\nFINAL APPROACH (keeping it simple):\n- Each cell: `<rect>` with fill color, stroke=\"#000\", stroke-width=\"0.5\"\n- Empty cells: fill=\"#111\"\n- Grid lines","signature":"6656944260984e88934f10da"}],"stop_reason":"max_tokens","stop_sequence":null,"usage":{"input_tokens":1282,"output_tokens":8000,"cache_read_input_tokens":2816,"server_tool_use":{"web_search_requests":0},"service_tier":"standard"},"context_management":null},"parent_tool_use_id":null,"session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","uuid":"65ebab3d-6b19-454a-937c-7fcb0578c69f"} +{"type":"result","subtype":"success","is_error":false,"duration_ms":271402,"duration_api_ms":271327,"num_turns":1,"result":"","stop_reason":"max_tokens","session_id":"8761afb2-cbdd-4fdc-8b88-28dda25ea1f5","total_cost_usd":0.1246908,"usage":{"input_tokens":0,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":0,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":0,"ephemeral_5m_input_tokens":0},"inference_geo":"","iterations":[],"speed":"standard"},"modelUsage":{"glm-5.1":{"inputTokens":1282,"outputTokens":8000,"cacheReadInputTokens":2816,"cacheCreationInputTokens":0,"webSearchRequests":0,"costUSD":0.1246908,"contextWindow":200000,"maxOutputTokens":32000}},"permission_denials":[],"terminal_reason":"completed","fast_mode_state":"off","uuid":"958c84fa-3bbd-4c0b-8304-c8d75bf8abd1"} diff --git a/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=webgl_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/meta.json b/results/runs/tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=webgl_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1/meta.json @@ -0,0 +1,37 @@ +{ + "model": "glm-5.1", + "effort": "high", + "prompt_style": "simple", + "language": "typescript", + "human_language": "en", + "tool_read": "on", + "tool_write": "on", + "tool_edit": "on", + "tool_glob": "on", + "tool_grep": "on", + "linter": "on", + "playwright": "off", + "context_file": "none", + "web_search": "on", + "max_budget": "low", + "tests_provided": "none", + "strategy": "none", + "design_guidance": "none", + "architecture": "none", + "error_checking": "none", + "context_noise": "clean", + "renderer": "webgl", + "provider": "zai", + "task": "tetris", + "actual_model": "glm-5.1", + "cell_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=webgl_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on", + "runs_per_cell": 3, + "timeout_seconds": 1200, + "max_budget_usd": 2.0, + "run_id": "tetris_arch=none_ctx=none_noise=clean_dsgn=none_eff=high_echk=none_hlang=en_lang=ts_lint=on_budget=low_model=glm51_pw=off_prompt=simple_prov=zai_rndr=webgl_strat=none_tst=none_tedit=on_tglob=on_tgrep=on_tread=on_twrite=on_web=on_run1", + "short_id": "16dab3d1", + "short_cell_id": "cd8ad131", + "run_number": 1, + "claude_version": "2.1.92 (Claude Code)", + "started_at": "2026-04-07T01:50:51.338095+00:00" +} +\ No newline at end of file