← Commit history
BUILD-SKILL.md+12−10
@@ -5,12 +5,12 @@ description: Build and release a new version of adom-parts-search. Use when the  # Release adom-parts-search -1. Bump `VERSION` + `Cargo.toml` + `wiki/page.json` version.-2. `./build.sh` β€” cargo build, install local binary.-3. Verify β€” `adom-parts-search search "STM32F103RBT6"` returns all three vendors.-4. Ralph-loop the webview (`adom-parts-search app --no-tab` + pup).+1. Bump `VERSION` + `Cargo.toml` + `wiki/page.json` + `package.json` + `page.json` versions, and add a `CHANGELOG.md` entry (publish.sh refuses a placeholder).+2. `./build.sh`: cargo build, install local binary.+3. Verify: `adom-parts-search search "STM32F103RBT6"` returns all three vendors.+4. Ralph-loop the page in pup (`adom-parts-search serve` then open the proxy URL in pup): fonts loaded, tooltips inside the viewport at the corners, the four settings dismissals with trusted input, settings read back from `~/.adom/parts-search-settings.json`, phone width with no horizontal scroll, `adom-ui-linter lint .` to zero FAILs. 5. Show user a screenshot of the 3-column grid + recommendation banner; wait for explicit approval.-6. `./publish.sh` β€” git tag, wiki asset upload, wiki page update, verify.+6. `./publish.sh`: git tag, registry tarball (bin + skills + dockbar.json + docs/icon.svg + screenshots), page-repo push of dockbar.json / docs/icon.svg / docs/hero.png, verify with a clean `adom-wiki pkg install`.  ## Pre-release checklist @@ -19,7 +19,7 @@ description: Build and release a new version of adom-parts-search. Use when the - [ ] Recommendation banner renders Mouser-preferred when Mouser is in stock - [ ] Product images render (web-view fetches mouser.com + digikey.com + LCSC images) - [ ] No console errors via `GET /console`-- [ ] πŸ›‘ Icon audit β€” EVERY icon monochrome white, no favicon carve-out.+- [ ] Icon audit: EVERY icon monochrome white, no favicon carve-out.       Run all three greps; each must return zero:       ```       # (a) Teal fills/strokes in any SVG, including docs/icon.svg itself@@ -36,12 +36,14 @@ description: Build and release a new version of adom-parts-search. Use when the         src/app/*.html 2>/dev/null       ```       The favicon/tab-icon is NOT exempt. See `brand/SKILL.md` Β§Icons +-      `app-creator/SKILL.md` Β§1b β€” the rule was tightened after this+      `app-creator/SKILL.md` Β§1b: the rule was tightened after this       app shipped v0.1.0 with a teal tab icon that slipped past three       audits.  ## Version bumping triggers -- Backend URL changes (slug rotation on service-mouser / service-digikey / service-jlcpcb) β†’ patch bump + republish to propagate.-- UI changes visible to the user β†’ minor bump.-- Policy changes (e.g. new vendor, different preference rules) β†’ minor bump + update the `adom-parts-search` skill to match.+- Backend URL changes (slug rotation on service-mouser / service-digikey / service-jlcpcb): patch bump + republish to propagate.+- The dock reads `dockbar.json` from the PAGE REPO, not the registry tarball; publish.sh pushes it, but a manual edit needs `adom-wiki repo push adom/adom-parts-search --files dockbar.json -m "..."`.+- The hero is human-gated: `hero-studio pose adom/adom-parts-search --surface pup --headline "Parts Search"`, then `adom-wiki repo push ... --files docs/hero.png` and `adom-wiki page hero adom/adom-parts-search --image docs/hero.png`.+- UI changes visible to the user: minor bump.+- Policy changes (e.g. new vendor, different preference rules): minor bump + update the `adom-parts-search` skill to match.
CHANGELOG.mdadded+23
@@ -0,0 +1,23 @@+# Changelog++## 1.1.0 (2026-08-23)++Dock Bar ready page with a settings modal, Say it strip, bundled brand fonts, taskbar progress, and AI drive verbs++- New 44px three-zone header (brand, subject, actions) with the settings cog and a live vendor health LED.+- Say it strip at the top of the page: copy a phrase, or Try it to stage it into the app's own AI thread.+- Settings modal per the settings-layout skill: results per vendor, vendor toggles, recommendation policy (Mouser preferred or cheapest in stock), product photos, taskbar progress, two-click Restore defaults. Stored in ~/.adom/parts-search-settings.json; `settings get|set|restore` on the CLI.+- `serve --print-url`: self-backgrounding, idempotent, version-aware; takes over the dock webview (ADOM_DOCK_WEBVIEW).+- `/api/status` (cached, per-facet LEDs, owned rollup) with CORS and OPTIONS on every /api/* route; `health` and `status` verbs.+- Taskbar progress on the Hydrogen button while a search runs (determinate from measured durations; indeterminate for AI-driven `show`).+- `ui toast`, `ui click`, `ui search` drive verbs; toasts bottom center; body-appended tooltips clamped to the viewport.+- Brand fonts bundled and served same-origin (adom.inc serves no CORS header, so the remote @font-face never loaded).+- dockbar.json 1.2.0 at the page root; favicon docs/icon.svg.+- Requests are handled on threads, so a long vendor search never blocks the health probe or the state poll.+- Say it strip can be closed for good (X, `showSayStrip` setting, Undo on the toast) and restored from Settings.+- New companion skill `adom-parts-search-dock`; `install` now fetches skills from the live wiki raw-file API instead of the dead slug host.+- Fixed: `show` printed "-" for every unit price.++## 1.0.13 (2026-08-18)++publish.sh portability and owner fixes
README.md+112−60
@@ -1,90 +1,142 @@-# adom-parts-search+# Adom Parts Search -Unified parts search across **Mouser + DigiKey + JLCPCB**. One Rust binary, CLI + Hydrogen webview.-Fires three parallel queries, normalizes the responses, and picks a single winner using the Adom-Mouser-preferred policy (40-min drone delivery from Mansfield, TX β†’ our Fort Worth facility;-near-zero shipping).+**One search box. Mouser, DigiKey and JLCPCB at once, with the fastest, cheapest pick chosen for you.** -![3-column grid with per-vendor product cards + Mouser-preferred recommendation banner](docs/screenshots/grid-lm555.png)+Sourcing a part used to mean three browser tabs, three logins, three different ways of saying "in+stock," and a mental spreadsheet to figure out who actually gets it to your bench fastest. Parts+Search collapses that into one query: type a part, or just ask your AI, and it fires three parallel+searches, normalizes the answers, and names the single best source.  ## Install -Every gallia container picks this up as a Tier A install. Manual install:- ```bash-curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-parts-search/adom-parts-search \-  -o /tmp/adom-parts-search && chmod +x /tmp/adom-parts-search && \-  sudo install -m 0755 /tmp/adom-parts-search /usr/local/bin/adom-parts-search && \-  adom-parts-search install+adom-wiki pkg install adom/adom-parts-search ``` -## Usage+Or click the **Parts Search** card in the Hydrogen Dock Bar: it installs, starts the page, and+opens it for you.++## Say it to your AI++You do not have to drive the page. Ask your AI, using the words **parts search**:++- "search for a 10k 0402 resistor with parts search"+- "find the cheapest LM358 with parts search"+- "price an STM32F103RBT6 across vendors with parts search"+- "check stock on an ESP32-S3-WROOM-1 with parts search"+- "source the parts in my BOM with parts search"++The same phrases sit at the top of the page: click one to copy it, or **Try it** to stage it into+your Parts Search AI thread.++## Quick start  ```bash-# User-facing β€” drives the webview tab + prints full per-vendor results to stdout-adom-parts-search show "LM555"-adom-parts-search show "ESP32-S3-WROOM-1U-N4R2" --limit 8 --in-stock-only+# Browse: opens or refreshes the Parts Search tab and prints the results+adom-parts-search show "STM32F103RBT6"++# Script: JSON only, no page+adom-parts-search search "LM555" | jq '.recommendation' -# Scripting / pipe β€” JSON only, no webview-adom-parts-search search "STM32F103RBT6" | jq '.recommendation'+# Dock contract: start the page server (idempotent) and print its direct URL+adom-parts-search serve --print-url -# Keep the app tab running without a query-adom-parts-search app+# Health of the three vendor backends, one line+adom-parts-search health ``` -The `show` subcommand auto-starts the app server on first call and opens a **Parts Search**-Hydrogen tab; subsequent calls reuse the same server + tab and re-render the 3-column grid in-place.+## Screenshots -## Architecture+### Three distributors, one comparable view -This app is **client-only** β€” no service container. It coordinates the three existing vendor-backends:+One keyword goes to Mouser, DigiKey and JLCPCB simultaneously; results land in three aligned+columns with product photos, and a recommendation banner names the winner and the policy that+chose it. -```-       any container-           β”‚-           β–Ό-      adom-parts-search show "…"-           β”‚   (3 parallel HTTP POSTs)-           β”œβ”€β”€β–Ά mouser-xr8t4f5d01bt.adom.cloud    (adom-mouser)-           β”œβ”€β”€β–Ά digikey-gjuu8l5t69uh.adom.cloud   (adom-digikey)-           └──▢ jlcpcb-wela51osctvp.adom.cloud    (adom-jlcpcb)-```+![Parts Search page: Say it strip, search bar, recommendation banner naming Mouser for an STM32F103RBT6, and three vendor columns with product photos](screenshots/results-grid.png) -Each vendor backend handles its own auth, caching, quota tracking, and watchdog restart. This-app only aggregates, applies the Mouser-preferred recommendation, and renders.+### Settings that explain themselves -### Recommendation policy+The cog in the header opens a dismissible settings modal: results per vendor, which vendors to+query, the recommendation policy (Mouser preferred or cheapest in stock), product photos, and the+taskbar progress bar. Every card says what it does and how, every row shows its default, and+Restore defaults takes two clicks. -1. **Mouser wins** if it has an in-stock hit without a 280+-day lead time β€” drone delivery +-   $0 shipping beats everything else within a 15-mile radius.-2. **DigiKey wins** if Mouser is out-of-stock or long-lead, and DigiKey has immediate stock.-3. **JLCPCB** is shown as a library column but does not participate in the recommendation-   (it's assembly-first; different workflow).+![Parts Search settings modal with the Search defaults, Vendors, Recommendation and Product photos cards](screenshots/settings.png) -When all three return zero hits or errors, the recommendation card flips into an-**empty-state** explainer with a suggested next step (try a canonical MPN from the skill's-family table, or retry once erroring backends recover).+![Parts Search settings modal scrolled to the Taskbar progress card and the Restore defaults footer](screenshots/settings-taskbar.png) -## Skill + build skill+### Every control explains itself -- [SKILL.md](SKILL.md) β€” how Claude drives this app (when to use `show` vs `search`, MPN-  extraction rules, common part-family corrections).-- [BUILD-SKILL.md](BUILD-SKILL.md) β€” release workflow (`./publish.sh`).+Hover anything and a tooltip says what it does and what will change, written for a newcomer. -Per [adom-cli-design], the skills are hosted on the wiki and fetched at install time; the-bundled copies in the binary are fallbacks for offline installs only.+![Tooltip on the Search all 3 button explaining the parallel search and the Mouser-preferred policy](screenshots/tooltip.png) -[adom-cli-design]: https://github.com/adom-inc/gallia/blob/main/skills/adom-cli-design/SKILL.md+## Dependencies -## Build+| Dependency | Required? | Why |+|---|---|---|+| `adom-mouser` (service-mouser) | Recommended | Mouser column and the Mouser-preferred recommendation |+| `adom-digikey` (service-digikey) | Recommended | DigiKey column and the fallback when Mouser cannot ship |+| `adom-jlcpcb` (service-jlcpcb) | Optional | JLCPCB assembly-library column | -```bash-./build.sh       # cargo build --release + install to /usr/local/bin + adom-parts-search install-./publish.sh     # git tag + gh release + wiki asset upload + wiki page update-```+Client-only: it owns no API keys and runs no service of its own; it federates the three vendor+backends and renders. At least one backend must be reachable; a missing one shows a friendly+error and the recommendation reasons around it.++## Features++- **One interface, three distributors**: parallel queries, side-by-side product photos.+- **Mouser-preferred routing**: 40-minute drone delivery from Mansfield, TX to the Fort Worth+  facility plus near-zero shipping is why Mouser wins when it is in stock.+- **A recommendation that flips**: DigiKey wins when Mouser is out of stock or long-lead, and a+  second policy, cheapest in stock, compares unit prices across every vendor that answered.+- **Two faces**: a page for browsing, a JSON CLI for scripting and BOMs.+- **Dock Bar ready**: a version-aware idempotent `serve`, a fast `/api/status` with per-vendor+  LEDs, webview ownership, and a Say it strip.+- **Taskbar progress**: while a search runs, a progress bar sized from measured durations is+  painted on the Hydrogen taskbar button (indeterminate for AI-driven searches).+- **AI-drivable**: `GET /state`, `GET /console`, `POST /api/toast`, `POST /api/click`, and the+  matching `ui` verbs, so an AI can drive and observe the page exactly as a person would.+- **Graceful degradation**: a rate-limited or down backend never fails the whole search.++## Skills++| Skill | Purpose |+|---|---|+| `adom-parts-search` | When and how the AI drives the app: `show` vs `search`, MPN extraction, part-family corrections |+| `adom-parts-search-dock` | How the app lives in the Hydrogen Dock Bar: the card, the launch steps, the health LED, diagnosis |+| `adom-parts-search-build` | Release workflow (build, publish to the wiki) |++## CLI reference++| Command | What it does |+|---|---|+| `adom-parts-search show "<q>"` | Open or refresh the Parts Search tab and print full per-vendor results |+| `adom-parts-search search "<q>"` | JSON only (no page); pipe to `jq` |+| `adom-parts-search serve [--print-url]` | Start the page server in the background, idempotent and version-aware; print its direct URL |+| `adom-parts-search app` | Run the page server in the foreground |+| `adom-parts-search health [--json]` | One-line health of the three vendor backends (or the full status JSON) |+| `adom-parts-search status` | The `/api/status` payload |+| `adom-parts-search ui toast "<msg>"` | Raise a toast on the page |+| `adom-parts-search ui click <id>` | Click a control on the page (search, instock, settings, restore, policy ...) |+| `adom-parts-search ui search "<q>"` | Run a search through the page |+| `adom-parts-search settings get\|set\|restore` | Read or change `~/.adom/parts-search-settings.json` |+| `--limit N` / `--in-stock-only` | Cap hits per vendor / hide zero-stock (defaults come from Settings) |++## Open source: make it yours, then give it back++This app is **open source under the MIT license**. Fork it, rewrite it, bend it to your workflow,+and when you have made it better, send your changes back to the Adom Wiki so the whole community+benefits. Every wiki page is a git repo with a package registry on top, so `adom-wiki pkg publish`+your own fork, or open a pull request against this page.++> **One caveat: the search backend is an Adom service.** The actual lookups run against Adom's+> hosted Mouser, DigiKey and JLCPCB backends, which use Adom's vendor API credentials and count+> against Adom's quota. That hosted backend is an Adom service and is **subject to change**: rate+> limits, endpoints, and availability can move at any time. Everything client-side is yours to fork+> and republish; the cloud API quota is not.  ## License -MIT.+MIT. See the license text at the bottom of the wiki page.
SKILL.md+64−31
@@ -1,6 +1,6 @@ --- name: adom-parts-search-description: Unified parts search across Mouser + DigiKey + JLCPCB with Mouser-preferred routing (40-min drone delivery from Mansfield, TX to our Fort Worth facility; near-zero shipping). CLI and Hydrogen webview app. Use when the user asks to source a part, price a component, compare vendors, check stock across distributors, or assemble a BOM. Trigger words β€” find part, search parts, source component, parts search, component search, where can I get, compare distributors, Mouser or DigiKey, compare prices, BOM sourcing, stock check, parts availability, open parts search, parts search app, parts search UI.+description: Unified parts search across Mouser + DigiKey + JLCPCB with Mouser-preferred routing (40-min drone delivery from Mansfield, TX to our Fort Worth facility; near-zero shipping). CLI and Hydrogen webview app. Use when the user asks to source a part, price a component, compare vendors, check stock across distributors, or assemble a BOM. Trigger words: find part, search parts, source component, parts search, component search, where can I get, compare distributors, Mouser or DigiKey, compare prices, BOM sourcing, stock check, parts availability, open parts search, parts search app, parts search UI, parts search settings, parts search health, parts search dock. ---  # adom-parts-search@@ -12,7 +12,7 @@ Searches Mouser + DigiKey + JLCPCB in parallel. Rust CLI + Hydrogen webview. Rec **For user-facing searches, always use `show`.** It drives the webview tab AND prints the full vendor-by-vendor result to stdout, so the user sees product photos + 3-column comparison and the AI sees the same data textually. Auto-starts the app server + opens the tab on first run.  ```bash-# βœ… DEFAULT β€” every search a human asks for+# DEFAULT: every search a human asks for adom-parts-search show  "ESP32-S3-WROOM-1U-N4R2" adom-parts-search show  "iCE40HX4K-TQ144" --limit 8 --in-stock-only @@ -27,11 +27,11 @@ adom-parts-search app  - User asked a conversational question about a part β†’ **`show`**. Always. - You're piping into `jq`, `awk`, or a batch script β†’ `search`.-- Silence: never just dump JSON to chat. If you would have run `search`, run `show` instead β€” the user wants photos and side-by-side comparison, not a wall of JSON.+- Silence: never just dump JSON to chat. If you would have run `search`, run `show` instead: the user wants photos and side-by-side comparison, not a wall of JSON.  ### Extract a clean MPN / part-family BEFORE calling `show` -Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, NOT full-text intent search. If the user says "find me a 3.3V LDO with 500 mA", do NOT pipe `"find me a 3.3V LDO with 500 mA"` into `show` β€” that's natural language, and every vendor will return zero hits. Extract the likely part family or MPN first, then call `show`.+Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, NOT full-text intent search. If the user says "find me a 3.3V LDO with 500 mA", do NOT pipe `"find me a 3.3V LDO with 500 mA"` into `show`: that's natural language, and every vendor will return zero hits. Extract the likely part family or MPN first, then call `show`.  **Extraction examples:** @@ -42,13 +42,13 @@ Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, | "need a 3.3V LDO 500mA" | `LM1117-3.3` or `AMS1117-3.3` | Well-known 3.3V LDOs; pick one, try the other if empty. | | "stm32 bluepill chip" | `STM32F103C8T6` | The canonical Blue Pill MCU. | | "what op-amp for unity gain audio" | `TL072` or `NE5532` | Common audio op-amps. Don't pass "op-amp audio" as a keyword. |-| "lm333 timer" | Ask first β€” LM333 isn't a 555-family timer. Probably `LM555` (typo). | Don't burn a search on a bogus part number. |+| "lm333 timer" | Ask first: LM333 isn't a 555-family timer. Probably `LM555` (typo). | Don't burn a search on a bogus part number. |  **Rules of thumb:**  - If the user typed a clearly valid MPN (has letters + digits + optional dash, 4+ chars, looks like `STM32F103RBT6` / `LM555` / `ESP32-S3-WROOM-1U-N4R2`), pass it through verbatim. - If the user typed a natural-language description, mentally map it to the 1-2 best-known part families and pass the first one to `show`. If that returns 0, try the second.-- If the user named a part that doesn't match a family you recognize (`LM333` for "timer"), **stop and ask one clarifying question** before searching β€” don't guess your way into a bogus API call.+- If the user named a part that doesn't match a family you recognize (`LM333` for "timer"), **stop and ask one clarifying question** before searching: don't guess your way into a bogus API call. - If the user names an exact variant (e.g. "ESP32-S3-WROOM-1U-N4R2"), use that; don't broaden it unless a search returns 0.  ### Handling empty results@@ -56,8 +56,8 @@ Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, If `show` returns 0 hits across all three vendors AND no vendor errored, the CLI will already print a helpful "no matches" line and the webview will render an empty-state card with suggestions. You still need to decide what to do next:  1. Try one alternative family name (e.g. `LM555` β†’ `NE555` β†’ `LM556`).-2. If the alternative also returns 0, surface that to the user with a brief explanation: "Neither LM555 nor NE555 matched β€” double-check the MPN or describe the part differently."-3. Do NOT silently run five searches in a row with minor variations β€” ask the user for a better name after the second attempt.+2. If the alternative also returns 0, surface that to the user with a brief explanation: "Neither LM555 nor NE555 matched: double-check the MPN or describe the part differently."+3. Do NOT silently run five searches in a row with minor variations: ask the user for a better name after the second attempt.  ### Common part families + corrections @@ -88,7 +88,7 @@ DIGIKEY   total=  1  hits= 1  676ms  [ok] JLCPCB    total=  0  hits= 0   74ms  [ok]  RECOMMENDATION β†’  Mouser  iCE40HX4K-TQ144  $10.20  stock 42-                  Mouser stocked β€” 40-min drone delivery from Mansfield.+                  Mouser has it in stock: 40-minute drone delivery from Mansfield. ```  followed by the full unified JSON (same schema as `search` below) so downstream tooling has structured access.@@ -106,26 +106,65 @@ The `search` output is a unified JSON:     "mpn": "iCE40HX4K-TQ144",     "unit_price": "$10.20",     "stock": 42,-    "reason": "Mouser stocked β€” 40-min drone delivery from Mansfield, near-zero shipping."+    "reason": "Mouser has it in stock: 40-minute drone delivery from Mansfield, near-zero shipping."   } } ``` -Each `hit` includes `image_url` for the webview β€” use the `app` subcommand when the user needs to eyeball product photos (Claude Code terminal can't show images).+Each `hit` includes `image_url` for the webview: use `show` when the user needs to eyeball product photos (Claude Code terminal can't show images). -## Webview app+## The page -`adom-parts-search app` opens a Hydrogen tab titled **"Parts Search"** with a 3-column grid:+`adom-parts-search show` (or `serve`, or the Dock Bar card) opens a Hydrogen tab titled **"Parts Search"**. The page is the dashboard: a 44px header (brand, current query, vendor health LED, settings cog), a **Say it** strip of phrases the user can copy or stage into this app's AI thread, the search bar, the recommendation banner, and three columns: -- **Mouser column** (blue top border) β€” preferred, badged "40-min drone Β· $0 ship"-- **DigiKey column** (red top border) β€” alternative-- **JLCPCB column** (green top border) β€” parts library only (SMT assembly)+- **Mouser column**: preferred under the default policy (40-minute drone, near-zero shipping)+- **DigiKey column**: the alternative when Mouser cannot ship+- **JLCPCB column**: parts library only (SMT assembly), never recommended for delivery -Each card shows the product photo, MPN, vendor PN, manufacturer, price (@1 and @100), stock, lead time, flags (RoHS / basic / preferred / lifecycle). Click any product photo to zoom.+Each card shows the product photo, MPN, vendor PN, manufacturer, price (@1 and @100), stock, lead time, flags (RoHS / basic / preferred / lifecycle), and View / Datasheet / 3D links. Click any product photo to zoom. -The recommendation banner at the top calls out the winning vendor with the reason β€” the same policy as the CLI, rendered visually.+The recommendation banner names the winner, the reason, and the policy that chose it. A vendor switched off in Settings keeps its column and says so. -## Pin-1 alignment check β€” moved to `adom-chipfit`+### Settings (the cog, upper right)++Stored in `~/.adom/parts-search-settings.json`; the CLI reads the same file.++| Key | Default | What it changes |+|---|---|---|+| `defaultLimit` | 5 | hits fetched per vendor (3, 5, 10) |+| `inStockOnly` | off | drop zero-stock hits before rendering |+| `vendorMouser` / `vendorDigikey` / `vendorJlcpcb` | on | whether that vendor is queried at all |+| `policy` | `mouser` | `mouser` (Mouser preferred) or `cheapest` (lowest in-stock unit price across vendors) |+| `showImages` | on | load product photos from the vendors' sites |+| `taskbarProgress` | on | paint a progress bar on the Hydrogen taskbar button while a search runs |+| `taskbarBox` | first connected | which Adom Desktop box to paint on |+| `showSayStrip` | on | the "Say it to your AI" strip at the top of the page (the X on the strip turns it off) |++```bash+adom-parts-search settings get+adom-parts-search settings set policy cheapest+adom-parts-search settings set taskbarProgress off+adom-parts-search settings restore+```++### Driving and observing the page (AI)++```bash+adom-parts-search serve --print-url      # start in the background (idempotent, version-aware), print http://127.0.0.1:8893/+adom-parts-search health                 # OK: v1.1.0 ok (all three vendor backends reachable) [Mouser=ok ...]+adom-parts-search status                 # full /api/status JSON: per-vendor LEDs with _hint, rollup state, settings, timing+adom-parts-search ui search "LM358"      # run a search through the page (paints an indeterminate taskbar bar)+adom-parts-search ui toast "Loading your BOM" --kind info+adom-parts-search ui click settings      # ids: search, instock, settings, close-settings, restore, limit --value 10, policy --value cheapest, vendor-jlcpcb, images, taskbar, query --value "LM358"+curl -s http://127.0.0.1:8893/state      # last query + results, settings, toasts, clicks, say phrases+curl -s http://127.0.0.1:8893/console    # the page's console.log/warn/error ring buffer+```++Every `/api/*` route answers OPTIONS and sends `Access-Control-Allow-Origin: *` (the Dock Bar probes `/api/status` cross-origin). `POST /shutdown` stops the server.++For the Dock Bar card (what a click does, `dockbar.json`, the LED, diagnosis) read the companion skill `adom-parts-search-dock`.++## Pin-1 alignment check: moved to `adom-chipfit`  The footprint ↔ 3D-chip validator that used to live here as `adom-parts-search align` is now its own app: **`adom-chipfit`**.@@ -136,10 +175,7 @@ parts-search was mixing two unrelated concerns. Install one-liner (paste-into-Claude style):  ```bash-curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-chipfit/adom-chipfit \-  -o /tmp/adom-chipfit && chmod +x /tmp/adom-chipfit \-  && sudo install -m 0755 /tmp/adom-chipfit /usr/local/bin/adom-chipfit \-  && adom-chipfit install+adom-wiki pkg install adom-chipfit ```  Then use it via:@@ -154,7 +190,7 @@ picks it up.  ## Why Mouser is preferred -See the companion skill `adom-parts-search` (the gallia one) for the full policy. Short version:+See the companion skill `adom-parts-search` for the full policy. Short version:  - **40-minute drone delivery** (Mansfield TX β†’ Fort Worth TX, ~15 miles) - **Near-zero shipping cost** (drone route, Mouser-operated)@@ -168,19 +204,16 @@ The three vendor backends are Tier A services. Current URLs: - DigiKey: `https://digikey-gjuu8l5t69uh.adom.cloud` - JLCPCB: `https://jlcpcb-wela51osctvp.adom.cloud` -Override with `--mouser-api` / `--digikey-api` / `--jlcpcb-api`, or env vars `MOUSER_API` / `DIGIKEY_API` / `JLCPCB_API`. Canonical source of truth for current slugs is `~/service-watcher/services.json` on the main gallia container.+Override with `--mouser-api` / `--digikey-api` / `--jlcpcb-api`, or env vars `MOUSER_API` / `DIGIKEY_API` / `JLCPCB_API`. Canonical source of truth for current slugs is `~/service-watcher/services.json`.  ## Architecture -This app is **client-only** β€” no service container of its own. It coordinates the three existing vendor backends (adom-mouser / adom-digikey / adom-jlcpcb). Each individual vendor CLI is still available for single-vendor queries.+This app is **client-only**, no service container of its own. It coordinates the three existing vendor backends (adom-mouser / adom-digikey / adom-jlcpcb). Each individual vendor CLI is still available for single-vendor queries.  ## Install -Tier A β€” fetched by `gallia/install.mjs` on every gallia container. Or manually:+Install from the wiki:  ```bash-curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-parts-search/adom-parts-search \-  -o /tmp/adom-parts-search && chmod +x /tmp/adom-parts-search && \-  sudo install -m 0755 /tmp/adom-parts-search /usr/local/bin/adom-parts-search && \-  adom-parts-search install+adom-wiki pkg install adom/adom-parts-search ```
bin/adom-parts-search
⋯ 1 unchanged line ⋯
dockbar.json+31−4
@@ -1,18 +1,45 @@ {-  "dock_manifest": "1.1.0",+  "dock_manifest": "1.2.0",+  "say": [+    "search for a 10k 0402 resistor with parts search",+    "find the cheapest LM358 with parts search",+    "price an STM32F103RBT6 across vendors with parts search",+    "check stock on an ESP32-S3-WROOM-1 with parts search",+    "source the parts in my BOM with parts search",+    "show me in-stock 3.3V LDOs with parts search"+  ],   "webview": {-    "title": "Parts Search"+    "title": "Parts Search",+    "favicon": "docs/icon.svg"+  },+  "health": {+    "url": "/api/status",+    "poll_seconds": 15,+    "timeout_ms": 2000   },   "launch": {     "mode": "container_command",+    "console": "show",     "steps": [+      {+        "label": "Installing Parts Search",+        "run": "sh -c 'PATH=\"$HOME/.local/bin:$PATH\"; adom-wiki pkg install adom/adom-parts-search; command -v adom-parts-search >/dev/null 2>&1 || { adom-wiki pkg uninstall adom/adom-parts-search >/dev/null 2>&1; adom-wiki pkg install adom/adom-parts-search; }'",+        "skip_if": "sh -c 'PATH=\"$HOME/.local/bin:$PATH\"; command -v adom-parts-search'",+        "timeout_seconds": 180+      },       {         "label": "Starting Parts Search",-        "run": "adom-parts-search serve --print-url",+        "run": "sh -c 'PATH=\"$HOME/.local/bin:$PATH\"; exec adom-parts-search serve --print-url'",         "await": "url",         "timeout_seconds": 60       }     ],-    "on_ready": "navigate_placeholder"+    "on_ready": "navigate_placeholder",+    "ai": {+      "prompt": "The user just opened Parts Search from the dock. It searches Mouser, DigiKey, and JLCPCB in one query and recommends where to buy (Mouser-preferred: 40-minute drone delivery from Mansfield to Fort Worth, near-zero shipping). Run `adom-parts-search health` and, if any vendor LED is not green, offer the fix its _hint names. Then ask which part they want to source and run `adom-parts-search show \"<part>\"` so the results render on the page.",+      "thread": "existing",+      "thread_fallback": "new",+      "submit": "staged"+    }   } }
install.sh+1−1
@@ -6,7 +6,7 @@ BIN_DIR="${HOME}/.local/bin"; mkdir -p "$BIN_DIR" install -m 0755 "$DIR/bin/adom-parts-search" "$BIN_DIR/adom-parts-search" echo "Installed adom-parts-search -> $BIN_DIR/adom-parts-search" SKILL_DIR="${HOME}/.claude/skills"-for s in adom-parts-search adom-parts-search-build; do+for s in adom-parts-search adom-parts-search-build adom-parts-search-dock; do   if [ -f "$DIR/skills/$s/SKILL.md" ]; then     mkdir -p "$SKILL_DIR/$s"     install -m 0644 "$DIR/skills/$s/SKILL.md" "$SKILL_DIR/$s/SKILL.md"
package.json+22−16
@@ -1,8 +1,8 @@ {   "slug": "adom-parts-search",-  "version": "1.0.13",+  "version": "1.1.0",   "type": "app",-  "description": "One search box across Mouser + DigiKey + JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-min drone delivery to Fort Worth) that reasons around stock and lead time.",+  "description": "One search box across Mouser, DigiKey and JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-minute drone delivery to Fort Worth) that reasons around stock and lead time. Dock Bar ready: serve, health, settings, Say it.",   "dependencies": {     "adom/adom-mouser": "*",     "adom/adom-digikey": "*",@@ -29,31 +29,37 @@   "files": [     "bin/**",     "skills/**",+    "docs/icon.svg",+    "dockbar.json",     "install.sh",     "uninstall.sh",     "package.json",-    "page.json",     "README.md",     "SKILL.md",     "BUILD-SKILL.md",-    "screenshots/**"+    "CHANGELOG.md"   ],-  "hero": {-    "path": "screenshots/hero.png"-  },+  "changelog": "Dock Bar ready page with a settings modal, Say it strip, bundled brand fonts, taskbar progress, and AI drive verbs",   "discovery_triggers": [-    "parts-search",-    "parts-search parts",-    "parts-search pricing",-    "parts-search search",-    "parts-search part number",+    "parts search",+    "find part",+    "source component",+    "source part",+    "compare distributors",+    "compare vendors",+    "Mouser or DigiKey",+    "BOM sourcing",+    "price this part",+    "where can I get",+    "check stock",+    "parts availability",+    "fastest delivery",+    "cheapest part",     "component search",     "part lookup",-    "price breaks",-    "datasheet parts-search",-    "in stock parts-search"+    "price breaks"   ],-  "discovery_pitch": "Search Parts Search Electronics for components, pricing, stock, and datasheets \u2014 CLI + webview app + shared backend service.",+  "discovery_pitch": "Search Mouser, DigiKey and JLCPCB in parallel with product photos; Mouser-preferred routing for 40-minute drone delivery from Mansfield to the Fort Worth facility. Say 'with parts search' to your AI.",   "sample_prompts": [     {       "label": "source an STM32F103RBT6",
page.json+23−14
@@ -4,7 +4,7 @@   "slug": "adom-parts-search",   "title": "Adom Parts Search",   "brief": "One search box across Mouser + DigiKey + JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-min drone delivery to Fort Worth) that reasons around stock and lead time.",-  "version": "1.0.13",+  "version": "1.1.0",   "install": {     "binary_name": "adom-parts-search",     "install_dir": "",@@ -52,22 +52,29 @@     }   ],   "discovery_triggers": [-    "parts-search",-    "parts-search parts",-    "parts-search pricing",-    "parts-search search",-    "parts-search part number",+    "parts search",+    "find part",+    "source component",+    "source part",+    "compare distributors",+    "compare vendors",+    "Mouser or DigiKey",+    "BOM sourcing",+    "price this part",+    "where can I get",+    "check stock",+    "parts availability",+    "fastest delivery",+    "cheapest part",     "component search",     "part lookup",-    "price breaks",-    "datasheet parts-search",-    "in stock parts-search"+    "price breaks"   ],-  "discovery_pitch": "Search Parts Search Electronics for components, pricing, stock, and datasheets β€” CLI + webview app + shared backend service.",+  "discovery_pitch": "Search Mouser, DigiKey and JLCPCB in parallel with product photos; Mouser-preferred routing for 40-minute drone delivery from Mansfield to the Fort Worth facility. Say 'with parts search' to your AI.",   "metadata": {     "platform": "linux"   },-  "description": "One search box across Mouser + DigiKey + JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-min drone delivery to Fort Worth) that reasons around stock and lead time.",+  "description": "One search box across Mouser, DigiKey and JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation (40-minute drone delivery to Fort Worth) that reasons around stock and lead time. Dock Bar ready: serve, health, settings, Say it.",   "dependencies": {     "adom/adom-mouser": "*",     "adom/adom-digikey": "*",@@ -81,15 +88,17 @@   "files": [     "bin/**",     "skills/**",+    "docs/icon.svg",+    "dockbar.json",     "install.sh",     "uninstall.sh",     "package.json",-    "page.json",     "README.md",     "SKILL.md",     "BUILD-SKILL.md",-    "screenshots/**"+    "CHANGELOG.md"   ],   "org": "adom",-  "updated_at": "2026-06-25T01:59:26.452Z"+  "updated_at": "2026-06-25T01:59:26.452Z",+  "changelog": "Dock Bar ready page with a settings modal, Say it strip, bundled brand fonts, taskbar progress, and AI drive verbs" }\ No newline at end of file
skills/adom-parts-search-build/SKILL.md+12−10
@@ -5,12 +5,12 @@ description: Build and release a new version of adom-parts-search. Use when the  # Release adom-parts-search -1. Bump `VERSION` + `Cargo.toml` + `wiki/page.json` version.-2. `./build.sh` β€” cargo build, install local binary.-3. Verify β€” `adom-parts-search search "STM32F103RBT6"` returns all three vendors.-4. Ralph-loop the webview (`adom-parts-search app --no-tab` + pup).+1. Bump `VERSION` + `Cargo.toml` + `wiki/page.json` + `package.json` + `page.json` versions, and add a `CHANGELOG.md` entry (publish.sh refuses a placeholder).+2. `./build.sh`: cargo build, install local binary.+3. Verify: `adom-parts-search search "STM32F103RBT6"` returns all three vendors.+4. Ralph-loop the page in pup (`adom-parts-search serve` then open the proxy URL in pup): fonts loaded, tooltips inside the viewport at the corners, the four settings dismissals with trusted input, settings read back from `~/.adom/parts-search-settings.json`, phone width with no horizontal scroll, `adom-ui-linter lint .` to zero FAILs. 5. Show user a screenshot of the 3-column grid + recommendation banner; wait for explicit approval.-6. `./publish.sh` β€” git tag, wiki asset upload, wiki page update, verify.+6. `./publish.sh`: git tag, registry tarball (bin + skills + dockbar.json + docs/icon.svg + screenshots), page-repo push of dockbar.json / docs/icon.svg / docs/hero.png, verify with a clean `adom-wiki pkg install`.  ## Pre-release checklist @@ -19,7 +19,7 @@ description: Build and release a new version of adom-parts-search. Use when the - [ ] Recommendation banner renders Mouser-preferred when Mouser is in stock - [ ] Product images render (web-view fetches mouser.com + digikey.com + LCSC images) - [ ] No console errors via `GET /console`-- [ ] πŸ›‘ Icon audit β€” EVERY icon monochrome white, no favicon carve-out.+- [ ] Icon audit: EVERY icon monochrome white, no favicon carve-out.       Run all three greps; each must return zero:       ```       # (a) Teal fills/strokes in any SVG, including docs/icon.svg itself@@ -36,12 +36,14 @@ description: Build and release a new version of adom-parts-search. Use when the         src/app/*.html 2>/dev/null       ```       The favicon/tab-icon is NOT exempt. See `brand/SKILL.md` Β§Icons +-      `app-creator/SKILL.md` Β§1b β€” the rule was tightened after this+      `app-creator/SKILL.md` Β§1b: the rule was tightened after this       app shipped v0.1.0 with a teal tab icon that slipped past three       audits.  ## Version bumping triggers -- Backend URL changes (slug rotation on service-mouser / service-digikey / service-jlcpcb) β†’ patch bump + republish to propagate.-- UI changes visible to the user β†’ minor bump.-- Policy changes (e.g. new vendor, different preference rules) β†’ minor bump + update the gallia `adom-parts-search` skill to match.+- Backend URL changes (slug rotation on service-mouser / service-digikey / service-jlcpcb): patch bump + republish to propagate.+- The dock reads `dockbar.json` from the PAGE REPO, not the registry tarball; publish.sh pushes it, but a manual edit needs `adom-wiki repo push adom/adom-parts-search --files dockbar.json -m "..."`.+- The hero is human-gated: `hero-studio pose adom/adom-parts-search --surface pup --headline "Parts Search"`, then `adom-wiki repo push ... --files docs/hero.png` and `adom-wiki page hero adom/adom-parts-search --image docs/hero.png`.+- UI changes visible to the user: minor bump.+- Policy changes (e.g. new vendor, different preference rules): minor bump + update the `adom-parts-search` skill to match.
skills/adom-parts-search-dock/SKILL.mdadded+96
@@ -0,0 +1,96 @@+---+name: adom-parts-search-dock+description: How Parts Search lives in the Hydrogen Dock Bar (the app-launcher rail on the right edge of ah). What the dock card does when clicked, the contract this app implements (serve verb, direct 127.0.0.1 URL, /api/status LEDs with CORS, webview ownership via ADOM_DOCK_WEBVIEW, the Say it strip, taskbar progress), where dockbar.json lives and why it is in the PAGE REPO, how to add the card to a dock, and how to diagnose a red LED or a launch that never answers. Parent skill: adom-parts-search. Trigger words: parts search dock, dock bar parts search, add parts search to my dock, parts search card, parts search LED red, parts search not answering, dockbar.json parts search, parts search serve, parts search dock webview, parts search say it.+---++# Parts Search in the Dock Bar++Parent skill: **adom-parts-search**. Read that one for searching; read this one for the launcher.++## Purpose++The Dock Bar is Hydrogen's app launcher: a rail of cards on the right edge of the workspace.+The Parts Search card is the zero-setup way in: one click installs the CLI into the user's+container, starts the page server, and shows the Parts Search page in a webview tab. The+card's LED is live health read from this app's own status endpoint, so a user can see at a+glance whether the three vendor backends are reachable before they search.++The page itself IS the dashboard. There is no separate launcher or status page: the dock+click lands on the same Parts Search page a user gets from `adom-parts-search show`.++## What a click does, step by step++1. Hydrogen opens a webview tab named **Parts Search** (from `webview.title` in+   `dockbar.json`) showing the launch interstitial, with this app's favicon+   (`docs/icon.svg`) from the first frame.+2. It runs the manifest's `container_command` steps in the user's workspace container:+   - **Installing Parts Search**: `adom-wiki pkg install adom/adom-parts-search`, skipped+     when `command -v adom-parts-search` already succeeds (the `skip_if`). PATH is set to+     include `~/.local/bin`, where wiki CLIs land.+   - **Starting Parts Search**: `adom-parts-search serve --print-url`. The step has+     `await: "url"`, so the dock scrapes the URL the verb prints and polls it until it+     answers (budget: the step's `timeout_seconds`, 60).+3. `serve` takes over the interstitial tab itself: every step runs with `ADOM_DOCK_WEBVIEW`+   (the tab name) and `ADOM_DOCK_APP` (`adom/adom-parts-search`) in its environment, and+   `serve` calls `adom-cli hydrogen webview open-or-refresh --name "$ADOM_DOCK_WEBVIEW"+   --url http://127.0.0.1:8893/`. Re-running with the same name just renavigates the tab,+   which is the ownership handle. When the variable is unset (a hand-run serve) nothing+   is touched.+4. While the rail is open, the dock polls `GET /api/status` every 15 seconds and paints the+   card's LED from the payload.++## The contract, as implemented here++| Rule | Where | How |+|---|---|---|+| Serve self-backgrounds | `src/serve.rs` | spawns `app --port 8893 --no-tab` detached (own process group), waits up to 15 s for `/api/status`, prints the URL, exits 0 |+| Serve is idempotent and version-aware | `src/serve.rs` | an instance of the same version is reused (its URL printed). A different version is stopped by the pid it published in `~/.adom/parts-search-server.json`, matched by EXACT argv (never a substring), then replaced |+| Direct URL | `src/serve.rs` | prints `http://127.0.0.1:8893/`, never the `:7380/proxy/` form and never the name `localhost` (IPv6-first on Windows, ~800 ms per request) |+| Fast health with CORS | `src/app/mod.rs` | `/api/status` (alias `/health`) is cached stale-while-revalidate: answers in ~10 ms from the last reading, refreshes in the background when older than 5 s. Every `/api/*` route sends `Access-Control-Allow-Origin: *` and answers `OPTIONS` |+| Per-facet LEDs + owned rollup | `src/app/mod.rs` | facets: Mouser, DigiKey, JLCPCB (each backend's own `/health`, with Mouser's daily quota surfaced), and Search (idle or the running query). Top-level `state`: `fail` when no backend answers, `warn` when any is down, off, or quota-hit, else `ok` |+| Say it | `dockbar.json` + the page | six phrases in the user's noun ("find the cheapest LM358 with **parts search**") shown on the interstitial and, as a strip at the top of the page, copy on click plus Try it (stages into the app's own thread: census first, history second, copy fallback). The strip's X hides it for good (`showSayStrip` setting) |+| Settings window | the page | the cog in the 44px header opens the settings modal (settings-layout skill) |+| Taskbar progress | `src/taskbar.rs` | a determinate bar on the Hydrogen taskbar button sized from measured search durations; indeterminate for an AI-driven `show` |++## Where the files live++- `dockbar.json` (manifest 1.2.0) is at the ROOT of the wiki **page repo**+  (`adom-wiki repo show adom/adom-parts-search dockbar.json`). The dock reads the page repo,+  NOT the registry tarball; the two stores are separate. `publish.sh` pushes it with+  `adom-wiki repo push`. A manual edit must be pushed the same way or the dock never sees it.+- `docs/icon.svg` (the favicon named in the manifest) must exist at that path in the page+  repo, monochrome white.+- The page's hero and one-line brief are what the card shows; the dock renders them from the+  wiki page on its next poll, nothing to ship.++## Add the card to a dock++Dock settings (the gear at the top of the rail), **Add app**, `adom/adom-parts-search`.+Being in the curated list is not required. The card appears with no LED until the app is+running; that is the honest state.++## Diagnose++Read the LED payload first; every facet carries a `_hint` naming the fix:++```bash+adom-parts-search health          # OK: v1.1.0 ok (all three vendor backends reachable) [Mouser=ok DigiKey=ok JLCPCB=ok Search=ok]+adom-parts-search status          # the full JSON the dock reads+curl -s http://127.0.0.1:8893/api/status | python3 -m json.tool+```++| Symptom | Cause | Fix |+|---|---|---|+| Card reads "not answering" while the page works | a proxy or a build stripped CORS from `/api/status` | `curl -si http://127.0.0.1:8893/api/status \| grep -i access-control` must show `*`; reinstall if missing |+| Launch fails "never answered" | the serve step ran in the foreground or the port is held by a stale server the pid file cannot identify | `adom-parts-search serve` by hand prints the error and a Hint; `curl -X POST http://127.0.0.1:8893/shutdown` frees the port |+| Works for the author, fails for users | `adom-parts-search` not on PATH in the exec shell | the manifest steps prefix `PATH="$HOME/.local/bin:$PATH"`; check `~/.local/bin/adom-parts-search` exists |+| Yellow LED | one backend down, switched off in Settings, or Mouser's daily quota hit | the facet's `detail` says which; quota resets at midnight CT |+| Red LED | no vendor backend reachable | the backend slugs rotated: override with `--mouser-api` etc. or ping an Adom admin |+| Users pinned to an old page after an update | an old server kept running | `serve` restarts a running instance whose version differs; run `adom-parts-search serve` once |+| The tab did not get taken over | `ADOM_DOCK_WEBVIEW` unset (hand-run) or `adom-cli` missing | expected for a hand-run; the dock navigates the interstitial itself as a fallback |++## Cold verify (what the dock thread checks)++On a box that has never had the CLI: add the card, click it, watch the console run the+install step, then the serve step printing `http://127.0.0.1:8893/`, then the tab navigate+to the Parts Search page with the Say it strip on top and the LED green within 15 s.
skills/adom-parts-search/SKILL.md+64−31
@@ -1,6 +1,6 @@ --- name: adom-parts-search-description: Unified parts search across Mouser + DigiKey + JLCPCB with Mouser-preferred routing (40-min drone delivery from Mansfield, TX to our Fort Worth facility; near-zero shipping). CLI and Hydrogen webview app. Use when the user asks to source a part, price a component, compare vendors, check stock across distributors, or assemble a BOM. Trigger words β€” find part, search parts, source component, parts search, component search, where can I get, compare distributors, Mouser or DigiKey, compare prices, BOM sourcing, stock check, parts availability, open parts search, parts search app, parts search UI.+description: Unified parts search across Mouser + DigiKey + JLCPCB with Mouser-preferred routing (40-min drone delivery from Mansfield, TX to our Fort Worth facility; near-zero shipping). CLI and Hydrogen webview app. Use when the user asks to source a part, price a component, compare vendors, check stock across distributors, or assemble a BOM. Trigger words: find part, search parts, source component, parts search, component search, where can I get, compare distributors, Mouser or DigiKey, compare prices, BOM sourcing, stock check, parts availability, open parts search, parts search app, parts search UI, parts search settings, parts search health, parts search dock. ---  # adom-parts-search@@ -12,7 +12,7 @@ Searches Mouser + DigiKey + JLCPCB in parallel. Rust CLI + Hydrogen webview. Rec **For user-facing searches, always use `show`.** It drives the webview tab AND prints the full vendor-by-vendor result to stdout, so the user sees product photos + 3-column comparison and the AI sees the same data textually. Auto-starts the app server + opens the tab on first run.  ```bash-# βœ… DEFAULT β€” every search a human asks for+# DEFAULT: every search a human asks for adom-parts-search show  "ESP32-S3-WROOM-1U-N4R2" adom-parts-search show  "iCE40HX4K-TQ144" --limit 8 --in-stock-only @@ -27,11 +27,11 @@ adom-parts-search app  - User asked a conversational question about a part β†’ **`show`**. Always. - You're piping into `jq`, `awk`, or a batch script β†’ `search`.-- Silence: never just dump JSON to chat. If you would have run `search`, run `show` instead β€” the user wants photos and side-by-side comparison, not a wall of JSON.+- Silence: never just dump JSON to chat. If you would have run `search`, run `show` instead: the user wants photos and side-by-side comparison, not a wall of JSON.  ### Extract a clean MPN / part-family BEFORE calling `show` -Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, NOT full-text intent search. If the user says "find me a 3.3V LDO with 500 mA", do NOT pipe `"find me a 3.3V LDO with 500 mA"` into `show` β€” that's natural language, and every vendor will return zero hits. Extract the likely part family or MPN first, then call `show`.+Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, NOT full-text intent search. If the user says "find me a 3.3V LDO with 500 mA", do NOT pipe `"find me a 3.3V LDO with 500 mA"` into `show`: that's natural language, and every vendor will return zero hits. Extract the likely part family or MPN first, then call `show`.  **Extraction examples:** @@ -42,13 +42,13 @@ Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, | "need a 3.3V LDO 500mA" | `LM1117-3.3` or `AMS1117-3.3` | Well-known 3.3V LDOs; pick one, try the other if empty. | | "stm32 bluepill chip" | `STM32F103C8T6` | The canonical Blue Pill MCU. | | "what op-amp for unity gain audio" | `TL072` or `NE5532` | Common audio op-amps. Don't pass "op-amp audio" as a keyword. |-| "lm333 timer" | Ask first β€” LM333 isn't a 555-family timer. Probably `LM555` (typo). | Don't burn a search on a bogus part number. |+| "lm333 timer" | Ask first: LM333 isn't a 555-family timer. Probably `LM555` (typo). | Don't burn a search on a bogus part number. |  **Rules of thumb:**  - If the user typed a clearly valid MPN (has letters + digits + optional dash, 4+ chars, looks like `STM32F103RBT6` / `LM555` / `ESP32-S3-WROOM-1U-N4R2`), pass it through verbatim. - If the user typed a natural-language description, mentally map it to the 1-2 best-known part families and pass the first one to `show`. If that returns 0, try the second.-- If the user named a part that doesn't match a family you recognize (`LM333` for "timer"), **stop and ask one clarifying question** before searching β€” don't guess your way into a bogus API call.+- If the user named a part that doesn't match a family you recognize (`LM333` for "timer"), **stop and ask one clarifying question** before searching: don't guess your way into a bogus API call. - If the user names an exact variant (e.g. "ESP32-S3-WROOM-1U-N4R2"), use that; don't broaden it unless a search returns 0.  ### Handling empty results@@ -56,8 +56,8 @@ Vendor APIs (Mouser, DigiKey, JLCPCB) do substring match on MPN and description, If `show` returns 0 hits across all three vendors AND no vendor errored, the CLI will already print a helpful "no matches" line and the webview will render an empty-state card with suggestions. You still need to decide what to do next:  1. Try one alternative family name (e.g. `LM555` β†’ `NE555` β†’ `LM556`).-2. If the alternative also returns 0, surface that to the user with a brief explanation: "Neither LM555 nor NE555 matched β€” double-check the MPN or describe the part differently."-3. Do NOT silently run five searches in a row with minor variations β€” ask the user for a better name after the second attempt.+2. If the alternative also returns 0, surface that to the user with a brief explanation: "Neither LM555 nor NE555 matched: double-check the MPN or describe the part differently."+3. Do NOT silently run five searches in a row with minor variations: ask the user for a better name after the second attempt.  ### Common part families + corrections @@ -88,7 +88,7 @@ DIGIKEY   total=  1  hits= 1  676ms  [ok] JLCPCB    total=  0  hits= 0   74ms  [ok]  RECOMMENDATION β†’  Mouser  iCE40HX4K-TQ144  $10.20  stock 42-                  Mouser stocked β€” 40-min drone delivery from Mansfield.+                  Mouser has it in stock: 40-minute drone delivery from Mansfield. ```  followed by the full unified JSON (same schema as `search` below) so downstream tooling has structured access.@@ -106,26 +106,65 @@ The `search` output is a unified JSON:     "mpn": "iCE40HX4K-TQ144",     "unit_price": "$10.20",     "stock": 42,-    "reason": "Mouser stocked β€” 40-min drone delivery from Mansfield, near-zero shipping."+    "reason": "Mouser has it in stock: 40-minute drone delivery from Mansfield, near-zero shipping."   } } ``` -Each `hit` includes `image_url` for the webview β€” use the `app` subcommand when the user needs to eyeball product photos (Claude Code terminal can't show images).+Each `hit` includes `image_url` for the webview: use `show` when the user needs to eyeball product photos (Claude Code terminal can't show images). -## Webview app+## The page -`adom-parts-search app` opens a Hydrogen tab titled **"Parts Search"** with a 3-column grid:+`adom-parts-search show` (or `serve`, or the Dock Bar card) opens a Hydrogen tab titled **"Parts Search"**. The page is the dashboard: a 44px header (brand, current query, vendor health LED, settings cog), a **Say it** strip of phrases the user can copy or stage into this app's AI thread, the search bar, the recommendation banner, and three columns: -- **Mouser column** (blue top border) β€” preferred, badged "40-min drone Β· $0 ship"-- **DigiKey column** (red top border) β€” alternative-- **JLCPCB column** (green top border) β€” parts library only (SMT assembly)+- **Mouser column**: preferred under the default policy (40-minute drone, near-zero shipping)+- **DigiKey column**: the alternative when Mouser cannot ship+- **JLCPCB column**: parts library only (SMT assembly), never recommended for delivery -Each card shows the product photo, MPN, vendor PN, manufacturer, price (@1 and @100), stock, lead time, flags (RoHS / basic / preferred / lifecycle). Click any product photo to zoom.+Each card shows the product photo, MPN, vendor PN, manufacturer, price (@1 and @100), stock, lead time, flags (RoHS / basic / preferred / lifecycle), and View / Datasheet / 3D links. Click any product photo to zoom. -The recommendation banner at the top calls out the winning vendor with the reason β€” the same policy as the CLI, rendered visually.+The recommendation banner names the winner, the reason, and the policy that chose it. A vendor switched off in Settings keeps its column and says so. -## Pin-1 alignment check β€” moved to `adom-chipfit`+### Settings (the cog, upper right)++Stored in `~/.adom/parts-search-settings.json`; the CLI reads the same file.++| Key | Default | What it changes |+|---|---|---|+| `defaultLimit` | 5 | hits fetched per vendor (3, 5, 10) |+| `inStockOnly` | off | drop zero-stock hits before rendering |+| `vendorMouser` / `vendorDigikey` / `vendorJlcpcb` | on | whether that vendor is queried at all |+| `policy` | `mouser` | `mouser` (Mouser preferred) or `cheapest` (lowest in-stock unit price across vendors) |+| `showImages` | on | load product photos from the vendors' sites |+| `taskbarProgress` | on | paint a progress bar on the Hydrogen taskbar button while a search runs |+| `taskbarBox` | first connected | which Adom Desktop box to paint on |+| `showSayStrip` | on | the "Say it to your AI" strip at the top of the page (the X on the strip turns it off) |++```bash+adom-parts-search settings get+adom-parts-search settings set policy cheapest+adom-parts-search settings set taskbarProgress off+adom-parts-search settings restore+```++### Driving and observing the page (AI)++```bash+adom-parts-search serve --print-url      # start in the background (idempotent, version-aware), print http://127.0.0.1:8893/+adom-parts-search health                 # OK: v1.1.0 ok (all three vendor backends reachable) [Mouser=ok ...]+adom-parts-search status                 # full /api/status JSON: per-vendor LEDs with _hint, rollup state, settings, timing+adom-parts-search ui search "LM358"      # run a search through the page (paints an indeterminate taskbar bar)+adom-parts-search ui toast "Loading your BOM" --kind info+adom-parts-search ui click settings      # ids: search, instock, settings, close-settings, restore, limit --value 10, policy --value cheapest, vendor-jlcpcb, images, taskbar, query --value "LM358"+curl -s http://127.0.0.1:8893/state      # last query + results, settings, toasts, clicks, say phrases+curl -s http://127.0.0.1:8893/console    # the page's console.log/warn/error ring buffer+```++Every `/api/*` route answers OPTIONS and sends `Access-Control-Allow-Origin: *` (the Dock Bar probes `/api/status` cross-origin). `POST /shutdown` stops the server.++For the Dock Bar card (what a click does, `dockbar.json`, the LED, diagnosis) read the companion skill `adom-parts-search-dock`.++## Pin-1 alignment check: moved to `adom-chipfit`  The footprint ↔ 3D-chip validator that used to live here as `adom-parts-search align` is now its own app: **`adom-chipfit`**.@@ -136,10 +175,7 @@ parts-search was mixing two unrelated concerns. Install one-liner (paste-into-Claude style):  ```bash-curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-chipfit/adom-chipfit \-  -o /tmp/adom-chipfit && chmod +x /tmp/adom-chipfit \-  && sudo install -m 0755 /tmp/adom-chipfit /usr/local/bin/adom-chipfit \-  && adom-chipfit install+adom-wiki pkg install adom-chipfit ```  Then use it via:@@ -154,7 +190,7 @@ picks it up.  ## Why Mouser is preferred -See the companion skill `adom-parts-search` (the gallia one) for the full policy. Short version:+See the companion skill `adom-parts-search` for the full policy. Short version:  - **40-minute drone delivery** (Mansfield TX β†’ Fort Worth TX, ~15 miles) - **Near-zero shipping cost** (drone route, Mouser-operated)@@ -168,19 +204,16 @@ The three vendor backends are Tier A services. Current URLs: - DigiKey: `https://digikey-gjuu8l5t69uh.adom.cloud` - JLCPCB: `https://jlcpcb-wela51osctvp.adom.cloud` -Override with `--mouser-api` / `--digikey-api` / `--jlcpcb-api`, or env vars `MOUSER_API` / `DIGIKEY_API` / `JLCPCB_API`. Canonical source of truth for current slugs is `~/service-watcher/services.json` on the main gallia container.+Override with `--mouser-api` / `--digikey-api` / `--jlcpcb-api`, or env vars `MOUSER_API` / `DIGIKEY_API` / `JLCPCB_API`. Canonical source of truth for current slugs is `~/service-watcher/services.json`.  ## Architecture -This app is **client-only** β€” no service container of its own. It coordinates the three existing vendor backends (adom-mouser / adom-digikey / adom-jlcpcb). Each individual vendor CLI is still available for single-vendor queries.+This app is **client-only**, no service container of its own. It coordinates the three existing vendor backends (adom-mouser / adom-digikey / adom-jlcpcb). Each individual vendor CLI is still available for single-vendor queries.  ## Install -Tier A β€” fetched by `gallia/install.mjs` on every gallia container. Or manually:+Install from the wiki:  ```bash-curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-parts-search/adom-parts-search \-  -o /tmp/adom-parts-search && chmod +x /tmp/adom-parts-search && \-  sudo install -m 0755 /tmp/adom-parts-search /usr/local/bin/adom-parts-search && \-  adom-parts-search install+adom-wiki pkg install adom/adom-parts-search ```
uninstall.sh+1−1
@@ -1,5 +1,5 @@ #!/bin/bash set -euo pipefail rm -f "${HOME}/.local/bin/adom-parts-search"-rm -rf "${HOME}/.claude/skills/adom-parts-search" "${HOME}/.claude/skills/adom-parts-search-build"+rm -rf "${HOME}/.claude/skills/adom-parts-search" "${HOME}/.claude/skills/adom-parts-search-build" "${HOME}/.claude/skills/adom-parts-search-dock" echo "Removed adom-parts-search"