Skip to content

Commit 4356eb0

Browse files
Initial commit
0 parents  commit 4356eb0

File tree

122 files changed

+29410
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+29410
-0
lines changed

.devcontainer/devcontainer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
2+
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
3+
{
4+
"name": "Node.js & TypeScript",
5+
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6+
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
7+
8+
// Features to add to the dev container. More info: https://containers.dev/features.
9+
// "features": {},
10+
11+
// Use 'forwardPorts' to make a list of ports inside the container available locally.
12+
// "forwardPorts": [],
13+
14+
// Use 'postCreateCommand' to run commands after the container is created.
15+
"postCreateCommand": "npm install"
16+
17+
// Configure tool-specific properties.
18+
// "customizations": {},
19+
20+
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
21+
// "remoteUser": "root"
22+
}

.github/copilot-instructions.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Turn-Based Games Platform - AI Developer Guide
2+
3+
## Architecture Overview
4+
5+
This is a **monorepo workspace** with three packages that work together to create a turn-based games platform:
6+
7+
- **`shared/`** - Core game logic, types, and SQLite storage (TypeScript library)
8+
- **`web/`** - Next.js 15 frontend with API routes (React + TailwindCSS)
9+
- **`mcp-server/`** - Model Context Protocol server providing AI opponents (Node.js service)
10+
11+
**Key Integration Pattern**: The MCP server communicates with the web app via HTTP calls to `/api/games/*` endpoints, not direct database access. This maintains clear service boundaries.
12+
13+
## Development Workflow
14+
15+
**Essential build order** (shared must be built first):
16+
```bash
17+
npm run build --workspace=shared # Always run first
18+
npm run dev --workspace=web # Starts Next.js dev server (port 3000)
19+
npm run dev --workspace=mcp-server # Starts MCP server (stdio)
20+
```
21+
22+
**Database location**: SQLite file is at `web/games.db` by default, controlled by `GAMES_DB_PATH` env var.
23+
24+
## Core Architecture Patterns
25+
26+
### Game Implementation Pattern
27+
All games follow the `Game<TGameState, TMove>` interface in `shared/src/types/game.ts`:
28+
- `validateMove()` - Check if move is legal
29+
- `applyMove()` - Apply move and return new state
30+
- `checkGameEnd()` - Determine win/draw/continue
31+
- `getValidMoves()` - Get available moves
32+
- `getInitialState()` - Create starting game state
33+
34+
### Storage Pattern
35+
Games use a dual-storage approach:
36+
- **Web app**: Direct SQLite access via `shared/src/storage/sqlite-storage.ts`
37+
- **MCP server**: HTTP calls to web API endpoints (no direct DB access)
38+
39+
### AI Integration Pattern
40+
The MCP server exposes tools like `play_tic_tac_toe` and `create_tic_tac_toe_game`. It calls the web API to:
41+
1. Fetch current game state
42+
2. Calculate AI move using algorithms in `mcp-server/src/ai/`
43+
3. Submit move back via API POST
44+
45+
## File Organization Conventions
46+
47+
### API Routes Structure
48+
- `web/src/app/api/games/[game-type]/route.ts` - Create/list games
49+
- `web/src/app/api/games/[game-type]/[id]/move/route.ts` - Make moves
50+
51+
### Game-Specific Types
52+
Game states extend `BaseGameState` and are defined in `shared/src/types/games.ts`:
53+
- `TicTacToeGameState` includes `board: Board` and `playerSymbols`
54+
- `RPSGameState` includes `rounds` and `scores`
55+
56+
### Component Organization
57+
- `web/src/components/games/` - Game-specific UI components
58+
- `web/src/app/games/[game-type]/` - Game-specific pages
59+
60+
## Development Guidelines
61+
62+
### Adding New Games
63+
1. Define types in `shared/src/types/games.ts`
64+
2. Implement game class in `shared/src/games/`
65+
3. Add API routes in `web/src/app/api/games/[new-game]/`
66+
4. Create AI implementation in `mcp-server/src/ai/`
67+
5. Add MCP tools in `mcp-server/src/server.ts`
68+
6. Build UI components in `web/src/components/games/`
69+
70+
### Environment Variables
71+
- `WEB_API_BASE` - MCP server's web app URL (default: `http://localhost:3000`)
72+
- `GAMES_DB_PATH` - SQLite database location (default: `./games.db`)
73+
74+
### Key Dependencies
75+
- `@modelcontextprotocol/sdk` - MCP server framework
76+
- `sqlite3` - Database (shared between web/mcp-server)
77+
- `@turn-based-mcp/shared` - Internal workspace dependency

.github/dependabot.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for more information:
4+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
# https://containers.dev/guide/dependabot
6+
7+
version: 2
8+
updates:
9+
- package-ecosystem: github-actions
10+
directory: /
11+
schedule:
12+
interval: weekly
13+
groups:
14+
actions-minor:
15+
update-types:
16+
- minor
17+
- patch
18+
19+
- package-ecosystem: npm
20+
directory: /
21+
schedule:
22+
interval: weekly
23+
groups:
24+
npm-development:
25+
dependency-type: development
26+
update-types:
27+
- minor
28+
- patch
29+
npm-production:
30+
dependency-type: production
31+
update-types:
32+
- patch
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
applyTo: "web/src/app/api/**/*.{ts,js}"
3+
description: Next.js API route development patterns for the turn-based games platform
4+
---
5+
6+
# API Route Instructions
7+
8+
Follow these patterns when creating Next.js API routes:
9+
10+
## File Structure and Naming
11+
12+
- Use Next.js 13+ App Router conventions (`route.ts`)
13+
- Group related routes by game type: `/api/games/[game-type]/`
14+
- Use dynamic routes for game instances: `/api/games/[game-type]/[id]/`
15+
- Include MCP-specific sanitized endpoints: `/api/games/[game-type]/mcp/`
16+
17+
## HTTP Method Handlers
18+
19+
Export named functions for each HTTP method:
20+
21+
```typescript
22+
import { NextRequest, NextResponse } from 'next/server'
23+
24+
export async function GET() {
25+
// Handle GET requests
26+
}
27+
28+
export async function POST(request: NextRequest) {
29+
// Handle POST requests with body
30+
}
31+
32+
export async function DELETE(request: NextRequest) {
33+
// Handle DELETE requests
34+
}
35+
```
36+
37+
## Request/Response Patterns
38+
39+
### Request Handling
40+
- Always use try-catch blocks for error handling
41+
- Parse request bodies with `await request.json()`
42+
- Extract URL parameters from dynamic routes: `{ params }: { params: Promise<{ id: string }> }`
43+
- Validate required fields and return 400 for missing data
44+
45+
### Response Patterns
46+
- Use `NextResponse.json()` for all responses
47+
- Include appropriate HTTP status codes:
48+
- 200: Success
49+
- 400: Bad request (validation errors, invalid moves)
50+
- 404: Resource not found
51+
- 500: Server errors
52+
- Return consistent error shapes: `{ error: 'Error message' }`
53+
54+
## Game Integration Patterns
55+
56+
### Game State Management
57+
- Create game instances at module level: `const ticTacToeGame = new TicTacToeGame()`
58+
- Use shared game storage functions from `@turn-based-mcp/shared`
59+
- Always validate moves using game logic before applying
60+
- Update game history with player moves and timestamps
61+
62+
### Move Processing Flow
63+
```typescript
64+
// 1. Validate game exists
65+
const gameSession = await getGameFromStorage(gameId)
66+
if (!gameSession) {
67+
return NextResponse.json({ error: 'Game not found' }, { status: 404 })
68+
}
69+
70+
// 2. Validate move
71+
if (!gameInstance.validateMove(gameSession.gameState, move, playerId)) {
72+
return NextResponse.json({ error: 'Invalid move' }, { status: 400 })
73+
}
74+
75+
// 3. Apply move and update state
76+
let updatedGameState = gameInstance.applyMove(gameSession.gameState, move, playerId)
77+
78+
// 4. Add to history
79+
const playerMove = { playerId, move, timestamp: new Date() }
80+
gameSession.history.push(playerMove)
81+
82+
// 5. Check for game end
83+
const gameResult = gameInstance.checkGameEnd(updatedGameState)
84+
if (gameResult) {
85+
updatedGameState = { ...updatedGameState, status: 'finished', winner: gameResult.winner }
86+
}
87+
88+
// 6. Save and return
89+
gameSession.gameState = updatedGameState
90+
await saveGameToStorage(gameId, gameSession)
91+
return NextResponse.json(gameSession)
92+
```
93+
94+
## Error Handling
95+
96+
- Log errors with `console.error()` before returning responses
97+
- Handle specific error types (validation, storage, parsing)
98+
- Return generic error messages to avoid exposing internals
99+
- Use 500 status for unexpected errors
100+
101+
## Security and Sanitization
102+
103+
### MCP Endpoints
104+
- Create separate `/mcp/` endpoints for MCP server access
105+
- Sanitize sensitive data (hide current player choices in RPS)
106+
- Remove incomplete rounds and private information
107+
- Validate all inputs from external MCP requests
108+
109+
### General Security
110+
- Validate all input parameters
111+
- Sanitize data before storage
112+
- Use proper TypeScript types for request/response shapes
113+
- Avoid exposing sensitive game state to clients
114+
115+
## Example Route Structure
116+
117+
```typescript
118+
import { NextRequest, NextResponse } from 'next/server'
119+
import { GameClass } from '@turn-based-mcp/shared'
120+
import { getGame, setGame } from '../../../lib/game-storage'
121+
122+
const gameInstance = new GameClass()
123+
124+
export async function POST(request: NextRequest) {
125+
try {
126+
const { playerName, gameId } = await request.json()
127+
128+
const players = [
129+
{ id: 'player1', name: playerName || 'Player', isAI: false },
130+
{ id: 'ai', name: 'AI', isAI: true }
131+
]
132+
133+
const gameState = gameInstance.getInitialState(players)
134+
if (gameId) gameState.id = gameId
135+
136+
const gameSession = {
137+
gameState,
138+
gameType: 'game-type',
139+
history: []
140+
}
141+
142+
await setGame(gameState.id, gameSession)
143+
return NextResponse.json(gameSession)
144+
} catch (error) {
145+
console.error('Error creating game:', error)
146+
return NextResponse.json({ error: 'Failed to create game' }, { status: 500 })
147+
}
148+
}
149+
```

0 commit comments

Comments
 (0)