l-pull-mercari-shops
Pull/fetch/download the latest product CSV from Mercari Shops and sync newly-published items into the website repo: fill mercariProductId in product-master-data.mjs, promote 'incoming' items to on-sal...
Pull from Mercari Shops
Pull the latest product CSV from Mercari Shops, propagate it into the website repo, and flip newly-listed items from “incoming” to “on sale”. This is the post-publication step that lives downstream of /l-add-product-page (creates the entry in master data) and /l-add-mercari-item (creates the local draft JSON), and downstream of the operator manually publishing the draft on Mercari Shops.
When to Use
Run this right after one or more draft listings have been published on Mercari Shops by the operator. The newly-listed items must already exist in src/data/product-master-data.mjs with mercariProductId: '' and mercariStatus: 'incoming'.
Do NOT run this if no new items have been published — the skill will simply do nothing useful.
What This Skill Does
┌───────────────────────────────────────────────────────────────┐
│ Mercari Shops admin (mercari-shops.com) │
│ ┌────────────────────────────────────────────────────────┐ │
operator publishes ──►│ │ /seller/shops/{SHOP_ID}/products/download │ │
draft on Mercari │ │ click 作成 → 閉じる → wait 完了 → click ダウンロード │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────┬─────────────────────────────────────────────────────┘
│
▼ (CSV download)
┌───────────────────────────────────────────────────────────────────────────┐
│ fetch-csv.mjs → mercari-data/product_data_YYYY-MM-DD.csv │
│ sync.mjs --apply → fill mercariProductId in master data │
│ promote-to-sale.mjs --apply → drop `mercariStatus: 'incoming'` + showNotifyMe │
│ csv-to-md → regenerate sub-packages/zmdpreview/.../*.md │
│ validate + (optional) mdx grep │
└───────────────────────────────────────────────────────────────────────────┘
Workflow
Step 1 — Fetch the latest CSV from Mercari Shops
node .claude/skills/l-pull-mercari-shops/fetch-csv.mjs
- Launches a headed Chromium with a persistent user-data dir at
$HOME/.config/zmod-mercari-pw/. - First run (or after session expiry): lands on the signin page. Operator does the passkey + phone login interactively. The script waits up to 3 minutes for the URL to match the seller dashboard.
- Subsequent runs: session restored from disk, lands directly on the dashboard.
- Navigates to the download page, clicks 作成, closes the confirmation dialog, polls until the new top row reads 完了, clicks ダウンロード.
- Captures the download via Playwright’s download event and saves to
mercari-data/{originalServerFilename}— overwriting any same-named file (Mercari labels by last-data-update date, which can repeat). - Last line of stdout is the absolute saved path; the orchestrator (Claude) should grep for it.
Session lifetime. Mercari sessions are typically valid for around a month. When the script reports “Not logged in” unexpectedly, the previous session has expired — just complete the passkey login again and the new session is cached. If something more pathological happens (e.g., Playwright user-data dir corrupts), reset with:
rm -rf "$HOME/.config/zmod-mercari-pw"
…then re-run.
Step 2 — Sync Mercari Product IDs into master data
# Dry run first
node .claude/skills/l-sync-mercari-ids/sync.mjs
# Apply once the report looks right
node .claude/skills/l-sync-mercari-ids/sync.mjs --apply
Refer to .claude/skills/l-sync-mercari-ids/SKILL.md for details. This is an existing, separately-maintained script — reuse, don’t duplicate.
Step 3 — Promote newly-listed items to on-sale state
# Dry run
node .claude/skills/l-pull-mercari-shops/promote-to-sale.mjs
# Apply
node .claude/skills/l-pull-mercari-shops/promote-to-sale.mjs --apply
For every product where mercariProductId is now set AND mercariStatus === 'incoming', this strips:
mercariStatus: 'incoming',lineshowNotifyMe: true,line (if present)
Convention: a product with no mercariStatus field is “available / on sale” (see lib/utils/types.ts, components/mdx/purchase-nav/purchase-item.tsx). The purchase-nav UI flips automatically; no MDX changes are required for the badge / buy button.
Other mercariStatus values ('sold', 'discontinued', 'askToBuy') are deliberately untouched.
Step 4 — Regenerate markdown files for zmdpreview
pnpm mdsync:csv-to-md -- mercari-data/product_data_YYYY-MM-DD.csv sub-packages/zmdpreview/src/content/docs/products
Use the saved CSV path from Step 1. This generates one {slug}__{mercariId}.md per product into the zmdpreview content dir; running this after Step 2 is what guarantees newly-listed items get a proper slug instead of unknown__*.
Step 5 — Validate
node --input-type=module -e "import('./src/data/product-master-data.mjs').then(() => console.log('OK'))"
If this fails, something in Step 2 or 3’s regex apply went wrong — diff the file and inspect.
Step 6 — MDX manual-cleanup check
After Step 3, the JS-side state transition is complete. But the source MDX (src/mdx/products/{slug}-intro.mdx and its .en.mdx counterpart) may still contain hard-coded “incoming”-style language that the purchase nav can’t see. Grep each promoted slug:
for slug in <slug1> <slug2> ...; do
echo "=== $slug ==="
grep -in "近日発売\|近日入荷\|入荷予定\|準備中\|coming soon\|incoming\|発売予定" \
src/mdx/products/${slug}-intro.mdx \
src/mdx/products/${slug}-intro.en.mdx 2>/dev/null
done
- If any matches show up, report them to the operator with file and snippet. Some matches are genuinely unrelated (e.g., the Takazudo Panels service blurb in
iromihon-*-intro.mdx); the operator decides whether to edit. Do NOT auto-edit MDX prose. - If no matches, say so explicitly and move on.
Step 7 — Diff review and commit
git diff src/data/product-master-data.mjs
git diff sub-packages/zmdpreview/src/content/docs/products/
git status mercari-data/
Suggested commit shape (split or combined per Claude’s judgment):
[data] Sync Mercari IDs and promote {slug...} to on-sale from {YYYY-MM-DD} CSV[mercari-viewer]if there’s anything insub-packages/mercari-viewer/draft.jsonto update (not produced by this skill — usually edited earlier by/l-add-mercari-item)[misc]for the CSV refresh
Do NOT auto-commit. Let the operator (or Claude after explicit approval) review the diff and decide grouping.
Edge Cases
| Case | Behavior |
|---|---|
| Session expired (forced relogin) | fetch-csv.mjs logs the situation, waits up to 3 min for operator to complete passkey, then continues. |
| 作成 → 完了 takes >90 s | Script aborts with timeout. Re-run later. |
| Filename collides with an already-tracked CSV | Overwrite — intentional. Old content is recoverable via git history if needed. |
| 0 newly-listed products | Sync reports 0 matches; promote reports 0 candidates; csv-to-md regenerates anyway (cheap). Skill exits cleanly. |
| Multiple products published in one batch | All scripts iterate; nothing special needed. |
mercariProductId filled but status is 'sold' / 'discontinued' | promote-to-sale leaves it alone — those are explicit terminal states. |
| Mercari Shops UI changes break selectors | fetch-csv.mjs errors out; operator falls back to manual download + Steps 2–7. |
Hardcoded Constants
SHOP_ID = 'bsFA3qAzCUgRjNuU7k6EoM'(Takazudo Modular’s Mercari Shops shop ID, infetch-csv.mjs)userDataDir = "$HOME/.config/zmod-mercari-pw"(persistent Playwright profile)
If the shop ever changes, update the SHOP_ID constant in fetch-csv.mjs.
Related Skills / Scripts
/l-add-product-page— upstream: creates the master data entry and MDX skeleton./l-add-mercari-item— upstream: creates thedraft.jsonentry that the operator publishes manually on Mercari Shops./l-sync-mercari-ids— reused as Step 2 here.pnpm mdsync:csv-to-md— used as Step 4 here.
Files in This Skill
.claude/skills/l-pull-mercari-shops/
├── SKILL.md # this file
├── fetch-csv.mjs # Playwright persistent-context CSV downloader
└── promote-to-sale.mjs # strip 'incoming' state for newly-listed products