用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/checkmate-works/blindfold-chess --skill verify命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| name | verify |
| description | Build/launch/drive recipe for runtime-verifying apps/web changes end-to-end (dev server + Playwright). |
pnpm dev from apps/web serves http://localhost:3000. The developer
usually already has it running — probe curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/en
first; a port clash just means reuse the running instance (it hot-reloads
the working tree, so your uncommitted changes are live).pnpm supabase start + pnpm db:run-migrate).
Check with psql postgresql://postgres:postgres@127.0.0.1:54322/postgres -c '\dt'.createRequire('<repo>/apps/web/package.json') then require('playwright')./en/... for stable text assertions.blindfold_chess_games
(StoredGame[], see src/lib/games/saved-game-types.ts). To drive
games/play/result?gameId=... without playing a full game, inject a
finished record via context.addInitScript before navigation. The
repository validates moves against startingFen on load — use a legal
sequence or the record silently drops.StatsAuthGate, .blur-sm + .pointer-events-none).
DOM assertions still work through the blur; for clean screenshots strip
those classes client-side, or note the blur./en/games/play?color=white&moves=<JSON array>&fen=<FEN>.
A brand-new game auto-saves to localStorage on mount (poll for it).button (SAN composer),
which is painful to automate, and the gamePrefs URL param can't switch it
(the mode is gated by enabledMoveInputModes from global preferences). Seed
global preferences instead, key blindfold-chess-game-preferences:
{"moveInputMode":"text","enabledMoveInputModes":["text"],"boardVisibility":"always"}
→ then input[placeholder*="Enter move"] + Enter submits moves. Undo/Resign
are button[title="Undo"|"Resign"] + a confirm modal with the same text.
The AI (stockfish wasm) works headless; allow ~10s per reply.play_settings snapshot — games.play_settings publishes
as null, so it is neither "constrained" (1kyu/1dan evaluators) nor gets
the AI review's blindfold block. Pass gamePrefs=<JSON> as the real
new-game dialog does, e.g. {"boardVisibility":"peek","showOwnPieces":true, "showOpponentPieces":true,"pieceShapeMode":"normal","pieceColors":"normal", "pawnHideMode":"none"}. In peek mode the reveal control is the board
mask's "Tap to reveal" text, not the inline "Show Board" header.games/shared/[id] → "AI Review" tab) needs the
author signed in with a subscriptions row in status active (fake Stripe
ids are fine locally), OPENAI_API_KEY in .env.local, and one free daily
slot: to regenerate, delete from rate_limit_events where action = 'generate_ai_review' and drop the game_ai_reviews row. A real call costs
well under a yen on gpt-5-mini. To see the raw model response (the app logs
only to the dev-server console), drive generateReview from a scratch
vitest file with vi.mock('server-only', () => ({})) and a logging wrapper
around createOpenAiClient().games table
(plus game_tokens for anonymous authors) — clean them up via psql afterwards.