mcpField
L
lgs-search

lgs-search

github.com/dan-blanchard其他22226 次安装2 天前更新
代码仓库

关于 lgs-search

lgs-search 是用于为《万智牌》卡牌清单跨本地游戏店与在线目录配货的命令行技能,面向需要按成本规划采购的玩家。它根据实际搜索和购物车结果分配卡牌,并比较在线购物车的商品与运费总额。

主要功能

  1. 01读取牌组 JSON 或逐行卡表
  2. 02并行搜索两家本地游戏店
  3. 03按价格与购物车规则分配卡牌
  4. 04比较在线平台商品及运费
  5. 05检查未找到卡牌并支持放宽条件
  6. 06生成购物车并打开结账页面

适用场景

  1. 01为牌组清单规划多店采购
  2. 02按条件筛选卡牌版本与品相
  3. 03检查缺货卡牌并重试搜索
  4. 04在结账前查看各店购物车

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dan-blanchard/mtg-skills --skill lgs-search

安装后在 Claude Code 中输入/lgs-search确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

CONTEXT.md
pyproject.toml
uv.lock

详细介绍

LGS 搜索

从两家本地游戏商店(The Gathering Place、Atomic Empire)和两家大型在线目录(TCGPlayer、Mana Pool)为 MTG 卡牌列表采购,并分配卡牌以尽量降低总成本。用户最终最多需要结算三个购物车:TGP、AE,以及(TCGPlayer | Mana Pool)中更便宜的一家,用于采购剩余卡牌。

铁律

绝 NEVER 报告 CLI 未返回的价格。 摘要中的每个价格都必须来自真实的 Playwright 搜索/购物车结果。Scryfall USD 仅在内部用作 LGS 与在线商店的对比检查代理值——它不会出现在报告中。缺货和无法找到的列表必须反映页面上的实际结果,而不是基于训练数据的猜测。

运行编排器

编排器是一个正常的长时间运行 CLI,会在第 5 阶段/第 7 阶段打开有头 Chromium 窗口。它可以安全地从 Bash 子进程启动;用户在操作系统中关闭有头窗口以继续运行,子进程会检测到关闭事件,无需任何终端交互。不要习惯性地要求用户使用 ! 前缀调用——只有在需要从标准输入读取内容时才需要这样做;使用 --yes 跳过初始确认、已保存登录信息且购物车为空时,不会触发任何 input() 提示。

建议 Agent 使用以下调用方式:

uv run --directory <skill-install-dir> lgs-search \
    --input <list> --output-dir <dir> --yes

使用 run_in_background=True,并在需要报告进度时持续读取输出文件。只有在有具体理由预计会出现标准输入提示时(未登录商店触发登录回退,或未使用 --clear-existing-carts 时出现购物车污染提示),才建议使用 ! lgs-search ...。

设置(首次运行)

uv sync --directory <skill-install-dir>
uv run --directory <skill-install-dir> playwright install chromium

# One-time login per store (saves to ~/.cache/mtg-skills/lgs-profiles/<store>/):
lgs-search login --store tgp
lgs-search login --store atomic_empire
lgs-search login --store tcgplayer
lgs-search login --store manapool

已保存的配置文件包含该商店的有效会话 Cookie,在会话过期前可像密码一样使用。配置文件目录仅限所有者访问(0700)。购物后如需忘记会话,请运行 lgs-search logout(所有商店)或 lgs-search logout --store <store>。

如果跳过显式登录,编排器首次检测到“未登录”时会弹出一个有头窗口——操作稍显繁琐,但功能相同。

工作流

第 1 阶段 — 解析输入

接受解析后的牌组 JSON 或纯文本列表(每行一张牌,可选 Nx 前缀)。主牌和备牌数量会相加。默认会过滤掉基本地(Plains、Island、Swamp、Mountain、Forest、Wastes),并在摘要中列出;传入 --include-basics 可覆盖此设置。雪境基本地(Snow-Covered Plains 等)不会被跳过。

第 2 阶段 — LGS 全面搜索

通过线程池并行查询两家 LGS 的每张牌,并设置各商店的并发上限。结果会保留符合用户偏好(品相、闪卡、首选系列)的最低价商品。查询失败时结果会设为 None,该商店会被视为没有这张牌。

阶段 3 — 分配

对于每张牌:

  • 如果两个 LGS 都没有这张牌,或在线价格代理低得多 (默认:低于 20% 以上或 $2 以上),则将这张牌分配到在线购物篮。
  • 否则:由价格最低的 LGS 获胜。如果两个 LGS 的价格相差不超过 $1 或 10%,则将这张牌集中分配给当前购物车总额较高的 LGS,以尽量减少跑腿次数。
  • 数量 > 1:如果没有一家商店能提供全部数量,则在多家商店之间拆分购买。剩余数量转到线上。

在线价格代理是每张牌所有印刷版本中最便宜的非闪、非数字版美元价格 (来自 MTGJSON 卡牌数据,通过共享卡牌池获取,因此以正面名称命名的双面牌——“Brazen Borrower”——也会计算价格),而不是默认印刷版本的 USD。默认印刷版本的价格经常会漏掉便宜的重印版(例如,Beast Within 的默认版本没有 usd,但便宜的重印版只要 $0.50;Kessig Wolf Run 的默认版本约为 $15,最便宜的重印版只要 $0.30)。没有批量数据时,代理价格为 0.0——溢出检查将不再提示,所有有库存的 LGS 商品都会胜出,即使 MP/TCG 的价格便宜 5-30 倍。

编排器会自动检测 download-mtgjson 写入的 MTGJSON 卡牌数据(位于 $MTG_SKILLS_CACHE_DIR 或 ~/.cache/mtg-skills/ 下),与其他工具使用相同的查找方式。找不到数据时,它会打印醒目的警告,说明静默不溢出的故障模式,并指向 download-mtgjson。除非需要指定路径,否则不要传入 --bulk-data。

阶段 4 — 优化线上购买

溢出清单会提交到 TCGPlayer Mass Entry 和 Mana Pool 的 /add-deck。每个站点的优化器都会运行(合并卖家并计算运费)。选择商品 + 运费总额较低的购物车。税费在结账时计算。

两个 Marketplace 的批量提交端点都会将商品追加到现有购物车,而不是替换购物车,因此优化器计算的总额反映的是整个购物车(已有商品 + 新提交内容)。适配器会在 bulk_submit_and_optimize 开始时执行 get_existing_cart 预检;若购物车非空,则抛出 CartNotEmptyError。编排器会在 optimize_marketplace 的逐商店循环中捕获此错误,清楚地打印“[store] cart already has N items”错误,并继续使用仍可正常工作的 Marketplace。

如果看到此错误,用户必须先清空被污染的购物车,然后再重新运行。MP 的界面“Clear cart”按钮在 MP 本身不可用(已验证:点击会触发 Sentry 错误,并发出无操作的 metadata-sync RPC),因此用户需在有头模式的交接窗口中手动清空 MP。TGP 的 clear_cart 可通过程序正常工作,并会在传入 --clear-existing-carts 时调用。

阶段 5 — 确认门槛 + 构建购物车

系统会打印完整的 Markdown 分配结果;默认选项为否的提示会询问是否继续。传入 --yes 可跳过提示;传入 --dry-run 可在生成分配结果后停止,不会触碰任何购物车。

触碰任何购物车前,系统都会检查每家目标商店的购物车。如果任何购物车非空,本次运行都会中止,并清楚指出被污染的商店;传入 --clear-existing-carts 可在添加商品前自动清空购物车。

阶段 6 — 无法找到的牌 + 放宽条件重试

列出阶段 5 后仍无法从任何商店购买到的牌。系统会提示用户是否放宽限制后重试(允许 MP/HP,允许闪卡,取消优先系列偏好)。--retry-relaxed 会自动执行一次此类重试。

阶段 7 — 交接

对于购物车非空的每家商店,系统会使用该商店的持久化配置文件,在购物车 URL 上启动一个有头模式的 Chromium 窗口。用户手动检查并结账。传入 --no-handoff 可跳过。

--collection 会根据纸质收藏规则(ADR-0058)扣除你已有的牌:基本地会视为已拥有,因此会从清单中移除——除非传入 --include-basics,此选项会将基本地保留在清单中,以购买收藏中已有的数量。

标志参考

lgs-search \
  --input <deck.json | cards.txt> \
  [--collection <collection.json>]
  [--bulk-data <default-cards.json>]
  [--condition {nm,lp,mp,hp,any}]   # default: lp (worst condition allowed)
  [--allow-foil]
  [--prefer-set <SET>]
  [--lgs-online-threshold-pct 20]
  [--lgs-online-threshold-usd 2.00]
  [--consolidate-threshold-pct 10]
  [--consolidate-threshold-usd 1.00]
  [--no-handoff]
  [--dry-run]
  [--retry-relaxed]
  [--clear-existing-carts]
  [--include-basics]
  [--yes]
  [--search-timeout-seconds 20]
  [--cart-timeout-seconds 30]
  [--max-retries 3]
  [--output-dir <dir>]

故障模式

  • 网站选择器已更改。 适配器会抛出 StoreSelectorError,并指出失效的选择器以及未找到该选择器的 URL。编排器会显示错误,并中止对该商店的扫描;绝不会悄悄跳过卡牌。
  • 登录已过期。 通过每个商店的 is_logged_in 检测。延迟回退机制会在运行过程中启动一个有头登录窗口;登录后将其关闭,运行便会恢复。
  • Marketplace 购物车污染。 如果 Marketplace 的购物车中已有商品,bulk_submit_and_optimize 会抛出 CartNotEmptyError(第 4 阶段会将用户预先添加的商品混入优化比较)。编排器会跳过该 Marketplace,并继续处理其他商店;用户需手动清空购物车后重新运行。
  • TCGPlayer 验证码。 TCG 的反机器人机制会检测 Playwright 的 persistent_context 并阻止登录(已验证)。支持按商店失败后继续的 optimize_marketplace 会跳过 TCG,并记录消息,默认由 MP 获胜。不要浪费时间尝试以有头模式登录 TCG——验证码无法通过。
  • MP 的“清空购物车”无效。 MP 自身用于“清空购物车”按钮的 SvelteKit 处理程序会抛出错误(Sentry 已报告),购物车不会发生变化。--clear-existing-carts 会针对 MP 回退到手动提示。用户在有头购物车窗口中清空购物车,然后按 Enter。
  • 购物车单项数量上限。 某些商店会限制每个购物车的单项数量。达到上限时,适配器会部分填入并报告剩余项;剩余项会记录在旁路文件中,并显示在摘要里。
  • HTTP 429/速率限制。 按 Retry-After 指示的时间等待;若无该指示,则默认等待 30 秒。同一家商店连续遇到 3 次 429 后,会跳过该商店并发出警告。
  • 第 5 阶段添加购物车失败。 这是致命错误。请修复根本问题后从头重新运行——无法从中断处恢复。<output-dir>/lgs-cart-allocation.json 中的旁路文件只是记录已发生情况的只写审计记录,不是检查点。

交接给 deck-wizard / cube-wizard

此技能绝不会修改套牌。找不到的卡牌会显示在 Markdown 摘要中——由调用此技能的技能或用户决定是否替换。没有自动“换成类似卡牌”的流程。

评论

支持 Markdown