skill
Electronics Industry Sites Skillpack
Public Made by Adomby adom
One skill per popular electronics-industry website (ST, TI, Mouser, DigiKey, SnapEDA, Ultra Librarian, Arrow, Analog, Microchip, Nordic, CSE, Octopart, JLCPCB, datasheets.com): which access lane works (fetch, curl, pup, nb, API), the bot defense each one runs, the exact failure signatures, and the task recipes. Verified live, dated, and built to grow.
← Commit history
v2.0.0: Electronics Industry Sites Skillpack. Root lane ladder + symptom table + 15 per-site skills (ST, Mouser, DigiKey, SnapEDA, TI, Microchip, Analog, Arrow, Nordic, Ultra Librarian, CSE, datasheets.com, Octopart, JLCPCB/LCSC, generic manufacturer), verified 2026-09-12; studio hero
5 files changed
+581
__pycache__/gen.cpython-312.pycadded⋯ 1 unchanged line ⋯
docs/hero.pngadded⋯ 1 unchanged line ⋯
gen.pyadded+581@@ -0,0 +1,581 @@+#!/usr/bin/env python3+"""Generate the electronics-sites-skillpack v2 files from one data table.++Run from the pack root: python3 gen.py+Every site skill has the same sections so an AI can pattern-match across+sites. ASCII punctuation only (wiki rule: no em/en dashes anywhere).+"""+import json, os, re, sys++ROOT = os.path.dirname(os.path.abspath(__file__))+VERIFIED = "2026-09-12"+PACK = "electronics-sites-skillpack"+TITLE = "Electronics Industry Sites Skillpack"+BRIEF = ("One skill per popular electronics-industry website (ST, TI, Mouser, DigiKey, SnapEDA, "+ "Ultra Librarian, Arrow, Analog, Microchip, Nordic, CSE, Octopart, JLCPCB, datasheets.com): "+ "which access lane works (fetch, curl, pup, nb, API), the bot defense each one runs, the "+ "exact failure signatures, and the task recipes. Verified live, dated, and built to grow.")++LANES = ["WebFetch", "curl", "pup", "nb"]+LANE_NOTE = {+ "WebFetch": "the Anthropic fetcher behind WebFetch / WebSearch",+ "curl": "curl or python from the Adom container",+ "pup": "pup, Chrome for Testing 148 in the durable adom-you profile, background window",+ "nb": "nb, the user's real signed-in Chrome 152 via the Adom Native Browser Extension",+}++# ---------------------------------------------------------------------------+# The data table. lane values: OK | BLOCKED | PARTIAL | untested, plus a note.+# ---------------------------------------------------------------------------+SITES = [+ dict(slug="st", name="STMicroelectronics", domains=["www.st.com", "community.st.com", "newsroom.st.com", "www.st.com/resource (CDN)"],+ what="Manufacturer. Product pages, datasheets, app notes, eval boards, myST CAD downloads, STM32Cube software.",+ defense="Akamai Bot Manager on www.st.com (sensor script issues _abck / bm_sz; the edge RSTs the HTTP/2 stream once the sensor verdict is negative). community.st.com is nginx, newsroom.st.com is CloudFront: both open.",+ lanes={+ "WebFetch": ("BLOCKED", "product page, datasheet PDF and eval-tool pages time out at 60 s; newsroom returns HTTP 473; community.st.com works"),+ "curl": ("BLOCKED", "curl: (92) HTTP/2 stream 1 was not closed cleanly: INTERNAL_ERROR in ~60 ms, even for /resource/*.pdf; community + newsroom return 200"),+ "pup": ("PARTIAL", "the FIRST page load renders, then every further www.st.com HTML navigation lands on chrome-error:// with ERR_HTTP2_PROTOCOL_ERROR (site root included). /resource/*.pdf still renders in the PDF viewer. A cold isolated profile and 15 s pacing do not help: it is the client verdict, not rate"),+ "nb": ("OK", "every page loads, hash-tab navigation works, nbrowser_fetch_url returns PDFs (200, base64) in under a second"),+ },+ symptoms=["ERR_HTTP2_PROTOCOL_ERROR on the second www.st.com page in pup", "curl (92) HTTP/2 INTERNAL_ERROR within 100 ms", "HTTP 473 from newsroom.st.com to a fetcher", "60 s WebFetch timeout on any www.st.com URL"],+ recipes=[+ ("Product page tabs (Documentation, Tools & Software, CAD)", "The tabs are already in the DOM. Read them by id instead of clicking: `#documentation-panel`, `#tools-software-panel`, `#cad-resources-panel`. Strip lines matching /Worldwide,Asia/ (a per-row country list that swamps innerText). Do NOT set location.hash: it reloads the SPA and, in pup, that reload is the one that dies."),+ ("Datasheet or data brief PDF", "`nbrowser_fetch_url {sessionId, url:\"https://www.st.com/resource/en/datasheet/<part>.pdf\"}` -> base64 body -> `base64 -d` -> `pdftotext -layout`. Data briefs live at /resource/en/data_brief/<part>.pdf. Document ids look like DS14879 (datasheet), DB5805 (data brief), UM/AN/TN."),+ ("Tools & Software list", "Rows are STSW-* (software), X-CUBE-* (STM32Cube packs), STEVAL-* / X-NUCLEO-* (boards). The list tells you which host the vendor actually supports (for the VL53L9CX it named STM32N6570-DK, Nucleo-H563ZI, Raspberry Pi, Rockchip)."),+ ("CAD (symbols, footprints, STEP)", "myST login gates exports by region/account; use the signed-in nb profile. See chip-fetcher-sites/st for the download choreography."),+ ("Spec tables when st.com is unreachable", "datasheets.com/stmicroelectronics/<part> mirrors the parametric table and works for WebFetch and pup; community.st.com posts often carry the numbers ST employees quote."),+ ],+ api="None public for product data. Stock and price: adom-mouser / adom-digikey backends via adom-parts-search (quota-limited, never loop).",+ gotchas=["A pup window that has been RST'd stays dead for that domain; do not reload it, switch lanes.", "st.com serves the HTML datasheet only from the product page modal; the /resource/*.pdf path is the reliable one.", "Country lists in innerText: filter /Worldwide,Asia/ before you read a tools table."],+ evidence="pup-bridge issue adom/pup-bridge#109 (verbatim sequence); DS14879 Rev 8 pulled via nb 2026-09-12."),++ dict(slug="mouser", name="Mouser Electronics", domains=["www.mouser.com"],+ what="Distributor. Product pages with stock, price breaks, datasheet and CAD links; Adom's preferred vendor.",+ defense="Akamai (AkamaiGHost) in front, PerimeterX / HUMAN bot defense behind it. The deny page is served with HTTP 200 and the title 'Access to this page has been denied.'",+ lanes={+ "WebFetch": ("untested", "assume blocked; use the API lane"),+ "curl": ("BLOCKED", "HTTP 200 with the PerimeterX denial page (server: AkamaiGHost)"),+ "pup": ("BLOCKED", "'Access to this page has been denied.' 899-char body, on the first navigation"),+ "nb": ("OK", "product page renders after ~9 s (the PX interstitial clears in a trusted profile); a 6 s wait reads as empty, wait 9 s"),+ },+ symptoms=["title 'Access to this page has been denied.' with HTTP 200", "'press and hold' human challenge", "x-px-* headers"],+ recipes=[+ ("Stock, price, lead time, datasheet URL", "Do not scrape. `adom-parts-search show \"<MPN>\"` (Mouser + DigiKey + JLCPCB in parallel, Mouser-preferred) or the adom-mouser CLI. Quota is shared: one search per user question."),+ ("Product page in a browser (photos, 3D tab, related parts)", "nb only: `nbrowser_open_window {profile, url:\"https://www.mouser.com/ProductDetail/<Mfr>/<MPN>\"}` then wait 9 s before eval. The URL redirects to /en/ProductDetail/..."),+ ("CAD downloads", "The 3D model sits behind a tab on the product page; see chip-fetcher-sites/mouser. Signed-in nb profile shows account pricing."),+ ],+ api="Mouser Search API via the adom-mouser backend (see the adom-parts-search skill for the current backend URL) and adom-parts-search. Free tier ~1000 calls/day shared by everyone: never poll.",+ gotchas=["The block page is HTTP 200: check the title, not the status code.", "Mouser is Adom's preferred vendor, so the API lane is the default for anything numeric."],+ evidence="curl sweep + pup/nb sweep 2026-09-12; pup denial also seen from a warm adom-you profile."),++ dict(slug="digikey", name="DigiKey", domains=["www.digikey.com"],+ what="Distributor. Product detail pages, parametric category filters, datasheet + ECAD links (SnapEDA / Ultra Librarian embeds).",+ defense="Cloudflare managed challenge ('Just a moment...') on every non-human client; HTTP 403 with a cf-ray header.",+ lanes={+ "WebFetch": ("BLOCKED", "HTTP 403"),+ "curl": ("BLOCKED", "HTTP 403, body 'Just a moment...', server cloudflare, cf-ray present"),+ "pup": ("BLOCKED", "stuck on the 'Just a moment...' challenge (263-char body, never resolves)"),+ "nb": ("OK", "product page title 'VL53L9CXV0VE/1 STMicroelectronics | Camera Modules | DigiKey' after ~9 s; the challenge clears itself in a trusted profile"),+ },+ symptoms=["title 'Just a moment...' and a 263-char body", "HTTP 403 with cf-ray", "endless spinner in pup"],+ recipes=[+ ("Stock, price, datasheet", "API lane: `adom-parts-search show \"<MPN>\"` or the adom-digikey CLI. DigiKey qty-1 pricing is often lower than Mouser on new parts (VL53L9CX: $49.07 vs $63.36); the recommendation banner still follows the Mouser-preferred policy unless you switch it."),+ ("Keyword -> category -> MPN list (parametric families)", "nb: `https://www.digikey.com/en/products/result?keywords=<QUERY>` lands on a category overview; collect the /products/filter/ links, navigate into one, then regex MPNs out of the DOM. Proven on the VL53L family (25 MPNs)."),+ ("Detail page", "`https://www.digikey.com/en/products/detail/<mfr-slug>/<mpn>/<pid>`: datasheet link, stock, price breaks, ECAD links. nb only."),+ ("CAD", "See chip-fetcher-sites/digikey: warm human profile, pace like a human, ask DigiKey's own assistant for the model path, or skip the rung (Arrow, CSE/UL)."),+ ],+ api="DigiKey Product Information API via the adom-digikey backend (URL in the adom-parts-search skill) and adom-parts-search.",+ gotchas=["Never try to solve the challenge programmatically; switch to nb.", "The 'ATTENTION: due to high order volume' banner is harmless noise in innerText."],+ evidence="curl sweep + pup/nb sweep 2026-09-12; chip-sourcing 1.0 notes (2026-06-22)."),++ dict(slug="snapeda", name="SnapEDA (SnapMagic)", domains=["www.snapeda.com"],+ what="CAD library. Symbols, footprints, 3D models per MPN; downloads gated behind a free login.",+ defense="Cloudflare managed challenge for non-human clients (403 + cf-ray); login wall on downloads; some downloads are email-gated.",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("BLOCKED", "HTTP 403 'Just a moment...'"),+ "pup": ("BLOCKED", "stuck on 'Just a moment...' (263-char body)"),+ "nb": ("OK", "part page renders after ~9 s; the signed-in profile skips the email gate on downloads"),+ },+ symptoms=["'Just a moment...'", "Download bounces to a login modal (session lost)", "'Request this design' instead of Download (no model yet)"],+ recipes=[+ ("Part page", "`https://www.snapeda.com/parts/<MPN-urlencoded>/<Manufacturer>/view-part/` in nb; wait 9 s."),+ ("Download flow", "Download (top right) -> pick Symbol and Footprint (KiCad), 3D Model (STEP), Eagle/Fusion, Altium. Zip lands in the desktop Downloads; pull it with `adom-bridge pull_file`. Full choreography in chip-fetcher-sites/snapeda."),+ ],+ api="None public. The Adom wiki hardware pages and adom-lbr are the first stop for parts we already have.",+ gotchas=["Only ever type SnapEDA credentials into SnapEDA's own login form.", "A 6 s wait after navigate reads as null in nb; give the challenge 9 s."],+ evidence="curl + pup + nb sweep 2026-09-12; chip-sourcing 1.0 notes."),++ dict(slug="ti", name="Texas Instruments", domains=["www.ti.com"],+ what="Manufacturer. Product pages, datasheets (PDF and HTML), reference designs, Ultra Librarian CAD embed, native STEP.",+ defense="None observed. Plain Apache, HTTP 200 to curl. The friendliest major manufacturer site.",+ lanes={+ "WebFetch": ("untested", "expected OK"),+ "curl": ("OK", "HTTP 200, server Apache, 0.36 s"),+ "pup": ("OK", "product page renders"),+ "nb": ("OK", ""),+ },+ symptoms=["myTI login wall only on some downloads and reference-design files"],+ recipes=[+ ("Product page", "`https://www.ti.com/product/<PART>`; datasheet at `https://www.ti.com/lit/ds/symlink/<part-lowercase>.pdf` (follows a redirect to the current revision)."),+ ("CAD", "CAD/CAE Symbols section embeds Ultra Librarian; native STEP under the 3D model link. See chip-fetcher-sites/ti."),+ ],+ api="TI Store API for stock and price (rarely needed; use adom-parts-search).",+ gotchas=["Because curl works, prefer the cheapest lane: WebFetch or curl first, browsers only for the UL embed."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="microchip", name="Microchip Technology", domains=["www.microchip.com"],+ what="Manufacturer (incl. Atmel, Microsemi). Product pages, datasheets, MPLAB tooling.",+ defense="Akamai on the edge: refuses curl with HTTP 403, but lets browsers through (pup included).",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("BLOCKED", "HTTP 403, server AkamaiGHost"),+ "pup": ("OK", "product page renders (5607 chars)"),+ "nb": ("OK", ""),+ },+ symptoms=["HTTP 403 to non-browser clients"],+ recipes=[("Product page", "`https://www.microchip.com/en-us/product/<PART>` in pup (background) or nb; datasheets link from the Documents tab.")],+ api="None needed; stock via adom-parts-search.",+ gotchas=["An Akamai site that does NOT RST pup: the fingerprint threshold differs per customer, so test each site rather than assuming 'Akamai = nb only'."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="analog", name="Analog Devices (incl. Maxim, Linear)", domains=["www.analog.com"],+ what="Manufacturer. Product pages, datasheets, LTspice models, eval boards.",+ defense="Akamai Bot Manager, strict: RSTs curl's HTTP/2 stream and serves an 'Access Denied' page to pup.",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("BLOCKED", "curl (92) HTTP/2 INTERNAL_ERROR in ~100 ms"),+ "pup": ("BLOCKED", "'Access Denied' page (217 chars)"),+ "nb": ("OK", "product page renders (AD8232 Datasheet and Product Info)"),+ },+ symptoms=["'Access Denied' + 'Reference #18.xxxxxxxx'", "HTTP/2 stream reset to curl"],+ recipes=[("Anything on analog.com", "nb only. Datasheet PDFs are under /media/en/technical-documentation/data-sheets/<part>.pdf; fetch them with nbrowser_fetch_url once you have the link from the page.")],+ api="None public. Stock via adom-parts-search.",+ gotchas=["Same edge behavior as st.com and arrow.com: do not retry, switch to nb."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="arrow", name="Arrow Electronics", domains=["www.arrow.com"],+ what="Distributor. Product search, stock, price, reference designs; free CAD via its own SnapEDA/UL embeds.",+ defense="Akamai Bot Manager, strict: RSTs curl, 'Access Denied' to pup.",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("BLOCKED", "curl (92) HTTP/2 INTERNAL_ERROR"),+ "pup": ("BLOCKED", "'Access Denied' (195 chars)"),+ "nb": ("OK", "home page renders and shows the user's logged-in account (Logout visible): real logins ride along"),+ },+ symptoms=["'Access Denied' + Akamai reference number"],+ recipes=[("Search and product pages", "nb only: `https://www.arrow.com/en/products/search?q=<MPN>`."), ("CAD", "Arrow is the mid-ladder fallback when DigiKey blocks; see chip-fetcher-sites.")],+ api="Arrow has a partner API (key required); not wired into Adom yet.",+ gotchas=["Because the user is typically logged in, treat everything read here as account data: do not paste it into other sites."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="nordic", name="Nordic Semiconductor", domains=["www.nordicsemi.com", "docs.nordicsemi.com", "devzone.nordicsemi.com"],+ what="Manufacturer. nRF product pages, docs site, DevZone forum.",+ defense="Cloudflare in front of www: curl gets the managed challenge, browsers pass (pup included).",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("BLOCKED", "HTTP 403 'Just a moment...', cf-ray present"),+ "pup": ("OK", "home page renders (15 k chars)"),+ "nb": ("OK", ""),+ },+ symptoms=["'Just a moment...' to non-browser clients"],+ recipes=[("Docs", "docs.nordicsemi.com is a static docs site; try WebFetch first, pup second."), ("DevZone", "Login needed to post; reading is open in pup.")],+ api="None needed.",+ gotchas=["A Cloudflare site that pup passes: Cloudflare's bot score for CfT is not uniformly 'block'; DigiKey and SnapEDA set a stricter rule than Nordic."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="ultralibrarian", name="Ultra Librarian", domains=["www.ultralibrarian.com", "app.ultralibrarian.com"],+ what="CAD library (also the engine behind many manufacturer CAD embeds). Symbols, footprints, 3D; free account needed to download.",+ defense="Open to curl (nginx, 200) but the download flow carries a captcha widget and a login wall.",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("OK", "HTTP 200 (the HTML contains a captcha widget for the download/login flow)"),+ "pup": ("OK", "home page renders"),+ "nb": ("OK", "signed-in profile skips the login; captcha, if shown, needs the human: nbrowser_flash and wait"),+ },+ symptoms=["captcha on download or account creation", "login bounce on the format picker"],+ recipes=[("Download flow", "Search MPN -> part page -> Download -> pick KiCad / STEP (Altium if offered). Choreography and the reskinned-picker recovery in chip-fetcher-sites/ultralibrarian."), ("Manufacturer embeds", "TI, Microchip and others embed UL; the same account works inside the embed.")],+ api="None public.",+ gotchas=["Never solve the captcha programmatically; flash the window and let the user click."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="componentsearchengine", name="Component Search Engine (SamacSys)", domains=["componentsearchengine.com", "www.samacsys.com"],+ what="CAD library (SamacSys / Supplyframe). Free symbols, footprints, 3D; the CSE desktop 'Library Loader' or web downloads.",+ defense="Cloudflare on componentsearchengine.com (curl 403), samacsys.com is Vercel and open. Browsers pass.",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("BLOCKED", "HTTP 403 'Just a moment...' (samacsys.com: 200)"),+ "pup": ("OK", "home page renders (6157 chars)"),+ "nb": ("OK", ""),+ },+ symptoms=["'Just a moment...' to curl"],+ recipes=[("Search + download", "pup works for browsing; downloads need the free login (use nb so the saved login applies). Format picker: KiCad, Altium, Eagle/Fusion, STEP.")],+ api="None public.",+ gotchas=["CSE and Ultra Librarian are the last two rungs of the chip-fetcher ladder; both pass pup, so they are the cheap fallback when DigiKey/SnapEDA block."],+ evidence="curl + pup + nb sweep 2026-09-12."),++ dict(slug="datasheets-com", name="datasheets.com", domains=["www.datasheets.com"],+ what="Aggregator (Supplyframe). Parametric spec tables and datasheet links per MPN; a handy mirror when the manufacturer blocks you.",+ defense="Cloudflare for curl only; the Anthropic fetcher and browsers pass.",+ lanes={+ "WebFetch": ("OK", "returned the VL53L9CX parametric table (interfaces, FoV, temperature, supply)"),+ "curl": ("BLOCKED", "HTTP 403 'Just a moment...'"),+ "pup": ("OK", "'VL53L9CX Datasheet | Stmicroelectronics' renders"),+ "nb": ("OK", ""),+ },+ symptoms=["'Just a moment...' to curl"],+ recipes=[("Quick spec table", "`https://www.datasheets.com/<manufacturer-slug>/<part-lowercase>` via WebFetch. Good for interface / rate / package numbers when the vendor page is unreachable; confirm against the vendor PDF before designing.")],+ api="None.",+ gotchas=["It summarizes the datasheet; it does not replace it (lane counts, timing tables and ambient tables were only in the ST PDF)."],+ evidence="WebFetch + curl + pup + nb 2026-09-12."),++ dict(slug="octopart", name="Octopart (and findchips)", domains=["octopart.com", "www.findchips.com"],+ what="Aggregators (Nexar / Supplyframe). Cross-distributor stock and price, datasheet links, CAD links.",+ defense="Cloudflare in front, but both pass curl with HTTP 200 today.",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("OK", "octopart search 200 (1.0 s); findchips 200"),+ "pup": ("untested", ""),+ "nb": ("untested", ""),+ },+ symptoms=["Octopart search results are JS-rendered; curl gets the shell, use a browser for the table"],+ recipes=[("Cross-distributor snapshot", "`https://octopart.com/search?q=<MPN>` in pup; for numbers you will act on, use adom-parts-search (real vendor APIs).")],+ api="Nexar GraphQL API (token required); not wired into Adom.",+ gotchas=["Prices here lag the distributors; treat as a map, not a quote."],+ evidence="curl sweep 2026-09-12 only; browser lanes not yet verified: contribute."),++ dict(slug="jlcpcb", name="JLCPCB parts and LCSC", domains=["jlcpcb.com", "www.lcsc.com"],+ what="Assembly-house parts library (JLCPCB SMT) and its distributor sibling LCSC. Basic/extended part flags, LCSC part numbers (C-numbers).",+ defense="Akamai on jlcpcb.com, but it passes curl (200); lcsc.com open (200).",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("OK", "jlcpcb.com/parts 200 (1.9 s); lcsc.com 200"),+ "pup": ("untested", ""),+ "nb": ("untested", ""),+ },+ symptoms=["Product URLs need the C-number: /product-detail/<slug>_C<number>.html (a bare C-number path 404s)"],+ recipes=[("Parts library lookup", "API lane first: the adom-jlcpcb backend via adom-parts-search; it returns basic/preferred flags and the LCSC number. Browser only for photos."), ("Assembly quotes", "jlcpcb.com in pup; login needed for a real quote.")],+ api="JLCPCB parts via the adom-jlcpcb backend and adom-parts-search.",+ gotchas=["JLCPCB is never the delivery recommendation in adom-parts-search; it is the assembly library."],+ evidence="curl sweep 2026-09-12; browser lanes not yet verified: contribute."),++ dict(slug="manufacturer", name="Other manufacturers (generic playbook)", domains=["www.nxp.com", "www.infineon.com", "www.renesas.com", "www.espressif.com", "www.newark.com (Farnell / Avnet)"],+ what="The generic approach for a manufacturer or distributor site that does not have its own skill yet, plus lane-0 readings for a few we have only curl-tested.",+ defense="Varies. Lane-0 readings 2026-09-12: infineon.com 200 (open), renesas.com 200 (Cloudflare, passes curl), espressif.com 200 (Apache, open), newark.com 200 (Akamai, passes curl), nxp.com 404 on /products/ (URL shape differs; product pages are /products/<family>/...:<PART>).",+ lanes={+ "WebFetch": ("untested", ""),+ "curl": ("PARTIAL", "see the per-domain readings above"),+ "pup": ("untested", ""),+ "nb": ("untested", ""),+ },+ symptoms=["Unknown site: run the ladder and record what you see"],+ recipes=[+ ("The ladder for a new site", "1) ONE WebFetch or curl. 2) If it fails or returns a wall, pup in the background. 3) If pup shows a denial/challenge, nb with a 9 s settle. 4) Data you will act on: the official API or the Adom vendor backends. Record the result in a new sub-skill (copy skills/_template)."),+ ("Reading a manufacturer product page", "Datasheet link is usually the first PDF on the page; CAD lives under 'Design resources' / 'CAD/CAE' / 'Symbols and footprints'; many embed Ultra Librarian or SnapEDA (see those skills)."),+ ],+ api="Stock and price for any of them: adom-parts-search.",+ gotchas=["The bot-defense vendor alone does not predict the outcome (Akamai: st.com blocks pup, microchip.com does not; Cloudflare: DigiKey blocks pup, Nordic does not). Test, then write it down with the date."],+ evidence="curl sweep 2026-09-12."),+]++SKILL_PREFIX = "electronics-site-"++def lane_table(site):+ rows = ["| Lane | Result | What we saw (" + VERIFIED + ") |", "|---|---|---|"]+ for L in LANES:+ r, note = site["lanes"].get(L, ("untested", ""))+ rows.append(f"| {L} | **{r}** | {note or '-'} |")+ return "\n".join(rows)++def site_skill(site):+ name = SKILL_PREFIX + site["slug"]+ doms = ", ".join(site["domains"])+ best = [L for L in LANES if site["lanes"].get(L, ("",))[0] == "OK"]+ best_lane = best[0] if best else "nb"+ trig = ", ".join(sorted(set([d.replace("www.", "").split(" ")[0] for d in site["domains"]] + [site["name"].split(" (")[0].lower()])))+ desc = (f"{site['name']} ({doms}): how the site treats AI clients on each access lane (WebFetch, curl, pup, nb, API), "+ f"the bot defense it runs, the exact failure signatures, and the task recipes. Verified {VERIFIED}. "+ f"Read BEFORE fetching anything from this domain, or when a fetch to it times out, 403s, or shows a challenge page. "+ f"Trigger words: {trig}, {site['slug']} blocked, {site['slug']} datasheet, {site['slug']} product page, {site['slug']} timeout, {site['slug']} access denied.")+ out = [+ "---", f"name: {name}", "description: >-", " " + desc, "---", "",+ f"Parent skill: **{PACK}** (the `electronics-sites` root skill has the lane ladder and the symptom table).", "",+ f"# {site['name']}", "",+ f"**Domains:** {doms} ", f"**What it is:** {site['what']} ", f"**Bot defense:** {site['defense']}", "",+ "## Lane matrix", "", lane_table(site), "",+ f"**Use first:** `{best_lane}`" + (" (cheapest lane that works)" if best else " (nothing cheaper works)") + ". For numbers you will act on (stock, price, lead time) use the API lane below, never a scrape.", "",+ "## Failure signatures", "",+ ]+ out += [f"- {s}" for s in site["symptoms"]]+ out += ["", "## Recipes", ""]+ for title, body in site["recipes"]:+ out += [f"### {title}", "", body, ""]+ out += ["## API / Adom backend lane", "", site["api"], "", "## Gotchas", ""]+ out += [f"- {g}" for g in site["gotchas"]]+ out += ["", "## Evidence and last verified", "", f"{site['evidence']} Re-verify when a lane changes and bump the date; the freshest reading wins.", ""]+ text = "\n".join(out)+ assert "\u2014" not in text and "\u2013" not in text, name+ return name, text++def matrix_md():+ rows = ["| Site | Bot defense | WebFetch | curl | pup | nb | Use first |", "|---|---|---|---|---|---|---|"]+ for s in SITES:+ vals = [s["lanes"].get(L, ("untested",))[0] for L in LANES]+ best = next((L for L, v in zip(LANES, vals) if v == "OK"), "nb")+ d = s["defense"].split(".")[0].split(",")[0].split(" on ")[0][:38]+ rows.append(f"| [{s['name']}](skills/{s['slug']}/SKILL.md) | {d} | " + " | ".join(vals) + f" | {best} |")+ return "\n".join(rows)++def skill_map_md():+ rows = ["| Skill | Site | One line |", "|---|---|---|"]+ rows.append(f"| **electronics-sites** | (root) | The lane ladder, the symptom table, what pup leaks that a real browser does not, and the matrix below. |")+ for s in SITES:+ rows.append(f"| **{SKILL_PREFIX}{s['slug']}** | {s['domains'][0]} | {s['what'].split('.')[0]}. |")+ rows.append("| **_template** | (copy me) | The fixed section layout for a new site skill. |")+ return "\n".join(rows)++ROOT_SKILL = f"""---+name: electronics-sites+description: >-+ THE map of how electronics-industry websites treat AI clients, one sub-skill per site (ST, TI, Mouser,+ DigiKey, SnapEDA, Ultra Librarian, Arrow, Analog, Microchip, Nordic, Component Search Engine, Octopart,+ JLCPCB/LCSC, datasheets.com, generic manufacturer). Which access lane works (WebFetch, curl, pup, nb,+ official API), which bot defense each runs (Akamai, PerimeterX, Cloudflare), the exact failure+ signatures, and what a Chrome-for-Testing window leaks that a real browser does not. Read BEFORE+ fetching anything from a vendor or manufacturer domain, and the MOMENT a fetch to one times out,+ 403s, 473s, shows 'Just a moment', 'Access Denied', 'Access to this page has been denied', or+ ERR_HTTP2_PROTOCOL_ERROR. Trigger words: st.com, ti.com, mouser, digikey, snapeda, ultralibrarian,+ arrow, analog.com, microchip, nordicsemi, componentsearchengine, octopart, jlcpcb, lcsc, datasheets.com,+ vendor site blocked, manufacturer site timeout, datasheet download blocked, bot wall, cloudflare+ just a moment, akamai access denied, perimeterx, captcha on vendor site, which browser for this site,+ electronics website, electronics industry site skills.+---++# Electronics Industry Site Skills++Nobody built skills for the electronics industry's websites, so an AI meets each one cold: a fetch to+st.com times out, a pup window on DigiKey spins forever, Mouser answers HTTP 200 with a denial page, and+the AI reports "the site is down" when the site is fine and only that CLIENT was refused. These+vendors block anything that does not look like a person because they have not noticed the AI era+yet. This pack records, per site, exactly how it behaves toward each lane we have, dated, with the+evidence, so the next AI routes around the wall in one move instead of rediscovering it.++Every sub-skill has the same sections (domains, bot defense, lane matrix, failure signatures, recipes,+API lane, gotchas, evidence). Verified live on {VERIFIED} from an Adom cloud container against a+Windows desktop running Adom Bridge 2.1.104, pup 2.0.464 (Chrome for Testing 148) and the Native+Browser Extension 0.16.14 (Chrome 152).++## The rule: a fetch failure on a vendor domain is a ROUTING signal++1. **One plain attempt only.** WebFetch or curl once. It is the cheapest lane and it works on TI,+ community.st.com, datasheets.com (WebFetch), Octopart, JLCPCB, Infineon, Espressif.+2. **pup second** (a real rendered Chrome, background, the durable adom-you profile). Passes+ Microchip, Nordic, CSE, Ultra Librarian, datasheets.com; renders vendor CDN PDFs.+3. **nb third and last** (the user's real signed-in Chrome via nbrowser_*). Passes EVERYTHING we have+ tested, including the four that refuse pup (st.com after the first page, Mouser, DigiKey, SnapEDA,+ Analog, Arrow). Give a challenge page **9 seconds** to clear before you read the DOM: a 6 s wait+ reads as empty and looks like a block that is not there.+4. **Numbers you will act on come from an API, never a scrape:** `adom-parts-search show "<MPN>"`+ (Mouser + DigiKey + JLCPCB backends, quota-limited: one search per question, never a loop).++Never retry the failing lane, never report "the site is timing out", never try to solve a captcha or+spoof a fingerprint. Switch lanes, then write down what you saw in that site's skill.++## Symptom -> cause -> lane++| You see | It is | Do |+|---|---|---|+| `ERR_HTTP2_PROTOCOL_ERROR` / `chrome-error://` on the SECOND page of a domain in pup; `curl: (92) HTTP/2 stream ... INTERNAL_ERROR` in ~100 ms | Akamai Bot Manager reset the stream after its sensor verdict (st.com, analog.com, arrow.com) | nb. Do not reload the pup tab; it stays dead for that domain |+| `Access Denied` + `Reference #18.xxxx` | Akamai deny page (analog, arrow to pup; microchip to curl) | nb (pup passes microchip; test, do not assume) |+| `Access to this page has been denied.` with **HTTP 200**, or `press and hold` | PerimeterX / HUMAN (mouser.com) | nb for the page, API for the data |+| title `Just a moment...`, 263-char body, HTTP 403, `cf-ray` header | Cloudflare managed challenge (digikey, snapeda, CSE, nordic, datasheets.com, alldatasheet) | pup passes CSE / nordic / datasheets.com; digikey + snapeda need nb; wait 9 s |+| HTTP 473 | Akamai to a fetcher (newsroom.st.com) | pup or nb |+| WebFetch 60 s timeout on a vendor URL | the fetcher is being tarpitted, not an outage | pup, then nb |+| `captcha` in the HTML but the page renders | login / download gate (ultralibrarian) | nb, `nbrowser_flash`, let the human click |+| `renderCheck.ok:true` but the body says `This site can't be reached` | pup's render check does not flag chrome-error pages (adom/pup-bridge#109) | read the body yourself; switch lanes |++## What pup leaks that a real browser does not (measured on st.com, {VERIFIED})++| Probe | pup (Chrome for Testing 148) | nb (installed Chrome 152) |+|---|---|---|+| `navigator.webdriver` | **true** | false |+| Widevine (`requestMediaKeySystemAccess('com.widevine.alpha')`) | **NotSupportedError** (CfT ships without the CDM) | available |+| `navigator.userAgentData.brands` | Not/A)Brand 99, Chromium 148 (no "Google Chrome") | Chromium 152, Not?A_Brand 24, Google Chrome 152 |+| User agent major | 148 (cached build, four majors behind) | 152 |+| `Notification.permission` on first visit | granted (pup pre-grants 32 permissions) | default |+| Akamai `_abck` on first load | ~-1~ (unvalidated) | ~-1~ (unvalidated) |+| plugins / cores / memory / h2 | 5 / 16 / 32 GB / h2 | identical |++Both clients get the same unvalidated Akamai cookie; the verdict comes from the sensor telemetry, and+webdriver + no Widevine + no Google Chrome brand is enough. A cold isolated pup profile and 15 s+between requests changed nothing; the same navigation in nb returned 200. That is why the ladder ends+at nb and why pup is still worth trying first on the sites that do not look this closely.++## The matrix (lane 0 = curl; verified {VERIFIED})++{matrix_md()}++Lane 0 readings for sites without a skill yet: infineon.com 200, renesas.com 200 (Cloudflare, passes),+espressif.com 200, newark.com 200 (Akamai, passes), alldatasheet.com 403 (Cloudflare), samacsys.com+200 (Vercel). Add a skill when you touch one.++## Skill map++{skill_map_md()}++## Adding a site (this pack is built to grow)++Copy `skills/_template/SKILL.md` to `skills/<site>/SKILL.md`, run the ladder against the site, fill+every section with what you SAW (dated), list the new skill in `install.sh`, `uninstall.sh` and+`package.json` `files[]`, bump the version, publish. Rules: one site per skill, ASCII punctuation only,+no captcha solving, no fingerprint spoofing, credentials only ever typed into the site's own login+form. Related packs: `chip-fetcher-sites` (the CAD download choreography per site, inside+adom/adom-chip-fetcher), `driving-sites` (nb login recipes, inside adom/nb-bridge), `pup` and+`adom-native-browser` (the two browser lanes themselves), `adom-parts-search` (the API lane).+"""++TEMPLATE = f"""---+name: {SKILL_PREFIX}SITE+description: >-+ (Template) <Site name> (<domain>): how the site treats AI clients on each access lane (WebFetch,+ curl, pup, nb, API), the bot defense it runs, the exact failure signatures, and the task recipes.+ Copy this folder to skills/<site>/, fill every section with what you SAW, and date it.+ Trigger words: <domain>, <site> blocked, <site> datasheet, <site> product page, <site> timeout.+---++Parent skill: **{PACK}**++# <Site name>++**Domains:** <www.example.com, cdn.example.com>+**What it is:** <manufacturer / distributor / CAD library / aggregator; what people fetch from it>+**Bot defense:** <Akamai / Cloudflare / PerimeterX / none observed; how it presents>++## Lane matrix++| Lane | Result | What we saw (<date>) |+|---|---|---|+| WebFetch | OK / BLOCKED / PARTIAL / untested | <status code, title, timing> |+| curl | ... | <curl -sS -o /dev/null -w 'http=%{{http_code}} server=%header{{server}} cf=%header{{cf-ray}}'> |+| pup | ... | <title + first 100 chars of body after a 6 s settle> |+| nb | ... | <same, after a 9 s settle> |++**Use first:** `<cheapest lane that works>`.++## Failure signatures++- <exact title / body text / status / header that identifies the wall>++## Recipes++### <Task, e.g. datasheet PDF>++<URL pattern, DOM ids, the verb sequence, the wait you needed>++## API / Adom backend lane++<official API, or the adom-* backend that already wraps it; quota notes>++## Gotchas++- <the thing that cost you an hour>++## Evidence and last verified++<how you verified, date, issue links>+"""++def write(rel, text):+ p = os.path.join(ROOT, rel); os.makedirs(os.path.dirname(p), exist_ok=True)+ assert "\u2014" not in text and "\u2013" not in text, rel+ with open(p, "w") as f: f.write(text)++def main():+ names = []+ for s in SITES:+ name, text = site_skill(s)+ write(f"skills/{s['slug']}/SKILL.md", text); names.append((name, f"skills/{s['slug']}/SKILL.md"))+ write("SKILL.md", ROOT_SKILL)+ write("skills/_template/SKILL.md", TEMPLATE)+ # installer / uninstaller list every skill explicitly (publish linter rule)+ inst = ["#!/usr/bin/env bash", "# electronics-sites-skillpack installer: the root skill plus one skill per site.", "set -euo pipefail",+ 'DEST="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}"',+ 'install_skill(){ mkdir -p "$DEST/$1"; cp "$2" "$DEST/$1/SKILL.md"; echo " installed $1"; }',+ 'echo "Installing electronics-sites-skillpack -> $DEST"',+ 'install_skill electronics-sites SKILL.md']+ inst += [f'install_skill {n} {p}' for n, p in names]+ inst += ['# v1 of this pack was named chip-sourcing-*; retire those copies so the two sets do not drift',+ 'for old in chip-sourcing chip-sourcing-digikey chip-sourcing-mouser chip-sourcing-snapeda chip-sourcing-manufacturer; do rm -rf "$DEST/$old"; done',+ f'echo "OK: installed electronics-sites plus {len(names)} site skills to $DEST/. Hint: read ~/.claude/skills/electronics-sites/SKILL.md before fetching from any vendor domain."']+ write("install.sh", "\n".join(inst) + "\n")+ un = ["#!/usr/bin/env bash", "set -euo pipefail", 'DEST="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}"',+ 'for s in electronics-sites ' + " ".join(n for n, _ in names) + '; do rm -rf "$DEST/$s"; done',+ 'echo "OK: removed electronics-sites-skillpack skills from $DEST/."']+ write("uninstall.sh", "\n".join(un) + "\n")+ files = ["SKILL.md", "README.md", "page.json", "package.json", "install.sh", "uninstall.sh", "skills/_template/SKILL.md"] + [p for _, p in names]+ TAGS = ["electronics", "skillpack", "vendor-sites", "bot-defense", "akamai", "cloudflare", "perimeterx", "pup", "nb", "datasheets", "digikey", "mouser", "st"]+ TRIGGERS = ["st.com", "digikey", "mouser", "snapeda", "ultralibrarian", "arrow.com", "analog.com", "microchip", "nordicsemi", "componentsearchengine", "octopart", "jlcpcb", "lcsc", "datasheets.com", "vendor site blocked", "just a moment", "access denied", "ERR_HTTP2_PROTOCOL_ERROR", "bot wall", "electronics website skills"]+ PITCH = "One skill per electronics-industry website: the access lane that works, the bot wall you hit, the recipe. Dated and verified."+ PROMPTS = [{"label": "st.com timing out", "prompt": "st.com is timing out, get me the VL53L9CX datasheet"},+ {"label": "Which browser for DigiKey", "prompt": "which browser lane do I need to read a DigiKey product page"},+ {"label": "Mouser 200 but denied", "prompt": "why does Mouser return HTTP 200 with access denied and what do I do"},+ {"label": "Add a site", "prompt": "add an electronics-sites skill for nxp.com and verify its lanes"}]+ pkg = {"name": PACK, "slug": PACK, "version": "2.0.0", "type": "skill", "title": TITLE, "description": BRIEF,+ "license": "MIT", "files": files, "scripts": {"install": "./install.sh", "uninstall": "./uninstall.sh"},+ "dependencies": {}, "tags": TAGS, "keywords": TAGS, "discovery_triggers": TRIGGERS, "discovery_pitch": PITCH,+ "sample_prompts": PROMPTS, "hero": {"path": "docs/hero.png"}}+ write("package.json", json.dumps(pkg, indent=2) + "\n")+ readme = f"""# {TITLE}++{BRIEF}++Every vendor site is different and most of them refuse anything that does not look like a person. This+pack turns that into a table an AI can act on: per site, which lane works (WebFetch, curl, pup, nb, API),+which wall you hit when it does not, and the recipe for the common tasks (datasheet, product page,+CAD, stock/price). Dated, evidence-linked, and shaped so a new site is one copied template away.++## The matrix (verified {VERIFIED})++{matrix_md()}++## Skills++{skill_map_md()}++## Install++```bash+adom-wiki pkg install john/{PACK}+```++The root skill `electronics-sites` carries the lane ladder and the symptom table; each site skill+auto-surfaces on its domain name. Old `chip-sourcing-*` copies from v1 are retired by the installer.++## Why this exists++An AI that fetches st.com gets a 60 s timeout; the same URL opens instantly in the user's own Chrome.+The failure was the client, not the site, but without a record the AI reports an outage and stops.+Recording each site's behavior once, with the date, is cheaper than every AI rediscovering it.+The two browser lanes are Adom's: `pup` (a real Chrome for Testing window, background, durable profile)+and `nb` (the user's real signed-in browser via the Native Browser Extension). The API lane is+`adom-parts-search` (Mouser, DigiKey, JLCPCB backends).++## Contributing++Copy `skills/_template/SKILL.md`, run the ladder, write down what you saw, list the skill in+`install.sh`, `uninstall.sh` and `package.json`, bump the version, publish. ASCII punctuation only.+No captcha solving, no fingerprint spoofing: this pack routes around walls, it does not break them.+"""+ write("README.md", readme)+ page = json.load(open(os.path.join(ROOT, "page.json")))+ page.update({"slug": PACK, "version": "2.0.0", "title": TITLE, "brief": BRIEF, "readme": readme, "license": "MIT",+ "tags": TAGS,+ "hero": {"type": "image", "path": "docs/hero.png"},+ "sample_prompts": PROMPTS, "discovery_triggers": TRIGGERS, "discovery_pitch": PITCH,+ "source_path": "SKILL.md"})+ write("page.json", json.dumps(page, indent=2) + "\n")+ print(f"OK: wrote root + {len(names)} site skills + template + installer + manifest + README + page.json")+ print("Hint: run `adom-wiki pkg lint` next, then rename the page, publish, push, verify in pup.")++if __name__ == "__main__":+ main()
install.shuninstall.sh