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
+5
View File
@@ -9,6 +9,11 @@ export const balanceSuggestionSchema = z.object({
count: z.number().int().min(1).max(8),
ref: z.string().optional(),
})),
/** Monsters to take out when the fight is over-tuned (already at/above target). */
remove: z.array(z.object({
name: z.string(),
count: z.number().int().min(1).max(8),
})).optional(),
targetDifficulty: z.string(),
});
export type BalanceSuggestion = z.infer<typeof balanceSuggestionSchema>;