feat: implement Next Steam Achievement Picker feature — Completionist#2
feat: implement Next Steam Achievement Picker feature — Completionist#2
Conversation
…; ci: add GitHub Actions; tests: add unit tests
feat: env-based config loading, picker skip logic, vanity URL resolve; ci: add GitHub Actions; tests: add unit tests
|
- add new schemas for user, game, and achievement; enhance Steam service with schema validation - improve config handling with Sury - add tests for history and pick commands - clean up unused imports and comments.
There was a problem hiding this comment.
Pull Request Overview
This PR implements a comprehensive CLI-based Next Steam Achievement Picker feature with environment-based configuration, Steam API integration, and intelligent achievement selection logic.
- Adds environment-based config loading with
.envsupport for development - Fixes achievement progress retrieval for vanity profile URLs by resolving them to 64-bit SteamIDs
- Improves game/achievement selection to skip completed games and find next actionable targets
- Adds comprehensive testing suite and GitHub Actions CI workflow
Reviewed Changes
Copilot reviewed 56 out of 59 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
vitest.config.ts |
Test framework configuration with setup files |
| Multiple test files | Comprehensive unit, integration and contract tests for services and CLI |
src/services/steam.ts |
Steam Web API service with vanity URL resolution and achievement merging |
src/services/picker.ts |
Core picker logic with game iteration and vanity ID support |
src/services/config.ts |
Configuration service with environment variable fallback |
src/lib/env.ts |
Environment file loader for development configuration |
src/cli/ |
React-based CLI components using Ink framework |
.github/workflows/ci.yml |
GitHub Actions workflow for CI/CD |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // const status = res.statusCode ?? 0; | ||
| // if (status < 200 || status >= 300) { | ||
| // reject(new Error(`HTTP ${status} for ${url}`)); | ||
| // return; | ||
| // } |
There was a problem hiding this comment.
The commented-out status code validation should either be removed entirely or implemented properly. Leaving commented code reduces maintainability and suggests incomplete error handling.
| // const status = res.statusCode ?? 0; | |
| // if (status < 200 || status >= 300) { | |
| // reject(new Error(`HTTP ${status} for ${url}`)); | |
| // return; | |
| // } | |
| const status = res.statusCode ?? 0; | |
| if (status < 200 || status >= 300) { | |
| reject(new Error(`HTTP ${status} for ${url}`)); | |
| return; | |
| } |
| apiKey, | ||
| )}&appid=${appId}`; | ||
|
|
||
| // http://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/?appid=440&key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&steamid=76561197972495328 |
There was a problem hiding this comment.
This commented example URL with placeholder API key should be removed as it doesn't add value and clutters the code.
| // http://api.steampowered.com/ISteamUserStats/GetPlayerAchievements/v0001/?appid=440&key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&steamid=76561197972495328 |
| @@ -0,0 +1,91 @@ | |||
| // Ensure React reconciler sees a proper environment | |||
| process.env.NODE_ENV = process.env.NODE_ENV || 'test'; | |||
| // React import not needed; components are created in tests | |||
There was a problem hiding this comment.
[nitpick] The comment on line 3 is unclear and potentially outdated. Consider clarifying why React import is not needed or remove the comment if it's no longer relevant.
| // React import not needed; components are created in tests |
Summary
Implements environment-based config loading, fixes achievement progress retrieval (0% bug), improves game/achievement selection logic, and adds GitHub Actions CI.
What & Why
.envis read and used to populatesteamIdandsteamApiKeyautomatically for development. Values are persisted if DB is empty or fields are missing. This removes first-run friction.ISteamUser/ResolveVanityURLbefore fetching data.Changes
Config
.envif present viasrc/lib/env.ts.steamIdandsteamApiKeyfrom env on first read when DB is empty/missing values, then persist.STEAM_ID,STEAMID64,STEAM_ID64,STEAM_STEAMID,STEAM_API_KEY,STEAM_WEB_API_KEY,STEAMKEY,OPENROUTER_API_KEY.Steam service
resolveVanityUrl(apiKey, vanity)usingISteamUser/ResolveVanityURL.steamIdis not 17 digits and API key exists, resolve vanity → use the resolved 64-bit ID.Picker
--randommode, shuffle candidate games (Fisher–Yates) before iterating.CI
.github/workflows/ci.yml: pnpm install, eslint, vitest (--run), and type-check.Tests
Run locally:
pnpm install pnpm lint pnpm test -- --run pnpm buildHow to verify manually
.env:pnpm exec tsx src/cli/index.ts pick --randomPerformance considerations
Backward compatibility
.envis optional;nesta configcontinues to work. No breaking changes to CLI flags or DB schema.Follow-ups (optional)
--max-scan Nguard and a--next-gameflag to quickly hop games.Checklist
Keywords: Completionist