• v3.1.1 99195fe627

    v3.1.1
    All checks were successful
    CI / build-and-test (push) Successful in 1m5s
    Stable

    joeyr released this 2026-07-15 20:42:09 -05:00 | 62 commits to main since this release

    Verified against a real League client (locked Lux Support, imported the top Sorcery+Domination page — confirmed applied and active in the client).

    Fixed

    • Rune import success message now names the imported combo. It previously only echoed the page name (Imported "LoLC: Lux Support"), so there was no way to tell which of the listed rune pages had actually been applied when several rows exist for the same champion. It now also names the combo, e.g. Imported "Sorcery + Domination" as "LoLC: Lux Support" — applied in your client.
    Downloads
  • v3.1.0 572dc42a23

    v3.1.0
    All checks were successful
    CI / build-and-test (push) Successful in 1m6s
    Stable

    joeyr released this 2026-07-15 17:51:21 -05:00 | 64 commits to main since this release

    Added

    • One-click rune import (build importer, runes-first). When you lock in your champion, the app fetches op.gg's recommended rune pages for that champion + role (same region/tier filters as the counters data) and shows a new Rune Import section: one row per keystone-tree combo with that exact page's own win rate, pick share, and games — click Import to write it into the running League client as the active page.
      • Off by default. Enable it in Settings → Rune import. While off, the app stays fully observation-only: nothing is scraped on lock-in, the section is hidden, and the main process refuses import requests.
      • Slot-safe. The companion maintains exactly one page of its own (name prefix LoLC:) and only ever overwrites that page — it never deletes a rune page you created. If every slot holds one of your pages, it asks you to free one instead.
      • Narrow write boundary. This release relaxes the app's read-only LCU contract to a property-tested write allowlist (amended Req 6): lol-perks rune pages (and later lol-item-sets) only; champ-select, lobby, matchmaking, and gameflow writes remain refused at the boundary. Imports are the only writes, and only ever fire on your explicit Import click.
      • Item sets are the planned follow-up on the same boundary (docs/build-importer-plan.md).
    Downloads
  • v3.0.2 a06ff121e5

    v3.0.2
    All checks were successful
    CI / build-and-test (push) Successful in 1m3s
    Stable

    joeyr released this 2026-07-08 10:30:30 -05:00 | 67 commits to main since this release

    Internal cleanup — no user-facing behavior change. Typecheck, 508 tests, build, and a dev smoke launch all green.

    Fixed

    • debug.log no longer grows unbounded. The logger appended at debug level across every run with rotation never landing — the dev-tree copy had reached 23 MB. The log now rotates at startup: debug.log holds the current run, debug.log.old the previous one, and anything older is dropped.

    Changed

    • startAssistant broken up. The scouting-report and benchmark-harvest subsystems are wired by dedicated wireScout / wireHarvest functions constructed before the live poller, which references them directly — the three mutable "forward hook" callbacks are gone, and the inbound IPC handler is registered last so it captures the real wiring.
    • The live-metrics and scout overlay windows share one createClickThroughOverlayWindow factory, and the three "mark the publisher ready" blocks share one publishWhenLoaded helper.
    • The default overlay-metric and scout-section lists are derived from DEFAULT_SETTINGS instead of being re-listed in src/main/index.ts.
    Downloads
  • v3.0.1 5d74e0c935

    v3.0.1
    All checks were successful
    CI / build-and-test (push) Successful in 1m7s
    Stable

    joeyr released this 2026-07-07 20:16:14 -05:00 | 68 commits to main since this release

    Fixed

    • Scouting report: champions with an apostrophe now load their mastery and "On champ" stats. Champions such as Kai'Sa, Kha'Zix, Cho'Gath, Vel'Koz, Rek'Sai, Kog'Maw, Bel'Veth, and K'Sante failed to resolve to a champion id because the in-game Live Client Data API and the LCU champion list spell the apostrophe with different characters (a straight ' vs. a curly ’), and the name→id lookup was an exact string match. The affected player'''s row still showed rank and role, but Mastery and On-champ stats stayed blank. The lookup is now apostrophe- and punctuation-tolerant (it also covers spacing/period differences like "Dr. Mundo" and "Nunu & Willump").
    Downloads
  • v3.0.0 89878b7119

    v3.0.0
    All checks were successful
    CI / build-and-test (push) Successful in 1m4s
    Stable

    joeyr released this 2026-07-07 09:15:48 -05:00 | 69 commits to main since this release

    Added

    • Real installers. The app now packages into a proper Windows installer
      (NSIS — per-user, no admin prompt) and a standalone portable .exe via
      npm run dist, instead of being launched from npm start. The native pieces
      are bundled and verified to run from the packaged build: the koffi FFI addon
      (global hotkey + screen capture) and the tesseract OCR worker with its
      language model.
    • Riot API key in Settings. A new field in the Settings panel stores your
      personal Riot API key locally in settings.json. It enables the scouting
      report and benchmark harvesting, and a status line shows whether a key is set.

    Changed

    • BREAKING — the Riot API key now comes only from the Settings panel. The
      app no longer reads RIOT_API_KEY from the environment or a .env file.
      After updating, enter your key in Settings once (it applies on the next
      launch); an existing .env key will be ignored by the app. The standalone
      npm run harvest:benchmarks CLI is unaffected and still reads RIOT_API_KEY
      from the environment.
    • The packaged app writes debug.log into your user-data folder
      (%APPDATA%\champ-select-assistant\) instead of next to the executable. Dev
      runs are unchanged (current working directory).

    Downloads: LoL Companion-3.0.0-setup.exe (installer) or
    LoL Companion-3.0.0-portable.exe (no install). The build is unsigned, so
    Windows SmartScreen warns on first run — choose More info → Run anyway.
    After installing, open Settings and enter your Riot API key to enable the
    scouting report and benchmark harvesting.

    Downloads
  • v2.1.2 ed00a34c5e

    v2.1.2
    All checks were successful
    CI / build-and-test (push) Successful in 1m10s
    Stable

    joeyr released this 2026-07-06 12:18:28 -05:00 | 75 commits to main since this release

    Added

    • Continuous integration. A Forgejo Actions workflow runs the full gate — type-check, tests, and build — on every push and pull request to main, so a broken build can no longer land unnoticed. It runs on Node 24 to match the shipped Electron runtime and skips the unused Electron binary download.

    Fixed

    • Tests are now timezone-independent. A renderer snapshot rendered a timestamp through toLocaleTimeString, so it only matched in the recording machine's local timezone and failed under CI (UTC); the test scripts now pin TZ=UTC. No change to app behavior.
    Downloads
  • v2.1.1 52f86f25e0

    v2.1.1 Stable

    joeyr released this 2026-07-04 23:06:01 -05:00 | 84 commits to main since this release

    Changed

    • A player the game never identifies now shows a muted amber ? instead of a red ✕. When Riot's local Live Client API exposes a player with no Riot ID at all (a bare # / champion-name placeholder — typically someone still on the loading screen or reconnecting), there is no name to look up. That is different from a name that was looked up and genuinely not found, and the red ✕ read as if the report had failed to load the player. The badge now distinguishes the two — amber ? ("no Riot ID in the game data") vs. red ✕ ("player not found") — with a tooltip explaining the amber case.

    Added

    • Diagnostics for unresolved scouting rows. Real games surfaced players the live feed left unidentifiable all game (the champion name as a placeholder, no tag), even across the 1- and 5-minute re-harvests. The app now logs the raw live-feed identity fields for any tag-less player, and on every scout run probes the LCU /lol-gameflow/v1/session and logs whether it exposes puuids for both teams — read-only groundwork for a fallback identity source that would not depend on the live feed's Riot IDs.
    Downloads
  • v2.1.0 ac36f73a82

    v2.1.0 Stable

    joeyr released this 2026-07-04 16:03:29 -05:00 | 86 commits to main since this release

    Added

    • The scouting report now calls each lane. Between every head-to-head pair a small verdict chip points to the favored side (green toward your team, red toward the enemy, grey = for even), combining the ranked-ladder gap with recent on-champ form. A thin on-champ sample is discounted quadratically, so a 1-2 game hot streak can't fake an edge, and the chip stays blank whenever either side's data hasn't loaded — it never shows a confident-but-guessed call.
    • Biggest-threat and weakest-link callouts. Exactly one enemy card is tagged ⚠ threat (highest combined rank + on-champ score) and one ally card weak link (lowest), so the two players who most shape the game are obvious at a glance.
    • "first time?" hint. When a player has no mastery and no recent games on the champion they locked, the on-champ line reads first time? instead of a blank .

    Changed

    • The report is laid out as head-to-head lane pairs (your player directly across from their opposite, TOP → SUP) instead of two independent columns.
    • On-champ stats from a small sample (< 5 games) are dimmed and marked * so a coinflip sample isn't read as a trend.
    • Clarified the stat labels with tooltips — "Record" notes it's overall ranked, not on this champ.

    Notes

    • The in-game overlays' on-screen render has not yet been verified in a live match.
    Downloads
  • v2.0.1 fa285e38e2

    v2.0.1 Stable

    joeyr released this 2026-07-01 08:46:00 -05:00 | 87 commits to main since this release

    Fixed

    • A player whose Riot ID is missing from the live feed no longer drops out of the scouting report. Riot's local Live Client API occasionally exposes a player with no Riot ID (a bare #, empty game name, summonerName defaulted to the champion name) — typically a teammate still on the loading screen. That player's game-name split to an empty string and the whole card was silently filtered out, leaving a gap in the lane. The card is now always kept: the champion and role render, and the identity badge shows a red ✕ ("couldn't identify this account") instead of the lane vanishing.
    • The scouting report now re-harvests when a player's identity didn't resolve. Previously the live feed was sampled exactly once per game (at game start), so a player whose Riot ID hadn't populated yet stayed blank all game no matter how many times the overlay was toggled — toggling only re-shows the cached snapshot. When any identity fails to resolve, the report now re-harvests at the 1-minute and 5-minute game-clock marks; a later snapshot usually carries the now-populated Riot ID, and the card fills in automatically. Re-runs are cheap (already-resolved players are served from the scout cache), bounded to those two marks per game, and cleared at game end. A genuinely hidden account that the feed never surfaces stays a ✕ — the read-only-against-the-LCU contract is unchanged.
    Downloads
  • v2.0.0 4d90185687

    v2.0.0 Stable

    joeyr released this 2026-06-30 22:19:07 -05:00 | 88 commits to main since this release

    The full-stack modernization milestone: every dependency is now on its latest release, with zero security advisories, zero deprecated packages, and zero deprecated APIs in our own code. Nothing about how the app is used changes — this is a foundation release. The major-version bump signals the scale of the under-the-hood jump (Electron, React, and zod all crossed a major), not a change to the read-only-against-the-LCU contract, which is unchanged.

    Fixed

    • The scouting report now routes Riot API calls to the correct region. Platform detection read the LCU's LoginDataPacket platform-config namespace, which is frequently empty and returned a 404, so region resolution silently fell back to na1 for everyone regardless of their actual server. It now reads the client's crash-reporting environment (/riotclient/v1/crash-reporting/environment), set at client startup, which returns the Riot platform id (e.g. na1) directly. NA players were unaffected (the fallback happened to match); other regions were mis-routed.

    Internal

    • Every dependency upgraded to latest, in gated phases. Runtime/framework majors: Electron 33 -> 43 (bundled Node 20 -> 24), React 18 -> 19, zod 3 -> 4, undici 7 -> 8, koffi 3.0 -> 3.1. Toolchain: TypeScript 5 -> 6, Vite 5 -> 8, Vitest 2 -> 4, @types/node -> 24 (pinned to match Electron 43's Node 24 runtime). Plus pino 9 -> 10, selfsigned 2 -> 5, jsdom 25 -> 29, fast-check 3 -> 4, and the React 19 / zod 4 type packages.
    • Deprecated APIs removed at the source, not silenced. zod 4: .passthrough() -> .loose() and z.string().datetime() -> z.iso.datetime(); enum-keyed z.record -> z.partialRecord where the data is partial (a real behavior fix — v4 enum records are exhaustive). React 19: the removed global JSX namespace is now imported explicitly. Vitest 4: vitest.workspace.ts folded into test.projects. TypeScript 6: tsconfig.main.json moduleResolution migrated off the deprecated node10.
    • Result: npm audit reports 0 vulnerabilities and the tree carries no deprecated packages. All 482 tests pass; the build is warning-free.
    Downloads