Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
1b888b5
feat: add meta-stats types (GameFormat, ArchetypeStat, DeckStat, Rank…
say8425 May 29, 2026
894b3ee
feat: add stats-math (wilson lower bound, margin of error, tier band)
say8425 May 29, 2026
fccb2f7
feat: add archetype-names (slug->display, Other detection, cached tra…
say8425 May 29, 2026
6955fc0
feat: add meta-stats (Firestone fetch+cache, pure rank transforms)
say8425 May 29, 2026
e6e6698
feat: add formatMetaStats (table/json) for ranked meta rows
say8425 May 29, 2026
bdb78f1
feat: wire hs meta archetypes/decks (Firestone live stats) into meta …
say8425 May 29, 2026
0147cf5
fix: wrap static meta branch in try/catch + format meta command
say8425 May 29, 2026
9929687
docs: document hs meta archetypes/decks + Firestone attribution
say8425 May 29, 2026
317b817
style: oxfmt normalize formatter + stats-math
say8425 May 29, 2026
3131860
style: oxfmt normalize meta-stats fixtures and test
say8425 May 29, 2026
3251449
refactor: drop unused isOtherBucket/CLASS_SLUGS, guard non-finite win…
say8425 May 29, 2026
631528a
feat: show no-rows message in meta table when min-games filters every…
say8425 May 29, 2026
dc84cfe
refactor: .ts import extensions + meaningful low-sample threshold (20k)
say8425 May 29, 2026
daa0f6c
docs(skill): document hs meta archetypes/decks live-meta in hearthsto…
say8425 May 29, 2026
e4b6e71
docs: require updating the hearthstone-deck skill on any CLI-surface …
say8425 May 30, 2026
793070c
test: pin low-sample boundary + json empty-rows contract
say8425 May 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ hs card <dbfId|cardId|name> [-l koKR] # card lookup
hs card --search <q> --class CLASS [-l koKR] # filtered search
hs card --class CLASS [--cost N] [-l koKR] # browse (blank/no --search = wildcard)
hs meta sets|classes|types|rarities [-l koKR]
hs meta archetypes [--game-format standard|wild|twist] [--rank legend|...] [--period last-patch|...] # live archetype winrate/tier (Firestone)
hs meta decks [--rank ...] [--period ...] [--sort wilson|winrate|games] # live decks + deck codes (Firestone)
hs skill install [--agent claude,cursor,codex,copilot,opencode] [--project] [--use-npx] # install the hearthstone-deck skill into agent skills dirs
```

Expand Down Expand Up @@ -65,6 +67,8 @@ Install the bundled `hearthstone-deck` skill into any agent (works across all CL

**Do not duplicate SKILL.md at the repo root.** The single source of truth lives inside the plugin. Root-level docs should link to it, not copy it.

**Keep the skill in sync with the CLI.** When a change adds/removes/renames a command, subcommand, or flag (or changes documented behavior), update the `hearthstone-deck` skill in the SAME change: `plugins/hs-cli/skills/hearthstone-deck/SKILL.md` (command surface + trigger description) and the relevant `recipes/*.md` (deck/card/meta). This is part of the definition-of-done for any CLI-surface change. Internal-only refactors that don't change the documented surface don't require a skill edit.

## Architecture

- `src/index.ts` — citty `runMain`, registers subcommands
Expand All @@ -77,6 +81,7 @@ Install the bundled `hearthstone-deck` skill into any agent (works across all CL
- `src/services/skill-bundle.ts` — `hearthstone-deck` SKILL.md + recipes embedded into the binary via Bun text imports. Single source of truth stays at `plugins/hs-cli/skills/hearthstone-deck/`; a test asserts byte-equality with disk.
- `src/services/skill-installer.ts` — pure FS writer for the embedded skill (`writeBundle`, `skillExists`)
- `src/services/skill-select.ts` — pure agent-selection resolver (`--agent` validation + non-TTY guard); clack multiselect lives in the command, not here
- `src/services/meta-stats.ts` — Firestone constructed win-rate/deck stats (CDN JSON, 1h cache). Helpers: `stats-math.ts` (Wilson lower bound / margin of error / tier band), `archetype-names.ts` (slug→display name, cached). Data: Firestone (firestoneapp.com), used with permission. Ranked by Wilson lower bound, not raw win rate.
- `src/types/index.ts` — `Card`, `Deck`, `DeckCard` types + Korean class name map
- `tests/` — bun:test files, one per service. Imports use `.ts` extension (Bun resolves native TS).
- `tsconfig.json` — typecheck + IDE config. `noEmit: true`, `allowImportingTsExtensions: true`. No separate build config.
Expand Down
13 changes: 13 additions & 0 deletions README.es.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ hs meta rarities # FREE, COMMON, RARE, EPIC, LEGENDARY
hs meta types # MINION, SPELL, WEAPON, HERO, ...
```

### Meta en vivo (tasas de victoria, tiers, códigos de mazo)

`hs meta archetypes` y `hs meta decks` muestran las tasas de victoria actuales del modo construido, tiers y códigos de mazo.

```bash
hs meta archetypes --game-format standard --rank legend --period past-7
hs meta decks --rank top-2000-legend -f json
```

Flags: `--game-format standard|wild|twist`, `--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all`, `--period last-patch|past-3|past-7|past-20|current-season`, `--min-games N`, `--sort wilson|winrate|games`, `--limit N`. Las filas están ordenadas por el límite inferior de Wilson (no por la tasa de victoria bruta) y muestran una columna de ±margen de error.

Datos: **Firestone** (firestoneapp.com), usado con permiso. Los códigos de mazo de `hs meta decks` se pueden pasar mediante pipe a `hs deck <code>`.

### Salida JSON

Agrega `-f json` a cualquier comando:
Expand Down
13 changes: 13 additions & 0 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ hs meta rarities # FREE, COMMON, RARE, EPIC, LEGENDARY
hs meta types # MINION, SPELL, WEAPON, HERO, ...
```

### ライブメタ(勝率・ティア・デッキコード)

`hs meta archetypes` と `hs meta decks` は現在の構築フォーマットの勝率、ティア、デッキコードを表示します。

```bash
hs meta archetypes --game-format standard --rank legend --period past-7
hs meta decks --rank top-2000-legend -f json
```

フラグ: `--game-format standard|wild|twist`、`--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all`、`--period last-patch|past-3|past-7|past-20|current-season`、`--min-games N`、`--sort wilson|winrate|games`、`--limit N`。行は Wilson 下限値(生の勝率ではない)で並び替えられ、±誤差の列が表示されます。

データ: **Firestone** (firestoneapp.com)、使用許可済み。`hs meta decks` のデッキコードは `hs deck <code>` にパイプできます。

### JSON出力

任意のコマンドに `-f json` を追加:
Expand Down
13 changes: 13 additions & 0 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ hs meta rarities # FREE, COMMON, RARE, EPIC, LEGENDARY
hs meta types # MINION, SPELL, WEAPON, HERO, ...
```

### 라이브 메타 (승률, 티어, 덱 코드)

`hs meta archetypes`와 `hs meta decks`는 현재 일반 모드 승률, 티어, 덱 코드를 보여줍니다.

```bash
hs meta archetypes --game-format standard --rank legend --period past-7
hs meta decks --rank top-2000-legend -f json
```

플래그: `--game-format standard|wild|twist`, `--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all`, `--period last-patch|past-3|past-7|past-20|current-season`, `--min-games N`, `--sort wilson|winrate|games`, `--limit N`. 행은 Wilson 하한값(원시 승률 기준 아님)으로 정렬되며 ±오차 범위 열이 포함됩니다.

데이터: **Firestone** (firestoneapp.com), 허가 후 사용. `hs meta decks`의 덱 코드는 `hs deck <code>`에 파이프로 전달할 수 있습니다.

### JSON 출력

모든 명령어에 `-f json` 추가:
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,19 @@ hs meta rarities # FREE, COMMON, RARE, EPIC, LEGENDARY
hs meta types # MINION, SPELL, WEAPON, HERO, ...
```

### Live meta (win rates, tiers, deck codes)

`hs meta archetypes` and `hs meta decks` show current constructed win rates, tiers, and deck codes.

```bash
hs meta archetypes --game-format standard --rank legend --period past-7
hs meta decks --rank top-2000-legend -f json
```

Flags: `--game-format standard|wild|twist`, `--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all`, `--period last-patch|past-3|past-7|past-20|current-season`, `--min-games N`, `--sort wilson|winrate|games`, `--limit N`. Rows are ranked by the Wilson lower bound (not raw win rate) and show a ±margin-of-error column.

Data: **Firestone** (firestoneapp.com), used with permission. Deck codes from `hs meta decks` can be piped into `hs deck <code>`.

### JSON output

Add `-f json` to any command for raw structured data:
Expand Down
13 changes: 13 additions & 0 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ hs meta rarities # FREE, COMMON, RARE, EPIC, LEGENDARY
hs meta types # MINION, SPELL, WEAPON, HERO, ...
```

### 实时环境(胜率、梯队、套牌代码)

`hs meta archetypes` 和 `hs meta decks` 显示当前构筑赛制的胜率、梯队和套牌代码。

```bash
hs meta archetypes --game-format standard --rank legend --period past-7
hs meta decks --rank top-2000-legend -f json
```

标志: `--game-format standard|wild|twist`、`--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all`、`--period last-patch|past-3|past-7|past-20|current-season`、`--min-games N`、`--sort wilson|winrate|games`、`--limit N`。行按 Wilson 下界排序(而非原始胜率),并显示 ±误差列。

数据来源: **Firestone** (firestoneapp.com),已获授权使用。`hs meta decks` 输出的套牌代码可通过管道传入 `hs deck <code>`。

### JSON 输出

任何命令添加 `-f json`:
Expand Down
14 changes: 14 additions & 0 deletions plugins/hs-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,25 @@ Once installed, just talk to Claude:

Or invoke explicitly: `/hs-cli:hearthstone-deck`.

## Live meta (win rates, tiers, deck codes)

`hs meta archetypes` and `hs meta decks` show current constructed win rates, tiers, and deck codes.

```bash
hs meta archetypes --game-format standard --rank legend --period past-7
hs meta decks --rank top-2000-legend -f json
```

Flags: `--game-format standard|wild|twist`, `--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all`, `--period last-patch|past-3|past-7|past-20|current-season`, `--min-games N`, `--sort wilson|winrate|games`, `--limit N`. Rows are ranked by the Wilson lower bound (not raw win rate) and show a ±margin-of-error column.

Data: **Firestone** (firestoneapp.com), used with permission. Deck codes from `hs meta decks` can be piped into `hs deck <code>`.

## Scope (Phase 1)

- ✅ Deck code decoding (offline-capable after first fetch)
- ✅ Card lookup + search with class/cost filters
- ✅ Game metadata (sets, classes, types, rarities)
- ✅ Live meta stats: archetype win rates, tiers, deck codes (Firestone)
- ❌ Match history / win rate (Phase 2 — requires Power.log parsing)
- ❌ "My saved decks" (Blizzard API has no Hearthstone profile endpoint — no workaround exists)

Expand Down
4 changes: 3 additions & 1 deletion plugins/hs-cli/skills/hearthstone-deck/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: hearthstone-deck
description: Use when the user wants anything involving Hearthstone — decode/analyze/compare decks, look up cards by name or id, search cards with filters, or query game metadata (sets, classes, card types, rarities). Triggers on deck-code strings (base64 starting with "AAEC", "AAEB", "AAEA"), Hearthstone in any language or community nickname (HS, Blizzard Hearthstone; 하스스톤, 하스, 돌겜, 하섭; ハースストーン, ハース, ハスス; 炉石传说, 炉石, 炉石酒馆战棋; 爐石戰記, 爐石, 爐戰; Hearth, Pedra do Lar; Хартстоун, Хартса), mode keywords in any language (Standard / Wild / Twist / Arena / Battlegrounds / BG; 정규 / 야생 / 전장 / 투기장 / 선술집난투 / 용병단; 标准 / 狂野 / 酒馆战棋 / 竞技场), mana-curve/dust/win-condition/meta/nerf discussion, single-card lookups, name searches in any language, and class/format/expansion queries.
description: Use when the user wants anything involving Hearthstone — decode/analyze/compare decks, look up cards by name or id, search cards with filters, or query game metadata (sets, classes, card types, rarities). Triggers on deck-code strings (base64 starting with "AAEC", "AAEB", "AAEA"), Hearthstone in any language or community nickname (HS, Blizzard Hearthstone; 하스스톤, 하스, 돌겜, 하섭; ハースストーン, ハース, ハスス; 炉石传说, 炉石, 炉石酒馆战棋; 爐石戰記, 爐石, 爐戰; Hearth, Pedra do Lar; Хартстоун, Хартса), mode keywords in any language (Standard / Wild / Twist / Arena / Battlegrounds / BG; 정규 / 야생 / 전장 / 투기장 / 선술집난투 / 용병단; 标准 / 狂野 / 酒馆战棋 / 竞技场), mana-curve/dust/win-condition/meta/nerf discussion, single-card lookups, name searches in any language, class/format/expansion queries, and current-meta tier-list / win-rate / best-deck questions (tier list, winrate, what's strong/best, 메타/티어/승률/무슨 덱이 좋아, ティア/勝率, 强势/胜率/上分).
---

# Hearthstone CLI (decks, cards, metadata)
Expand All @@ -13,6 +13,8 @@ This skill covers the full surface of the `hs` CLI:
- `hs card <dbfId|cardId|name>` — single-card lookup
- `hs card --search <q> [--class CLASS] [--cost N]` — name + filter search
- `hs meta sets|classes|types|rarities` — game metadata
- `hs meta archetypes` — live archetype win rates + tiers (current meta, Firestone data)
- `hs meta decks` — live top decks with deck codes (current meta, Firestone data)

## Language and naming triggers

Expand Down
56 changes: 55 additions & 1 deletion plugins/hs-cli/skills/hearthstone-deck/recipes/meta.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Metadata recipes

Workflows that use `hs meta sets|classes|types|rarities` to validate filters, normalize user input, or build enum-driven helpers.
Workflows that use `hs meta sets|classes|types|rarities` to validate filters, normalize user input, or build enum-driven helpers — plus the live-meta types `hs meta archetypes|decks` for current win rates, tiers, and deck codes.

## Contents

Expand All @@ -9,6 +9,7 @@ Workflows that use `hs meta sets|classes|types|rarities` to validate filters, no
- [Dust cheat-sheet from rarities](#dust-cheat-sheet-from-rarities)
- [Play-relevant card types only](#play-relevant-card-types-only)
- [Latest expansion / set membership of a card](#latest-expansion--set-membership-of-a-card)
- [Live meta: tiers, win rates, deck codes](#live-meta-tiers-win-rates-deck-codes)

## JSON shape reminder

Expand Down Expand Up @@ -78,3 +79,56 @@ hs card EX1_572 -f json | jq .set # set of a specific card -> "EXPERT1"
```

For "is this set in Standard right now?", point the user to the official Blizzard rotation page — that data is not in the CLI. For per-deck set distribution see `recipes/deck.md` (`Set distribution & rotation risk`).

## Live meta: tiers, win rates, deck codes

User intent: "what's the best deck right now?", "현재 메타 티어", "强势卡组", "is X tier 1?"

`hs meta archetypes` (aggregated win rate per archetype = tier view) and `hs meta decks` (individual decks + deck codes) return live constructed stats from **Firestone (firestoneapp.com), used with permission**. This is the ONLY meta/win-rate source in the CLI — `hs meta sets|classes|types|rarities` are static and have no win rates.

Flags (both): `--game-format standard|wild|twist` (default standard), `--rank legend|top-2000-legend|competitive|legend-diamond|diamond|platinum|bronze-gold|all` (default legend), `--period last-patch|past-3|past-7|past-20|current-season` (default last-patch), `--min-games N` (default 2000 archetypes / 400 decks), `--sort wilson|winrate|games` (default wilson), `--limit N` (table only). Add `-f json` for piping.

### Reading the output honestly

```text
hs meta archetypes -f json
{
"meta": { "source": "Firestone (firestoneapp.com)", "gameFormat", "rank", "period", "lastUpdated", "dataPoints" },
"rows": [ { "displayName", "playerClass", "winrate", "wilsonLower", "moe", "tier", "totalGames", "deckcode"? } ]
}
```

- **Sort is by `wilsonLower` (Wilson score lower bound), not raw `winrate`** — this prevents a tiny-sample 80% deck from topping a proven 55% one. Report the tier/rank from `wilsonLower`, cite `winrate` as the headline number, and mention `±moe` when a deck is close to another.
- **`winrate`/`wilsonLower`/`moe` are 0–1 fractions** (multiply by 100 for %). `moe` is the ±95% margin of error at p=0.5; large `moe` (small `totalGames`) = treat as preliminary.
- **`tier`** is a heuristic band (S ≥57% · A 54–57 · B 52–54 · C 50–52 · D <50) on `wilsonLower`.
- A `[⚠ low sample]` flag (table) / low `dataPoints` (json) means the whole bracket/period is thin — widen `--period` or drop to a broader `--rank`.
- Always attribute Firestone when surfacing these numbers.

### Top tier list for the current meta

```bash
hs meta archetypes --rank legend --period past-7 -f json | jq -r '
.rows[] | "\(.tier) \((.winrate*100)|round/1)% \(.displayName) (n=\(.totalGames))"' | head -15
```

### Best deck of a class, with a ready-to-import code

```bash
hs meta decks --rank top-2000-legend -f json \
| jq -r '[.rows[] | select(.playerClass=="rogue")][0] | .deckcode'
# pipe straight into the decoder for the full card list:
CODE=$(hs meta decks -f json | jq -r '.rows[0].deckcode')
hs deck "$CODE"
```

### "Is X strong right now?"

Match the user's archetype name against `displayName` (case-insensitive substring), then quote `winrate` + `tier` + `totalGames`:

```bash
hs meta archetypes -f json | jq -r --arg q "rogue" '
.rows[] | select(.displayName|ascii_downcase|contains($q))
| "\(.displayName): \((.winrate*100)|round/1)% (tier \(.tier), n=\(.totalGames))"'
```

Cache live-meta output within an agent turn (1h server cadence; CLI already caches to `~/.hs-cli/` for 1h).
Loading