← Commit history

v2.0.18: Module 2.4.0: the panel gutter check now measures against the containing block

John Lauer ·fe5ed16060 ·15d ago ·parent c7076a1
8 files changed +64−94
Cargo.lock+1−1
@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"  [[package]] name = "adom-parts-search"-version = "2.0.17"+version = "2.0.18" dependencies = [  "base64",  "clap",
Cargo.toml+1−1
@@ -1,6 +1,6 @@ [package] name = "adom-parts-search"-version = "2.0.17"+version = "2.0.18" edition = "2021" description = "Parts Search Electronics component search — CLI, backend HTTP service, and Hydrogen webview app" license = "MIT"
VERSION+1−1
@@ -1 +1 @@-2.0.17+2.0.18
install.sh

  
package.json+2−41
@@ -1,6 +1,6 @@ {   "slug": "adom-parts-search",-  "version": "2.0.18",+  "version": "2.0.4",   "type": "app",   "description": "One search box across Mouser, DigiKey and JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation that reasons around stock and lead time. Dock Bar ready: serve, health, settings, Say it.",   "dependencies": {@@ -38,44 +38,5 @@     "SKILL.md",     "BUILD-SKILL.md",     "CHANGELOG.md"-  ],-  "changelog": "Module 2.4.0: the panel gutter check now measures against the containing block",-  "discovery_triggers": [-    "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"-  ],-  "discovery_pitch": "Search Mouser, DigiKey and JLCPCB in parallel with product photos; Mouser-preferred best-source pick. Say 'with parts search' to your AI.",-  "sample_prompts": [-    {-      "label": "source an STM32F103RBT6",-      "prompt": "source an STM32F103RBT6"-    },-    {-      "label": "where can I get an ESP32-S3-WROOM cheape",-      "prompt": "where can I get an ESP32-S3-WROOM cheapest and fastest"-    },-    {-      "label": "compare Mouser, DigiKey and JLCPCB for a",-      "prompt": "compare Mouser, DigiKey and JLCPCB for an LM555"-    },-    {-      "label": "price this BOM across distributors",-      "prompt": "price this BOM across distributors"-    }   ]-}\ No newline at end of file+}
page.json+9−50
@@ -4,7 +4,7 @@   "slug": "adom-parts-search",   "title": "Parts Search",   "brief": "One search box across Mouser, DigiKey and JLCPCB: parallel queries, side-by-side product photos, and a Mouser-preferred recommendation that reasons around stock and lead time.",-  "version": "2.0.18",+  "version": "2.0.4",   "install": {     "binary_name": "adom-parts-search",     "install_dir": "",@@ -33,25 +33,13 @@   },   "hero": {     "type": "image",-    "path": "screenshots/hero.png"+    "path": "docs/hero.png"   },   "sample_prompts": [-    {-      "label": "source an STM32F103RBT6",-      "prompt": "source an STM32F103RBT6"-    },-    {-      "label": "where can I get an ESP32-S3-WROOM cheape",-      "prompt": "where can I get an ESP32-S3-WROOM cheapest and fastest"-    },-    {-      "label": "compare Mouser, DigiKey and JLCPCB for a",-      "prompt": "compare Mouser, DigiKey and JLCPCB for an LM555"-    },-    {-      "label": "price this BOM across distributors",-      "prompt": "price this BOM across distributors"-    }+    "source an STM32F103RBT6",+    "where can I get an ESP32-S3-WROOM cheapest and fastest",+    "compare Mouser, DigiKey and JLCPCB for an LM555",+    "price this BOM across distributors"   ],   "discovery_triggers": [     "parts search",@@ -66,41 +54,12 @@     "where can I get",     "check stock",     "parts availability",-    "fastest delivery",-    "cheapest part",-    "component search",-    "part lookup",-    "price breaks"+    "fastest delivery"   ],-  "discovery_pitch": "Search Mouser, DigiKey and JLCPCB in parallel with product photos; Mouser-preferred best-source pick. Say 'with parts search' to your AI.",+  "discovery_pitch": "Search Mouser + DigiKey + JLCPCB in parallel from one interface, with product photos and a Mouser-preferred best-source pick.",   "metadata": {     "platform": "linux"   },   "category": "tools",-  "org": "adom",-  "description": "One search box across Mouser, DigiKey and JLCPCB. Parallel queries, side-by-side product photos, and a Mouser-preferred recommendation that reasons around stock and lead time. Dock Bar ready: serve, health, settings, Say it.",-  "dependencies": {-    "adom/adom-mouser": "*",-    "adom/adom-digikey": "*",-    "adom/adom-jlcpcb": "*"-  },-  "needs_sudo": false,-  "scripts": {-    "install": "./install.sh",-    "uninstall": "./uninstall.sh"-  },-  "files": [-    "bin/**",-    "skills/**",-    "docs/icon.svg",-    "dockbar.json",-    "install.sh",-    "uninstall.sh",-    "package.json",-    "README.md",-    "SKILL.md",-    "BUILD-SKILL.md",-    "CHANGELOG.md"-  ],-  "changelog": "Module 2.4.0: the panel gutter check now measures against the containing block"+  "org": "adom" }\ No newline at end of file
src/vendors.rs+50
@@ -816,7 +816,35 @@ fn pick_cheapest(agg: &AggregatedResults, query: &str) -> Option<Recommendation> ///      vendor beats the wrong part from the first) ///   3. a variant, FLAGGED as a substitution, never silent /// A family/keyword query has no exact hit and keeps the vendor-order policy.+/// The Mouser-preferred policy only recommends a distributor that ships parts+/// to you (Mouser, then DigiKey); JLCPCB stock feeds their assembly line. So a+/// substitution there must say WHICH vendors lacked the part, and must not hide+/// that JLCPCB has the exact one. 2026-10-06: TPS2553DBVR read "not available in+/// stock from the vendors that answered" while JLCPCB answered with 44,248.+fn distributor_substitution(rec: Option<Recommendation>, agg: &AggregatedResults, query: &str) -> Option<Recommendation> {+    let mut rec = rec?;+    if rec.substitution.is_none() { return Some(rec); }+    let q = norm_mpn(query);+    let mut text = format!(+        "You asked for {} but it is not in stock at Mouser or DigiKey. {} is a DIFFERENT orderable \+         part (packaging or grade variant): check its own datasheet before substituting.",+        query.trim(), rec.mpn+    );+    if let Some(j) = agg.jlcpcb.hits.iter().find(|h| h.stock > 0 && norm_mpn(&h.mpn) == q) {+        text.push_str(&format!(+            " The exact part IS in stock at JLCPCB ({} {}, {} in stock): use that if JLCPCB is assembling the board.",+            j.vendor_pn, j.mpn, j.stock+        ));+    }+    rec.substitution = Some(text);+    Some(rec)+}+ fn pick_winner(agg: &AggregatedResults, query: &str) -> Option<Recommendation> {+    distributor_substitution(pick_winner_inner(agg, query), agg, query)+}++fn pick_winner_inner(agg: &AggregatedResults, query: &str) -> Option<Recommendation> {     let long_lead = |lt: &str| lt.contains("280");     let exact_query = is_exact_query(agg, query);     let q = norm_mpn(query);@@ -928,6 +956,28 @@ mod recommendation_tests {         assert!(r.reason.contains("SUBSTITUTION"));     } +    /// 2026-10-06, live: TPS2553DBVR was out of stock at Mouser and DigiKey+    /// but in stock at JLCPCB, and the note claimed no vendor that answered had+    /// it. The distributor pick stays a distributor; the note must be accurate+    /// and must point at JLCPCB's exact part.+    #[test]+    fn substitution_names_the_distributors_and_points_at_jlcpcb_stock() {+        let mut a = agg("TPS2553DBVR", vec![+            hit(Vendor::Mouser, "TPS2553DBVR-1", 11183, "$0.90"),+            hit(Vendor::Mouser, "TPS2553DBVR", 0, "$0.85"),+        ], vec![hit(Vendor::DigiKey, "TPS2553DBVR", 0, "$0.88")]);+        let mut j = hit(Vendor::JLCPCB, "TPS2553DBVR", 44248, "$0.40");+        j.vendor_pn = "C61101".into();+        a.jlcpcb.hits = vec![j];+        let r = pick_winner(&a, &a.query).unwrap();+        assert_eq!(r.winner, Vendor::Mouser);+        assert_eq!(r.mpn, "TPS2553DBVR-1");+        let note = r.substitution.expect("still a flagged substitution");+        assert!(note.contains("not in stock at Mouser or DigiKey"), "{note}");+        assert!(!note.contains("vendors that answered"), "the false claim is gone: {note}");+        assert!(note.contains("IS in stock at JLCPCB") && note.contains("C61101") && note.contains("44248"), "{note}");+    }+     /// A family/keyword query matches no hit exactly and keeps the old     /// vendor-order behaviour, unflagged.     #[test]
uninstall.sh