Commit Graph
65 Commits
Author SHA1 Message Date
KoalaTrapLord a23fdc55a4 feat: PolicyControllerAi integration — Forge AI decision interception via policy server
## New File
- PolicyControllerAi.java (840 lines): Extends Forge's PlayerControllerAi
  to intercept AI decisions at chooseSpellAbilityToPlay() and route them
  through the Python policy server. Falls back to Forge built-in AI on
  any failure. Inner PolicyAiController overrides AiController with full
  legal action gathering via ComputerUtilAbility.

## Wiring
- GameSession.java: Import + Javadoc for PolicyControllerAi decision flow.
  Logs decision pipeline when policy server connects. End-of-game reward
  submission via PolicyControllerAi lifecycle.
- BatchRunner.java: New setPolicyServer(url) method. Appends
  --policy midrange --policyServer <url> to Forge subprocess command when
  policy server URL is configured.

## Path Updates (Forge-Repo rename)
- README.md: Forge link → KoalaTrapLord/Forge-Repo, build path updated
- .env.example: FORGE_JAR_PATH and FORGE_WORKING_DIR → Forge-Repo
- lab_api.py: Auto-detect paths try Forge-Repo first, forge-repo as legacy

## MacroActionExecutor
- Added public isRemovalCard(), isDrawCard(), isRampCard() wrappers so
  PolicyControllerAi can consult the same card-role databases.

Refs: Issue #83 Phase 2.4
2026-04-05 14:47:15 +00:00
rgriffithandClaude Opus 4.6 9eaa41a4ae feat: deck dropdown, user-decks pipeline, deckgen fixes, gpt-oss removal
- Add user-decks/ directory and USER_DECKS_DIR config for exported decks
- Update export-to-sim to write to user-decks/ with static mount in lab_api
- Replace import/paste UI with API-backed "My Decks" dropdown in LAN client
  and AI Lab, fetching from GET /api/lab/decks with source grouping
- Fix GET /api/lab/decks to JOIN deck_cards for totalCards count
- Fix deckgenerator: add missing DOM elements (dg-strategy-bar, dg-stats-bar,
  dg-card-groups) inside #dg-results, null guards on render functions,
  fix setLoading always hiding results
- Replace gpt-oss:20b with claude-opus-4-20250514 across all files
- Add user-decks/ to _BUILTIN_DECK_DIRS in deck_service.py
- Enrich missing type_line from Forge card cache in DB deck path
- Collapse import bar behind <details> toggle in AI Lab

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 01:17:30 -04:00
KoalaTrapLord e8f8766d59 fix: register policy routes at module scope before StaticFiles mounts
The root cause of the persistent /api/policy/health 404:
- app.mount("/", StaticFiles(...)) is called at module load time
- StaticFiles acts as a sub-app and consumes matching requests,
  returning its own 404 for unknown files rather than falling through
- register_policy_routes() was called in lifespan (runtime), AFTER
  the "/" mount was already in the route list — so the policy router
  was effectively unreachable

Fix: move route registration to module scope right after all other
app.include_router() calls and BEFORE any app.mount() calls. Only
the model load (_POLICY_SVC.load()) stays in lifespan.
2026-04-03 13:09:12 -04:00
KoalaTrapLord a69b273f5f fix: always register policy routes at startup regardless of model load state
Previously /api/policy/health returned 404 when the model wasn't loaded
because register_policy_routes() was gated behind _policy_svc.load().
The health endpoint itself already handles the unloaded state gracefully
(returns {ready: false, status: degraded}), so the router must be mounted
unconditionally so ai-bridge.js can poll it during startup.
2026-04-03 12:29:18 -04:00
Commander AI Lab e90efe1654 fix: serve lan-client from backend at /lan on port 8080
- Mount lan-client/ as static files at /lan with html=True
- Mount precon-decks/ at /precon-decks/ for direct .dck access
- ai-bridge.js: use same-origin (empty URLs, auto-detect from window.location)
- engine.js: simplify deck fetch to use /api/lab/precons/deck endpoint + /precon-decks/ static fallback
- Eliminates cross-origin issues by serving everything from localhost:8080

Access the LAN battlefield at http://localhost:8080/lan/
2026-04-03 14:30:55 +00:00
KoalaTrapLord 53fd1c9257 fix: wire RESULTS_DIR and FORGE_DIR env vars into CFG at startup 2026-04-02 14:24:28 -04:00
KoalaTrapLord 3f5d6d12e8 feat: 4-player Commander Battleground UI (issues #138–#151)
* chore: add battleground UI task tracker (2026-03-28)

* feat(#142): add [NonSerialized] battleground runtime state to CardModel

* feat(#143): add LoadArtCrop and LoadCardRaw (RawImage) to ImageCache

* feat(#148): add GameStateManager singleton and GameState/SeatState POCOs

* feat(#138): add BattlegroundController scene orchestrator

* feat(#139): add LifeTrackerWidget, CommanderDamageRow, PoisonCounter

* feat(#140): add PhaseTrackerWidget and PhaseStepButton

* feat(#141): add TurnOrderBar and TurnOrderPill

* feat(#142): add CardZone and CardView battlefield zone components

* feat(#143): add CommanderZoneWidget with art crop, cast counter, and tax display

* feat(#144): add TokenModel POCO, TokenPanelController, and TokenRowView

* chore: mark issues 1-8 as complete in task tracker

* feat(#146): add StackZoneController, StackItemView, and ManaPoolDisplay

* feat(#147 #150 #151): add LobbySetupModal, ZoneViewerModal, EliminationHandler; add Play Live button to SimulationController

* feat(#151): add Play Live button to SimulationController

* feat(#149): add GameWebSocketClient with reconnect, ping, and main-thread dispatch

* fix: add PostGameAction to ApiClient + update TODO.md all issues complete

- ApiClient.cs: add PostGameAction() wrapper → POST /api/game/action
  (fixes compile error in HumanActionBar.cs)
- TODO.md: mark issues #145, #146, #147, #149, #150, #151 as ✅
  all 14 battleground issues now committed

* feat(game): add routes/game.py + wire lab_api + fix GameWebSocketClient game_id URL

- routes/game.py: POST /api/game/start, POST /api/game/action (new)
- lab_api.py: import + register game_router
- GameWebSocketClient.cs: read game_id from PlayerPrefs, build
  ws://{host}/ws/game/{game_id} — fixes URL mismatch with ws_game.py

* fix(lobby): wire OnConfirm to POST /api/game/start, save game_id to PlayerPrefs

- OnConfirm() now calls ApiClient.PostGameStart() with 4-seat config
- On success: saves BattleSeats + GameId + WsUrl to PlayerPrefs,
  loads Battleground scene
- On failure: shows inline error label (red), re-enables Confirm button
- Added StartGameRequest/Response POCOs matching routes/game.py schema
- Added _errorLabel [SerializeField] for user-facing error feedback
2026-03-29 05:35:29 -04:00
KoalaTrapLord ac536999eb Update lab_api.pyfeat: wire validate_forge_config into lifespan startup 2026-03-28 14:48:43 -04:00
KoalaTrapLord 61fa37dc48 fix: lifespan indent error, get_running_loop, remove double rag init, register policy routes 2026-03-27 20:22:42 -04:00
KoalaTrapLord 0010b0f394 refactor: RAG improvements — shared card_text, Chroma fallback, staleness monitor (fixes #133, #134, #135) (#136)
* refactor: add shared build_card_text() utility

* refactor: unify _build_document via shared card_text + add is_chroma_available/check_staleness (fixes #133, #134, #135)

* refactor: delegate embeddings._build_card_text to shared utility

* feat: add background RAG staleness monitor to lab_api lifespan (fixes #135)
2026-03-27 16:46:33 -04:00
KoalaTrapLord bcf558418a fix(rag): squash all RAG/ChromaDB bugs #123–#130
Fixes critical API contract mismatch, batch_size wiring, lifespan init, failure tracking, build_meta persistence, mana_cost in embeddings, pyproject.toml deps, and adds full test suite.

Closes #123, #124, #125, #126, #127, #128, #129, #130
2026-03-27 13:24:41 -04:00
KoalaTrapLord fc2e9d88d5 feat(rag): wire ensure_rag_store into main() startup (#121) 2026-03-27 09:13:03 -04:00
KoalaTrapLord 4b0cd34eda feat(rag): Phase 2 — ChromaDB vector index over bulk card DB (#120)
* feat(rag): Phase 2 — ChromaDB vector index over bulk card DB

* feat(rag): add routes/rag.py with build, search, status endpoints

* Update lab_api.pyfeat(rag): register rag_router in lab_api.py, remove old inline rag_status

* Update requirements.txtfeat(rag): add chromadb>=0.5.0 to requirements.txtfeat(rag): add chromadb to requirements.txt
2026-03-27 08:39:02 -04:00
KoalaTrapLord 8df5900ff9 feat(rag): Phase 1 — Scryfall bulk offline card database (SQLite FTS5) (#117)
* feat(rag): add scryfall_bulk.py — offline SQLite FTS5 card database (RAG Phase 1)

* feat(rag): wire ensure_bulk_db() into startup and add /api/rag/status endpoint (RAG Phase 1)

* fix: migrate on_event to lifespan handler, fix /api/rag/status route ordering
2026-03-27 07:16:55 -04:00
KoalaTrapLord 8f180820f9 fix: add missing _DEFAULT_ORIGINS definition in lab_api.py (#105) 2026-03-25 21:00:34 -04:00
KoalaTrapLord 3906b93c6a feat: add WebSocket support for Unity game state streaming (#107)
* feat: add ws/ package for WebSocket game state streaming

* feat: add WebSocket ConnectionManager with per-game broadcasting

* feat: add GameStateTracker with deep-diff delta engine

* feat: add WebSocket route with delta push and REST bridge endpoints

* feat: register ws_game_router in lab_api.py
2026-03-25 19:51:15 -04:00
KoalaTrapLord af2a71d1a5 fix: eliminate event-loop-blocking sync calls in async FastAPI routes (#106)
* feat: add async DB wrapper and eliminate event-loop blocking

* fix: rewrite llm_client.py with native async httpx - removes urlopen and run_in_executor

* fix: rewrite routes/coach.py - replace all sync DB/HTTP with async (aiosqlite + httpx)

* fix: add async DB shutdown hook to lab_api.py

* feat: add aiosqlite>=0.19.0 to requirements
2026-03-25 19:17:41 -04:00
KoalaTrapLord 9556f9d7d0 feat: replace Perplexity with Anthropic Claude in lab_api.py (#105) 2026-03-25 15:18:14 -04:00
87404f3702 refactor: move logging out of routes/shared.py into services/logging.py (#99)
Create services/logging.py as the canonical home for setup_logging(),
all log format constants, named loggers, and _ml_logging_enabled.

Update all route modules and lab_api.py to import logging symbols from
services.logging and all other symbols from their canonical sources
(models.state, models.requests, models.responses, services.database,
services.deck_service, services.scryfall, services.import_helpers,
services.import_service, services.precon_service, services.forge_runner).

Delete routes/shared.py — the re-export hub is no longer needed.

Closes #61

Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:04:25 -04:00
KoalaTrapLordandClaude Code f0dfb41f2f fix: default Ollama endpoints to localhost instead of 192.168.0.240 (#98)
The hardcoded 192.168.0.240 IP was a developer-specific LAN address
that breaks out-of-the-box for anyone running Ollama locally or via
WSL2 on Windows. Switch every default and docstring reference to
localhost so the project works without manual configuration.

Files changed:
- coach/config.py: LLM_URL and DECK_GEN_BASE_URL defaults
- ui/simulator.html: API endpoint input value and placeholder
- lab_api.py: remove LAN IP from default CORS origins
- routes/coach.py: warning message text
- src/commander_ai_lab/sim/deepseek_brain.py: docstrings
- src/commander_ai_lab/sim/deepseek_engine.py: docstring example
- src/commander_ai_lab/sim/validator_brain.py: docstring example

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-03-23 21:03:17 -04:00
KoalaTrapLord 1b95659f14 fix: add LAN origins (192.168.0.240) to default CORS allowlist (#71) 2026-03-21 19:41:05 -04:00
KoalaTrapLord 2088da6fd8 fix: correct indentation in _resolve_forge_dir forge-gui sibling check 2026-03-20 11:33:42 -04:00
KoalaTrapLord a2fbc30b2b fix: resolve forge_dir to forge-gui sibling when res/ not found in forge-gui-desktop 2026-03-20 11:22:44 -04:00
rgriffith c83f7e0141 fix: repair broken if-statement on line 162 2026-03-19 21:45:42 -04:00
KoalaTrapLord e5377ef4bc fix: correct indentation and add forge-gui candidate path 2026-03-19 18:24:57 -04:00
KoalaTrapLord 56ea2602b4 fix: scan sibling dirs for res/ in _resolve_forge_dir (finds forge-gui/res) 2026-03-19 18:19:32 -04:00
Computer c6329d377a fix: register missing /api/ml and /api/health routes 2026-03-19 06:48:41 +00:00
KoalaTrapLord 1cc0b696d3 feat: add dotenv support for .env file loading 2026-03-18 23:46:27 -04:00
KoalaTrapLord 9863f7590b Update lab_api.py 2026-03-18 23:38:55 -04:00
Commander AI Lab Agent fbc3bdb6b5 fix: add _resolve_precon_dir() auto-detection so CFG.precon_dir is not empty
The precon deck list was missing after the monolith refactor because
PRECON_DIR was hardcoded in services/precon_service.py with no CLI arg,
env var, or auto-resolve fallback — unlike forge_jar, forge_dir, etc.

Changes:
- Add precon_dir field to Config class (models/state.py)
- Add --precon-dir CLI arg and PRECON_DIR env var support
- Add _resolve_precon_dir() with project-root, parent-dir, and
  forge_dir-relative detection; creates dir as fallback for downloads
- Refactor precon_service.py to use _get_precon_dir() helper that reads
  CFG.precon_dir at runtime instead of a hardcoded module-level Path
- Update routes/precon.py to use _get_precon_dir() for install endpoints
- Wire _on_startup to resolve precon_dir for uvicorn-direct launches
- Remove unused PRECON_DIR/PRECON_INDEX imports from routes/lab.py
- Audit confirms all other CFG path fields already have fallbacks
2026-03-18 04:56:03 +00:00
ClaudeandClaude Opus 4.6 85df46364a fix: add _resolve_forge_dir() auto-detection so CFG.forge_dir is not empty
Same pattern as the previous _resolve_forge_jar() fix — when --forge-dir
is not passed via CLI or FORGE_DIR env var, auto-detect the Forge
installation directory by:
1. Deriving from the already-resolved forge_jar path (parent of target/)
2. Checking common sibling directories (forge/, forge-repo/)
3. Checking platform user data dirs (~/.forge, ~/Forge, %APPDATA%/Forge)

Also audited all other CFG fields — forge_jar, forge_decks_dir, lab_jar,
port, results_dir all already have proper defaults or auto-resolve
fallbacks. Added Forge Dir, Lab JAR, and Results Dir to startup log
output for better diagnostics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 04:50:23 +00:00
Claude 32f3c9dfa3 fix: add _resolve_forge_jar() auto-detection so CFG.forge_jar is not empty
During the refactor from the monolith into services/, the forge JAR path
had no auto-resolve fallback — unlike lab_jar and forge_decks_dir which
both had resolver functions. When --forge-jar CLI arg and FORGE_JAR env
var are both unset, CFG.forge_jar stayed "" causing POST /api/lab/start
to fail with "Forge JAR not found: ".

Add _resolve_forge_jar() that scans common sibling directories for
forge-gui-desktop-*-jar-with-dependencies.jar (matching the pattern
from start-lab.bat), and wire it as the fallback in main().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 04:44:20 +00:00
KoalaTrapLord fd74f157e8 Phase 4: Slim lab_api.py to thin main() - closes #25
Refactor lab_api.py to streamline imports, improve logging, and enhance argument parsing.
2026-03-17 16:17:53 -04:00
KoalaTrapLord 312d13949d feat: extract ML endpoints into routes/ml.py (#36)
Moved all 15 /api/ml/* endpoints, 4 state dicts, and 3 background
pipeline functions from lab_api.py into routes/ml.py. Wired via
app.include_router(ml_router) in lab_api.py.
2026-03-17 00:41:31 -04:00
Commander AI Lab 872f6c38ca security: remove hardcoded API keys, add .env support (fixes #26)
- Remove plaintext Ximilar and Perplexity API keys from start-lab.bat
- Remove hardcoded key defaults from lab_api.py, lab_api_backup.py, lab_api_new.py
- start-lab.bat now reads from environment variables or .env file
- Add .env.example with placeholder values
- .env already in .gitignore (confirmed)
- Git history purged of all key values via git-filter-repo

Closes #26
2026-03-17 02:00:15 +00:00
KoalaTrapLord c60719a0a9 refactor: extract deckgen (14) + coach (12) routes
- routes/deckgen.py: classic generator, Perplexity V1, V3 generator + exports
  Helpers: _resolve_commander, _generate_deck, _build_collection_summary,
  _call_pplx_api, _fill_basic_lands, etc.
  Uses _coach._deck_gen_v3 via module reference for V3 state
- routes/coach.py: all coaching endpoints + init_coach_service(),
  _build_deck_report_from_db, globals (_coach_service, _deck_gen_v3, etc.)
- lab_api.py: 3265 -> 1063 lines (16 remaining: ML + SPA catch-all)
- Total: 90 extracted + 16 remaining = 106 endpoints verified
2026-03-15 07:26:09 +00:00
KoalaTrapLord 87a2090c68 refactor: extract scanner (6) + deepseek/sim (9) routes
- routes/scanner.py: scan, scan/add, re-enrich, auto-classify, auto-classify-all, edhrec
- routes/deepseek.py: sim/run, sim/status, sim/result, sim/run-from-deck,
  sim/run-deepseek, deepseek/connect, deepseek/status, deepseek/configure, deepseek/logs
- lab_api.py: 4464 -> 3265 lines (42 remaining endpoints)
- Total: 64 extracted + 42 remaining = 106 endpoints verified
2026-03-15 06:56:02 +00:00
KoalaTrapLord 8a6fbfaa8a fix: 3 post-refactor bugs (COMMANDER_META, PRECON_INDEX, startup)
Task 1: Move BUILTIN_COMMANDERS + load_commander_meta() to shared.py
        Fix import_routes.py to use _shared.COMMANDER_META (module ref)
Task 2: Rewrite precon.py to use _shared.PRECON_INDEX (module ref)
Task 3: Add @app.on_event('startup') safety net for uvicorn --reload
2026-03-14 19:08:21 +00:00
KoalaTrapLord 36077c94ab refactor: extract 49 endpoints into 5 route modules
- Extract collection (10), deckbuilder (18), precon (4), import (5), lab (12) routes
- All share helpers/models/state from routes/shared.py
- Gut lab_api.py from 8872 to 4487 lines (57 remaining endpoints)
- Delete routes/_wire.py and routes/_autoload.py (replaced by include_router)
- Add _scryfall_fuzzy_lookup to shared.py
- 106 total endpoints verified: 49 extracted + 57 remaining
2026-03-14 18:55:32 +00:00
KoalaTrapLord 2b2383f5c8 wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 02:02:53 -04:00
KoalaTrapLord 911fde9f5f wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 02:02:26 -04:00
KoalaTrapLord 6799f0c402 wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 01:57:18 -04:00
KoalaTrapLord da4e225db0 wire routes._autoload.register_startup(app) after CORSMiddleware 2026-03-14 01:55:50 -04:00
KoalaTrapLord 2d02fcc770 Add files via upload 2026-03-14 01:00:25 -04:00
KoalaTrapLord 6c547664fb Delete lab_api.py 2026-03-14 00:55:32 -04:00
KoalaTrapLord d95f0b57c0 fix: commander card correctly flagged in deck tracker
Two fixes:
1. _parse_text_decklist(): replace fragile startswith() section-header
   detection with case-insensitive regex so [Commander], [Main], [Deck]
   etc. are always recognised regardless of capitalisation.

2. add_deck_card endpoint: when a card is added with is_commander=1,
   also update the deck-level commander_name + commander_scryfall_id
   so the portrait and top-bar label stay in sync.
2026-03-14 00:48:19 -04:00
KoalaTrapLord 264fb33957 fix: commander card correctly flagged in deck tracker
Two fixes:
1. _parse_text_decklist(): replace fragile startswith() section header
   detection with proper case-insensitive regex so [Commander], [Main],
   [Deck] etc. are always recognised regardless of capitalisation.

2. add_deck_card endpoint: when a card is added with is_commander=1,
   also update the deck-level commander_name and commander_scryfall_id
   fields so the portrait and top-bar label stay in sync without
   requiring a full reload.
2026-03-14 00:47:59 -04:00
KoalaTrapLord e4ebd84c04 test 2026-03-14 00:47:37 -04:00
KoalaTrapLord 4c7c3495fb feat(api): accept 2-4 decks in batch start, dynamic Java CLI args (Task 2C) 2026-03-13 18:59:25 -04:00
KoalaTrapLord c1371849e5 feat(api): accept 2-4 decks in batch start, dynamic Java CLI args (Task 2C) 2026-03-13 18:58:33 -04:00