← Commit history
README.md+49−123
@@ -1,161 +1,87 @@ # adom-lbr -EAGLE .lbr generator, linter, validator, and KiCad converter. Converts between KiCad `.kicad_sym` and EAGLE `.lbr` formats so both Fusion 360 and KiCad users can share component libraries.+**One part → every major EDA tool. A library generator, linter, and converter that takes KiCad sources and delivers to KiCad, Fusion 360, Altium and OrCAD — standalone Rust, no local EAGLE.** -![adom-lbr lint output](docs/screenshot-lint.png)+adom-lbr turns a KiCad `.kicad_sym` (and optional `.kicad_mod`) into a true EAGLE `.lbr` with a complete deviceset — symbol + package + pin→pad connects. Because EAGLE libraries are the universal interchange format, that one `.lbr` imports cleanly into **Fusion 360 Electronics, Altium, and OrCAD**; and for KiCad it round-trips back to a native `.kicad_sym`. It can also synthesize a placeable symbol from a footprint's pads when there's no schematic symbol, and verify a library through `service-kicad`. Standalone Rust, no Node, no gallia. -![RP2040 in Fusion 360 — generated by adom-lbr](docs/screenshot-fusion.png)+## Formats & targets -Standalone Rust — no Node, no gallia, no local EAGLE/Fusion install. Ships a-live, AI-drivable lint-report app (`adom-lbr serve`) alongside the CLI.+| Direction | Format | Used by |+|---|---|---|+| **Generate** | EAGLE `.lbr` (symbol + package + connects) | the source of truth adom-lbr builds |+| **Deliver → Fusion 360** | `.lbr` imported directly | Autodesk Fusion 360 Electronics |+| **Deliver → Altium** | `.lbr` import | Altium Designer |+| **Deliver → OrCAD** | `.lbr` import | Cadence OrCAD / Allegro |+| **Deliver → KiCad** | converted to native `.kicad_sym` | KiCad 6+ |+| **Import (reverse)** | EAGLE `.lbr` → `.kicad_sym` | bring EAGLE parts into KiCad | -## Why this exists+The **Send to** bar in the live app pushes the loaded library to whichever of those tools you're running (via the Adom Desktop bridge); the Altium/OrCAD bridges are an open contribution slot. -Fusion 360 Electronics shows "No Components" when an `.lbr` file has an empty `<packages>` section or empty `<connects/>`. The old JS generator produced these broken files. adom-lbr generates a **complete** deviceset: symbol + placeholder SMD package + full pin-to-pad connect mappings.+## The 3-column library viewer — and an interactive embed -KiCad users can import any `.lbr` back to `.kicad_sym` with `adom-lbr import`, validated locally (Rust parser).+![The Fusion-style 3-column viewer: symbol, footprint, 3D, and the pin→pad mapping table](docs/viewer3col.png) -## Install+▶ **[Open the live ADS1115 3-column viewer](https://wiki.adom.inc/api/v1/pages/john/adom-lbr/files/demo/ads1115-viewer.html)** — the exact self-contained file `adom-lbr embed` produces, served straight from this page (pan/zoom each panel; the pin→pad table is fully populated from the datasheet). It is built to sit in an `<iframe>` once the wiki enables component-page iframe embedding. -```-adompkg install adom-lbr-``` -## Quick start+`adom-lbr embed` exports a **Fusion 360-style three-column viewer** as one self-contained `.html` file: **symbol** in column 1, **footprint** in column 2, the **3D chip** in column 3 — each independently pan/zoomable — with the full **pin → pad mapping table** below, carrying each pin's **type and datasheet description**. It's built to drop straight into an `<iframe>` on a **wiki component page**: a single portable file, no server, no external assets.  ```bash-# Fusion user: KiCad symbol to EAGLE .lbr-adom-lbr generate --sym RP2040.kicad_sym -o RP2040.lbr--# KiCad user: EAGLE .lbr to KiCad symbol-adom-lbr import RP2040.lbr -o RP2040.kicad_sym-adom-lbr check RP2040.kicad_sym--# Lint any .lbr for Fusion compatibility-adom-lbr lint suspicious.lbr--# Run the live lint-report app (AI-drivable: /state, /load, /eval, /console)-adom-lbr serve --port 8784 --file RP2040.lbr+adom-lbr embed --dir <chip-dir>                    # → <mpn>-lbr-embed.html ```--## Screenshots--### RP2040 in Fusion 360 Electronics--The generated `.lbr` opens in Fusion with all 57 pins, complete deviceset, and the symbol rendering correctly. The device table shows the package and connect mappings that make Fusion recognize the component.--### Linting the old broken .lbr--The linter catches the exact bugs that cause Fusion to show "No Components":--```json-{-  "passed": false,-  "errors": [-    {"code": "empty-packages", "message": "Packages section is empty"},-    {"code": "empty-connects", "message": "Device has no pin-to-pad connect mappings"},-    {"code": "device-no-package", "message": "Device has no package attribute"}-  ]-}+```html+<iframe src="…/<mpn>-lbr-embed.html" width="100%" height="640" style="border:0"></iframe> ``` -### Round-trip into KiCad 10--The same `.lbr` imported back to `.kicad_sym`, validated locally, and installed as a KiCad 10 symbol library. Renders with all pins, body rectangle, and description.--## Dependencies+It assembles the three renders, the pin→pad connects, and the datasheet pin descriptions from a chip directory — exactly the part data adom-symbol, adom-footprint, ds2sf and chip-thumbnailer already produce. -### adompkg (auto-installed)+## The library at a glance -None — standalone Rust binary.+![The library viewer: stats and a clean lint pass](docs/lintpass.png) -### System (manual)+Load an `.lbr` and the viewer breaks it down at a glance — **symbols, packages, devicesets, pins, pads** — and re-lints it server-side. A green **Lint passed** badge means the library is ready to import into Fusion 360 Electronics with no surprises. The top bar carries the **Send to** targets (KiCad / Fusion / Altium / OrCAD). -| Dependency | Required? | Purpose |-|---|---|---|-| service-kicad | Optional | Remote validation of `.kicad_sym` via SVG export (no local KiCad install needed) |-| adom-desktop | Optional | Used by adom-symbol's Send to for Fusion 360 delivery (not yet on adompkg) |+## The linter catches what Fusion rejects -**Upstream**: adom-symbol creates the `.kicad_sym` input. chip-fetcher downloads `.lbr` files from manufacturer sites.+![A lint failure: empty pin-to-pad connects](docs/lintfail.png) -**Downstream**: generated `.lbr` opens directly in Fusion 360 Electronics. Imported `.kicad_sym` installs into KiCad via `kicad_install_library`.+This is the whole point. Fusion will silently show "No Components" or refuse to place a part when a library is subtly broken — adom-lbr catches it first. Here the deviceset has **no pin-to-pad connect mappings**, so the linter flags `empty-connects` with a plain-English reason: *"Fusion cannot use this component."* It also catches missing packages, devices with no package attribute, malformed XML, and invisible symbol bodies — each with a code and a fix. -## Features+## Generate from the command line -- Bidirectional conversion: `.kicad_sym` to `.lbr` and `.lbr` to `.kicad_sym`-- Generates complete EAGLE `.lbr` with symbol + placeholder SMD package + connect mappings-- Handles duplicate pin names (IOVDD x6, DVDD x2) with EAGLE `@N` suffix convention-- 7-check linter: empty-packages, empty-connects, device-no-package, duplicate-pin-name, connect-pad-missing, malformed-xml, no-symbol-layer-- JSON lint output for programmatic use-- `check` validates `.kicad_sym` locally (Rust parser)-- Shell completions (bash/zsh/fish)+![Generating an .lbr from KiCad sources](docs/generate.png) -## Talk to the AI+`generate` builds the whole library in one shot from a `.kicad_sym` (+ optional `.kicad_mod`), lint-checks it, and writes a native `.lbr`. The same engine powers the **Send to → Fusion/Altium/OrCAD** flow in adom-symbol and adom-footprint, so whatever you see in those apps is exactly what lands in your library. -**Generate:**-- "Generate an lbr from RP2040.kicad_sym"-- "Convert this KiCad symbol to EAGLE format"-- "Make a Fusion 360 library from this symbol"+## What it does -**Import:**-- "Import this .lbr to KiCad format"-- "Convert EAGLE library to .kicad_sym"+- **`generate`** — `.kicad_sym` (+ `.kicad_mod`) → native `.lbr`, lint-checked for Fusion compatibility.+- **`lint` / `validate`** — catch the things Fusion rejects: missing connects, incomplete devicesets, bad pad maps.+- **`import`** — EAGLE `.lbr` → KiCad `.kicad_sym`.+- **Live app** — a viewer that lints the loaded `.lbr` and shows symbols / packages / devicesets / pins / pads at a glance. -**Lint:**-- "Lint this .lbr file"-- "Check if this library will work in Fusion"-- "Why does Fusion show No Components?"+## Send to -## Skills+Fusion 360 (open the `.lbr` directly), Altium / OrCAD (download the `.lbr` + import steps; native exporters on the roadmap), KiCad (converted back to `.kicad_sym`). -| Skill | Purpose |-|---|---|-| adom-lbr | Generate, import, lint, validate, check EAGLE .lbr / KiCad .kicad_sym files |+## Open source — check it out, vibe-code it, send it back -## CLI reference+adom-lbr is MIT and **fully open**. The complete Rust source is in this page's **Files** tab — browse it, or grab `src/` + `Cargo.toml`. -| Command | Description |-|---|---|-| `generate --sym <file> [-o out] [--fp <file>] [--name <name>]` | KiCad `.kicad_sym` to EAGLE `.lbr` |-| `import <file> [-o out]` | EAGLE `.lbr` to KiCad `.kicad_sym` |-| `lint <file>` | Lint `.lbr`, output JSON with error codes |-| `validate <file>` | Validate `.lbr`, human-readable output |-| `check <file>` | Validate `.kicad_sym` locally (structure, pins, properties) |-| `serve [--port 8784] [--file <lbr>]` | Run the live AI-drivable lint-report app |-| `health` | Print version |-| `install` | Install Claude Code skill + shell completions |-| `completions <shell>` | Generate bash/zsh/fish completions |+1. **Build it.** `cargo build --release` drops a standalone binary (no Node, no gallia).+2. **Point your install at your checkout.** `adompkg link john/adom-lbr ./adom-lbr` so the `adom-lbr` you run is your local copy.+3. **Vibe-code a change.** Open the folder in Claude Code and describe what you want — a new lint rule, another export target, a smarter symbol synthesizer. The lint rules live in one readable list, easy to extend.+4. **Send it back.** Open a **pull request** on this page (the wiki reviews and merges per-repo PRs), or start a discussion thread. Good additions get folded into the shipped app. -The live app (`serve`) follows the Adom app-creator contract: `GET /state`,-`POST /load` (push raw `.lbr` XML — it's re-linted server-side), `POST /eval` +-`GET /eval/pending` + `POST /eval/:id/result`, `GET/POST /console`,-`POST /shutdown`, `GET /favicon.svg`, and best-effort HD port registration.+## Part of the Adom EDA family -## Build from source+Used by **chip-fetcher** and the Send-to flow across **adom-symbol** and **adom-footprint**; pairs with **ds2sf**. -The full source ships on the wiki app page — anyone in the community can build-it locally:+## Run it  ```bash-adompkg source adom-lbr               # downloads + unpacks the repo-cargo build --release                 # standalone — only needs Rust + cargo-cp target/release/adom-lbr ~/.local/bin/+adom-lbr generate --sym part.kicad_sym --fp part.kicad_mod --name PART --output part.lbr+adom-lbr serve --port 8784          # live linter app (AI-drivable)+adom-lbr embed --dir <chip-dir>     # Fusion-style 3-column viewer as one .html ```--No runtime dependencies — `generate`, `import`, `lint`, `validate`, and `check`-all run fully locally in Rust.--## Contribute back via pull request--adom-lbr is public, source included. To propose a change:--1. `adompkg source adom-lbr` to get the repo.-2. Make your change and `cargo build --release` to confirm it compiles.-3. Open a pull request against the wiki page for `adom-lbr`.--> **Note:** real PR support on wiki.adom.inc is in progress. Until it lands,-> send patches or a branch link to the maintainers and they will apply it.--## Wiki--https://wiki.adom.inc/apps/adom-lbr+MIT, contributions welcome.
bin/adom-lbr
⋯ 1 unchanged line ⋯
install.sh+2−12
@@ -1,14 +1,4 @@ #!/bin/bash-# install.sh for adom-lbr (app).-# Runs from the extracted module directory (~/project/adom_modules/adom-lbr/). set -euo pipefail--DIR="$(cd "$(dirname "$0")" && pwd)"-cd "$DIR"--# App install: link the binary onto PATH.-BIN_DIR="${HOME}/.local/bin"-mkdir -p "$BIN_DIR"-install -m 0755 "$DIR/bin/adom-lbr" "$BIN_DIR/adom-lbr"-echo "Installed adom-lbr -> $BIN_DIR/adom-lbr"-+DIR="$(cd "$(dirname "$0")" && pwd)"; BIN="${HOME}/.local/bin"; mkdir -p "$BIN"+install -m 0755 "$DIR/bin/adom-lbr" "$BIN/adom-lbr"; echo "Installed adom-lbr"
package.json+17−2
@@ -1,9 +1,24 @@ {   "slug": "adom-lbr",-  "version": "0.1.4",+  "version": "1.0.4",   "type": "app",-  "description": "EAGLE .lbr generator, 7-check linter, and bidirectional KiCad converter",+  "description": "Symbol, footprint and 3D side by side with the pin to pad map and datasheet descriptions, exportable as one embeddable file.",   "dependencies": {},+  "tags": [+    "eda",+    "kicad",+    "eagle",+    "lbr",+    "fusion360",+    "viewer"+  ],+  "hero": {+    "type": "billboard",+    "headline": "See the part, three ways.",+    "subhead": "Symbol, footprint and 3D side by side with the pin to pad map and datasheet descriptions, exportable as one embeddable file.",+    "screenshot": "screenshots/shot.png",+    "accent": "#00b8b1"+  },   "scripts": {     "install": "./install.sh",     "uninstall": "./uninstall.sh"
page.json+9−5
@@ -1,20 +1,23 @@ {   "slug": "adom-lbr",-  "version": "1.0.3",+  "version": "1.0.4",   "type": "app",   "description": "Symbol, footprint and 3D side by side with the pin to pad map and datasheet descriptions, exportable as one embeddable file.",   "dependencies": {},   "tags": [     "eda",-    "library",+    "kicad",     "eagle",     "lbr",     "fusion360",     "viewer"   ],   "hero": {-    "type": "image",-    "path": "adom-lbr.png"+    "type": "billboard",+    "headline": "See the part, three ways.",+    "subhead": "Symbol, footprint and 3D side by side with the pin to pad map and datasheet descriptions, exportable as one embeddable file.",+    "screenshot": "screenshots/shot.png",+    "accent": "#00b8b1"   },   "scripts": {     "install": "./install.sh",@@ -26,5 +29,6 @@     "name": "John Lauer",     "email": "[email protected]"   },-  "title": "Adom Library"+  "title": "Adom Library",+  "org": "adom" }\ No newline at end of file
src/main.rs+13−67
@@ -1,4 +1,3 @@-mod provenance; mod deliver; mod server; @@ -990,17 +989,6 @@ fn main() {                         process::exit(1);                     }                 }-                // Build the 3-column (symbol|footprint|3D) viewer from the part dir-                // (the .lbr's parent), so GET / shows the full studio, not just lint.-                if let Some(dir) = f.parent() {-                    match build_embed_html(dir) {-                        Ok((html, pins)) => {-                            eprintln!("[adom-lbr] 3-column viewer ready ({pins} pins) from {}", dir.display());-                            server::set_embed(html);-                        }-                        Err(e) => eprintln!("[adom-lbr] no 3-column viewer ({e}); serving lint card"),-                    }-                }             }             if let Err(e) = server::run(port) {                 eprintln!("ERROR: {e:#}");@@ -1074,59 +1062,34 @@ fn read_first(dir: &std::path::Path, names: &[String]) -> Option<String> { }  fn cmd_embed(dir: &std::path::Path, out: Option<PathBuf>) -> Result<(), String> {-    let mpn = dir.file_name().and_then(|s| s.to_str()).ok_or("bad --dir")?.to_string();-    let (html, pin_count) = build_embed_html(dir)?;-    let out = out.unwrap_or_else(|| dir.join(format!("{mpn}-lbr-embed.html")));-    fs::write(&out, &html).map_err(|e| format!("writing {}: {e}", out.display()))?;-    println!("OK: 3-column interactive embed ({pin_count} pins) → {}", out.display());-    Ok(())-}--/// Build the 3-column (symbol | footprint | 3D) interactive HTML for a part dir.-/// Reads pre-rendered assets, tolerating both `<mpn>-` prefixed and generic-/// (`symbol.svg`, `assets/footprint.svg`, …) names so the same renders that-/// drive the wiki page also drive the live app and the `embed` export.-pub fn build_embed_html(dir: &std::path::Path) -> Result<(String, usize), String> {     let mpn = dir.file_name().and_then(|s| s.to_str()).ok_or("bad --dir")?.to_string();     // renders-    let sym_svg = read_first(dir, &[format!("{mpn}-symbol.svg"), "symbol.svg".into(), "assets/symbol.svg".into()])+    let sym_svg = read_first(dir, &[format!("{mpn}-symbol.svg")])         .map(|s| s)         .unwrap_or_else(|| "<div class=\"ph\">no symbol render in this directory</div>".into());-    let fp_svg = read_first(dir, &[format!("{mpn}-footprint.authoritative.svg"), format!("{mpn}-footprint.svg"), "footprint.svg".into(), "assets/footprint.svg".into()])+    let fp_svg = read_first(dir, &[format!("{mpn}-footprint.authoritative.svg"), format!("{mpn}-footprint.svg")])         .unwrap_or_else(|| "<div class=\"ph\">no footprint render in this directory</div>".into());     let threed = {-        let names = [-            format!("{mpn}-3d-iso-named.png"), format!("{mpn}-3d-iso.png"), format!("{mpn}-3d-iso-lg.png"),-            "3d-iso.png".into(), "assets/3d-iso.png".into(),-        ];-        let cands = names.iter().map(|s| dir.join(s)).find(|p| p.exists());+        let cands = ["-3d-iso-named.png", "-3d-iso.png", "-3d-iso-lg.png"]+            .iter().map(|s| dir.join(format!("{mpn}{s}"))).find(|p| p.exists());         match cands.and_then(|p| fs::read(&p).ok()) {             Some(bytes) => format!("<img src=\"data:image/png;base64,{}\">", b64(&bytes)),             None => "<div class=\"ph\">no 3D render in this directory</div>".into(),         }     };-    // optional pin→pad connects from a .lbr (tolerate generic name)+    // optional pin→pad connects from a .lbr     let mut pin_to_pad: std::collections::HashMap<String, String> = std::collections::HashMap::new();-    let mut connect_order: Vec<(String, String)> = Vec::new();-    let lbr_text = read_first(dir, &[format!("{mpn}.lbr"), "library.lbr".into()])-        .or_else(|| {-            // any *.lbr in the dir-            fs::read_dir(dir).ok().and_then(|rd| rd.filter_map(|e| e.ok())-                .find(|e| e.path().extension().map(|x| x == "lbr").unwrap_or(false))-                .and_then(|e| fs::read_to_string(e.path()).ok()))-        });-    if let Some(lbr) = &lbr_text {+    if let Some(lbr) = read_first(dir, &[format!("{mpn}.lbr")]) {         if let Ok(re) = regex_lite::Regex::new(r#"<connect gate="[^"]*" pin="([^"]+)" pad="([^"]+)"/>"#) {-            for cap in re.captures_iter(lbr) {+            for cap in re.captures_iter(&lbr) {                 pin_to_pad.insert(cap[1].to_string(), cap[2].to_string());-                connect_order.push((cap[1].to_string(), cap[2].to_string()));             }         }     }     // pins + descriptions from the extracted symbol JSON     let mut pins_json = String::from("[]");     let mut pad_count = fp_svg.matches("adom-pad").count().max(0);-    if let Some(ext) = read_first(dir, &[format!("{mpn}-symbol.extracted.json"), "symbol.extracted.json".into(), "assets/symbol.extracted.json".into()]) {+    if let Some(ext) = read_first(dir, &[format!("{mpn}-symbol.extracted.json")]) {         if let Ok(v) = serde_json::from_str::<serde_json::Value>(&ext) {             if let Some(arr) = v.get("pins").and_then(|p| p.as_array()) {                 let rows: Vec<serde_json::Value> = arr.iter().map(|p| {@@ -1149,36 +1112,19 @@ pub fn build_embed_html(dir: &std::path::Path) -> Result<(String, usize), String             }         }     }-    // fallback: no extracted JSON — build the pin→pad rows straight from the .lbr connects-    if pins_json == "[]" && !connect_order.is_empty() {-        let rows: Vec<serde_json::Value> = connect_order.iter().map(|(pin, pad)| {-            serde_json::json!({ "number": pad, "name": pin, "pad": pad, "type": "Signal", "color": "#80cbc4", "desc": "" })-        }).collect();-        pad_count = pad_count.max(rows.len());-        pins_json = serde_json::to_string(&rows).unwrap_or_else(|_| "[]".into());-    }     let pin_count = serde_json::from_str::<serde_json::Value>(&pins_json).ok()         .and_then(|v| v.as_array().map(|a| a.len())).unwrap_or(0); -    // Display name: prefer the .lbr's deviceset/symbol name over the dir name.-    let display_name = lbr_text.as_deref()-        .and_then(|l| ["deviceset", "symbol", "package"].iter().find_map(|t| {-            let n = format!("<{t} ");-            let i = l.find(&n)? + n.len();-            let r = &l[i..];-            let k = r.find("name=\"")? + 6;-            let j = r[k..].find('"')? + k;-            Some(r[k..j].to_string())-        }))-        .filter(|s| !s.is_empty())-        .unwrap_or_else(|| mpn.clone());     let html = include_str!("embed.html")-        .replace("__NAME__", &esc_html(&display_name))+        .replace("__NAME__", &esc_html(&mpn))         .replace("__SYM__", &sym_svg)         .replace("__FP__", &fp_svg)         .replace("__THREED__", &threed)         .replace("__PINS__", &pins_json)         .replace("__PADN__", &pad_count.to_string())         .replace("__PINN__", &pin_count.to_string());-    Ok((html, pin_count))+    let out = out.unwrap_or_else(|| dir.join(format!("{mpn}-lbr-embed.html")));+    fs::write(&out, &html).map_err(|e| format!("writing {}: {e}", out.display()))?;+    println!("OK: 3-column interactive embed ({pin_count} pins) → {}", out.display());+    Ok(()) }
src/server.rs+1−15
@@ -28,8 +28,6 @@ pub struct AppState { }  static STATE: Mutex<Option<AppState>> = Mutex::new(None);-/// Filled 3-column (symbol | footprint | 3D) HTML, served at `/` when present.-static EMBED_HTML: Mutex<Option<String>> = Mutex::new(None); static EVAL_PENDING: Mutex<VecDeque<(u64, String)>> = Mutex::new(VecDeque::new()); static EVAL_RESULTS: Mutex<Option<HashMap<u64, Value>>> = Mutex::new(None); static CONSOLE: Mutex<Option<Vec<String>>> = Mutex::new(None);@@ -42,11 +40,6 @@ pub fn set_state(s: AppState) {     *STATE.lock().unwrap() = Some(s); } -/// Install the 3-column viewer HTML so `GET /` shows symbol|footprint|3D live.-pub fn set_embed(html: String) {-    *EMBED_HTML.lock().unwrap() = Some(html);-}- /// Parse + lint an `.lbr` (EAGLE XML) into the displayable app state. pub fn analyze_lbr(content: &str) -> AppState {     let lint = crate::lint_lbr(content);@@ -160,14 +153,7 @@ fn hd_post(body: &str) {  fn route(method: &Method, url: &str, body: &str) -> Response<std::io::Cursor<Vec<u8>>> {     match (method, url) {-        (Method::Get, "/") | (Method::Get, "/index.html") => {-            // 3-column viewer when render assets are loaded; lint card otherwise.-            match &*EMBED_HTML.lock().unwrap() {-                Some(h) => html(h),-                None => html(APP_HTML),-            }-        }-        (Method::Get, "/lint") => html(APP_HTML),+        (Method::Get, "/") | (Method::Get, "/index.html") => html(APP_HTML),         (Method::Get, "/favicon.svg") => svg(FAVICON),         (Method::Get, "/state") => json_resp(&state_json()),         (Method::Post, "/load") => {
uninstall.sh+1−5
@@ -1,7 +1,3 @@ #!/bin/bash-# uninstall.sh for adom-lbr (app). set -euo pipefail--rm -f "${HOME}/.local/bin/adom-lbr"-echo "Uninstalled adom-lbr"-+rm -f "${HOME}/.local/bin/adom-lbr"; echo "Uninstalled adom-lbr"