Fixes batch 2: player quests, AI parse, advisor, iPad share

- Player view: a Quest log now syncs to players (snapshot += quests; broadcaster
  passes campaign quests; PlayerBoards renders titles + objective checkboxes).
- AI (DeepSeek etc.): robust JSON extraction — strip code fences anywhere + a
  brace-balanced scanner that ignores prose/braces in strings. Fixes "AI unavailable
  (parse)" with OpenAI-compatible providers. +4 tests.
- Encounter advisor: now bidirectional — for an over-tuned (too-hard) fight it
  suggests REMOVING/swapping monsters instead of only ever adding. +3 tests.
- Character share: works on iPad — native share sheet → clipboard → a copyable
  link modal fallback (was a silently-failing clipboard write).

230 unit + 34 e2e + 2 realtime green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 21:56:10 +02:00
parent 426824fd78
commit 3f524ce82c
15 changed files with 292 additions and 21 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ function fake(): Sender & { msgs: ServerMessage[] } {
const msgs: ServerMessage[] = [];
return { msgs, send: (m) => msgs.push(m) };
}
const snap: Snapshot = { campaignName: 'C', calendarDay: null, party: [], encounter: null, map: null, mapImageId: null };
const snap: Snapshot = { campaignName: 'C', calendarDay: null, party: [], encounter: null, map: null, mapImageId: null, quests: [] };
const char: Character = characterSchema.parse({
id: 'ch1', campaignId: 'cmp1', system: '5e', name: 'Lia',
abilities: { str: 10, dex: 12, con: 14, int: 10, wis: 13, cha: 8 },