builder2ibek 2.0.1__tar.gz → 2.0.2__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 (307) hide show
  1. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/ioc-convert.md +20 -1
  2. builder2ibek-2.0.2/.claude/skills/beamline-gui/SKILL.md +109 -0
  3. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/ibek-concepts/SKILL.md +40 -0
  4. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/support-yaml-rules.md +5 -0
  5. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.copier-answers.yml +4 -1
  6. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.devcontainer/Dockerfile +7 -0
  7. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.devcontainer/devcontainer.json +10 -2
  8. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.devcontainer/postCreate.sh +3 -1
  9. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.devcontainer/postStart.sh +4 -3
  10. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/CONTRIBUTING.md +1 -1
  11. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.gitignore +1 -0
  12. builder2ibek-2.0.2/Dockerfile +31 -0
  13. {builder2ibek-2.0.1/src/builder2ibek.egg-info → builder2ibek-2.0.2}/PKG-INFO +3 -2
  14. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/README.md +2 -1
  15. builder2ibek-2.0.2/justfile +22 -0
  16. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/pyproject.toml +2 -1
  17. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/_version.py +3 -3
  18. builder2ibek-2.0.2/src/builder2ibek/converters/insertionDevice.py +17 -0
  19. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/interlock.py +4 -0
  20. builder2ibek-2.0.2/src/builder2ibek/converters/mks937a.py +21 -0
  21. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mks937b.py +9 -0
  22. {builder2ibek-2.0.1 → builder2ibek-2.0.2/src/builder2ibek.egg-info}/PKG-INFO +3 -2
  23. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek.egg-info/SOURCES.txt +2 -0
  24. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/conftest.py +24 -5
  25. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl04i-va-ioc-01.yaml +9 -9
  26. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl11i-va-ioc-01.yaml +13 -13
  27. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl15i-va-ioc-01.yaml +9 -9
  28. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl16i-va-ioc-01.yaml +10 -10
  29. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl19i-va-ioc-01.yaml +11 -11
  30. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/sr03c-va-ioc-01.ioc.subst +11 -11
  31. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/sr03c-va-ioc-01.yaml +40 -42
  32. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/uv.lock +200 -170
  33. builder2ibek-2.0.1/Dockerfile +0 -13
  34. builder2ibek-2.0.1/justfile +0 -13
  35. builder2ibek-2.0.1/src/builder2ibek/converters/mks937a.py +0 -14
  36. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/beamline-check.md +0 -0
  37. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/beamline-convert.md +0 -0
  38. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/beamline-reconvert.md +0 -0
  39. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/ioc-check.md +0 -0
  40. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/ioc-inspect.md +0 -0
  41. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/memo.md +0 -0
  42. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/support-create.md +0 -0
  43. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/support-fix.md +0 -0
  44. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/commands/support-inspect.md +0 -0
  45. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/settings.json +0 -0
  46. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/ibek-support-ansible/SKILL.md +0 -0
  47. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/builder-py-analysis.md +0 -0
  48. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/error-categorization.md +0 -0
  49. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/find-boot-script.md +0 -0
  50. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/find-ioc-xmls.md +0 -0
  51. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/find-module-path.md +0 -0
  52. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/module-special-cases.md +0 -0
  53. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/services-repo-resolution.md +0 -0
  54. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/shared/vxworks-to-rtems-differences.md +0 -0
  55. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.claude/skills/skills-edit/SKILL.md +0 -0
  56. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.devcontainer/local_build.sh +0 -0
  57. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.gitattributes +0 -0
  58. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  59. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  60. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  61. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/copilot-instructions.md +0 -0
  62. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/pages/index.html +0 -0
  63. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/pages/make_switcher.py +0 -0
  64. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/_dist.yml +0 -0
  65. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/_docs.yml +0 -0
  66. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/_pypi.yml +0 -0
  67. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/_release.yml +0 -0
  68. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/_test.yml +0 -0
  69. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/_tox.yml +0 -0
  70. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/ci.yml +0 -0
  71. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.github/workflows/periodic.yml +0 -0
  72. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.gitleaks.toml +0 -0
  73. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.gitmodules +0 -0
  74. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.gitremotes +0 -0
  75. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.pre-commit-config.yaml +0 -0
  76. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.python-version +0 -0
  77. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.vscode/extensions.json +0 -0
  78. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.vscode/mcp.json +0 -0
  79. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.vscode/settings.json +0 -0
  80. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/.vscode/tasks.json +0 -0
  81. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/CLAUDE.md +0 -0
  82. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/LICENSE +0 -0
  83. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/bl21i-mo-ioc-01_blacklist.txt +0 -0
  84. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/_api.rst +0 -0
  85. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/_templates/custom-module-template.rst +0 -0
  86. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/conf.py +0 -0
  87. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/conftest.py +0 -0
  88. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  89. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  90. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/explanations/decisions/0003-remove-mcp-server-for-copilot.md +0 -0
  91. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/explanations/decisions/COPYME +0 -0
  92. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/explanations/decisions.md +0 -0
  93. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/explanations.md +0 -0
  94. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/genindex.md +0 -0
  95. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/after-beamline-convert.md +0 -0
  96. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/autosave.md +0 -0
  97. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/contribute.md +0 -0
  98. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/convert-ioc-instance.md +0 -0
  99. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/create-converter.md +0 -0
  100. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/create-generic-ioc-repo.md +0 -0
  101. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/runtime-support.md +0 -0
  102. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to/verify-with-devcontainer.md +0 -0
  103. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/how-to.md +0 -0
  104. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/images/dls-logo.svg +0 -0
  105. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/index.md +0 -0
  106. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/reference/dlsplc-migration.md +0 -0
  107. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/reference.md +0 -0
  108. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/tutorials/convert-ioc-xml.md +0 -0
  109. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/tutorials/create-support-yaml-advanced.md +0 -0
  110. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/tutorials/create-support-yaml.md +0 -0
  111. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/tutorials/installation.md +0 -0
  112. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/docs/tutorials.md +0 -0
  113. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/out.yaml +0 -0
  114. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/renovate.json +0 -0
  115. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/setup.cfg +0 -0
  116. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/__init__.py +0 -0
  117. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/__main__.py +0 -0
  118. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/builder.py +0 -0
  119. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/convert.py +0 -0
  120. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ACCELCryoIP.py +0 -0
  121. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADAndor.py +0 -0
  122. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADAravis.py +0 -0
  123. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADCore.py +0 -0
  124. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADIvium.py +0 -0
  125. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADOdin.py +0 -0
  126. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADOdinTristan.py +0 -0
  127. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADPilatus.py +0 -0
  128. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ADZMQ.py +0 -0
  129. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/AMI186.py +0 -0
  130. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BL11I.py +0 -0
  131. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BL15I-BUILDER.py +0 -0
  132. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BL19I.py +0 -0
  133. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BL20J.py +0 -0
  134. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BL21I.py +0 -0
  135. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BL46P-BUILDER.py +0 -0
  136. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BLGui.py +0 -0
  137. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/BLfeedback.py +0 -0
  138. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/CrateMonitor.py +0 -0
  139. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/CryoCoolerXV.py +0 -0
  140. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/DLS8515.py +0 -0
  141. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/DruckDPI515.py +0 -0
  142. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ETLdetector.py +0 -0
  143. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/FINS.py +0 -0
  144. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/FastVacuum.py +0 -0
  145. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/Hy8401ip-asyn.py +0 -0
  146. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/Hy8401ip.py +0 -0
  147. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/Hy8401ipTemplates.py +0 -0
  148. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/Hy8402ip.py +0 -0
  149. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/Hy8414.py +0 -0
  150. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/IOCInfo.py +0 -0
  151. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/OXCS700.py +0 -0
  152. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/OXCS700asyn.py +0 -0
  153. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/OXCryo.py +0 -0
  154. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/QPC.py +0 -0
  155. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/README.md +0 -0
  156. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/SR-VA.py +0 -0
  157. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/SchottLLS.py +0 -0
  158. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/SycosH-Hot.py +0 -0
  159. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/TimingTemplates.py +0 -0
  160. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/Xspress3.py +0 -0
  161. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/__init__.py +0 -0
  162. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/adUtil.py +0 -0
  163. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/agilent33220A.py +0 -0
  164. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/agilent53220.py +0 -0
  165. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/alicatGasFlow.py +0 -0
  166. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/asyn.py +0 -0
  167. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/autosave.py +0 -0
  168. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/bronkhorstFlowBus.py +0 -0
  169. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/cmsIon.py +0 -0
  170. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/cognexDataMan100.py +0 -0
  171. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/currAmp.py +0 -0
  172. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/deltaTauPLCStat.py +0 -0
  173. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/deviocstats.py +0 -0
  174. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/digitelMpc.py +0 -0
  175. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/digitelSpc.py +0 -0
  176. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/directoryMonitor.py +0 -0
  177. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/dlsPLC.py +0 -0
  178. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/enzLoCuM4.py +0 -0
  179. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/epics_base.py +0 -0
  180. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ether_ip.py +0 -0
  181. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ethercat.py +0 -0
  182. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/eurotherm2k.py +0 -0
  183. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/eurothermModbus.py +0 -0
  184. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/femto.py +0 -0
  185. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ffmpegServer.py +0 -0
  186. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/filters.py +0 -0
  187. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/fogaleHLS.py +0 -0
  188. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/fw102.py +0 -0
  189. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/fzoom.py +0 -0
  190. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/gasInjectionRig.py +0 -0
  191. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/gdaPlugins.py +0 -0
  192. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/gdaPlugins.yaml +0 -0
  193. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/globalHandler.py +0 -0
  194. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/harvardSyringe.py +0 -0
  195. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/hidenRGA.py +0 -0
  196. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/ipac.py +0 -0
  197. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/keithley6514.py +0 -0
  198. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/lakeshore336.py +0 -0
  199. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/lakeshore340.py +0 -0
  200. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/laudaRE2xx.py +0 -0
  201. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/leybold.py +0 -0
  202. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mca.py +0 -0
  203. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mirror.py +0 -0
  204. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mitsubishiRobot.py +0 -0
  205. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mks9xx.py +0 -0
  206. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/motomanNX100.py +0 -0
  207. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/motor.py +0 -0
  208. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/motorSmarAct.py +0 -0
  209. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mrfTiming.py +0 -0
  210. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mrfioc2.py +0 -0
  211. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/mxEH.py +0 -0
  212. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/pgmVls.py +0 -0
  213. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/picotechPT104.py +0 -0
  214. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/pmac.py +0 -0
  215. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/pmacCoord.py +0 -0
  216. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/pmacUtil.py +0 -0
  217. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/positioner.py +0 -0
  218. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/procServControl.py +0 -0
  219. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/pvlogging.py +0 -0
  220. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/quadEM.py +0 -0
  221. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/rackFan.py +0 -0
  222. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/records.py +0 -0
  223. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/rga.py +0 -0
  224. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/rgamv2.py +0 -0
  225. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/scpi.py +0 -0
  226. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/slsDetector.py +0 -0
  227. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/smaractEcm.py +0 -0
  228. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/smargon.py +0 -0
  229. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/strainGauge.py +0 -0
  230. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/temperature.py +0 -0
  231. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/terminalserver.py +0 -0
  232. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/tpmac.py +0 -0
  233. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/transfocator.py +0 -0
  234. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/uniblitz.py +0 -0
  235. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/userIO.py +0 -0
  236. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/utility.py +0 -0
  237. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/vacuumSpace.py +0 -0
  238. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/vacuumValve.py +0 -0
  239. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/water.py +0 -0
  240. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/converters/zebra.py +0 -0
  241. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/db2autosave.py +0 -0
  242. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/dbcompare.py +0 -0
  243. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/moduleinfos.py +0 -0
  244. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/reconvert.py +0 -0
  245. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/support_defaults.py +0 -0
  246. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/types.py +0 -0
  247. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek/utils.py +0 -0
  248. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek.egg-info/dependency_links.txt +0 -0
  249. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek.egg-info/entry_points.txt +0 -0
  250. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek.egg-info/requires.txt +0 -0
  251. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/src/builder2ibek.egg-info/top_level.txt +0 -0
  252. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/__init__.py +0 -0
  253. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL04I-MO-IOC-03.xml +0 -0
  254. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL04I-VA-IOC-01.xml +0 -0
  255. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL04I-VA-IOC-01_expanded.db +0 -0
  256. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL11I-CS-IOC-09.xml +0 -0
  257. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL11I-VA-IOC-01.xml +0 -0
  258. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL15I-VA-IOC-01.xml +0 -0
  259. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL16I-VA-IOC-01.xml +0 -0
  260. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL19I-VA-IOC-01.xml +0 -0
  261. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL21I-MO-IOC-01.xml +0 -0
  262. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL45P-MO-IOC-01.xml +0 -0
  263. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL99P-EA-IOC-05.xml +0 -0
  264. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/BL99P-EA-IOC-05.yaml +0 -0
  265. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/SR03C-VA-IOC-01.xml +0 -0
  266. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/SR03C-VA-IOC-01_expanded.db +0 -0
  267. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl04i-mo-ioc-03.ioc.subst +0 -0
  268. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl04i-mo-ioc-03.st.cmd +0 -0
  269. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl04i-mo-ioc-03.yaml +0 -0
  270. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl04i-va-ioc-01.ioc.subst +0 -0
  271. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl04i-va-ioc-01.st.cmd +0 -0
  272. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl11i-cs-ioc-09.ioc.subst +0 -0
  273. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl11i-cs-ioc-09.st.cmd +0 -0
  274. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl11i-cs-ioc-09.yaml +0 -0
  275. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl11i-va-ioc-01.ioc.subst +0 -0
  276. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl11i-va-ioc-01.st.cmd +0 -0
  277. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl15i-va-ioc-01.ioc.subst +0 -0
  278. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl15i-va-ioc-01.st.cmd +0 -0
  279. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl16i-va-ioc-01.ioc.subst +0 -0
  280. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl16i-va-ioc-01.st.cmd +0 -0
  281. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl19i-va-ioc-01.ioc.subst +0 -0
  282. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl19i-va-ioc-01.st.cmd +0 -0
  283. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl21i-mo-ioc-01.ioc.subst +0 -0
  284. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl21i-mo-ioc-01.st.cmd +0 -0
  285. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl21i-mo-ioc-01.yaml +0 -0
  286. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl21i-mo-ioc-01_blacklist.txt +0 -0
  287. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl45p-mo-ioc-01.ioc.subst +0 -0
  288. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl45p-mo-ioc-01.st.cmd +0 -0
  289. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl45p-mo-ioc-01.yaml +0 -0
  290. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl99p-ea-ioc-05.ioc.subst +0 -0
  291. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl99p-ea-ioc-05.st.cmd +0 -0
  292. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/bl99p-ea-ioc-05.yaml +0 -0
  293. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/compare.diff +0 -0
  294. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/make_samples.sh +0 -0
  295. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/motor.template +0 -0
  296. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/motorpositioner.ioc.subst +0 -0
  297. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/motorpositioner.st.cmd +0 -0
  298. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/motorpositioner.xml +0 -0
  299. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/motorpositioner.yaml +0 -0
  300. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/sr03c-va-ioc-01.db +0 -0
  301. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/samples/sr03c-va-ioc-01.st.cmd +0 -0
  302. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/test_autosave.py +0 -0
  303. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/test_cli.py +0 -0
  304. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/test_compare.py +0 -0
  305. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/test_file_conversion.py +0 -0
  306. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/tests/test_reconvert_cli.py +0 -0
  307. {builder2ibek-2.0.1 → builder2ibek-2.0.2}/update-schema +0 -0
@@ -283,7 +283,26 @@ To check what macros a db file expects:
283
283
  grep "^# % macro" /dls_sw/prod/R3.14.12.7/support/<module>/<version>/db/<file>.db
284
284
  ```
285
285
 
286
- ### 5c. Report and suggest commits
286
+ ### 5c. Refresh the global schema
287
+
288
+ The isolated `EPICS_ROOT` from Phase 0 keeps this run's schema separate, but it
289
+ also means the **global** schema at `/epics/ibek-defs/ioc.schema.json` (which
290
+ the editor's yaml-language-server reads — see line 1 of every `ioc.yaml`) is
291
+ unaware of any new support YAMLs created during this run. The result is
292
+ spurious "unknown type" warnings in the IDE on freshly-converted ioc.yaml
293
+ files, even though `ibek runtime generate2` succeeded.
294
+
295
+ If any support YAMLs were created or modified during this run, refresh the
296
+ global schema so the editor sees the new entity types:
297
+
298
+ ```bash
299
+ EPICS_ROOT=/epics ./update-schema
300
+ ```
301
+
302
+ If no support YAMLs changed (pure ioc.yaml-only conversion), this step can be
303
+ skipped.
304
+
305
+ ### 5d. Report and suggest commits
287
306
 
288
307
  Once clean, **do not commit anything**. Report to the user:
289
308
 
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: beamline-gui
3
+ description: DLS beamline EDM screen layout and conventions — use when locating, reading, or editing `*.edl` files for hardware-status / IOC-status synoptics, debugging wrong-target buttons (PC / Terminal / Start-Stop), or making sense of EDM positional layout.
4
+ ---
5
+
6
+ # Beamline GUI (EDM Screens)
7
+
8
+ DLS beamline GUIs are EDM `.edl` files. This skill covers where they live and
9
+ how the common synoptic screens are wired.
10
+
11
+ ---
12
+
13
+ ## Where the screens live
14
+
15
+ Pattern (same for every beamline):
16
+
17
+ ```
18
+ /dls_sw/{work,prod}/R<EPICS-VER>/ioc/BLxxI/BL/
19
+ BLxxIApp/opi/edl/*.edl # SOURCE — edit these
20
+ data/*.edl # deployed copy — overwritten by build; do not edit
21
+ ```
22
+
23
+ `*.edl~` are EDM editor backups — ignore.
24
+
25
+ `/dls_sw/work/` is the unreleased tree (edit here); `/dls_sw/prod/` is the
26
+ released equivalent (read-only).
27
+
28
+ **EPICS version varies per beamline.** `R3.14.12.7` is currently the most
29
+ common, but older beamlines may still live under `R3.14.11`, `R3.14.12.3`,
30
+ `R3.14.8.2`, etc., and newer / RTEMS-based ones under `R7.0.7`. Don't hard-code
31
+ the version — discover it:
32
+
33
+ ```bash
34
+ ls -d /dls_sw/{work,prod}/R*/ioc/BLxxI/BL 2>/dev/null
35
+ ```
36
+
37
+ Pick the most recent / actively-modified tree (check mtimes on the `edl/`
38
+ directory if there are several).
39
+
40
+ ---
41
+
42
+ ## Key screens
43
+
44
+ | File | Purpose |
45
+ |---|---|
46
+ | `BLxxI-hardware-status.edl` | Top-level synoptic for the beamline |
47
+ | `BLxxI-ioc-status-embed.edl` | Per-IOC rows; embedded in hardware-status via `activePipClass` |
48
+
49
+ The hardware-status screen embeds the ioc-status-embed via `displayFileName`.
50
+
51
+ ---
52
+
53
+ ## How a row is laid out
54
+
55
+ EDM is positional. A row of buttons shares a single `y` coordinate; the row's
56
+ human-readable name is a `(Static Text)` object at the same y on the left.
57
+ Buttons sit at increasing `x`. **Object order in the file does not follow
58
+ visual order — match by coordinates, not file position.**
59
+
60
+ Typical row (left to right):
61
+
62
+ | Element | Class | Real wiring lives in |
63
+ |---|---|---|
64
+ | Row label | `activeXTextClass` | `value { "Merlin 01 IOC" }` — cosmetic |
65
+ | IOC button | `relatedDisplayClass` | `displayFileName: ioc_stats_soft`, `symbols: ioc=$(dom)-XX-IOC-NN` |
66
+ | Traffic light | `activeSymbolClass` | `controlPvs: <IOC>:LOAD.SEVR` |
67
+ | Terminal | `shellCmdClass` | `command: gnome-terminal -x console <IOC>` |
68
+ | Start/Stop | `relatedDisplayClass` | `procServControl.edl`, `symbols: procServ=<IOC>` |
69
+ | PC | `shellCmdClass` | `command: dls-remote-desktop.sh ... <hostname>` |
70
+ | Save/Restore icon | `relatedDisplayClass` | `save_restoreStatus_more`, `symbols: P=<IOC>` |
71
+
72
+ `$(dom)` is the beamline domain macro (e.g. `BL20I`), substituted at runtime.
73
+
74
+ ---
75
+
76
+ ## Finding the code behind a visible button
77
+
78
+ 1. Grep the row's static-text label (the name shown on screen):
79
+ ```bash
80
+ grep -n '"Merlin 02 IOC"' BLxxI-ioc-status-embed.edl
81
+ ```
82
+ 2. Read around the hit to find the row's `y` coordinate.
83
+ 3. Grep `buttonLabel` (or the action class — `shellCmdClass`, `relatedDisplayClass`)
84
+ and look for objects with the same y — those are the buttons in that row.
85
+
86
+ Don't trust `buttonLabel` text alone: the visible label and the actual target
87
+ in `command` / `symbols` can disagree. That mismatch is the "wrong PC" bug class.
88
+
89
+ ---
90
+
91
+ ## Wiring/label mismatch (the wrong-target bug)
92
+
93
+ Each PC / Terminal / Start-Stop button has a `command` string (or `symbols`
94
+ substitution) naming the real target. The visible label is decorative. When
95
+ a button "opens the wrong thing", the fix is in `command` or `symbols`, not
96
+ in the label or the static text next to it.
97
+
98
+ Two buttons that target swapped hosts get fixed by swapping the `command`
99
+ strings — coordinates, colours, and labels stay put.
100
+
101
+ ---
102
+
103
+ ## Editing rules
104
+
105
+ - Edit `BLxxIApp/opi/edl/<file>.edl` — never `data/<file>.edl` (deployed
106
+ output, overwritten on build).
107
+ - Never touch `*.edl~` (EDM autosave).
108
+ - When swapping wiring between rows, preserve x/y/colours/labels; change only
109
+ the `command` / `symbols` lines.
@@ -106,6 +106,46 @@ float, `42` becomes int. Type mismatch → schema validation failure.
106
106
 
107
107
  ---
108
108
 
109
+ ## Leading-zero int params (gauge ids, controller addresses)
110
+
111
+ XML attributes like `id="02"` or `address="001"` are zero-padded because the
112
+ builder XML used them as raw PV-name segments. In ibek, these should almost
113
+ always be `type: int` — the zero padding is a *rendering* concern for the db
114
+ substitution, not a property of the parameter itself.
115
+
116
+ Three-part pattern:
117
+
118
+ 1. **Support YAML** — declare `type: int`, render padded in `databases.args`:
119
+ ```yaml
120
+ id:
121
+ type: int
122
+ description: Gauge ID. Rendered zero-padded to 2 digits in PV
123
+ substitutions (e.g. 1 -> "01").
124
+ ...
125
+ databases:
126
+ - file: $(MOD)/db/foo.template
127
+ args:
128
+ id: "{{ '%02d' % id }}"
129
+ ```
130
+ 2. **Converter** — coerce the string to int in the module's converter. The
131
+ generic `convert.py::_has_leading_zero` deliberately preserves
132
+ zero-padded strings (so PV-name segments survive), so per-module
133
+ converters must override:
134
+ ```python
135
+ if entity_type == "mks937aGauge" and entity.id is not None:
136
+ entity.id = int(entity.id)
137
+ ```
138
+ 3. **Result** — ioc.yaml holds `id: 2` (bare int), and ibek's Jinja step
139
+ renders `"02"` in ioc.subst. st.cmd / ioc.subst output is unchanged
140
+ byte-for-byte.
141
+
142
+ **When to keep them as strings instead**: if the value is a PV-name
143
+ quadrant code or a string enum (e.g. `SR-VA.gaugeSetA.q` = "S" / "A" / "SS",
144
+ `dlsPLC.fastVacuumChannel.id` declared `type: enum` with string values like
145
+ "01"), leave it as `type: str` / `type: enum`.
146
+
147
+ ---
148
+
109
149
  ## Reference examples
110
150
 
111
151
  | Module | Path | Notes |
@@ -34,6 +34,11 @@ topics. Key reminders:
34
34
  module — it is not always `PORT`. Always check the `ArgInfo` declaration in
35
35
  builder.py; if it uses `Ident(...)` it must be `type: object` in the support YAML.
36
36
  - `.*:` in `databases.args` passes all parameters through.
37
+ - Zero-padded numeric params (gauge ids like `"02"`, controller addresses
38
+ like `"001"`) → `type: int` in the support YAML, render padded in
39
+ `databases.args` with `{{ '%02d' % id }}`, and add a per-module
40
+ converter coercion `entity.id = int(entity.id)` so ioc.yaml holds a bare
41
+ int. See [ibek-concepts](../ibek-concepts/SKILL.md) for the full pattern.
37
42
 
38
43
  ## STREAM_PROTOCOL_PATH
39
44
 
@@ -1,6 +1,7 @@
1
1
  # Changes here will be overwritten by Copier
2
- _commit: 5.0.2
2
+ _commit: 5.0.3-3-gd645eb3
3
3
  _src_path: gh:diamondlightsource/python-copier-template
4
+ add_claude: true
4
5
  author_email: giles.knap@diamond.ac.uk
5
6
  author_name: Giles Knap
6
7
  description: Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml
@@ -9,6 +10,8 @@ docker: false
9
10
  docs_type: sphinx
10
11
  git_platform: github.com
11
12
  github_org: epics-containers
13
+ install_gh: true
14
+ install_glab: true
12
15
  package_name: builder2ibek
13
16
  pypi: true
14
17
  repo_name: builder2ibek
@@ -19,6 +19,13 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \
19
19
  apt-get update && apt-get install -y gh && \
20
20
  rm -rf /var/lib/apt/lists/*
21
21
 
22
+ # Install glab (GitLab CLI) — no apt repo, use the release tarball from gitlab.com
23
+ ARG GLAB_VERSION=1.92.1
24
+ RUN curl -fsSL "https://gitlab.com/gitlab-org/cli/-/releases/v${GLAB_VERSION}/downloads/glab_${GLAB_VERSION}_linux_amd64.tar.gz" \
25
+ | tar -xz -C /tmp bin/glab && \
26
+ install -m 0755 /tmp/bin/glab /usr/local/bin/glab && \
27
+ rm -rf /tmp/bin
28
+
22
29
  FROM base as developer
23
30
 
24
31
  WORKDIR /workspace
@@ -21,6 +21,8 @@
21
21
  "VSCODE_GIT_ASKPASS_MAIN": "",
22
22
  "VSCODE_GIT_ASKPASS_NODE": "",
23
23
  "VSCODE_GIT_ASKPASS_EXTRA_ARGS": "",
24
+ // Mark this shell as running inside the devcontainer
25
+ "IN_DEVCONTAINER": "1",
24
26
  // Put things that allow it in the persistent cache
25
27
  "PRE_COMMIT_HOME": "/cache/pre-commit",
26
28
  "UV_CACHE_DIR": "/cache/uv",
@@ -61,8 +63,8 @@
61
63
  "streetsidesoftware.code-spell-checker",
62
64
  "moshfeu.compare-folders",
63
65
  "nsd.vscode-epics",
64
- "anthropic.claude-code",
65
- "github.copilot-chat"
66
+ "ms-azuretools.vscode-docker",
67
+ "anthropic.claude-code"
66
68
  ]
67
69
  }
68
70
  },
@@ -97,6 +99,12 @@
97
99
  "target": "/root/.config/gh",
98
100
  "type": "volume"
99
101
  },
102
+ // Persist glab auth across container rebuilds (GitLab CLI, for ibek-support-dls)
103
+ {
104
+ "source": "glab-auth-${localWorkspaceFolderBasename}",
105
+ "target": "/root/.config/glab-cli",
106
+ "type": "volume"
107
+ },
100
108
  // Mount Claude config from host (settings, memory, skills)
101
109
  {
102
110
  "source": "${localEnv:HOME}/.claude",
@@ -8,4 +8,6 @@ curl -fsSL https://claude.ai/install.sh | bash
8
8
  uv venv --clear
9
9
  uv sync
10
10
  pre-commit install --install-hooks
11
- git submodule update --init
11
+
12
+ # Initialise git submodules if any are declared
13
+ [ -f .gitmodules ] && git submodule update --init || true
@@ -8,10 +8,11 @@ set -euo pipefail
8
8
  git config --global credential.helper ''
9
9
  git config --global --unset-all url.ssh://git@github.com/.insteadOf 2>/dev/null || true
10
10
 
11
- # Force all GitHub SSH URLs to use HTTPS so the gh credential helper handles
12
- # auth. This keeps the container SSH-key-free (Claude stays sandboxed) while
13
- # still allowing push/pull on repos whose remotes are set to git@github.com:.
11
+ # Force all SSH-style remotes to use HTTPS so the gh/glab credential helpers
12
+ # handle auth. This keeps the container SSH-key-free (Claude stays sandboxed)
13
+ # while still allowing push/pull on repos whose remotes are set to git@...:.
14
14
  git config --global url."https://github.com/".insteadOf "git@github.com:"
15
+ git config --global url."https://gitlab.diamond.ac.uk/".insteadOf "git@gitlab.diamond.ac.uk:"
15
16
 
16
17
  # If gh CLI has cached credentials (survive container rebuild), re-register
17
18
  # its git credential helper so HTTPS remotes authenticate automatically.
@@ -24,4 +24,4 @@ It is recommended that developers use a [vscode devcontainer](https://code.visua
24
24
 
25
25
  This project was created using the [Diamond Light Source Copier Template](https://github.com/DiamondLightSource/python-copier-template) for Python projects.
26
26
 
27
- For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.2/how-to.html).
27
+ For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.3/how-to.html).
@@ -78,3 +78,4 @@ lockfiles/
78
78
  .claude/commands/ioc-convert/last-services-repo
79
79
  .claude/commands/ioc-check/last-services-repo
80
80
  DONE
81
+ .claude/scheduled_tasks.lock
@@ -0,0 +1,31 @@
1
+ # The devcontainer should use the developer target and run as root with podman
2
+ # or docker with user namespaces.
3
+ ARG PYTHON_VERSION=3.13
4
+ FROM ghcr.io/diamondlightsource/ubuntu-devcontainer:noble AS developer
5
+
6
+ # Add any system dependencies for the developer/build environment here
7
+ RUN apt-get update -y && apt-get install -y --no-install-recommends \
8
+ graphviz \
9
+ && apt-get dist-clean
10
+
11
+ # Node is required by Claude Code's hook runtime
12
+ RUN apt-get update -y && apt-get install -y --no-install-recommends \
13
+ nodejs \
14
+ && apt-get dist-clean
15
+
16
+ # GitHub CLI — used by Claude to authenticate to github.com via PAT
17
+ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \
18
+ dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
19
+ chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
20
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
21
+ | tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \
22
+ apt-get update && apt-get install -y --no-install-recommends gh && \
23
+ apt-get dist-clean
24
+
25
+ # GitLab CLI — used by Claude to authenticate to gitlab instances via PAT.
26
+ # No apt repo, so install from the upstream release tarball.
27
+ ARG GLAB_VERSION=1.92.1
28
+ RUN curl -fsSL "https://gitlab.com/gitlab-org/cli/-/releases/v${GLAB_VERSION}/downloads/glab_${GLAB_VERSION}_linux_amd64.tar.gz" \
29
+ | tar -xz -C /tmp bin/glab && \
30
+ install -m 0755 /tmp/bin/glab /usr/local/bin/glab && \
31
+ rm -rf /tmp/bin
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: builder2ibek
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml
5
5
  Author-email: Giles Knap <giles.knap@diamond.ac.uk>
6
6
  License: Apache License
@@ -225,8 +225,9 @@ Dynamic: license-file
225
225
  A tool suite for converting DLS XMLbuilder IOC projects to
226
226
  [epics-containers](https://github.com/epics-containers) ibek.
227
227
 
228
- Source | <https://github.com/epics-containers/builder2ibek>
228
+ What | Where
229
229
  :---: | :---:
230
+ Source | <https://github.com/epics-containers/builder2ibek>
230
231
  PyPI | `pip install builder2ibek`
231
232
  Documentation | <https://epics-containers.github.io/builder2ibek>
232
233
  Releases | <https://github.com/epics-containers/builder2ibek/releases>
@@ -8,8 +8,9 @@
8
8
  A tool suite for converting DLS XMLbuilder IOC projects to
9
9
  [epics-containers](https://github.com/epics-containers) ibek.
10
10
 
11
- Source | <https://github.com/epics-containers/builder2ibek>
11
+ What | Where
12
12
  :---: | :---:
13
+ Source | <https://github.com/epics-containers/builder2ibek>
13
14
  PyPI | `pip install builder2ibek`
14
15
  Documentation | <https://epics-containers.github.io/builder2ibek>
15
16
  Releases | <https://github.com/epics-containers/builder2ibek/releases>
@@ -0,0 +1,22 @@
1
+ # Start Claude Code in sandbox mode (no SSH agent, skip permission prompts)
2
+ claude:
3
+ SSH_AUTH_SOCK= IS_SANDBOX=1 claude --dangerously-skip-permissions
4
+
5
+
6
+ # Authenticate gh CLI with a GitHub PAT (token not stored in shell history)
7
+ gh-auth:
8
+ #!/bin/bash
9
+ read -sp "GitHub PAT: " t && echo
10
+ echo "$t" | gh auth login --with-token
11
+ unset t
12
+ gh auth setup-git
13
+ gh auth status
14
+
15
+
16
+ # Authenticate glab CLI with a GitLab PAT (token not stored in shell history). --git-protocol https prevents glab's SSH insteadOf rewrite.
17
+ glab-auth hostname="gitlab.diamond.ac.uk":
18
+ #!/bin/bash
19
+ read -sp "GitLab PAT for {{ hostname }}: " t && echo
20
+ echo "$t" | glab auth login --stdin --hostname {{ hostname }} --git-protocol https
21
+ unset t
22
+ glab auth status
@@ -26,6 +26,7 @@ dev = [
26
26
  "pytest",
27
27
  "pytest-cov",
28
28
  "pytest-mock",
29
+ "pytest-xdist",
29
30
  "ruff",
30
31
  "sphinx-autobuild",
31
32
  "sphinx-copybutton",
@@ -53,7 +54,7 @@ ignore_missing_imports = true # Ignore missing stubs in imported modules
53
54
  [tool.pytest.ini_options]
54
55
  # Run pytest with all our checkers, and don't spam us with massive tracebacks on error
55
56
  addopts = """
56
- --tb=native -vv --doctest-modules --doctest-glob="*.rst"
57
+ --tb=native -vv --doctest-modules --doctest-glob="*.rst" -n auto
57
58
  """
58
59
  # https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings
59
60
  filterwarnings = "error"
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.0.1'
22
- __version_tuple__ = version_tuple = (2, 0, 1)
21
+ __version__ = version = '2.0.2'
22
+ __version_tuple__ = version_tuple = (2, 0, 2)
23
23
 
24
- __commit_id__ = commit_id = 'g576c57179'
24
+ __commit_id__ = commit_id = 'g73d451bd1'
@@ -0,0 +1,17 @@
1
+ from builder2ibek.converters.globalHandler import globalHandler
2
+ from builder2ibek.types import Entity, Generic_IOC
3
+
4
+ xml_component = "insertionDevice"
5
+
6
+
7
+ @globalHandler
8
+ def handler(entity: Entity, entity_type: str, ioc: Generic_IOC):
9
+ """
10
+ XML to YAML converter for the insertionDevice support module.
11
+ """
12
+
13
+ entity.remove("name")
14
+
15
+ if entity_type == "insertionDevice4V_generic_DTTemplate":
16
+ if hasattr(entity, "comptable"):
17
+ entity.comptable = str(entity.comptable)
@@ -20,6 +20,10 @@ def handler(entity: Entity, entity_type: str, ioc: Generic_IOC):
20
20
  entity.type = "dlsPLC.interlock"
21
21
  entity.remove("name")
22
22
  hex_to_int(entity, "ilk")
23
+ # addr is type: int in the support YAML; XML can encode it zero-padded
24
+ # ("07"), which the generic converter preserves as a string. Coerce.
25
+ if entity.addr is not None:
26
+ entity.addr = int(entity.addr)
23
27
 
24
28
  if entity_type == "overrideRequestMain":
25
29
  entity.type = "dlsPLC.overrideRequestMain"
@@ -0,0 +1,21 @@
1
+ from builder2ibek.converters.globalHandler import globalHandler
2
+ from builder2ibek.types import Entity, Generic_IOC
3
+
4
+ xml_component = "mks937a"
5
+
6
+
7
+ @globalHandler
8
+ def handler(entity: Entity, entity_type: str, ioc: Generic_IOC):
9
+ """
10
+ XML to YAML specialist convertor function for the mks937a support module
11
+ """
12
+ # remove GUI only parameters (except on mks937aGauge which uses it for object ref)
13
+ if entity_type not in ["mks937aGauge", "mks937a"]:
14
+ entity.remove("name")
15
+
16
+ # mks937aGauge(EGU).id is type: int in the support YAML, but XML encodes
17
+ # it as a zero-padded string (e.g. "02") which the generic converter
18
+ # preserves. Coerce to int so ioc.yaml holds a bare integer; the support
19
+ # YAML re-pads with Jinja (`{{ '%02d' % id }}`) when rendering databases.
20
+ if entity_type in ("mks937aGauge", "mks937aGaugeEGU") and entity.id is not None:
21
+ entity.id = int(entity.id)
@@ -20,3 +20,12 @@ def handler(entity: Entity, entity_type: str, ioc: Generic_IOC):
20
20
  "mks937bCap",
21
21
  ):
22
22
  entity.remove("name")
23
+
24
+ # mks937bGauge.id and mks937b.address are type: int in the support YAML,
25
+ # but XML encodes them zero-padded ("02", "001") which the generic
26
+ # converter preserves. Coerce to int; the support YAML re-pads with Jinja
27
+ # (`{{ '%02d' % id }}`, `{{ '%03d' % address }}`) when rendering.
28
+ if entity_type == "mks937bGauge" and entity.id is not None:
29
+ entity.id = int(entity.id)
30
+ if entity_type == "mks937b" and entity.address is not None:
31
+ entity.address = int(entity.address)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: builder2ibek
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: Conversion tool for DLS XML builder IOC instances to ibek ioc.yaml
5
5
  Author-email: Giles Knap <giles.knap@diamond.ac.uk>
6
6
  License: Apache License
@@ -225,8 +225,9 @@ Dynamic: license-file
225
225
  A tool suite for converting DLS XMLbuilder IOC projects to
226
226
  [epics-containers](https://github.com/epics-containers) ibek.
227
227
 
228
- Source | <https://github.com/epics-containers/builder2ibek>
228
+ What | Where
229
229
  :---: | :---:
230
+ Source | <https://github.com/epics-containers/builder2ibek>
230
231
  PyPI | `pip install builder2ibek`
231
232
  Documentation | <https://epics-containers.github.io/builder2ibek>
232
233
  Releases | <https://github.com/epics-containers/builder2ibek/releases>
@@ -28,6 +28,7 @@ uv.lock
28
28
  .claude/commands/support-create.md
29
29
  .claude/commands/support-fix.md
30
30
  .claude/commands/support-inspect.md
31
+ .claude/skills/beamline-gui/SKILL.md
31
32
  .claude/skills/ibek-concepts/SKILL.md
32
33
  .claude/skills/ibek-support-ansible/SKILL.md
33
34
  .claude/skills/shared/builder-py-analysis.md
@@ -187,6 +188,7 @@ src/builder2ibek/converters/gdaPlugins.yaml
187
188
  src/builder2ibek/converters/globalHandler.py
188
189
  src/builder2ibek/converters/harvardSyringe.py
189
190
  src/builder2ibek/converters/hidenRGA.py
191
+ src/builder2ibek/converters/insertionDevice.py
190
192
  src/builder2ibek/converters/interlock.py
191
193
  src/builder2ibek/converters/ipac.py
192
194
  src/builder2ibek/converters/keithley6514.py
@@ -3,17 +3,14 @@ import subprocess
3
3
  from pathlib import Path
4
4
 
5
5
  import pytest
6
+ from filelock import FileLock
6
7
 
7
8
  REPO_ROOT = Path(__file__).parent.parent
8
9
  DLS_SUPPORT = REPO_ROOT / "ibek-support-dls"
9
10
  HAS_DLS_SUPPORT = any(DLS_SUPPORT.glob("*/*.ibek.support.yaml"))
10
11
 
11
12
 
12
- @pytest.fixture(scope="session", autouse=True)
13
- def update_schema(tmp_path_factory):
14
- """Regenerate the ibek schema before tests so support YAMLs stay in sync."""
15
- if not HAS_DLS_SUPPORT:
16
- pytest.skip("ibek-support-dls not available")
13
+ def _run_update_schema(tmp_path_factory):
17
14
  env = os.environ.copy()
18
15
  # Use a temp dir when /epics is not writable (e.g. CI runners)
19
16
  epics_root = Path(env.get("EPICS_ROOT", "/epics"))
@@ -30,6 +27,28 @@ def update_schema(tmp_path_factory):
30
27
  assert result.returncode == 0, f"update-schema failed:\n{result.stderr}"
31
28
 
32
29
 
30
+ @pytest.fixture(scope="session", autouse=True)
31
+ def update_schema(tmp_path_factory, worker_id):
32
+ """Regenerate the ibek schema before tests so support YAMLs stay in sync.
33
+
34
+ With pytest-xdist, every worker wants to run this — but they all write to
35
+ the same $EPICS_ROOT/ibek-defs, so the classic xdist file-lock pattern
36
+ runs it exactly once and lets the rest wait for the sentinel.
37
+ """
38
+ if not HAS_DLS_SUPPORT:
39
+ pytest.skip("ibek-support-dls not available")
40
+ if worker_id == "master":
41
+ # non-xdist run: just do it
42
+ _run_update_schema(tmp_path_factory)
43
+ return
44
+ shared_tmp = tmp_path_factory.getbasetemp().parent
45
+ done = shared_tmp / "schema.done"
46
+ with FileLock(str(shared_tmp / "schema.lock")):
47
+ if not done.exists():
48
+ _run_update_schema(tmp_path_factory)
49
+ done.touch()
50
+
51
+
33
52
  requires_dls = pytest.mark.skipif(
34
53
  not HAS_DLS_SUPPORT,
35
54
  reason="ibek-support-dls submodule not available",
@@ -232,7 +232,7 @@ entities:
232
232
  port: ty_42_0
233
233
 
234
234
  - type: mks937b.mks937b
235
- address: '001'
235
+ address: 1
236
236
  device: BL04I-VA-GCTLR-01
237
237
  name: GCTLR01
238
238
  port: ty_40_5
@@ -240,28 +240,28 @@ entities:
240
240
  - type: mks937a.mks937aGauge
241
241
  c: 50
242
242
  dom: BL04I
243
- id: '03'
243
+ id: 3
244
244
  name: GAUGE3
245
245
  s: 3
246
246
 
247
247
  - type: mks937a.mks937aGauge
248
248
  c: 50
249
249
  dom: BL04I
250
- id: '04'
250
+ id: 4
251
251
  name: GAUGE4
252
252
  s: 4
253
253
 
254
254
  - type: mks937a.mks937aGauge
255
255
  c: 50
256
256
  dom: BL04I
257
- id: '05'
257
+ id: 5
258
258
  name: GAUGE5
259
259
  s: 5
260
260
 
261
261
  - type: mks937a.mks937aGauge
262
262
  c: 50
263
263
  dom: BL04I
264
- id: '06'
264
+ id: 6
265
265
  name: GAUGE6
266
266
  s: 6
267
267
 
@@ -306,13 +306,13 @@ entities:
306
306
 
307
307
  - type: mks937b.mks937bGauge
308
308
  dom: BL04I
309
- id: '01'
309
+ id: 1
310
310
  name: GAUGE1
311
311
  plog_adc_pv: BL04I-VA-ADC-01:CH1
312
312
 
313
313
  - type: mks937b.mks937bGauge
314
314
  dom: BL04I
315
- id: '02'
315
+ id: 2
316
316
  name: GAUGE2
317
317
  plog_adc_pv: BL04I-VA-ADC-01:CH2
318
318
 
@@ -854,7 +854,7 @@ entities:
854
854
  port: ty_40_0
855
855
 
856
856
  - type: dlsPLC.interlock
857
- addr: '07'
857
+ addr: 7
858
858
  desc: Water Flow Interlocks
859
859
  device: BL04I-VA-VLVCC-01
860
860
  ilk0: I04 Filter
@@ -877,7 +877,7 @@ entities:
877
877
  port: ty_40_0
878
878
 
879
879
  - type: dlsPLC.interlock
880
- addr: '09'
880
+ addr: 9
881
881
  desc: Front End Permit
882
882
  device: BL04I-VA-VLVCC-01
883
883
  ilk0: Waterflows