feat(entity): Chunk #4 data layer + entity UI (characters & world-building)

Data layer:
- Fuzzy scorer (packages/core/src/fuzzy.ts) with index recovery + unit tests
- Backlink computation (packages/core/src/backlinks.ts) incl. entity-level backlinks
- Consistency checker (packages/core/src/consistency.ts) incl. reciprocity/scope + unit tests
- StorageAdapter contract extended with listEntities/searchEntities/saveEntity/deleteEntity;
  implemented in Local (Dexie) and Server adapters; contract tests cover entity CRUD + ?q= search
- WorldItem.fields now supports list values (keyPeople, rivals); expanded RelationshipKind
- @mention autocomplete extension + picker in the editor package

Entity UI (apps/web/src/features/entities/):
- Generic field renderer (EntityFields) driven by ENTITY_FIELDS/FieldDef
- Tabbed directory with fuzzy search + entity cards (EntitiesView)
- Create/edit/delete drawer (EntityEditor) reusing shared fields
- Relationship editor + force-directed SVG relationship map
- Entity engine stylesheet; wired into nav

Store: project-store entity methods (load/create/update/delete) over the StorageAdapter contract.

CI-green: typecheck, lint, 65 tests, and web build all pass.
This commit is contained in:
Schwitzz
2026-10-25 22:42:55 -05:00
parent 81a44b6e95
commit 4efa71515e
36 changed files with 2764 additions and 82 deletions
+12
View File
@@ -40,6 +40,18 @@ export interface StorageAdapter {
saveDocument(doc: DocumentRef): Promise<void>;
getChapter(id: string): Promise<Chapter | null>;
saveEntity(e: Entity): Promise<void>;
/**
* List entities for a project, optionally filtered by kind ("character" |
* "world" | "note"). Returns every entity when `kind` is omitted.
*/
listEntities(projectId: string, kind?: string): Promise<Entity[]>;
getEntity(projectId: string, kind: string, id: string): Promise<Entity | null>;
deleteEntity(projectId: string, kind: string, id: string): Promise<void>;
/**
* Fuzzy search across an entity's name and field values. Returns matches
* ordered best-first; empty `q` returns all entities for the project.
*/
searchEntities(projectId: string, q: string): Promise<Entity[]>;
saveBoard(b: Board): Promise<void>;
saveAISession(s: AISession): Promise<void>;