refactor: remove legacy types.ts file and update frontend to use new contracts feat: add applyActions function to manage action application and world state mutation chore: remove empty .gitkeep file from sqlite data directory refactor: update frontend App component to align with new API contracts and improve UX docs: revise project.md to reflect updated architecture and system requirements docs: update thoughts.md with current status, architecture decisions, and remaining checks
128 lines
2.6 KiB
TypeScript
128 lines
2.6 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
|
|
import { createDatabase, CharacterGardenDatabase } from "./db";
|
|
import type { Entity } from "./contracts/entity";
|
|
import type { Turn } from "./contracts/turn";
|
|
import type { WorldState } from "./contracts/world";
|
|
import { processTurn, ProcessTurnResponse } from "./turns/processTurn";
|
|
|
|
export interface AppSnapshot {
|
|
worldState: WorldState;
|
|
turns: Turn[];
|
|
}
|
|
|
|
export interface CharacterGardenApp {
|
|
db: CharacterGardenDatabase;
|
|
getSnapshot(): AppSnapshot;
|
|
processTurn(rawText: string): ProcessTurnResponse;
|
|
reset(): AppSnapshot;
|
|
}
|
|
|
|
function createSeedWorldState(): WorldState {
|
|
const now = Date.now();
|
|
|
|
const entities: Record<string, Entity> = {
|
|
room_start: {
|
|
id: "room_start",
|
|
name: "Start Room",
|
|
type: "room",
|
|
attributes: {
|
|
description: "A plain room with a locked door.",
|
|
},
|
|
},
|
|
room_exit: {
|
|
id: "room_exit",
|
|
name: "Exit Room",
|
|
type: "room",
|
|
attributes: {
|
|
description: "A simple room beyond the door.",
|
|
},
|
|
},
|
|
player: {
|
|
id: "player",
|
|
name: "Player",
|
|
type: "character",
|
|
attributes: {
|
|
location: "room_start",
|
|
has_key_1: false,
|
|
},
|
|
},
|
|
door_1: {
|
|
id: "door_1",
|
|
name: "Old Door",
|
|
type: "door",
|
|
attributes: {
|
|
location: "room_start",
|
|
openable: true,
|
|
locked: true,
|
|
requiredKey: "key_1",
|
|
open: false,
|
|
},
|
|
},
|
|
key_1: {
|
|
id: "key_1",
|
|
name: "Brass Key",
|
|
type: "item",
|
|
attributes: {
|
|
location: "room_start",
|
|
takeable: true,
|
|
},
|
|
},
|
|
};
|
|
|
|
return {
|
|
id: randomUUID(),
|
|
entities,
|
|
metadata: {
|
|
domain: "door_key_mvp",
|
|
version: 1,
|
|
},
|
|
createdAt: now,
|
|
};
|
|
}
|
|
|
|
function ensureSeedState(db: CharacterGardenDatabase): WorldState {
|
|
db.init();
|
|
|
|
const latest = db.getLatestWorldState();
|
|
if (latest) {
|
|
return latest;
|
|
}
|
|
|
|
const seed = createSeedWorldState();
|
|
db.upsertEntities(Object.values(seed.entities));
|
|
db.insertWorldState(null, seed);
|
|
return seed;
|
|
}
|
|
|
|
export function createCharacterGardenApp(dbPath: string): CharacterGardenApp {
|
|
const db = createDatabase({ dbPath });
|
|
let worldState = ensureSeedState(db);
|
|
|
|
return {
|
|
db,
|
|
|
|
getSnapshot() {
|
|
return {
|
|
worldState,
|
|
turns: db.listTurns(),
|
|
};
|
|
},
|
|
|
|
processTurn(rawText: string) {
|
|
const result = processTurn(rawText, worldState, db);
|
|
worldState = result.worldState;
|
|
return result;
|
|
},
|
|
|
|
reset() {
|
|
db.wipe();
|
|
worldState = ensureSeedState(db);
|
|
return {
|
|
worldState,
|
|
turns: db.listTurns(),
|
|
};
|
|
},
|
|
};
|
|
}
|