ecadlib 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. ecadlib-0.3.0/CHANGELOG.md +189 -0
  2. ecadlib-0.3.0/LICENSE +21 -0
  3. ecadlib-0.3.0/MANIFEST.in +6 -0
  4. ecadlib-0.3.0/NOTICE +53 -0
  5. ecadlib-0.3.0/PKG-INFO +2245 -0
  6. ecadlib-0.3.0/README.md +2191 -0
  7. ecadlib-0.3.0/ecadlib/__init__.py +3 -0
  8. ecadlib-0.3.0/ecadlib/__main__.py +5 -0
  9. ecadlib-0.3.0/ecadlib/a365_sync.py +637 -0
  10. ecadlib-0.3.0/ecadlib/agent.py +1407 -0
  11. ecadlib-0.3.0/ecadlib/agent_queue.py +780 -0
  12. ecadlib-0.3.0/ecadlib/agent_watch.py +732 -0
  13. ecadlib-0.3.0/ecadlib/altium365.py +385 -0
  14. ecadlib-0.3.0/ecadlib/altium_dblib_sync.py +530 -0
  15. ecadlib-0.3.0/ecadlib/altium_export.py +209 -0
  16. ecadlib-0.3.0/ecadlib/altium_forms.py +768 -0
  17. ecadlib-0.3.0/ecadlib/altium_lib.py +1089 -0
  18. ecadlib-0.3.0/ecadlib/altium_menu.py +1751 -0
  19. ecadlib-0.3.0/ecadlib/altium_pkg.py +396 -0
  20. ecadlib-0.3.0/ecadlib/altium_project.py +1095 -0
  21. ecadlib-0.3.0/ecadlib/app.py +1458 -0
  22. ecadlib-0.3.0/ecadlib/approvals.py +395 -0
  23. ecadlib-0.3.0/ecadlib/assets/demo_bom.csv +8 -0
  24. ecadlib-0.3.0/ecadlib/assets/kicad_action_plugin.py +607 -0
  25. ecadlib-0.3.0/ecadlib/assets/kicad_reread.py +60 -0
  26. ecadlib-0.3.0/ecadlib/assets/pcblib_template.json.gz +0 -0
  27. ecadlib-0.3.0/ecadlib/bom_inputs.py +339 -0
  28. ecadlib-0.3.0/ecadlib/bom_triage.py +519 -0
  29. ecadlib-0.3.0/ecadlib/cad_model.py +528 -0
  30. ecadlib-0.3.0/ecadlib/cfb.py +171 -0
  31. ecadlib-0.3.0/ecadlib/cli.py +185 -0
  32. ecadlib-0.3.0/ecadlib/clihelp.py +149 -0
  33. ecadlib-0.3.0/ecadlib/cliutil.py +119 -0
  34. ecadlib-0.3.0/ecadlib/completion.py +173 -0
  35. ecadlib-0.3.0/ecadlib/costs.py +276 -0
  36. ecadlib-0.3.0/ecadlib/crosscheck.py +412 -0
  37. ecadlib-0.3.0/ecadlib/datasheet.py +2168 -0
  38. ecadlib-0.3.0/ecadlib/dedupe.py +572 -0
  39. ecadlib-0.3.0/ecadlib/detect.py +170 -0
  40. ecadlib-0.3.0/ecadlib/doctor.py +450 -0
  41. ecadlib-0.3.0/ecadlib/ds_route.py +541 -0
  42. ecadlib-0.3.0/ecadlib/eagle_export.py +1409 -0
  43. ecadlib-0.3.0/ecadlib/easy_setup.py +338 -0
  44. ecadlib-0.3.0/ecadlib/easyeda_convert.py +386 -0
  45. ecadlib-0.3.0/ecadlib/easyeda_pro_export.py +972 -0
  46. ecadlib-0.3.0/ecadlib/eval/__init__.py +0 -0
  47. ecadlib-0.3.0/ecadlib/eval/baselines/kicad-v1.json +404 -0
  48. ecadlib-0.3.0/ecadlib/eval/build_set.py +299 -0
  49. ecadlib-0.3.0/ecadlib/eval/cli.py +119 -0
  50. ecadlib-0.3.0/ecadlib/eval/gate.py +358 -0
  51. ecadlib-0.3.0/ecadlib/eval/golden/demo.txt +379 -0
  52. ecadlib-0.3.0/ecadlib/eval/golden/specs.txt +3120 -0
  53. ecadlib-0.3.0/ecadlib/eval/golden/testpack.txt +463 -0
  54. ecadlib-0.3.0/ecadlib/eval/golden.py +446 -0
  55. ecadlib-0.3.0/ecadlib/eval/replay/kicad-v1.json.gz +0 -0
  56. ecadlib-0.3.0/ecadlib/eval/runner.py +456 -0
  57. ecadlib-0.3.0/ecadlib/eval/score.py +179 -0
  58. ecadlib-0.3.0/ecadlib/eval/sets/kicad-v1.json +630 -0
  59. ecadlib-0.3.0/ecadlib/firstrun.py +400 -0
  60. ecadlib-0.3.0/ecadlib/footprint_adv.py +1006 -0
  61. ecadlib-0.3.0/ecadlib/footprint_bench.py +218 -0
  62. ecadlib-0.3.0/ecadlib/footprint_check.py +562 -0
  63. ecadlib-0.3.0/ecadlib/footprint_gen.py +582 -0
  64. ecadlib-0.3.0/ecadlib/footprint_rules.py +1092 -0
  65. ecadlib-0.3.0/ecadlib/forge.py +267 -0
  66. ecadlib-0.3.0/ecadlib/fp_share.py +95 -0
  67. ecadlib-0.3.0/ecadlib/fp_tidy.py +389 -0
  68. ecadlib-0.3.0/ecadlib/fsutil.py +62 -0
  69. ecadlib-0.3.0/ecadlib/house_style.py +1051 -0
  70. ecadlib-0.3.0/ecadlib/httpcache.py +124 -0
  71. ecadlib-0.3.0/ecadlib/hub.py +1490 -0
  72. ecadlib-0.3.0/ecadlib/hub_copy.py +161 -0
  73. ecadlib-0.3.0/ecadlib/hub_tools.py +79 -0
  74. ecadlib-0.3.0/ecadlib/kicad_dblib.py +257 -0
  75. ecadlib-0.3.0/ecadlib/kicad_export.py +837 -0
  76. ecadlib-0.3.0/ecadlib/kicad_import.py +913 -0
  77. ecadlib-0.3.0/ecadlib/kicad_index.py +160 -0
  78. ecadlib-0.3.0/ecadlib/kicad_menu.py +193 -0
  79. ecadlib-0.3.0/ecadlib/kicad_pcm.py +475 -0
  80. ecadlib-0.3.0/ecadlib/launcher.py +156 -0
  81. ecadlib-0.3.0/ecadlib/librarian.py +963 -0
  82. ecadlib-0.3.0/ecadlib/lifecycle.py +691 -0
  83. ecadlib-0.3.0/ecadlib/llm/__init__.py +276 -0
  84. ecadlib-0.3.0/ecadlib/llm/cli.py +70 -0
  85. ecadlib-0.3.0/ecadlib/llm/openai_compat.py +214 -0
  86. ecadlib-0.3.0/ecadlib/llm/profiles.py +245 -0
  87. ecadlib-0.3.0/ecadlib/llm/rails.py +570 -0
  88. ecadlib-0.3.0/ecadlib/llm/run.py +126 -0
  89. ecadlib-0.3.0/ecadlib/llm/sampling.py +49 -0
  90. ecadlib-0.3.0/ecadlib/mcp_server.py +723 -0
  91. ecadlib-0.3.0/ecadlib/messages.py +419 -0
  92. ecadlib-0.3.0/ecadlib/migrate.py +407 -0
  93. ecadlib-0.3.0/ecadlib/notify.py +329 -0
  94. ecadlib-0.3.0/ecadlib/package_schema.json +1238 -0
  95. ecadlib-0.3.0/ecadlib/package_specs/CP_EIA-3216-18_Kemet-A.json +27 -0
  96. ecadlib-0.3.0/ecadlib/package_specs/C_0402_1005Metric.json +22 -0
  97. ecadlib-0.3.0/ecadlib/package_specs/C_0805_2012Metric.json +22 -0
  98. ecadlib-0.3.0/ecadlib/package_specs/DFN-8-1EP_3x3mm_P0.5mm_EP1.66x2.38mm.json +40 -0
  99. ecadlib-0.3.0/ecadlib/package_specs/D_SMA.json +27 -0
  100. ecadlib-0.3.0/ecadlib/package_specs/D_SMB.json +27 -0
  101. ecadlib-0.3.0/ecadlib/package_specs/D_SOD-123.json +43 -0
  102. ecadlib-0.3.0/ecadlib/package_specs/D_SOD-323.json +43 -0
  103. ecadlib-0.3.0/ecadlib/package_specs/LED_0603_1608Metric.json +23 -0
  104. ecadlib-0.3.0/ecadlib/package_specs/LED_0805_2012Metric.json +23 -0
  105. ecadlib-0.3.0/ecadlib/package_specs/LQFP-48_7x7mm_P0.5mm.json +31 -0
  106. ecadlib-0.3.0/ecadlib/package_specs/L_0805_2012Metric.json +22 -0
  107. ecadlib-0.3.0/ecadlib/package_specs/MSOP-8_3x3mm_P0.65mm.json +31 -0
  108. ecadlib-0.3.0/ecadlib/package_specs/QFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm.json +39 -0
  109. ecadlib-0.3.0/ecadlib/package_specs/QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm.json +37 -0
  110. ecadlib-0.3.0/ecadlib/package_specs/R_0402_1005Metric.json +22 -0
  111. ecadlib-0.3.0/ecadlib/package_specs/R_0603_1608Metric.json +22 -0
  112. ecadlib-0.3.0/ecadlib/package_specs/R_0805_2012Metric.json +22 -0
  113. ecadlib-0.3.0/ecadlib/package_specs/R_1206_3216Metric.json +22 -0
  114. ecadlib-0.3.0/ecadlib/package_specs/SOIC-16_3.9x9.9mm_P1.27mm.json +32 -0
  115. ecadlib-0.3.0/ecadlib/package_specs/SOIC-8_3.9x4.9mm_P1.27mm.json +32 -0
  116. ecadlib-0.3.0/ecadlib/package_specs/SOT-223-3_TabPin2.json +56 -0
  117. ecadlib-0.3.0/ecadlib/package_specs/SOT-23-5.json +57 -0
  118. ecadlib-0.3.0/ecadlib/package_specs/SOT-23-6.json +62 -0
  119. ecadlib-0.3.0/ecadlib/package_specs/SOT-23.json +48 -0
  120. ecadlib-0.3.0/ecadlib/package_specs/TSSOP-16_4.4x5mm_P0.65mm.json +31 -0
  121. ecadlib-0.3.0/ecadlib/package_specs/VQFN-16-1EP_3x3mm_P0.5mm_EP1.68x1.68mm.json +39 -0
  122. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-100_11.0x11.0mm_Layout10x10_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD.json +26 -0
  123. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-121_9.0x9.0mm_Layout11x11_P0.8mm_Ball0.4mm_Pad0.35mm_NSMD.json +26 -0
  124. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-144_7.0x7.0mm_Layout13x13_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD.json +29 -0
  125. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-169_11.0x11.0mm_Layout13x13_P0.8mm_Ball0.5mm_Pad0.4mm_NSMD.json +23 -0
  126. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-256_11.0x11.0mm_Layout20x20_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD.json +26 -0
  127. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-256_17.0x17.0mm_Layout16x16_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD.json +26 -0
  128. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-324_15.0x15.0mm_Layout18x18_P0.8mm_Ball0.5mm_Pad0.4mm_NSMD.json +26 -0
  129. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-36_3.396x3.466mm_Layout6x6_P0.4mm_Ball0.25mm_Pad0.2mm_NSMD.json +24 -0
  130. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-672_27.0x27.0mm_Layout26x26_P1.0mm_Ball0.6mm_Pad0.5mm_NSMD.json +32 -0
  131. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-68_5.0x5.0mm_Layout9x9_P0.5mm_Ball0.3mm_Pad0.25mm_NSMD.json +30 -0
  132. ecadlib-0.3.0/ecadlib/package_specs/advanced/BGA-90_8.0x13.0mm_Layout2x3x15_P0.8mm.json +26 -0
  133. ecadlib-0.3.0/ecadlib/package_specs/advanced/DFN-8-1EP_3x3mm_P0.5mm_EP1.65x2.38mm_ThermalVias.json +60 -0
  134. ecadlib-0.3.0/ecadlib/package_specs/advanced/Example_Custom_LPad_Slot.json +24 -0
  135. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_GH_SM04B-GHS-TB_1x04-1MP_P1.25mm_Horizontal.json +49 -0
  136. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_PH_B4B-PH-K_1x04_P2.00mm_Vertical.json +33 -0
  137. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_PH_S4B-PH-SM4-TB_1x04-1MP_P2.00mm_Horizontal.json +55 -0
  138. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_Horizontal.json +49 -0
  139. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_XH_B2B-XH-A_1x02_P2.50mm_Vertical.json +34 -0
  140. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_XH_B4B-XH-A_1x04_P2.50mm_Vertical.json +34 -0
  141. ecadlib-0.3.0/ecadlib/package_specs/advanced/JST_XH_B6B-XH-A_1x06_P2.50mm_Vertical.json +33 -0
  142. ecadlib-0.3.0/ecadlib/package_specs/advanced/LFBGA-144_10x10mm_Layout12x12_P0.8mm.json +23 -0
  143. ecadlib-0.3.0/ecadlib/package_specs/advanced/Molex_KK-254_AE-6410-04A_1x04_P2.54mm_Vertical.json +34 -0
  144. ecadlib-0.3.0/ecadlib/package_specs/advanced/Molex_PicoBlade_53398-0471_1x04-1MP_P1.25mm_Vertical.json +54 -0
  145. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P1.00mm_Vertical_SMD_Pin1Left.json +14 -0
  146. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P1.27mm_Vertical_SMD_Pin1Left.json +14 -0
  147. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P2.00mm_Vertical.json +12 -0
  148. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P2.00mm_Vertical_SMD_Pin1Left.json +14 -0
  149. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P2.54mm_Vertical.json +12 -0
  150. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1Left.json +25 -0
  151. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x05_P2.54mm_Vertical_SMD_Pin1Right.json +14 -0
  152. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_1x10_P1.00mm_Vertical.json +15 -0
  153. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x05_P1.00mm_Vertical_SMD.json +13 -0
  154. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x05_P1.27mm_Vertical.json +18 -0
  155. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x05_P1.27mm_Vertical_SMD.json +24 -0
  156. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x05_P2.00mm_Vertical_SMD.json +13 -0
  157. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x05_P2.54mm_Vertical.json +12 -0
  158. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x05_P2.54mm_Vertical_SMD.json +24 -0
  159. ecadlib-0.3.0/ecadlib/package_specs/advanced/PinHeader_2x20_P2.54mm_Vertical.json +12 -0
  160. ecadlib-0.3.0/ecadlib/package_specs/advanced/QFN-16-1EP_3x3mm_P0.5mm_EP1.75x1.75mm_ThermalVias.json +87 -0
  161. ecadlib-0.3.0/ecadlib/package_specs/advanced/UFBGA-132_7x7mm_Layout12x12_P0.5mm.json +43 -0
  162. ecadlib-0.3.0/ecadlib/package_specs/advanced/USB_C_Receptacle_HRO_TYPE-C-31-M-12.json +218 -0
  163. ecadlib-0.3.0/ecadlib/package_specs/standard.json.gz +0 -0
  164. ecadlib-0.3.0/ecadlib/parity.py +1204 -0
  165. ecadlib-0.3.0/ecadlib/parts_export.py +154 -0
  166. ecadlib-0.3.0/ecadlib/partview.py +215 -0
  167. ecadlib-0.3.0/ecadlib/plugins.py +231 -0
  168. ecadlib-0.3.0/ecadlib/providers.py +226 -0
  169. ecadlib-0.3.0/ecadlib/rebuild.py +471 -0
  170. ecadlib-0.3.0/ecadlib/release_check.py +437 -0
  171. ecadlib-0.3.0/ecadlib/reports.py +274 -0
  172. ecadlib-0.3.0/ecadlib/resolve.py +556 -0
  173. ecadlib-0.3.0/ecadlib/review_cli.py +292 -0
  174. ecadlib-0.3.0/ecadlib/rules.py +979 -0
  175. ecadlib-0.3.0/ecadlib/rules_infer.py +1205 -0
  176. ecadlib-0.3.0/ecadlib/sexpr.py +149 -0
  177. ecadlib-0.3.0/ecadlib/sheetsafe.py +65 -0
  178. ecadlib-0.3.0/ecadlib/sim_models.py +1087 -0
  179. ecadlib-0.3.0/ecadlib/sourcing.py +1161 -0
  180. ecadlib-0.3.0/ecadlib/stdparts.py +755 -0
  181. ecadlib-0.3.0/ecadlib/step_gen.py +929 -0
  182. ecadlib-0.3.0/ecadlib/symbol_layout.py +798 -0
  183. ecadlib-0.3.0/ecadlib/team.py +558 -0
  184. ecadlib-0.3.0/ecadlib/team_setup.py +288 -0
  185. ecadlib-0.3.0/ecadlib/term.py +420 -0
  186. ecadlib-0.3.0/ecadlib/term_views.py +64 -0
  187. ecadlib-0.3.0/ecadlib/testpack.py +334 -0
  188. ecadlib-0.3.0/ecadlib/ui/__init__.py +1 -0
  189. ecadlib-0.3.0/ecadlib/ui/__main__.py +3 -0
  190. ecadlib-0.3.0/ecadlib/ui/server.py +1029 -0
  191. ecadlib-0.3.0/ecadlib/ui/static/hairline.js +2 -0
  192. ecadlib-0.3.0/ecadlib/ui/static/index.html +2098 -0
  193. ecadlib-0.3.0/ecadlib/ui/static/setup.html +294 -0
  194. ecadlib-0.3.0/ecadlib/upkeep.py +717 -0
  195. ecadlib-0.3.0/ecadlib/upstream.py +573 -0
  196. ecadlib-0.3.0/ecadlib/userconfig.py +257 -0
  197. ecadlib-0.3.0/ecadlib/visual_check.py +1603 -0
  198. ecadlib-0.3.0/ecadlib/ws_status.py +203 -0
  199. ecadlib-0.3.0/ecadlib.egg-info/PKG-INFO +2245 -0
  200. ecadlib-0.3.0/ecadlib.egg-info/SOURCES.txt +416 -0
  201. ecadlib-0.3.0/ecadlib.egg-info/dependency_links.txt +1 -0
  202. ecadlib-0.3.0/ecadlib.egg-info/entry_points.txt +2 -0
  203. ecadlib-0.3.0/ecadlib.egg-info/requires.txt +31 -0
  204. ecadlib-0.3.0/ecadlib.egg-info/top_level.txt +2 -0
  205. ecadlib-0.3.0/examples/ecadlib_example_plugin/ecadlib_example_plugin/__init__.py +56 -0
  206. ecadlib-0.3.0/examples/ecadlib_example_plugin/pyproject.toml +17 -0
  207. ecadlib-0.3.0/examples/kicad_import_parts.json +18 -0
  208. ecadlib-0.3.0/examples/kicad_lib/ecadlib_demo.kicad_sym +102 -0
  209. ecadlib-0.3.0/examples/lifecycle-watch.yml +77 -0
  210. ecadlib-0.3.0/examples/sample_bom.csv +15 -0
  211. ecadlib-0.3.0/examples/symbols/CH340C.json +26 -0
  212. ecadlib-0.3.0/examples/symbols/Capacitor.json +1 -0
  213. ecadlib-0.3.0/examples/symbols/Resistor.json +1 -0
  214. ecadlib-0.3.0/examples/symbols/TPS62133RGTR.json +27 -0
  215. ecadlib-0.3.0/examples/upkeep.yml +111 -0
  216. ecadlib-0.3.0/examples/upstream-watch.yml +106 -0
  217. ecadlib-0.3.0/pyproject.toml +61 -0
  218. ecadlib-0.3.0/setup.cfg +4 -0
  219. ecadlib-0.3.0/tests/__init__.py +5 -0
  220. ecadlib-0.3.0/tests/e2e_support.py +432 -0
  221. ecadlib-0.3.0/tests/fixtures/bom_inputs/house_columns.csv +5 -0
  222. ecadlib-0.3.0/tests/fixtures/bom_inputs/house_columns.toml +2 -0
  223. ecadlib-0.3.0/tests/fixtures/bom_inputs/semicolon_utf8bom.csv +4 -0
  224. ecadlib-0.3.0/tests/fixtures/bom_inputs/tab_cp1252.txt +4 -0
  225. ecadlib-0.3.0/tests/fixtures/bom_inputs/workbook_title_rows.xlsx +0 -0
  226. ecadlib-0.3.0/tests/fixtures/e2e/anthropic/datasheet_DSPART16.json +26 -0
  227. ecadlib-0.3.0/tests/fixtures/e2e/anthropic/proof_default.json +26 -0
  228. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Capacitor_SMD.pretty/C_0402_1005Metric.kicad_mod +112 -0
  229. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Capacitor_SMD.pretty/C_0603_1608Metric.kicad_mod +112 -0
  230. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Package_QFP.pretty/LQFP-48_7x7mm_P0.5mm.kicad_mod +630 -0
  231. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Package_SO.pretty/SOIC-8_3.9x4.9mm_P1.27mm.kicad_mod +300 -0
  232. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Package_TO_SOT_SMD.pretty/SOT-23-5.kicad_mod +327 -0
  233. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Resistor_SMD.pretty/R_0402_1005Metric.kicad_mod +112 -0
  234. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-footprints/Resistor_SMD.pretty/R_0603_1608Metric.kicad_mod +112 -0
  235. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-symbols/Amplifier_Operational.kicad_symdir/LM2904.kicad_sym +277 -0
  236. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-symbols/Amplifier_Operational.kicad_symdir/LM358.kicad_sym +86 -0
  237. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-symbols/Device.kicad_symdir/C.kicad_sym +160 -0
  238. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-symbols/Device.kicad_symdir/R.kicad_sym +145 -0
  239. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-symbols/MCU_ST_STM32F1.kicad_symdir/STM32F103C8Tx.kicad_sym +87 -0
  240. ecadlib-0.3.0/tests/fixtures/e2e/kicad/kicad-symbols/MCU_ST_STM32F1.kicad_symdir/STM32F103C_8-B_Tx.kicad_sym +1091 -0
  241. ecadlib-0.3.0/tests/fixtures/easyeda/C2002.json +58 -0
  242. ecadlib-0.3.0/tests/fixtures/easyeda/C7593.json +65 -0
  243. ecadlib-0.3.0/tests/fixtures/kicad/Regulator_Linear_AMS1117.kicad_sym +238 -0
  244. ecadlib-0.3.0/tests/fixtures/kicad/USB_C_Receptacle_HRO_TYPE-C-31-M-12.kicad_mod +373 -0
  245. ecadlib-0.3.0/tests/fixtures/kicad/ecadlib_demorgan.kicad_sym +47 -0
  246. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/AMASS_XT60-M_1x02_P7.20mm_Vertical.kicad_mod +44 -0
  247. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/Banana_Cliff_FCR7350R_S16N-PC_Horizontal.kicad_mod +58 -0
  248. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/D_SMC-RM10_Universal_Handsoldering.kicad_mod +38 -0
  249. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/Infineon_PG-HSOF-8-2_ThermalVias2.kicad_mod +305 -0
  250. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/LFCSP-40-1EP_6x6mm_P0.5mm_EP4.6x4.6mm_ThermalVias.kicad_mod +183 -0
  251. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/MMCX_Molex_73415-0961_Horizontal_1.6mm-PCB.kicad_mod +68 -0
  252. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/Mounting_Wuerth_WA-SMSE-ExternalM3_H14mm_9771140360.kicad_mod +105 -0
  253. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/Nexperia_DSN0603-2_0.6x0.3mm_P0.4mm.kicad_mod +37 -0
  254. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/QFN-24-1EP_3x3mm_P0.4mm_EP1.75x1.6mm.kicad_mod +130 -0
  255. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/README.md +6 -0
  256. ecadlib-0.3.0/tests/fixtures/kicad/tool_export/SOT-89-3.kicad_mod +73 -0
  257. ecadlib-0.3.0/tests/fixtures/kicad_bench.json +60 -0
  258. ecadlib-0.3.0/tests/fixtures/kicad_golden/BGA-256_17.0x17.0mm_Layout16x16_P1.0mm_Ball0.5mm_Pad0.4mm_NSMD.kicad_mod +2015 -0
  259. ecadlib-0.3.0/tests/fixtures/kicad_golden/CP_EIA-3216-18_Kemet-A.kicad_mod +156 -0
  260. ecadlib-0.3.0/tests/fixtures/kicad_golden/CP_Radial_D5.0mm_P2.00mm.kicad_mod +1196 -0
  261. ecadlib-0.3.0/tests/fixtures/kicad_golden/C_0805_2012Metric.kicad_mod +112 -0
  262. ecadlib-0.3.0/tests/fixtures/kicad_golden/DIP-8_W7.62mm.kicad_mod +234 -0
  263. ecadlib-0.3.0/tests/fixtures/kicad_golden/D_DO-41_SOD81_P10.16mm_Horizontal.kicad_mod +217 -0
  264. ecadlib-0.3.0/tests/fixtures/kicad_golden/D_SMA.kicad_mod +265 -0
  265. ecadlib-0.3.0/tests/fixtures/kicad_golden/D_SOD-123.kicad_mod +275 -0
  266. ecadlib-0.3.0/tests/fixtures/kicad_golden/JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_Horizontal.kicad_mod +350 -0
  267. ecadlib-0.3.0/tests/fixtures/kicad_golden/LED_0603_1608Metric.kicad_mod +156 -0
  268. ecadlib-0.3.0/tests/fixtures/kicad_golden/LQFP-48_7x7mm_P0.5mm.kicad_mod +630 -0
  269. ecadlib-0.3.0/tests/fixtures/kicad_golden/L_0805_2012Metric.kicad_mod +112 -0
  270. ecadlib-0.3.0/tests/fixtures/kicad_golden/PinHeader_1x04_P2.54mm_Vertical.kicad_mod +199 -0
  271. ecadlib-0.3.0/tests/fixtures/kicad_golden/PinHeader_2x05_P2.54mm_Vertical.kicad_mod +259 -0
  272. ecadlib-0.3.0/tests/fixtures/kicad_golden/QFN-24-1EP_4x4mm_P0.5mm_EP2.6x2.6mm_ThermalVias.kicad_mod +596 -0
  273. ecadlib-0.3.0/tests/fixtures/kicad_golden/QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm.kicad_mod +595 -0
  274. ecadlib-0.3.0/tests/fixtures/kicad_golden/R_0402_1005Metric.kicad_mod +112 -0
  275. ecadlib-0.3.0/tests/fixtures/kicad_golden/R_0603_1608Metric.kicad_mod +112 -0
  276. ecadlib-0.3.0/tests/fixtures/kicad_golden/SOIC-8_3.9x4.9mm_P1.27mm.kicad_mod +300 -0
  277. ecadlib-0.3.0/tests/fixtures/kicad_golden/SOT-223-3_TabPin2.kicad_mod +251 -0
  278. ecadlib-0.3.0/tests/fixtures/kicad_golden/SOT-23-5.kicad_mod +327 -0
  279. ecadlib-0.3.0/tests/fixtures/kicad_golden/SOT-23.kicad_mod +315 -0
  280. ecadlib-0.3.0/tests/fixtures/kicad_golden/TO-220-3_Vertical.kicad_mod +198 -0
  281. ecadlib-0.3.0/tests/fixtures/kicad_golden/TSSOP-20_4.4x6.5mm_P0.65mm.kicad_mod +336 -0
  282. ecadlib-0.3.0/tests/fixtures/kicad_sch/board.kicad_pro +1 -0
  283. ecadlib-0.3.0/tests/fixtures/kicad_sch/board.kicad_sch +616 -0
  284. ecadlib-0.3.0/tests/fixtures/kicad_sch/board_netlist_kicad7.net +276 -0
  285. ecadlib-0.3.0/tests/fixtures/kicad_sch/board_netlist_kicad7.xml +340 -0
  286. ecadlib-0.3.0/tests/fixtures/kicad_sch/board_pybom_kicad7.xml +324 -0
  287. ecadlib-0.3.0/tests/fixtures/kicad_sch/sub.kicad_sch +218 -0
  288. ecadlib-0.3.0/tests/fixtures/kicad_sch/sub2/leaf.kicad_sch +109 -0
  289. ecadlib-0.3.0/tests/fixtures/sim/bridge.ibs +30 -0
  290. ecadlib-0.3.0/tests/fixtures/sim/broken.lib +3 -0
  291. ecadlib-0.3.0/tests/fixtures/sim/comment_char.ibs +11 -0
  292. ecadlib-0.3.0/tests/fixtures/sim/vendor/EEPART1.lib +11 -0
  293. ecadlib-0.3.0/tests/fixtures/sim/vendor/led_red.mod +2 -0
  294. ecadlib-0.3.0/tests/fixtures/sim/vendor/tps1234.cir +8 -0
  295. ecadlib-0.3.0/tests/fixtures/stdparts_kicad_numbers.json.gz +0 -0
  296. ecadlib-0.3.0/tests/fixtures/symbols/esp32_wroom_32.csv +40 -0
  297. ecadlib-0.3.0/tests/fixtures/symbols/ft232rl_ssop28.csv +29 -0
  298. ecadlib-0.3.0/tests/fixtures/symbols/stm32f103vet6_lqfp100.csv +101 -0
  299. ecadlib-0.3.0/tests/fixtures/term/dblib_sync_plain.txt +12 -0
  300. ecadlib-0.3.0/tests/fixtures/term/kicad_export_plain.txt +17 -0
  301. ecadlib-0.3.0/tests/fixtures/term/migrate_plain.txt +6 -0
  302. ecadlib-0.3.0/tests/fixtures/term/parity_plain.txt +11 -0
  303. ecadlib-0.3.0/tests/fixtures/term/release_check_60cols.txt +18 -0
  304. ecadlib-0.3.0/tests/fixtures/term/release_check_plain.txt +14 -0
  305. ecadlib-0.3.0/tests/fixtures/term/release_check_quiet.txt +2 -0
  306. ecadlib-0.3.0/tests/fixtures/term/release_check_tty.txt +14 -0
  307. ecadlib-0.3.0/tests/fixtures/term/release_check_verbose.txt +15 -0
  308. ecadlib-0.3.0/tests/fixtures/term/status_plain.txt +14 -0
  309. ecadlib-0.3.0/tests/fixtures/term/status_tty.txt +15 -0
  310. ecadlib-0.3.0/tests/fixtures/upgrade/r5-agent.tar.gz +0 -0
  311. ecadlib-0.3.0/tests/fixtures/upgrade/r7-stdparts.tar.gz +0 -0
  312. ecadlib-0.3.0/tests/fixtures/upgrade/v0.2.0.tar.gz +0 -0
  313. ecadlib-0.3.0/tests/fixtures/upgrade/v0.3.0.tar.gz +0 -0
  314. ecadlib-0.3.0/tests/fixtures/voice/PR.md +23 -0
  315. ecadlib-0.3.0/tests/fixtures/voice/parity.md +31 -0
  316. ecadlib-0.3.0/tests/fixtures/voice/release_check.md +27 -0
  317. ecadlib-0.3.0/tests/fixtures/voice/review.md +89 -0
  318. ecadlib-0.3.0/tests/kicad_pcbnew_job.py +206 -0
  319. ecadlib-0.3.0/tests/nexar/schema.graphql +6867 -0
  320. ecadlib-0.3.0/tests/rules_fixtures.py +204 -0
  321. ecadlib-0.3.0/tests/run_all.py +33 -0
  322. ecadlib-0.3.0/tests/test_a365_sync.py +483 -0
  323. ecadlib-0.3.0/tests/test_agent.py +379 -0
  324. ecadlib-0.3.0/tests/test_agent_e2e.py +368 -0
  325. ecadlib-0.3.0/tests/test_agent_queue.py +360 -0
  326. ecadlib-0.3.0/tests/test_agent_soak.py +813 -0
  327. ecadlib-0.3.0/tests/test_agent_watch.py +412 -0
  328. ecadlib-0.3.0/tests/test_altium_ad26_fixes.py +258 -0
  329. ecadlib-0.3.0/tests/test_altium_interop.py +192 -0
  330. ecadlib-0.3.0/tests/test_altium_menu.py +741 -0
  331. ecadlib-0.3.0/tests/test_altium_polish.py +186 -0
  332. ecadlib-0.3.0/tests/test_altium_project.py +478 -0
  333. ecadlib-0.3.0/tests/test_altium_tht.py +242 -0
  334. ecadlib-0.3.0/tests/test_approvals.py +229 -0
  335. ecadlib-0.3.0/tests/test_bom_formats.py +106 -0
  336. ecadlib-0.3.0/tests/test_cli_smoke.py +240 -0
  337. ecadlib-0.3.0/tests/test_costs.py +82 -0
  338. ecadlib-0.3.0/tests/test_crosscheck.py +409 -0
  339. ecadlib-0.3.0/tests/test_datasheet.py +343 -0
  340. ecadlib-0.3.0/tests/test_datasheet_batch.py +839 -0
  341. ecadlib-0.3.0/tests/test_dblib_sync.py +332 -0
  342. ecadlib-0.3.0/tests/test_dedupe.py +235 -0
  343. ecadlib-0.3.0/tests/test_ds_route.py +524 -0
  344. ecadlib-0.3.0/tests/test_e2e.py +487 -0
  345. ecadlib-0.3.0/tests/test_easy_setup.py +351 -0
  346. ecadlib-0.3.0/tests/test_eval.py +354 -0
  347. ecadlib-0.3.0/tests/test_evalgate.py +249 -0
  348. ecadlib-0.3.0/tests/test_firstrun.py +348 -0
  349. ecadlib-0.3.0/tests/test_footprint_review.py +366 -0
  350. ecadlib-0.3.0/tests/test_footprint_rulebook.py +516 -0
  351. ecadlib-0.3.0/tests/test_footprints.py +261 -0
  352. ecadlib-0.3.0/tests/test_footprints_advanced.py +399 -0
  353. ecadlib-0.3.0/tests/test_fp_share.py +112 -0
  354. ecadlib-0.3.0/tests/test_fp_tidy.py +134 -0
  355. ecadlib-0.3.0/tests/test_fuzz.py +332 -0
  356. ecadlib-0.3.0/tests/test_hooks.py +604 -0
  357. ecadlib-0.3.0/tests/test_house_style.py +338 -0
  358. ecadlib-0.3.0/tests/test_hub.py +459 -0
  359. ecadlib-0.3.0/tests/test_independent_review.py +173 -0
  360. ecadlib-0.3.0/tests/test_integration_io.py +363 -0
  361. ecadlib-0.3.0/tests/test_kicad_export.py +268 -0
  362. ecadlib-0.3.0/tests/test_kicad_import.py +261 -0
  363. ecadlib-0.3.0/tests/test_kicad_menu.py +102 -0
  364. ecadlib-0.3.0/tests/test_kicad_real.py +430 -0
  365. ecadlib-0.3.0/tests/test_librarian.py +478 -0
  366. ecadlib-0.3.0/tests/test_librarian_ui.py +115 -0
  367. ecadlib-0.3.0/tests/test_lifecycle.py +341 -0
  368. ecadlib-0.3.0/tests/test_llm.py +559 -0
  369. ecadlib-0.3.0/tests/test_messages.py +200 -0
  370. ecadlib-0.3.0/tests/test_offline.py +282 -0
  371. ecadlib-0.3.0/tests/test_packaging.py +96 -0
  372. ecadlib-0.3.0/tests/test_parity.py +370 -0
  373. ecadlib-0.3.0/tests/test_qol.py +396 -0
  374. ecadlib-0.3.0/tests/test_realworld_boms.py +341 -0
  375. ecadlib-0.3.0/tests/test_release_check.py +233 -0
  376. ecadlib-0.3.0/tests/test_resolve.py +256 -0
  377. ecadlib-0.3.0/tests/test_resolve_ui.py +208 -0
  378. ecadlib-0.3.0/tests/test_review_altium.py +131 -0
  379. ecadlib-0.3.0/tests/test_review_core.py +111 -0
  380. ecadlib-0.3.0/tests/test_review_full_agent.py +186 -0
  381. ecadlib-0.3.0/tests/test_review_full_altiumfiles.py +86 -0
  382. ecadlib-0.3.0/tests/test_review_full_altiumint.py +64 -0
  383. ecadlib-0.3.0/tests/test_review_full_followup.py +103 -0
  384. ecadlib-0.3.0/tests/test_review_full_footprints.py +72 -0
  385. ecadlib-0.3.0/tests/test_review_full_frontends.py +117 -0
  386. ecadlib-0.3.0/tests/test_review_full_kicad.py +121 -0
  387. ecadlib-0.3.0/tests/test_review_full_llm.py +129 -0
  388. ecadlib-0.3.0/tests/test_review_full_pipeline.py +181 -0
  389. ecadlib-0.3.0/tests/test_review_full_queue_race.py +69 -0
  390. ecadlib-0.3.0/tests/test_review_rvh.py +333 -0
  391. ecadlib-0.3.0/tests/test_review_rvj.py +190 -0
  392. ecadlib-0.3.0/tests/test_review_tool_exports.py +31 -0
  393. ecadlib-0.3.0/tests/test_review_ui.py +261 -0
  394. ecadlib-0.3.0/tests/test_rules.py +286 -0
  395. ecadlib-0.3.0/tests/test_rules_infer.py +252 -0
  396. ecadlib-0.3.0/tests/test_sim_models.py +445 -0
  397. ecadlib-0.3.0/tests/test_site.py +17 -0
  398. ecadlib-0.3.0/tests/test_sourcing.py +524 -0
  399. ecadlib-0.3.0/tests/test_stdparts.py +255 -0
  400. ecadlib-0.3.0/tests/test_step_gen.py +224 -0
  401. ecadlib-0.3.0/tests/test_symbol_layout.py +438 -0
  402. ecadlib-0.3.0/tests/test_team.py +748 -0
  403. ecadlib-0.3.0/tests/test_team_history.py +135 -0
  404. ecadlib-0.3.0/tests/test_team_setup.py +231 -0
  405. ecadlib-0.3.0/tests/test_term.py +335 -0
  406. ecadlib-0.3.0/tests/test_testpack.py +159 -0
  407. ecadlib-0.3.0/tests/test_tool_exports.py +380 -0
  408. ecadlib-0.3.0/tests/test_tool_packages.py +529 -0
  409. ecadlib-0.3.0/tests/test_ui.py +218 -0
  410. ecadlib-0.3.0/tests/test_ui_browser.py +291 -0
  411. ecadlib-0.3.0/tests/test_ui_voice.py +221 -0
  412. ecadlib-0.3.0/tests/test_upgrade.py +472 -0
  413. ecadlib-0.3.0/tests/test_upkeep.py +459 -0
  414. ecadlib-0.3.0/tests/test_upstream.py +354 -0
  415. ecadlib-0.3.0/tests/test_visual_check.py +538 -0
  416. ecadlib-0.3.0/tests/ui_browser.js +307 -0
  417. ecadlib-0.3.0/tests/ui_fixture.py +124 -0
  418. ecadlib-0.3.0/tests/upgrade_fixtures.py +127 -0
@@ -0,0 +1,189 @@
1
+ # Changelog
2
+
3
+ All notable changes to ecadlib are recorded here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the
5
+ project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Until 1.0.0,
6
+ a minor release may change command-line options and file formats.
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2026-10-17
11
+
12
+ ### Added
13
+
14
+ - KiCad: the ecadlib window in the PCB editor (`ecadlib/assets/kicad_action_plugin.py`, `ecadlib/kicad_menu.py`): an ecadlib button in the top toolbar and Tools > External Plugins entries open a dark window like the Altium dialog with Add part from MPN (live lookup, then the footprint placed), Check project BOM (counts per kind, Later / Fill the library now, the report on request) and Open review queue; it does not block KiCad. `ecadlib kicad-menu run-job` does the work with the Altium menu's actions and a KiCad library as the target; `ecadlib kicad-menu check-bom "%I"` hooks into the schematic editor's Generate BOM. The plugin package (`kicad-pcm --plugin`, setup page's Add to KiCad) gains the toolbar icon. Fixed: the plugin ran ecadlib in the project folder, where `python -m ecadlib` imported the project's `ecadlib/` library folder. Tried in KiCad 7.0.11.
15
+ - Altium menu: the ecadlib dialog (`ecadlib/altium_forms.py`, `ecadlib_dialog.pas` + `.dfm`): Check project BOM, Add part from MPN and Fill the library run in one dark dialog like Altium's own, with the live lookup, a progress line, a count with one row per kind and Later / Fill the library now, then reinstall the library; no browser unless a part needs a person (review queue) or you ask for the full report. `run-job` writes `progress.ini` and the result's `big` / `row1..` lines and has an `open` action for reports in the workspace. `dialogs=0` keeps the plain message boxes. Run in Altium Designer 26.10 on a real PC.
16
+ - Symbol house rule for every IC (`symbol_layout`, `[symbols] power_side`): inputs left, outputs right, power on top, ground on the bottom (`"top"`, the default), or the top and bottom edges empty with power at the top of the left side and ground at its bottom (`"left"`). Applies from 1 pin (`layout_pins` default was 40), to EasyEDA IC symbols, and to KiCad library symbols whose pin text would overlap in Altium. New groups `other_in` / `other_out` from names (IN+, TRIG, THRES, FB / OUT, Q, DISCH, PGOOD, SW) and pin types, `other` for pins with no direction (moved between sides to keep the body square); `power_out` (VOUT, VCAP) now goes right. `symbol_layout.text_problems` finds pin names or numbers that overlap or run out of the body; `check` and `ecadlib symbol` report them. Found on the NE555DR from EasyEDA in Altium, whose VCC / RST / GND names ran into the side pin names.
17
+ - `fp_tidy.py`: converted EasyEDA footprints are tidied to the rule book: the reference on silk above the part and `${REFERENCE}` on fab, rounded-rectangle SMD pads (copper size and place unchanged), silk under the body removed, a pin-1 dot beside pad 1 when silk shows none, the fab pin-1 corner chamfered, the value moved below the part, silk specks and doubled segments removed, silk widths set to 0.12 mm and an outline that crowds a pad row pulled in to 0.2 mm clearance. Each change is noted on the part. The EasyEDA converter now keeps silk arcs (pin-1 notches) and draws the body region (layer 99) as the fab outline.
18
+ - Symbols: a dual or quad part's pins go one channel at a time (1IN-, 1IN+, 2IN-, 2IN+).
19
+ - Librarian: a converted footprint is named after its .kicad_mod file (EasyEDA's package name made the rule book report "footprint name is not its file name"), and an LCSC number ecadlib found itself fills Supplier 1 / Supplier Part Number 1 and the LCSC link, as one from the BOM does.
20
+ - `ecadlib eagle-export` (`eagle_export.py`) and `ecadlib easyeda-export` (`easyeda_pro_export.py`): the library as an Autodesk Fusion Electronics / EAGLE `.lbr` and an EasyEDA Pro `.elibz` (symbols, footprints, devices with their fields; STEP models beside them), built from `kicad-export`. Every footprint is read back and compared pad by pad with its KiCad original, mask and paste also as layer areas, symbols pin by pin, and through KiCad's own importers where pcbnew is found. Release-check rules `[release] eagle` / `easyeda` (`hold` / `warn` / `off`, default `warn`), web UI buttons, `POST /api/export/tool`, Workspace and MCP `tool_export`. Surveyed on 1,927 KiCad library footprints; `tests/test_tool_exports.py`. Each export writes `INSTALL.md` (import steps, STEP model per footprint, differences) and one hand-off zip; the web UI and MCP return it; Fusion parts carry Fusion's standard attributes (PACKAGE, CATEGORY_L1/L2, VENDOR/VPN) and passives a user value; `ecadlib testpack` exports both with a checklist section for each tool. Pin name / number visibility is carried and compared (resistor and capacitor pins were read as hidden).
21
+ - Your library across tools (`ecadlib/hub.py`): a **Your library** page in the web UI (shortcut `l`), `ecadlib hub`, Workspace `hub` / `hub_part` / `hub_fix` / `hub_build_bom`, `GET /api/hub`, `GET /api/hub/part`, `POST /api/hub/fix` (librarian), MCP `library_hub` / `library_hub_part`. Every part once, from your libraries (`--lib` and `[hub] libraries`: .SchLib, .PcbLib, .DbLib, .kicad_sym, .pretty, .kicad_dbl, Altium 365 lists) and ecadlib's plans, with a cell per tool (Altium, Altium 365, KiCad, Fusion, EasyEDA): missing, same, different or behind, compared on pads, pins and value. Last changed and by whom per part and per copy (git commit, Altium 365 revision, file date plus the web-app action), history of added / changed / removed copies in `<workspace>/hub/history.jsonl`, a part page with footprint pictures, pinout sketch, sources, release check, sign-off, where-used (`[hub] projects`), lifecycle and history, and fix buttons (make the KiCad version, Altium 365 dry run, build a library-only part with ecadlib). `hub.register_tool()` lets other tools' readers fill their columns. New `[hub]` rules section. The page opens on a tile per tool (parts, libraries, last change and by whom, what it lacks) that shows your library as it is in that tool, next to Compare all. Parts copy between Altium and KiCad (`POST /api/hub/copy`, librarian; `ecadlib hub --copy-to`; MCP `library_hub_copy`) into `<workspace>/hub/library`, and into a KiCad or Altium project from `[hub] projects` (its lib tables or .PrjPcb), with a Project filter using KiCad and Altium where-used.
22
+ - Web UI, more fluid and human-friendly: first-visit welcome with *Try it with a sample BOM* (`POST /api/demo`) and the setup check; drop a BOM anywhere; live per-part progress lines and a Stop button for long jobs (`POST /api/job/cancel`); parts as cards with a footprint picture and chips (status, cross-check, KiCad / Altium, cost and model); a side panel per part with the held reason and next step in plain words (`ecadlib/messages.py`), both values of a disagreement and the datasheet page; Undo for approve / reject / release anyway; search, filters, keyboard shortcuts (`?`); skip link, labels, contrast checked in both themes, reduced motion. `ecadlib/partview.py`, Workspace `library_parts` / `demo_bom`, `GET /api/parts`, MCP `library_parts`.
23
+ - The terminal, human-friendly (`ecadlib/term.py`): one status vocabulary (✓ ready, ! held, ○ waiting for sign-off), colour and symbols only on a terminal (never with `NO_COLOR`, `--json` or in CI), tables that fit the width, a summary block with what was written and the next commands, a live progress line for `librarian`, "waiting on X (12 s)" for slow network sources and model calls, and `-q` / `-v` on every command; used by `demo`, `init`, `doctor`, `librarian`, `triage`, `release-check`, `status`, `kicad-export`, `dblib-sync`, `altium-pkg`, `parity`, `eval gate`, `migrate`, `rebuild`, `agent status`, `queue list`. New `ecadlib review`: held parts one at a time with the reason in plain words; pick a candidate, release anyway or open the datasheet (never asks with `--yes` or when piped). `--json` output is unchanged; `ecadlib agent status` prints a summary and takes `--json` for the old JSON.
24
+ - One voice for everything people read (`docs/ui-voice.md`, `ecadlib/messages.py`): every held reason (release check, footprint check, KiCad/Altium match, cross-check, datasheet reader, standard parts, sign-off, library agent) has a code, a plain sentence and a next step (`messages.held(code, **values)`, `messages.explain(raw_reason)`); plans and `--json` keep their machine strings. Reports rewritten outcome first, grouped by what to do: `review.md` plus a new `review.html` (web UI look, light/dark), `release_check.md`, datasheet `*.review.md`, parity, eval `report.md`, test pack `CHECKLIST.md`, agent PR body and notifications, `ecadlib doctor`, Altium menu and KiCad plugin dialogs, init questions, MCP errors. Workspace `librarian_run` rows gain `word`/`says`, `held_parts` gains `reasons`; kicad-export `skipped` entries gain `says`. Tests: `tests/test_messages.py` (a new reason without a sentence fails), `tests/test_ui_voice.py` (snapshots, no internal names or absolute paths).
25
+ - `ecadlib style` (`house_style.py`): teach ecadlib your house style. `learn --from DIR` learns description patterns, value formats, common parameters, active-low pin notation and example parts on top of what `init` infers, and writes `house_style.json`. `direct "TEXT"` adds written direction. `learn --ai` has any configured model (`[style]`, else `[ai]`) write a guide and turn the direction into validated `ecadlib.toml` settings (`--write-rules`). The librarian adapts new parts by code when a profile exists (`[style] apply = "auto"|"off"`). `check` / `apply [--ai]` work on a plan; a model's rewording is rejected when it adds a number, and identity fields are never shown. Help scales with the model's tier. `export-dataset` writes chat-format JSONL for fine-tuning your own model. UI card, Workspace methods, MCP tools `learn_house_style`, `house_style`, `check_house_style`, `apply_house_style`. Guide: `docs/house-style.md`.
26
+ - Footprint rule book (`docs/footprint-rulebook.md`, `ecadlib/footprint_rules.py`): what a footprint must contain and look like, drawn from KLC F1-F9, KiCad's official library, IPC-7351 naming, Altium's IPC wizard layer conventions and Bogatin's public guidance. New rules `name` (KLC and IPC-7351 names checked against pin count, EP / MP count, pitch, body, chip codes, BGA grid and pad), `meta`, `attr`, `origin`, `layers`, `padshape`, `tht`, `vias`, `text`, `model`, `margin`, `polarity`, `graphics`, `connect`, `pinmap` (reversed diode / LED / polarized capacitor) and `silktext` (silkscreen text 0.5-2.0 mm, not over pads, the designator not over the body; also on the `.Designator` the Altium export writes and on the PcbLib read back, after the first real Altium run showed `.Designator` over an EasyEDA part), plus `check_pcblib` for the Altium side. `ecadlib check` runs the whole book (`--summary` for a library, `--geometry-only` for the old checks); the release check holds ecadlib's own and converted parts for `name`, `layers`, `attr`, `tht`, `vias` and `silktext` errors and every part for `pinmap`. Calibrated on 4,976 official KiCad footprints (errors on 0.5 %, all read); 24 of them are golden test fixtures.
27
+
28
+ - `ecadlib eval gate` (`ecadlib/eval/gate.py`): CI accuracy gate (own job `accuracy-gate`): the 331-case eval set offline with standard parts and a committed synthetic replay pack (`eval/replay/kicad-v1.json.gz`), checked against `eval/baselines/kicad-v1.json` (327/331); fails when a family drops more than 1 % or a passing case breaks; about 20 s. `ecadlib eval golden` (`ecadlib/eval/golden.py`): normalised fingerprints of the KiCad and Altium files for the testpack, the demo and 96 package specs (`eval/golden/*.txt`, no uuids, GUIDs or dates), checked by `tests/test_evalgate.py`; `--update` regenerates them for one reviewed commit.
29
+ - Updates never break a library: every file ecadlib writes and reads back has a schema version and a migration registry (`ecadlib/migrate.py`); older files are migrated (on disk only after a backup in `.ecadlib_backup/`), files from a newer ecadlib are refused with one "made by ecadlib X.Y; upgrade ecadlib" line. `ecadlib migrate [--check] [--dry-run]`, a doctor line, Workspace `file_formats`, MCP `file_formats`. `librarian_state.json` is now v2 (footprint name + geometry hash). Proved with sample workspaces made by v0.2.0, v0.3.0 and two later commits (`tests/fixtures/upgrade/`). The librarian writes `library.lock.json` (per part: fetched inputs with hashes, datasheet PDF / model / prompt version, ecadlib version, rules hash, output hashes); `ecadlib rebuild --check` rebuilds offline and reports drift (Workspace `rebuild_check`, MCP `rebuild_check`).
30
+
31
+ - Datasheet cross-checks (`crosscheck.py`): every footprint read from a datasheet is checked against the standard package table or an independent second read of only the critical numbers (reversed pages, cached, costed in `cost.jsonl`). A disagreement holds the part with both values in the review. Rules `[datasheet] cross_check = "auto"|"always"|"off"` (default `auto`) and `cross_check_model`. `[ai] temperature = "auto"` sends temperature 0 and a seed only to models that accept it, so default Claude requests are unchanged. Eval `--repeat` / `consistency` metric. Workspace + MCP `cross_checks`. Offline tests only.
32
+ - `ecadlib altium-menu` (`altium_menu.py`): an "ecadlib" menu inside Altium Designer, a DelphiScript script project with Add part from MPN, Check this project BOM and Open review queue; each entry runs `ecadlib altium-menu run-job` hidden through a request.ini / result.ini exchange, reinstalls the DbLib (or points at Altium 365), and an optional `.DXPPrf` adds the menu. Workspace `altium_menu` and MCP tool of the same name. The .pas is checked offline against a cited API allow-list; never run inside Altium.
33
+ - `ecadlib parity` (`parity.py`): reads back the KiCad and the Altium library of every part and compares pads, drills, paste / mask, exposed pad, courtyard, 3D model, pins, pin-to-pad mapping, key fields and the `.kicad_dbl` vs DbLib rows, with explicit tolerances; the release check (librarian, agent) holds a mismatched part with a per-field diff (`[release] parity = "hold" | "warn" | "off"`); `parity survey` covers every generator and standard-table footprint; run by `testpack` and `demo`; Workspace `parity` and MCP tool.
34
+ - `ecadlib kicad-pcm` (`kicad_pcm.py`): the library as a KiCad Plugin and Content Manager package (zip for "Install from File...", optional `repository.json`/`packages.json` with `--base-url`), metadata checked against KiCad's PCM schema; symbols point at `PCM_<lib>`, 3D models at `${KICADn_3RD_PARTY}`; `--kicad 7` writes KiCad 7 files; `--plugin` packages a pcbnew action plugin "ecadlib: add part". `ecadlib altium-pkg` (`altium_pkg.py`): Altium hand-off folder with a `.LibPkg` (compile to IntLib), a DelphiScript install project and a relative DbLib. Workspace `tool_packages` and MCP tool of the same name. Installed and checked in real KiCad 7.0.11; not run in Altium.
35
+
36
+ - First run (`ecadlib/firstrun.py`, `ecadlib/clihelp.py`): `ecadlib demo` builds a small library from a bundled BOM offline with no keys (1 s here); `ecadlib init` asks for the tool, library folders, workspace and sources (`--yes` / `--tool` / `--lib` / `--workspace` / `--sources`), writes them to `[setup]`, then runs the doctor and prints the next commands; `[setup] libs / workspace` are the default `--lib` / `--workspace`. Every command and subcommand has a description and examples in `-h`; `librarian` and `kicad-export` take `--json`; the librarian prints progress and a `note:`/`fix:` line when a source was unreachable or the datasheet reader has no key; a missing `--lib` folder, an unwritable `-o`, a BOM without recognised columns or without rows give one line and a fix.
37
+ - Bring your own model (`ecadlib/llm/`, README section 33): `[ai]` provider `anthropic` (default, requests unchanged) or `openai-compatible` (OpenAI, OpenRouter, Gemini, Ollama, LM Studio, vLLM, llama.cpp presets; keys from env vars only), capability profiles (table + endpoint detection + `[ai.profiles]`), guide rails in layers (support for every model incl. one feedback retry with the checks' exact errors; capability and tier-scaled guidance: JSON repair, examples, split steps, hold on doubt), mixed ladders (`name:model`), `ecadlib ai show|rails`, doctor `ai model` line, `eval run --provider/--base-url/--assist`. Fixed: `ecadlib eval compare` crashed printing its text.
38
+
39
+ - `ecadlib testpack --out DIR`: a 6-part Altium + KiCad test pack (0603 R, SOT-23, SOIC-8, VQFN-16 with exposed pad, USB-C, THT header) built offline through the librarian and every exporter, with a `CHECKLIST.md` of what to open in Altium Designer, Altium 365 and KiCad and what each part must look like (its geometry claims are checked by `tests/test_testpack.py`).
40
+ - `tests/test_e2e.py`: the golden path through the real CLI in subprocesses from an empty folder (init, Altium project BOM, librarian on a KiCad schematic / Altium BOM / .xlsx with recorded KiCad, EasyEDA and Claude answers, release check, KiCad / Altium / Altium 365 exports), each output loaded by its tool (KiCad 7 kicad-cli + pcbnew DRC through the written library tables; pyaltiumlib and ecadlib's reader; a fake Nexar for the release), `ecadlib agent run` against a bare git remote with PR / queue / approve / push, `ecadlib mcp` over stdio, a second and third run (no file changes) and a killed librarian (recovers). The datasheet reader honours `ANTHROPIC_BASE_URL` (gateways, proxies, local test servers).
41
+ - Cheaper datasheet reads (`ecadlib/ds_route.py`): every PDF is cut to the pages for this part's package (drawing, land pattern, pin table, ordering row; `[datasheet] page_budget = 6`) and widened when the answer is incomplete; `[datasheet] route = "ladder"` starts each part on Haiku 5.5 / Sonnet 5.5 / Opus 5.5 by package family, pins and pages and escalates when datasheet's checks fail (default stays one model, Opus 5.5); failed cheap answers are cached as failed steps, never as the answer; tokens and USD per answer in `<out>/datasheet/cost.jsonl`, the librarian review, `ecadlib status` and the per-model estimate; `ecadlib datasheet pages` shows what a read would send.
42
+ - `ecadlib eval`: an accuracy test set and scorer. `ecadlib/eval/sets/kicad-v1.json` holds 331 real parts in 11 families (chip passives, SOT, SOIC, TSSOP/MSOP, QFN/DFN, QFP, BGA/CSP, diodes, power SMD, THT, connectors) with MPN, manufacturer, package, datasheet link, the KiCad footprint it should match and the symbol's pins, each recording where it came from (`ecadlib eval build-set` rebuilds it from KiCad library checkouts). `eval run` sends the set through the librarian with any sources and scores each part (pad count, pin 1, pitch, pads, courtyard, symbol pins and names): pass rate overall / per family / per source, tokens and USD per part, wall time; `--record` / `--replay` save and re-score Claude's answers without paying; `eval compare A B` shows the flips. `footprint-bench`'s `numbers()` no longer fails on an SMD pad with only a drill offset.
43
+
44
+ - Standard parts without Claude (`ecadlib stdparts`, librarian source `standard`, now in the default `[sources] order` between easyeda and datasheet): chip passives (size from the footprint, value/description or MPN: Yageo, Murata, Samsung, KEMET, TDK, Panasonic, Vishay, Stackpole, Bourns, KOA, Uni-Royal) and 615 named standard packages (SOT/SOD/SMA-SMC/MELF/DPAK/TO-220/TO-92, SOIC/TSSOP/MSOP/SSOP/QFN/DFN/QFP with the size in the name) are built offline, each checked against KiCad's official footprint (`stdparts bench`); R/C/L/LED/diode symbols, and BJT/MOSFET/LDO pinouts for listed MPN families (review note). Ambiguous names resolve to nothing; it never runs ahead of the KiCad library and never replaces a half already found. `footprint_gen` honours a spec's `ipc_family` (KiCad's force_small_pitch).
45
+ - Library agent watch step (`ecadlib agent-watch [--dry-run]`, MCP `agent_watch_scan`, `[agent.watch]` rules): new, changed and removed parts in watched BOM files, folders (including web UI uploads), Altium projects and Altium 365 projects (Nexar queries schema-checked, not yet run live), with state in `agent/watch_state.json`.
46
+ - Library agent (`ecadlib agent run|serve|status|approve|reject|push`): watches projects, builds and proves new parts through the librarian, opens one GitHub PR per review batch with before/after pictures (or writes the batch to `agent/batches/` without a token or git), pushes approved parts to Altium 365, turns upkeep findings into queue items; `[agent]` rules (off by default) and an optional `agent` Docker Compose profile.
47
+ - Library agent review queue (`ecadlib/agent_queue.py`, `ecadlib queue`): a durable, locked work-item store under `<workspace>/agent/queue/` with a state machine, history, batches and per-part dedupe. A **Review queue** page in the web UI shows the change, the build, the proof findings and before/after pictures, with Approve (approver role), Reject and Rebuild (librarian role); approvals are also recorded through `approvals.py`. MCP tools: `agent_queue_list`, `agent_queue_get`, `agent_queue_decide`.
48
+ - Visual proof (`ecadlib visual-check`, `Workspace.visual_check`, MCP `visual_check`, `[agent.proof]` rules): top-view footprint and symbol PNGs (pin 1, pitch, dimensions, grid, BGA maps) next to the datasheet pages, one Claude call with a JSON-schema verdict checked strictly (pass / doubt / fail / skipped without a key), cached by content hash, with a cost cap.
49
+ - Command-line quality of life: `ecadlib doctor [--json]` (Python, packages, tools, API key names, `ecadlib.toml` errors with file:line, workspace, library folders; exit 1 on any FAIL; MCP `doctor`), `ecadlib status [--json]` (read-only workspace summary; `Workspace.status`, MCP `workspace_status`), `ecadlib completion bash|zsh|fish` (generated from the argparse tree), one-line errors with a hint instead of tracebacks (`--debug` / `ECADLIB_DEBUG=1` for the traceback), `ECADLIB_LIB` / `ECADLIB_WORKSPACE` / `ECADLIB_CONFIG` as defaults for `--lib` / `--workspace` / the rules file, and `--json` on `triage`, `release-check` and `approve ... status`.
50
+ - Connections to other tools (`ecadlib/notify.py`, `ecadlib/forge.py`, `ecadlib/plugins.py`): `[notify]` webhooks (Slack, Microsoft Teams workflow, generic JSON) for agent batches ready, held parts, upkeep changes and EOL/NRND, with URLs and tokens only from named environment variables, retries with backoff and no effect on the run when a post fails (`ecadlib notify show|test`); GitLab merge requests (REST v4, self-hosted base URL) for the agent's review batches and `ecadlib upkeep --gitlab issue|pr`, picked by the origin remote or `[agent] git_host`; part-source and exporter plugins through the `ecadlib.providers` / `ecadlib.exporters` entry points, `[providers] order`, `ecadlib plugins list|export`, MCP `list_plugins` / `plugin_export`, and an example plugin in `examples/ecadlib_example_plugin/`.
51
+ - Integration inputs and outputs (`bom_inputs.py`, `kicad_dblib.py`, `parts_export.py`): BOMs straight from KiCad schematics (hierarchical sheets, DNP, exclude-from-BOM, multi-unit) and KiCad XML / S-expression netlists, checked against KiCad 7.0.11's own netlist export; `.xlsx` read without openpyxl; `[bom] columns` takes a list of house names and helps find the header row; `ecadlib kicad-dblib` writes a KiCad 7+ database library (`.kicad_dbl` over ODBC to SQLite, one table per category, a `Database` row in `sym-lib-table`); `ecadlib export-parts --format csv|json|xlsx` writes the parts table with stable columns for PLM / ERP imports. Workspace methods and MCP tools `export_parts` and `kicad_dblib`.
52
+
53
+ - Web UI: a **Past triages** list that any signed-in user (viewer and up), and local mode, can open read-only (`GET /api/triage/history`, `/api/triage/result`, MCP `triage_history`). Each upload is now stored in its own folder, `uploads/<time>-<random>/<name>`, so BOMs with the same file name no longer overwrite each other, or each other's reports.
54
+ - Resolve held parts: work through the release check's held items and record how each was fixed.
55
+ - KiCad export: write the library's symbols, footprints and 3D models as KiCad libraries.
56
+ - Altium DbLib/SVNDbLib sync: keep a database library in step with the living library.
57
+ - STEP generation: build simple 3D bodies for generated footprints.
58
+ - Sourcing and alternates: look up stock and suggest drop-in alternates per BOM line.
59
+ - Approvals and dedupe: sign off parts before release and merge duplicate library entries.
60
+ - Weekly upkeep (`ecadlib upkeep`): lifecycle, KiCad upstream, price/stock and Altium 365 drift in one run,
61
+ only new changes reported, one rolling GitHub issue or a PR with applied KiCad reconversions; `examples/upkeep.yml`.
62
+ - Live datasheet reader (`ecadlib datasheet batch|estimate PLAN|BOM`, `librarian --datasheet-batch`, MCP `datasheet_batch`/`datasheet_estimate`): a whole BOM's missing symbols and footprints from datasheets in one Message Batch, with datasheet download and PDF checks, page selection, retries and backoff, a request log without the key, a cost estimate and cap, a result cache, and a self-check. All results are held as `verify`.
63
+ - Run the team server for a team in one command: `python3 -m ecadlib team setup` (or `scripts/team-setup.sh`) writes `.env` (no secrets), builds the image, creates the first admin in the data volume without writing the password anywhere, and starts ecadlib behind Caddy (Let's Encrypt for a public name, Caddy's internal CA for an IP/LAN name) or with your own certificate (`docker-compose.own-cert.yml`); `Dockerfile` (non-root, `/data` volume, health check), `docker-compose.yml` with `--trusted-proxy` pinned to Caddy's fixed address, and a `docker` workflow that runs the stack on PRs and publishes to ghcr.io only on `v*` tags.
64
+ - Team server (`ecadlib ui --team`, `ecadlib team add-user|set-role|reset-password|remove|list`): sign-in with scrypt-hashed passwords, viewer/librarian/approver/admin roles enforced per route, CSRF tokens, lockout, built-in TLS (`--cert/--key`) or `--allow-http` behind a proxy, optional trusted SSO proxy header, approvals signed as the signed-in user, per-user jobs, `team_audit.jsonl`, and a users page. Local mode is unchanged.
65
+ - Harder footprints: BGA/LGA/CSP grids (JEDEC row letters, depopulated balls or a ball map, IPC-7351B land from the ball size, NSMD/SMD), pin headers, connectors and odd shapes from a datasheet `pad_table` (mm/mil/in, y up/down, bottom views, datum origins; polygon pads, slots, NPTH, mounting/shield pads, split paste, thermal vias, keep-outs, union courtyard) with consistency checks; BGA and connector rules in `ecadlib check`; BGA/connector STEP models; `ecadlib footprint-bench` compares 20 parts pad by pad with KiCad's library.
66
+ - Simulation models (`ecadlib sim-models`): built-in R/C/L SPICE models, vendor SPICE/IBIS models found and parsed, pin maps checked, attached as Altium SIM/SI links and KiCad `Sim.*` fields.
67
+ - Tidy big-chip symbols (`ecadlib symbol`, `ecadlib/symbol_layout.py`): pins grouped by function (power top, ground bottom, control/debug left, ports right), ports in order, same-name power pins stacked, optional multi-part split, SVG preview; used for datasheet and EasyEDA symbols of 40+ pins, `[symbols]` rules section.
68
+
69
+ ### Changed
70
+
71
+ - Web UI redesign in the Hairline style (github.com/lucasmarkes/hairline): one ground colour, 1px lines, mono labels, status shown as a toned dot on a hairline pill, and motion that eases out (cards and rows rise in, a sliding underline in the step bar, a sweeping progress line), all held still under `prefers-reduced-motion`. Animated line figures from Hairline: a chip seating on its footprint in the BOM drop zone (`scripts/hairline/seat.js`, our own), a conveyor while a BOM check or the librarian runs, and empty sieves and drawers for empty lists. The bundle is `ecadlib/ui/static/hairline.js` (25 KB, served at `/hairline.js`), rebuilt by `scripts/build_ui_figures.sh`.
72
+ - Footprint preview looks like Altium's PCB editor: black board on a 0.5 / 2.5 mm grid, Top Layer pads in red with their numbers, through-hole pads in Multi-Layer silver, assembly outline in magenta, courtyard in green, the origin as a cross, and Altium-style layer tabs under it.
73
+
74
+ ### Fixed
75
+
76
+ - A part no source describes is no longer held for an empty Description: the librarian writes a plain one from the plan ("IC, SOIC-8, Texas Instruments LM358DR"), records it as written by ecadlib, and the release check warns instead (LM358DR from Add part from MPN was held only for this when the KiCad index was rate-limited).
77
+ - Model rail plans were cached by the rules table's id(): a new table could get a freed one's plan (an extra feedback turn with `feedback_retry = false`; test_ds_route flaked on Windows CI). Cached by content now.
78
+ - The menu build checks that no DelphiScript routine is called above where it is written (Altium stopped on "Undeclared identifier: ClipboardMpn").
79
+ - Altium dialog: it moves by dragging its header (it has no Windows title bar).
80
+ - Altium dialog: Ctrl+V / Shift+Insert / Ctrl+C / Ctrl+X / Ctrl+A work in the MPN and manufacturer boxes (Altium took them as its own shortcuts), a Paste link sits by the MPN box, a part number on the clipboard is filled in when Add part opens, row values are cut to what the right-hand column shows, and the Next note keeps the dialog's width.
81
+ - Altium projects (`altium_project.py`, the menu's Check this project BOM / Fill): `[DeviceSheetN]` sheets are read (next to the project, as written, or in Altium's device-sheet and data folders / `$ECADLIB_DEVICE_SHEETS`) and one that cannot be found is a warning, not a silent skip (Altium's Bluetooth Sentinel example lost 10 sheets, 45 components); multi-channel sheets (`REPEAT(CH,1,4)`, or one file under several sheet symbols; the name is RECORD=32, the old check read 33) are listed once per channel with Altium's channel designators (`ChannelDesignatorFormatString`, default `$Component_$RoomName`); a component without an MPN parameter whose Comment reads as a part number uses the Comment (Content Vault parts), with a warning and a triage note.
82
+ - Found in Altium AD26 with NE555DR (EasyEDA C7593): EasyEDA footprints put REF** on silk above the courtyard and the value on fab below it (1 mm, 0.15 mm stroke; before both sat at the centre, so Altium drew ".Designator" across the pads), a `${REFERENCE}` goes on fab in the body (0.5-1.0 mm), and a pin-1 dot inside the body is moved beside pad 1, 0.2 mm clear of the pads; the result passes `footprint_rules` text / silktext. `texts_from_kicad` keeps a Fab-layer reference on Mechanical 13 (only a silk reference becomes Top Overlay).
83
+ - Altium vault item ids (`CMP-1035-02800-1`, the LibRef / Comment / Part Number of Content Vault and Altium 365 parts) are never used as an MPN: not from parameters, the Comment, ActiveBOM or the triage's LibRef fallback (`altium_project.is_vault_id`).
84
+ - JLCPCB answering 403 (or 429) is reported as "JLCPCB refused the request (403)"; nothing more is sent to JLCPCB in that run (no retries) and the other sources are still tried.
85
+ - Repeat channels whose sheet symbols share one name (Bluetooth Sentinel: six "Red_LED") get numbered rooms (Red_LED1 ... Red_LED6), so designators are unique.
86
+ - A held part that another ecadlib version or build (`librarian.BUILD_REV`, stamped in the state) or other rules built is built again on the next run; it was skipped, so the release check judged the old version's models and fields ("silk 0.000 mm", "Description empty" after upgrading). Ready parts are still kept untouched (`--refresh` rebuilds them).
87
+ - Standard chip resistors / capacitors (0201 ... 2512) and SOT-23 / SOD-123 / SOD-323 / SOT-323 get a package default 3D height when nothing better is known; the release check warns "HEIGHT from package default ..., verify" instead of holding the part.
88
+ - `ecadlib doctor --altium-menu X.ini` checks the ini's `workspace=` (relative to the ini's folder) unless `--workspace` is given.
89
+ - Report CSVs (triage, review, release check, project BOM, where-used, sourcing, lifecycle, dedupe, upstream) are written as UTF-8 with a BOM so Excel shows ± and µ; ecadlib's own readers (pandas, `read_bom`) already accept it.
90
+ - `ecadlib altium-menu` (found on a Windows PC with Altium AD26, ecadlib in a venv, no API key): `build` writes `command="<sys.executable>" -m ecadlib` on Windows when no `--command` is given and fills an empty `command=` of an existing `ecadlib_menu.ini` (before, the runner looked only on PATH / `py -3` / `python` and a venv install failed with "ecadlib was not found"); the script's and `altium-pkg`'s `IsInstalled` / `UninstallAll` loop over `InstalledLibraryCount`, the count `InstalledLibraryPath` indexes (was `AvailableLibraryCount`). `ecadlib doctor` checks the menu's `command=` (`--altium-menu`, or an `ecadlib_menu.ini` in the current folder / `out/altium_menu`).
91
+ - EasyEDA footprints: silk lines are cut back to 0.2 mm from the pads and a silk circle within 0.1 mm of a pad is left out (EasyEDA outlines can run up to or over the copper; converted chip passives were held for "silkscreen is 0.000 mm from pad 1"). The part search's own description (JLCPCB `describe`, EasyEDA `description`, else its category + package) fills an empty Description.
92
+ - KiCad library index: tree pages are fetched with a 20 s timeout; a build that stops (timeout, HTTP 429) is not retried for 15 min (1 h after a 429), so runs in between go straight to the other sources, and resumes from the cached pages afterwards (`--refresh-index` retries at once).
93
+ - `dblib-sync` / `altium-pkg`: the Excel connection's `Data Source` stays machine-independent on every OS (`--win-dir`, else the `C:\ecadlib\library` placeholder), never the library folder's absolute path; Altium opens the workbook through `DatabasePathRelative=1`, so the folder can be moved. A connection edited in Altium is kept.
94
+ - `footprint_check`: an F.Cu lead and a B.Cu heat spreader under thermal vias no longer count as overlapping copper.
95
+
96
+ - Cross-check: a pad-table (custom) read counts a numbered exposed pad as a pin (package_schema), the standard table does not; such reads of EP packages (WSON, LFCSP, TQFN, MSOP-EP) were held as "pin count 13 vs 12". The eval gate's replay pack now also answers the second read.
97
+ - `sexpr.courtyard_bbox` ignored `fp_arc` / `fp_circle` courtyards: round cans (TO-18, TO-46) got a 2 x 2 mm box off to one side, also in the eval set's references (3 rebuilt; `tht-LM134H`, `tht-SFH216` now pass the gate). `footprint_adv`: pad names `H…` / `S…` were mounting / shield pads (outside a detected JEDEC grid), so audio-jack sleeve contacts, rotary-encoder switch pins S1/S2 and H/S ball rows lost their pins; only `MP`, `SH` (KiCad's names) and `MH`/`MTG`/`MOUNT`/`MECH`/`NPTH` are non-pins now.
98
+ - KiCad library import (librarian) and `kicad-export`, found by `parity survey` over KiCad's own footprint library: a through-hole pad's drill offset is kept (Altium hole-offset field; before, the copper sat on the hole), an SMD pad's shape offset moves its copper, copper-less mask / paste apertures keep their round or custom shape and both their layers (before: a square on paste only), and `kicad-export` folds a custom pad's regions that touch the anchor, and the mask / paste of stroked outlines, back into the pad without swallowing separate paste polygons.
99
+ - `kicad-export`: footprints without a KiCad 3D model (all generated and standard ones) now get the Altium footprint's model (its embedded STEP, or its extruded body as a STEP) in `<lib>.3dshapes/`; before, the KiCad library had no 3D model where Altium had one.
100
+ - `ecadlib dblib`: the Excel `.DbLib` names its workbook relative to itself (`DatabasePathRelative=1`), so the folder can move.
101
+ - Web UI: a step bar (1. Check a BOM, 2. Fill the library, 3. Send to Altium, Review queue, Footprints, Status, Settings), a "what happened, what next" line after every action, a Status card (`GET /api/status`) and an in-page setup check (`GET /api/doctor`, admin in team mode), the librarian's progress in its own card, a note telling team viewers which role they need, and `tests/test_ui_browser.py` (Chromium via Playwright at desktop and phone width; skips without it).
102
+
103
+ - Web UI: a BOM that can't be read now gives one plain line (no `ValueError`, no server path, and the error is scrolled into view); "Check again" is disabled with a reason when there is no BOM; the queue's filter chips work from the keyboard; white-on-light-blue buttons in dark mode; no `/favicon.ico` 404; the triage result opens next to the BOM instead of below the review queue; a queue approval the plan refuses no longer says "approvals.py refused".
104
+ - Found by the new end-to-end tests (`tests/test_e2e.py`): a KiCad library part whose 3D model could not be downloaded (offline, blocked host) lost its official footprint (the librarian fell back to another source); the model is now just made here. `kicad-export` replaced the whole `fp-lib-table` / `sym-lib-table` (a second library, a project's own rows or the database row were dropped); it now adds or replaces only its own row, in place. `ecadlib init` crashed printing a numeric proposal (`symbols.pin_length`). Re-running the librarian rewrote an unchanged `.PcbLib` with a new date and `release-check --allow` left `plan.json` in a key order the next run changed: a second run now changes no library file. `.PcbLib` / `.SchLib` are written atomically.
105
+ - Librarian: two BOM lines with the same footprint name no longer share one footprint file unless the pads are the same (`ecadlib/fp_share.py`); a different land pattern gets its own name (the real package name, else `<name>_<part>`), carried into `footprint.ref`, the `.PcbLib`, the symbol's footprint link, `resolve`, the KiCad export and the agent. Parts an older run shared by name only are re-resolved; files parts already have keep their names. Eval over the `kicad` source: 20 wrong shared footprints -> 0. `eval run` gives chip passives and diodes R/C/L/D designators (chips were unresolved by every source). `stdparts`: pin-removed variants (`SOIC-8-N7`, `SOIC-14-16`) are no longer resolved as the full package.
106
+ - `standard` source never guesses: an IC family name without a body size (`SOIC-8`, `SO-14`, `TSSOP-14`, `LQFP-100`; `MSOP-8` excepted, JEDEC has one), a QFN/DFN or `-1EP` name without the exposed-pad size, and `TO-252-2` / `TO-263-2` / DPAK / D2PAK without a library prefix (KiCad also has `_TabPin1`) now return nothing, so the next source (datasheet) answers; TVS diodes get the footprint only (uni- or bidirectional pin names are not certain from the MPN). Eval, `standard` alone: 115 answers with 14 wrong -> 74 answers, 0 wrong.
107
+
108
+ - Datasheet route / stdparts / eval review (rvK): `[datasheet] max_attempts` no longer ends a ladder on a cheaper model (the last try allowed goes to the top model); a synchronous refusal / max_tokens answer is costed from its usage block (was a 6,000-token estimate); a missing API key no longer logs phantom costs and caches every step as failed (the next run used to start on the top model); a stale failed step at the end of a route no longer pays in a loop; the eval reports every paid answer of a part's route (and replays it), prices Haiku 5.5's >100K-token tier, and fails two pin names swapped between pins; stdparts gives nothing for tantalum / polymer / electrolytic capacitors (was a chip-capacitor land and an unpolarized symbol).
109
+ - Library agent batch PRs: when a part's new build has fewer files than its last one (a part removed from its BOM before a requested rebuild: nothing built, no AFTER pictures), its old pictures now leave the batch branch, and its other old files stay recorded in `batch.json`; before, they were forgotten and stayed in the open PR even after the part was rejected (rare soak-test failure).
110
+ - Inputs / exports / Altium review (rvJ): unannotated `R?` symbols in a `.kicad_sch` are counted one by one (two were one part); `kicad-dblib` merges tables and columns that differ only in case (SQLite crashed) and, on Windows, rewrites a database KiCad has open in one transaction; `export-parts --format xlsx` drops control characters openpyxl refused; the KiCad database library and parts export read and write UTF-8 on every locale; SchLib text gets Altium's `%UTF8%` twin for every non-ASCII value (`±`, `°`, `µ` too, as Altium writes it); on Windows the plan lock waits past msvcrt's 10-second limit and atomic writes retry while another process holds the file open.
111
+ - Hooks review: GitLab API calls and webhook posts no longer follow HTTP redirects (urllib resent `PRIVATE-TOKEN` / `Authorization` to whatever host a 30x named); a GitLab origin on a self-hosted host with `[agent] gitlab_api` left at gitlab.com is refused instead of sending that host's token to gitlab.com; a provider plugin whose constructor or `configured()` raises, or one in `[providers] order` that fails to load, no longer stops triage; `[notify]` skips the remaining posts once its time budget is used up.
112
+ - Plan rewrites wait for the library agent: `release-check`, `resolve choose` and `dedupe --merge` on an agent plan wait for `agent/plan.lock`, and the web UI / MCP release check, choose and merge refuse while the agent rebuilds (locked methods call unlocked internals, so choose and merge re-check without deadlocking), so an `--allow` is no longer dropped by the agent's save. `dedupe --merge` keeps the first `plan.json.pre-dedupe` and timestamps later backups. `approve status` names a policy from `[release.approvals]`. `count_refs` reads `R1 - R4` and counts `U1A, U1B` once.
113
+ - Core pipeline review: text files are UTF-8 on every platform (a `10kΩ` BOM value crashed the triage report on Windows, and a `µ` written as cp1252 could not be read back); plan and state files are written atomically, so a crash no longer leaves a truncated `plan.json`; `resolve choose` re-checks every part that shares the model file it overwrites (they stayed `ready`); prices like `0,125 €` are 0.125, not 125; RKM names `1F5` / `1m5` instead of `15` / `1M5`; `dedupe --bom` remaps the BOM sheet, not a cover sheet; lifecycle reads a DbLib in a folder named with `#`; concurrent HTTP cache writers no longer share one temp file, and a damaged cache entry is a miss.
114
+ - Checked against real KiCad 7.0.11 (`tests/test_kicad_real.py`, skips without KiCad; optional CI job `kicad`): `kicad_import` failed on footprint text `(at x y unlocked)` (48 of 2291 KiCad 7 library footprints sampled) and on zero-length arcs; KiCad 7 symbols lost their `ki_description`; an EasyEDA pin with a slanted path made KiCad reject the whole symbol library; an SMD-defined BGA land could leave 0.02 mm copper gaps without an error; density C put REF** on the silk outline; `footprint-bench` crashed on a drill offset. `test_kicad_export`'s kicad-cli check now knows KiCad 7 cannot open the KiCad 8 export.
115
+ - Spreadsheet formula injection: every report and export CSV (triage, sourcing, release check, librarian review, dedupe and its BOM copy, where-used, project BOM, lifecycle, upstream, the agent's library BOM) writes cells starting with `= + - @`, tab or CR with a leading apostrophe (`ecadlib/sheetsafe.py`); plain numbers such as `-5` stay, the DbLib keeps Altium's `=Value` literal, and BOMs read back unchanged. Excel number cells read as typed (`1e-07` F becomes `100n`, `1.0` becomes `1`), so part names never show exponents. UTF-16 BOMs without a byte-order mark are detected and read.
116
+ - Team server security review: the sign-in lockout could be beaten with parallel requests (now counted before the password check), **Change password** checked the current password with no lockout, a removed user's sessions came back when the name was added again, `TEAM_USERS.JSON` (case-insensitive disks) or a hard link served the password hashes, team files could be triaged as a BOM, sign-in accepted 20 MB JSON bodies, the Docker stack believed a `proxy_user_header` from `team.json` that Caddy passed on from any client, and the audit line was written after the response (a flaky test).
117
+ - Datasheet batches: a create whose answer was lost (timeout, 5xx) leaves a marker; the next run lists recent batches and adopts the matching one instead of paying twice, and refuses to resubmit an unconfirmed one without `--yes`. `output_config.effort` is only sent to models that accept it (stepping down to a supported level), 200K-context models get the 100-page PDF limit, worst-case estimates include a fallback re-run, responses are shape-checked by hand when jsonschema is missing, and a part's spec and symbol JSON never overwrite each other.
118
+ - Datasheet reader and visual proof (review): `[datasheet] max_cost_usd` now holds on every path (the librarian's synchronous calls, the single-part CLI with new `--rules`/`--yes`, cumulatively across parts) and refuses a model with no known price; collecting an already-submitted batch is never blocked by the cap. A visual proof no longer says "pass" when the model marked every check not_applicable (pad_count / pin_count / pin_numbers must match). Staggered pin headers report their real pitch and alternating numbering. Password-protected or damaged PDFs give a clear error instead of a crash when cut to pages, and a page the model cites outside the pages sent is flagged instead of shown as an original page number.
119
+ - Team server hardening: one deadline per request (a client trickling bytes held a thread forever), a cap on connections per address, listen backlog 128 (60 simultaneous sign-ins got connection resets), `team_audit.jsonl` rotation with tail-only reading, and per-address rate limiting of unauthenticated refusals in the audit log.
120
+ - Library agent follow-up (rvC): rejected/failed parts' files leave the batch branch and the PR says so; decided batches with a pushed part get one "ready to merge" comment and stay open, those with nothing pushed are closed; `[agent] manufacturer_aliases` extends the built-in maker alias table; every approval path respects `agent/plan.lock`; manufacturer names are normalised in part keys (ST/STMicroelectronics/blank = one part) with a one-time migration of queue and watch state; `agent run --dry-run` writes nothing.
121
+ - Library agent, long-run safety (review rvC; `tests/test_agent_soak.py`): a pass killed between the scan and the queue no longer loses those changes; items left in `building`/`proving` by a dead pass (or after a clock step back) are resumed instead of stuck forever; an approve made while the librarian ran is no longer overwritten in `plan.json`; an approve is refused when the part was rebuilt after the reviewer opened it; approved removals/upkeep findings and parts whose files changed since approval are no longer pushed to Altium 365; a change after approval is no longer lost once the part is pushed; one bad change, a concurrent reject or a rules typo no longer stops the run or `serve`; PR bodies escape part data (HTML, links, @mentions, "fixes #N"); the batch branch starts from the remote base (local unpushed commits were pushed); retried parts get a new batch and closed PRs are replaced; a half-written BOM no longer reports every part removed; weekly upkeep restarts after a clock that ran ahead; upserting a huge BOM is no longer quadratic.
122
+ - Real-world BOMs and robustness (tests `test_realworld_boms.py`, `test_fuzz.py`, `test_cli_smoke.py`): `olefile` is now a core dependency (on a plain `pip install` the release check held every part and `kicad-export` wrote nothing); European decimals (`4,7k`, `2,2µF`) parse as 4.7 k / 2.2 µF, not 4 Ω / 2 F; a `Total` footer row is no longer a part; DigiKey's own `Part Number` is not taken as the MPN; a workbook's BOM sheet is found behind a cover sheet; a CSV named `.xlsx` reads, a corrupt workbook is a clear error; quoted cells spanning lines and `R1–R4` (en dash) ranges read right; UTF-16 BOMs upload in the web UI / MCP; `sourcing`, `upkeep` and the lifecycle reader honour the rules' `[bom] columns`; `parts.xlsx` keeps `=Value` as text, not an Excel formula; unreadable BOMs, bad `ecadlib.toml` and malformed KiCad / Altium files give a message, not a traceback; package-spec validation is ~40x faster.
123
+ - Footprints and symbols (review): same-looking supply pins (VDD1 / VDD2 of an isolator, VDD18 / VDD33) are no longer stacked onto one spot, which joined them in Altium; hidden power pins keep their Altium HiddenNetName in the KiCad export; single-row SMD pin headers get KiCad's single-row land (they used the dual-row one) and the 2.00 mm dual-row land is KiCad's; drill-only through-hole pads honour the pad rotation; BGA row H is no longer taken for mounting holes (footprint_check, release_check); a BGA with A1 depopulated passes, a misnamed ball is reported instead of switching the BGA rules off; SMD-defined lands keep their paste margin in the PcbLib, and PcbLib -> KiCad keeps mask margins and tented pads; STEP models of SMD headers no longer push pins through the board, and rotated connector pads turn in the model. The KiCad benchmark grows from 20 to 57 footprints (2942 pads). PcbLib -> KiCad writes polygon pads as KiCad custom pads; `symbol_layout.check` reports pins lying on or crossing another pin's line; `thermal_vias.unit` accepts mil / in / the table's unit; a 0.17 mm ball gets IPC-7351B's 0.15 mm land (was 0.14).
124
+
125
+ - Library agent integration (end-to-end test `tests/test_agent_e2e.py` with the real watch, queue, visual check and agent): the proof now gets the queue item's built footprint, symbol and datasheet (it always said "nothing to check"). `ecadlib agent approve|reject` no longer crashes. A rebuild keeps who asked for it, so that person cannot approve it. A BOM line without an MPN no longer stops the run. A part changed in its source while in review is rebuilt and its PR updated. The queue's batch record gets the PR link. `visual-check PART --workspace` reads librarian plans again. The batch PR links http(s) datasheets and does not name a model when no proof ran.
126
+ - Altium interop, checked against 553 Altium-saved Celestial Library files and pyaltiumlib (nothing opened in Altium): the PcbLib reader saw records on Mechanical 17-32 as Mechanical 16, so `rules infer` proposed Mechanical16 as the courtyard layer (and `87` as the 3D body layer); `%UTF8%` text in Altium SchLibs (CJK, `μ`) was read as `?`; the SchLib writer turned text cp1252 can't hold (`10kΩ`, `≤`) into `?` and now writes Altium's `%UTF8%` twin; a filled fab polygon with the rules' assembly layer on any mechanical layer but 13/15 crashed the PcbLib writer (`KeyError`); one Altium 365 footprint name cp1252 can't hold stopped `a365 pull` before it wrote anything.
127
+
128
+ - Footprint approval now writes the Altium `.PcbLib` for through-hole parts (pin headers, connectors, custom), with drills, slots, NPTH holes and polygon pads as anchor pad + copper/mask/paste regions instead of a bounding rectangle; BGA NSMD pads get their mask expansion. SMD output is unchanged. The footprint preview fits its view to the actual pads, holes and courtyard, so through-hole connectors are no longer drawn off-centre.
129
+
130
+ ## [0.2.0] - 2026-10-14
131
+
132
+ ### Added
133
+
134
+ - Packaging for PyPI: complete project metadata, `pdf`, `altium` and `all` extras,
135
+ version single-sourced from `ecadlib.__version__`, `ecadlib --version`, this changelog,
136
+ a CI job that builds and smoke-tests the sdist and wheel, and a tag-triggered release
137
+ workflow (GitHub release plus PyPI trusted publishing).
138
+ - Altium 365 workspace exporter through the Nexar Design API (`ecadlib altium365 plan|workspaces|push`),
139
+ with every GraphQL operation validated against Nexar's published schema and a dry-run mode.
140
+ - Pure-Python Altium `.PcbLib` / `.SchLib` writer (`ecadlib altium-lib`): SMD and through-hole pads,
141
+ arcs, keep-outs, extruded and embedded-STEP 3D bodies, multi-part symbols, hidden pins,
142
+ designator and comment text, pin graphics (clock, inverted, active-low) and De Morgan display modes.
143
+ - Local web UI (`ecadlib ui`) and MCP server (`ecadlib mcp`) on a shared Workspace layer, plus the
144
+ single `ecadlib` command for all tools.
145
+ - KiCad library import (`kicad_import`): official KiCad footprints, symbols and STEP models converted
146
+ to Altium files, with provenance recorded in `manifest.json`.
147
+ - Datasheet reader (`datasheet`): Claude reads a PDF and fills the package spec and the symbol.
148
+ - Lifecycle watcher (`lifecycle`): checks part status with Nexar, DigiKey and Mouser and can write the
149
+ lifecycle back to Altium 365.
150
+ - Librarian (`ecadlib librarian`): one command from a BOM to a filled library, sourcing missing parts
151
+ from KiCad, then LCSC/EasyEDA, then the datasheet reader; available in the UI and the MCP server.
152
+ - Release check (`ecadlib release-check`): holds back parts that fail pin/pad, footprint, 3D-height,
153
+ required-field and verification checks before an Altium 365 push; `--allow` overrides per part.
154
+ - Upstream change alerts (`ecadlib upstream check-kicad|check-a365`): diffs KiCad sources against
155
+ imported parts and reports Altium 365 drift from the release plan.
156
+ - Footprint checker (`ecadlib check`) for KLC/IPC rules; SOT-223 tabs, polarity marks, QFP and
157
+ DFN families; IPC-7351B numbers taken from the tables KiCad builds its library with.
158
+ - GitHub Actions workflow running the offline test suite (`python -m tests.run_all`) on every PR.
159
+
160
+ ### Changed
161
+
162
+ - `jsonschema` is a runtime dependency; the example package specs ship as package data
163
+ (`ecadlib/package_specs`).
164
+ - Altium 365 push skips parts already up to date, sends the merged parameter set, and never
165
+ pushes parts the release check held.
166
+
167
+ ### Fixed
168
+
169
+ - Real-world BOM shapes: Altium ActiveBOM, UTF-16 files, designator ranges, binary and
170
+ headerless BOMs, and generic LibRefs no longer promoted to MPNs.
171
+ - Independent review findings in the core modules, the Altium writer (P1-P11) and the UI,
172
+ MCP server and footprint code (U1-U14).
173
+
174
+ ### Security
175
+
176
+ - Query-string secrets (API keys, tokens) are redacted from the HTTP cache.
177
+ - The UI checks the Host header, listens on loopback only, and reads BOMs only from the workspace.
178
+
179
+ ## [0.1.0] - 2026-10-13
180
+
181
+ ### Added
182
+
183
+ - Initial prototypes: IPC-7351B footprint generator driven by `package_schema.json`, BOM triage
184
+ against local KiCad libraries and public part sources, and Altium Database Library (DbLib) export.
185
+
186
+ [Unreleased]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.3.0...HEAD
187
+ [0.3.0]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.2.0...v0.3.0
188
+ [0.2.0]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/compare/v0.1.0...v0.2.0
189
+ [0.1.0]: https://github.com/oliBrowne/PCBLIVINGLIBRARY/releases/tag/v0.1.0
ecadlib-0.3.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 oliver browne
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ # sdist extras (the wheel ships only the ecadlib package and its package-data)
2
+ include CHANGELOG.md
3
+ graft tests
4
+ graft examples
5
+ global-exclude *.py[cod]
6
+ prune **/__pycache__
ecadlib-0.3.0/NOTICE ADDED
@@ -0,0 +1,53 @@
1
+ ecad-librarian
2
+ Copyright (c) 2026 oliver browne. Licensed under the MIT License (see LICENSE).
3
+
4
+ This product includes material derived from AltiumSharp
5
+ (https://github.com/issus/AltiumSharp), licensed under the Apache License,
6
+ Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0):
7
+
8
+ * ecadlib/altium_lib.py ports the PcbLib/SchLib binary record layouts
9
+ (primitive common header, track, fill, region and pad records including
10
+ the pad main-block tail template, SchLib pin records, library/section
11
+ stream structure) from AltiumSharp's C# readers and writers. Modified:
12
+ rewritten in Python, reduced to the subset this project writes.
13
+ * ecadlib/assets/pcblib_template.json.gz holds the Library/Data header
14
+ parameters and the FileVersionInfo stream extracted from the AltiumSharp
15
+ TestData file "PCB - LEADLESS - QFN - PSEMI QFN-24 4x4.PcbLib"
16
+ (FILENAME and 2DCONFIGFULLFILENAME blanked).
17
+ * ecadlib/altium_lib.py also ports the through-hole pad hole fields, the arc
18
+ record, the ComponentBody record and parameter order, the Library/Models
19
+ storage and the 3D model checksum (PcbLibWriter.cs, PcbModel.cs).
20
+ * ecadlib/altium_lib.py also ports the PCB text record (252-byte block layout
21
+ and its constant fields, PcbLibWriter.cs WriteText/BuildTextExtended), the
22
+ WideStrings ENCODEDTEXT stream, the SchLib pin symbol and display-mode bytes
23
+ and the OwnerPartDisplayMode parameter order (SchLibWriter.cs).
24
+ * tests/test_kicad_import.py embeds three records from AltiumSharp TestData
25
+ (PAD_TH_SLOT, ARCS_TEST and BODY_3D .PcbLib files) as byte references.
26
+ * tests/test_altium_polish.py embeds three text records (TEXT_DESIGNATOR and
27
+ TEXT_TEST .PcbLib) and three pin records (CLOCK_PIN, INVERTED_PIN and
28
+ ACTIVE_LOW_PIN .SchLib) from AltiumSharp TestData as byte references.
29
+
30
+ tests/fixtures/kicad_golden/*.kicad_mod (24 footprints, kicad-footprints commit
31
+ f8440fa61a5690b48b325c891fdb99c0038a5a59, unmodified) and
32
+ tests/fixtures/kicad/USB_C_Receptacle_HRO_TYPE-C-31-M-12.kicad_mod and
33
+ tests/fixtures/kicad/Regulator_Linear_AMS1117.kicad_sym (symbols AP1117-15 and
34
+ AMS1117-3.3 combined into one library file) are from the KiCad libraries
35
+ (https://gitlab.com/kicad/libraries, kicad-footprints and kicad-symbols),
36
+ Copyright the KiCad Library contributors, licensed CC-BY-SA 4.0 with the KiCad
37
+ libraries' design-use exception (https://www.kicad.org/libraries/license/).
38
+ Footprints, symbols and 3D models converted from those libraries by
39
+ ecadlib/kicad_import.py are written to out/altium_models_kicad/, which is not
40
+ committed.
41
+
42
+ tests/nexar/schema.graphql is from NexarDeveloper/nexar-release-component-demo-wpf
43
+ (MIT).
44
+
45
+ No code from altium-designer-mcp (GPL-3.0) is included; it was read only
46
+ for behavioural notes about which files Altium Designer accepts.
47
+
48
+ ecadlib/ui/static/hairline.js bundles line figures from Hairline
49
+ (https://github.com/lucasmarkes/hairline), Copyright (c) 2026 Lucas Marques,
50
+ licensed under the MIT License: the slow, drawer and sieve figures and the
51
+ package's drawing and motion core, unmodified. scripts/hairline/seat.js is
52
+ ecadlib's own figure, written with Hairline's hairline-create skill and built
53
+ on that core (scripts/build_ui_figures.sh).