# AGENTS.md - boardgame-core ## Commands Prefer `bash.exe`(C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps\bash.exe) over Powershell. ```bash npm run build # Build ESM bundle + declarations to dist/ npm run test # Run vitest in watch mode npm run test:run # Run vitest once (no watch) npm run typecheck # Type-check without emitting (tsc --noEmit) ``` ### Running a single test file ```bash npx vitest run tests/samples/tic-tac-toe.test.ts ``` ### Running a single test by name ```bash npx vitest run -t "should detect horizontal win for X" ``` ## Code Style ### Imports - Use **double quotes** for local imports, **single quotes** for npm packages - Use `@/**/*` for `./src/**/*` import alias - Use `@/index` for code in `samples` ### Formatting - **4-space indentation** - **Semicolons** at statement ends - **Arrow functions** for callbacks; `function` keyword for methods needing `this` (e.g. command handlers) - No trailing whitespace ### Naming Conventions - **Types/Interfaces**: `PascalCase` — `Part`, `Region`, `Command`, `IGameContext` - **Classes**: `PascalCase` — `Entity`, `AsyncQueue`, `Mulberry32RNG` - **Functions**: `camelCase`, verb-first — `createGameContext`, `parseCommand`, `isValidMove` - **Variables**: `camelCase` - **Constants**: `UPPER_SNAKE_CASE` — `BOARD_SIZE`, `WINNING_LINES` - **Test files**: `*.test.ts` mirroring `src/` structure under `tests/` ### Types - **Strict TypeScript** is enabled — no `any` - Use **generics** heavily: `Entity`, `CommandRunner` - Use **type aliases** for object shapes (not interfaces) - Use **discriminated unions** for results: `{ success: true; result: T } | { success: false; error: string }` - Use `unknown` for untyped values, narrow with type guards or `as` ### Error Handling - Prefer **result objects** over throwing: return `{ success, result/error }` - When catching: `const error = e as Error;` then use `error.message` - Use `throw new Error(...)` only for truly exceptional cases - Validation error messages are in Chinese (e.g. `"参数不足"`) ### Testing - **Vitest** with globals enabled (`describe`, `it`, `expect` available without import) - Use `async/await` for async tests - Narrow result types with `if (result.success)` before accessing `result.result` - Define inline helper functions in test files when needed - No mocking — use real implementations - Test helpers: `createTestContext()`, `createTestRegion()` ## Architecture Notes - **Reactivity**: `Entity` extends Preact Signal — access state via `.value`, mutate via `.produce(draft => ...)` - **Command system**: CLI-style parsing with schema validation via `inline-schema` - **Prompt system**: Commands prompt for input via `PromptEvent` with `resolve`/`reject` - **Barrel exports**: `src/index.ts` is the single public API surface