Skip to content

Add game-scout extension#27267

Draft
Glct26 wants to merge 11 commits intoraycast:mainfrom
Glct26:ext/game-scout
Draft

Add game-scout extension#27267
Glct26 wants to merge 11 commits intoraycast:mainfrom
Glct26:ext/game-scout

Conversation

@Glct26
Copy link
Copy Markdown

@Glct26 Glct26 commented Apr 18, 2026

Description

Game Scout is a comprehensive extension for gamers to search across multiple storefronts, track historical lows, discover free giveaways, and catch the best daily deals without leaving the launcher.

Key Features

  • Search Games: Quickly look up any game, see its current price, all-time low, and active bundles (via IsThereAnyDeal API).
  • Smart Recommendation Engine: Get instant verdicts (🔥 GREAT DEAL, 🔴 HIGH PRICE, etc.) based on historical lows and bundle value analysis (via IsThereAnyDeal API).
  • Price History Charts: View visual price trend graphs with 3m, 6m, and 1y toggles directly in the detail view (via QuickChart.io).
  • Bundle Content Viewer: Inspect active bundle tiers, prices, and included games without leaving the extension (via IsThereAnyDeal API).
  • Manage Stores: Globally filter Search, Saved Games, and Top Deals to only show prices from your preferred storefronts.
  • Saved Games: Add games to your personal watchlist. Prices and price-drops are automatically tracked and updated (via IsThereAnyDeal API).
  • Top Deals: Discover the highest-rated game deals across 30+ official stores, powered by the CheapShark Deal Rating algorithm (via CheapShark API - No API key required).
  • Free Games: Never miss a 100% free game or DLC giveaway across PC, PlayStation, Xbox, VR and Mobile platforms (via GamerPower API - No API key required).

Screencast

1 2 3 4 5 6 7

Checklist

@raycastbot raycastbot added the new extension Label for PRs with new extensions label Apr 18, 2026
@raycastbot
Copy link
Copy Markdown
Collaborator

Congratulations on your new Raycast extension! 🚀

We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days.

Once the PR is approved and merged, the extension will be available on our Store.

@Glct26 Glct26 marked this pull request as ready for review April 18, 2026 15:56
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 18, 2026

Greptile Summary

Game Scout is a new extension for tracking game prices, deals, and giveaways across multiple storefronts using IsThereAnyDeal, CheapShark, and GamerPower APIs. The implementation is feature-rich, but there is one clear behavioral defect in the Saved Games command that needs to be fixed before merging.

  • Bundle counts always 0 in Saved Games (saved-games.tsx line 149): the /games/overview/v2 endpoint returns an array of per-game objects; accessing oJson.bundles on the array is always undefined, so every game's bundle indicator is permanently suppressed.
  • Conditional early returns before hook definitions (search-games.tsx, saved-games.tsx): hooks are declared after a conditional return, violating React's Rules of Hooks.
  • Selectable separator item with empty value in the country dropdown can produce an empty country code that bypasses region validation in saved-games.tsx.

Confidence Score: 3/5

Not safe to merge as-is — the bundle count bug in Saved Games causes a feature to be permanently non-functional.

One confirmed P1 defect (bundle counts always 0 in saved-games) plus a Rules of Hooks violation that will be flagged by the linter lower the score from the P1 ceiling of 4.

extensions/game-scout/src/saved-games.tsx (bundle count logic), extensions/game-scout/src/search-games.tsx (hooks ordering), extensions/game-scout/package.json (separator dropdown value)

Important Files Changed

Filename Overview
extensions/game-scout/src/saved-games.tsx Watchlist command with price-drop tracking; bundle count mapping is broken (always 0) due to incorrect parsing of the overview API response, and hooks are defined after an early conditional return.
extensions/game-scout/src/search-games.tsx Core search + game detail view; hooks are defined after a conditional early return (Rules of Hooks violation).
extensions/game-scout/package.json Extension manifest; missing $schema reference, contains a selectable separator item with empty-string value that can bypass region validation.
extensions/game-scout/src/top-deals.tsx Top deals via CheapShark API; clean implementation, no notable issues.
extensions/game-scout/src/free-games.tsx GamerPower giveaway browser; clean implementation with platform categorization, no notable issues.
extensions/game-scout/src/manage-stores.tsx Store filter manager; intentional Deselect All without persisting to LocalStorage is documented with a comment; overall logic is sound.
extensions/game-scout/src/utils.ts Shared utilities (store map, price formatting, store filter); clean and correct.
Prompt To Fix All With AI
Fix the following 4 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 4
extensions/game-scout/src/saved-games.tsx:149-159
**Bundle counts always zero in Saved Games**

The `/games/overview/v2` endpoint returns an **array** of per-game objects (each with a numeric `bundles` field), not a top-level object with a `bundles` array. `oJson.bundles` is therefore always `undefined`, so `(oJson.bundles || []).filter(...)` always resolves to `[]` with length 0 — bundle counts are never populated and the bundle indicator never appears in the saved-games list.

A corrected version would look up each game's overview entry and read its numeric `bundles` field:
```ts
gameIds.forEach((id) => {
  const entry = Array.isArray(oJson)
    ? oJson.find((g: any) => g.id === id)
    : oJson?.[id];
  bMap[id] = typeof entry?.bundles === "number" ? entry.bundles : 0;
});
```

### Issue 2 of 4
extensions/game-scout/src/search-games.tsx:49-80
**React hooks called after a conditional return**

`useState(false)` is called at line 49, then lines 53–72 conditionally return early before the remaining `useState`/`useEffect`/`useFetch` calls at lines 74–163. This violates the Rules of Hooks: hooks must be called in the same order on every render. The same pattern appears in `saved-games.tsx` (lines 50–66 return early before all hook definitions starting at line 69).

In practice this doesn't crash today because `API_KEY` and `COUNTRY` are module-level constants that never change between renders. However, the ESLint `react-hooks/rules-of-hooks` rule will flag this and future refactors could inadvertently break it.

### Issue 3 of 4
extensions/game-scout/package.json:1-5
**Missing `$schema` reference in package.json**

The `package.json` doesn't include the Raycast schema reference, which enables autocomplete, validation, and IntelliSense for extension fields in editors.

```suggestion
{
  "$schema": "https://www.raycast.com/schemas/extension.json",
  "name": "game-scout",
```

### Issue 4 of 4
extensions/game-scout/package.json:112-115
**Separator dropdown item produces empty country code, bypassing region validation in some commands**

Selecting the `──────────` separator item sets `preferences.country` to `""`. `search-games.tsx` catches this (checks `COUNTRY.length === 2`), but `saved-games.tsx` has no such guard — ITAD API calls would be made with `country=` (empty string), likely producing unexpected results or silent failures.

Consider removing the interactive separator item or mapping it to a valid default value.

Reviews (3): Last reviewed commit: "fix: multiple improvements and bug fixes" | Re-trigger Greptile

Comment thread extensions/game-scout/src/saved-games.tsx Outdated
Comment thread extensions/game-scout/src/search-games.tsx Outdated
Comment thread extensions/game-scout/package.json Outdated
Comment thread extensions/game-scout/src/search-games.tsx Outdated
@Glct26
Copy link
Copy Markdown
Author

Glct26 commented Apr 18, 2026

All mentioned issues have been resolved and pushed.

@Glct26
Copy link
Copy Markdown
Author

Glct26 commented Apr 25, 2026

Hi, could a maintainer please approve the workflows so the CI checks can run? Thank you!

@Glct26
Copy link
Copy Markdown
Author

Glct26 commented Apr 27, 2026

All Greptile issues from first review resolved:

  • refreshFrequency preference now controls CACHE_TTL
  • Removed manual Preferences interfaces
  • Fixed duplicate FR country code
  • English comments only
  • CHANGELOG.md added

Phase 1.5 additions:

  • Smart Recommendation Engine (BUY/GOOD DEAL/WAIT/SKIP) with bundle priority
  • Bundle Value Calculator (tier pricing, per-game cost)
  • Price History Charts (3m/6m/1y, toggleable)
  • Manage Stores command
  • BundleContentViewer with Open/Copy actions
  • OST/Soundtrack detection
  • Platform-specific shortcuts (Windows/macOS)
  • Screenshot metadata

@Glct26
Copy link
Copy Markdown
Author

Glct26 commented Apr 27, 2026

Updated screenshots to strictly follow store guidelines.

- Fix CACHE_TTL to use refreshFrequency preference

- Remove unused imports and variables (lint fixes)

- Fix Price Drops: deduplication, regular price format, separator
Glct26 added 7 commits April 27, 2026 22:51
…afe, verdict fixes, truncation with ellipsis
- Improve bundle status logic

- Fix price history chart preference not applying

- Replace mature content icon with tag

- Fix TypeScript preference types

- Add null checks for prices and priceData
Comment on lines +149 to +159
const now = Date.now();
const bMap: any = {};
gameIds.forEach((id) => {
bMap[id] = (oJson.bundles || []).filter((b: any) => {
const isNotExpired = !b.expiry || new Date(b.expiry).getTime() > now;
return (
isNotExpired &&
b.tiers?.some((t: any) => t.games?.some((gm: any) => gm.id === id))
);
}).length;
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Bundle counts always zero in Saved Games

The /games/overview/v2 endpoint returns an array of per-game objects (each with a numeric bundles field), not a top-level object with a bundles array. oJson.bundles is therefore always undefined, so (oJson.bundles || []).filter(...) always resolves to [] with length 0 — bundle counts are never populated and the bundle indicator never appears in the saved-games list.

A corrected version would look up each game's overview entry and read its numeric bundles field:

gameIds.forEach((id) => {
  const entry = Array.isArray(oJson)
    ? oJson.find((g: any) => g.id === id)
    : oJson?.[id];
  bMap[id] = typeof entry?.bundles === "number" ? entry.bundles : 0;
});
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/game-scout/src/saved-games.tsx
Line: 149-159

Comment:
**Bundle counts always zero in Saved Games**

The `/games/overview/v2` endpoint returns an **array** of per-game objects (each with a numeric `bundles` field), not a top-level object with a `bundles` array. `oJson.bundles` is therefore always `undefined`, so `(oJson.bundles || []).filter(...)` always resolves to `[]` with length 0 — bundle counts are never populated and the bundle indicator never appears in the saved-games list.

A corrected version would look up each game's overview entry and read its numeric `bundles` field:
```ts
gameIds.forEach((id) => {
  const entry = Array.isArray(oJson)
    ? oJson.find((g: any) => g.id === id)
    : oJson?.[id];
  bMap[id] = typeof entry?.bundles === "number" ? entry.bundles : 0;
});
```

How can I resolve this? If you propose a fix, please make it concise.

@Glct26 Glct26 marked this pull request as draft April 30, 2026 01:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new extension Label for PRs with new extensions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants