@litfamily/lithermes 1.0.7 → 1.0.9

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 (652) hide show
  1. package/README.md +299 -13
  2. package/README_Ko-KR.md +300 -14
  3. package/assets/lithermes-plugin/README.md +17 -6
  4. package/assets/lithermes-plugin/__init__.py +96 -21
  5. package/assets/lithermes-plugin/core.py +15 -6
  6. package/assets/lithermes-plugin/core_commands.py +140 -28
  7. package/assets/lithermes-plugin/core_contexts.py +88 -15
  8. package/assets/lithermes-plugin/core_contract.py +118 -9
  9. package/assets/lithermes-plugin/core_routing.py +197 -8
  10. package/assets/lithermes-plugin/deliverable_hedge_guard.py +378 -357
  11. package/assets/lithermes-plugin/diagnostics.py +76 -8
  12. package/assets/lithermes-plugin/humanizer_detector.py +348 -0
  13. package/assets/lithermes-plugin/humanizer_ko_metrics.py +108 -0
  14. package/assets/lithermes-plugin/humanizer_office.py +18 -0
  15. package/assets/lithermes-plugin/lit_mark.py +1 -1
  16. package/assets/lithermes-plugin/motion_receipts.py +80 -0
  17. package/assets/lithermes-plugin/payload-version.json +2240 -64
  18. package/assets/lithermes-plugin/plugin.yaml +1 -1
  19. package/assets/lithermes-plugin/rules/bundled-rules/lit-humanizer.md +14 -0
  20. package/assets/lithermes-plugin/skills/autoconference/assets/report_template.md +2 -1
  21. package/assets/lithermes-plugin/skills/autoconference/modes/ship/SKILL.md +11 -8
  22. package/assets/lithermes-plugin/skills/autoresearch/modes/ship/type-checklists.md +2 -2
  23. package/assets/lithermes-plugin/skills/browser-drive/ORIGIN.json +17 -0
  24. package/assets/lithermes-plugin/skills/browser-drive/SKILL.md +41 -16
  25. package/assets/lithermes-plugin/skills/browser-drive/scripts/capability_probe.py +122 -10
  26. package/assets/lithermes-plugin/skills/frontend-ui-ux/SKILL.md +45 -13
  27. package/assets/lithermes-plugin/skills/frontend-ui-ux/examples/phase-3-readme-ab/README.md +51 -0
  28. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/README.md +44 -0
  29. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/adaptive-layout.md +34 -62
  30. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/brand-and-imagery.md +22 -70
  31. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/complete-contract.md +18 -4
  32. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/composition.md +27 -78
  33. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/craft-floor.md +74 -0
  34. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/creative-directions.md +25 -69
  35. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/evidence-review.md +18 -97
  36. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/implementation-platforms.md +23 -83
  37. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/inclusive-interface.md +22 -70
  38. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/interaction-motion.md +34 -68
  39. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/motion-guide.md +62 -0
  40. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/operating-lanes.md +14 -78
  41. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/performance-delivery.md +22 -71
  42. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/product-direction.md +17 -70
  43. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/production.md +19 -7
  44. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/redesign-playbook.md +23 -76
  45. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/slop-register.md +69 -0
  46. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/system-foundations.md +22 -67
  47. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/visual-language.md +16 -72
  48. package/assets/lithermes-plugin/skills/frontend-ui-ux/references/visual-reconstruction.md +16 -81
  49. package/assets/lithermes-plugin/skills/frontend-ui-ux/resources/THIRD-PARTY-NOTICE.txt +15 -0
  50. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/probe-page.js +311 -0
  51. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/probe-rules.json +46 -0
  52. package/assets/lithermes-plugin/skills/frontend-ui-ux/scripts/probe.mjs +231 -0
  53. package/assets/lithermes-plugin/skills/lit-comprehend/SKILL.md +36 -25
  54. package/assets/lithermes-plugin/skills/lit-comprehend/references/artifact-template.md +45 -87
  55. package/assets/lithermes-plugin/skills/lit-comprehend/scripts/verify-explainer.py +3 -27
  56. package/assets/lithermes-plugin/skills/lit-diagram-drawer/NOTICE +33 -0
  57. package/assets/lithermes-plugin/skills/lit-diagram-drawer/SKILL.md +308 -0
  58. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-architecture-dark.html +1 -0
  59. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-architecture-full.html +1 -0
  60. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-architecture-light.html +1 -0
  61. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bar-dark.html +1 -0
  62. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bar-full.html +1 -0
  63. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bar-light.html +1 -0
  64. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-beeswarm-dark.html +1 -0
  65. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-beeswarm-full.html +1 -0
  66. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-beeswarm-light.html +1 -0
  67. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bubble-dark.html +1 -0
  68. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bubble-full.html +1 -0
  69. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bubble-light.html +1 -0
  70. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bump-dark.html +1 -0
  71. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bump-full.html +1 -0
  72. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-bump-light.html +1 -0
  73. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-data-flow-dark.html +1 -0
  74. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-data-flow-full.html +1 -0
  75. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-data-flow-light.html +1 -0
  76. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-datalake-dark.html +1 -0
  77. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-datalake-full.html +1 -0
  78. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-datalake-light.html +1 -0
  79. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-db-schema-dark.html +1 -0
  80. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-db-schema-full.html +1 -0
  81. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-db-schema-light.html +1 -0
  82. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dependency-dark.html +1 -0
  83. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dependency-full.html +1 -0
  84. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dependency-light.html +1 -0
  85. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-deployment-dark.html +1 -0
  86. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-deployment-full.html +1 -0
  87. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-deployment-light.html +1 -0
  88. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dp-integration-dark.html +1 -0
  89. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dp-integration-full.html +1 -0
  90. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dp-integration-light.html +1 -0
  91. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-dark.html +1 -0
  92. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-full.html +1 -0
  93. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-light.html +1 -0
  94. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-er-dark.html +1 -0
  95. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-er-full.html +1 -0
  96. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-er-light.html +1 -0
  97. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-fishbone-dark.html +1 -0
  98. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-fishbone-full.html +1 -0
  99. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-fishbone-light.html +1 -0
  100. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-flowchart-dark.html +1 -0
  101. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-flowchart-full.html +1 -0
  102. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-flowchart-light.html +1 -0
  103. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-gantt-dark.html +1 -0
  104. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-gantt-full.html +1 -0
  105. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-gantt-light.html +1 -0
  106. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-heatmap-dark.html +1 -0
  107. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-heatmap-full.html +1 -0
  108. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-heatmap-light.html +1 -0
  109. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-high-level-dark.html +1 -0
  110. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-high-level-full.html +1 -0
  111. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-high-level-light.html +1 -0
  112. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-dark.html +1 -0
  113. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-full.html +1 -0
  114. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-light.html +1 -0
  115. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-drawio-dark.html +1 -0
  116. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-drawio-full.html +1 -0
  117. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-drawio-light.html +1 -0
  118. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-dark.html +1 -0
  119. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-full.html +1 -0
  120. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-light.html +1 -0
  121. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-dark.html +1 -0
  122. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-full.html +1 -0
  123. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-light.html +1 -0
  124. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-it-state-dark.html +1 -0
  125. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-it-state-full.html +1 -0
  126. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-it-state-light.html +1 -0
  127. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-journey-dark.html +1 -0
  128. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-journey-full.html +1 -0
  129. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-journey-light.html +1 -0
  130. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-kanban-dark.html +1 -0
  131. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-kanban-full.html +1 -0
  132. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-kanban-light.html +1 -0
  133. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-layers-dark.html +1 -0
  134. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-layers-full.html +1 -0
  135. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-layers-light.html +1 -0
  136. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-line-dark.html +1 -0
  137. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-line-full.html +1 -0
  138. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-line-light.html +1 -0
  139. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-loop-dark.html +1 -0
  140. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-loop-full.html +1 -0
  141. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-loop-light.html +1 -0
  142. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-dark.html +1 -0
  143. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-full.html +1 -0
  144. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-light.html +1 -0
  145. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-marimekko-dark.html +1 -0
  146. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-marimekko-full.html +1 -0
  147. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-marimekko-light.html +1 -0
  148. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-medallion-dark.html +1 -0
  149. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-medallion-full.html +1 -0
  150. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-medallion-light.html +1 -0
  151. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-nested-dark.html +1 -0
  152. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-nested-full.html +1 -0
  153. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-nested-light.html +1 -0
  154. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-org-chart-dark.html +1 -0
  155. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-org-chart-full.html +1 -0
  156. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-org-chart-light.html +1 -0
  157. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-dark.html +1 -0
  158. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-full.html +1 -0
  159. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-light.html +1 -0
  160. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-polar-dark.html +1 -0
  161. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-polar-full.html +1 -0
  162. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-polar-light.html +1 -0
  163. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-dark.html +1 -0
  164. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-full.html +1 -0
  165. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-light.html +1 -0
  166. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-process-dark.html +1 -0
  167. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-process-full.html +1 -0
  168. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-process-light.html +1 -0
  169. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-pyramid-dark.html +1 -0
  170. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-pyramid-full.html +1 -0
  171. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-pyramid-light.html +1 -0
  172. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-dark.html +1 -0
  173. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-full.html +1 -0
  174. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-light.html +1 -0
  175. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-quadrant-dark.html +1 -0
  176. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-quadrant-full.html +1 -0
  177. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-quadrant-light.html +1 -0
  178. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-queue-animated-dark.html +1 -0
  179. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-queue-animated-full.html +1 -0
  180. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-queue-animated-light.html +1 -0
  181. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-radar-dark.html +1 -0
  182. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-radar-full.html +1 -0
  183. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-radar-light.html +1 -0
  184. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-ridgeline-dark.html +1 -0
  185. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-ridgeline-full.html +1 -0
  186. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-ridgeline-light.html +1 -0
  187. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sankey-dark.html +1 -0
  188. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sankey-full.html +1 -0
  189. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sankey-light.html +1 -0
  190. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-scatter-dark.html +1 -0
  191. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-scatter-full.html +1 -0
  192. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-scatter-light.html +1 -0
  193. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sequence-dark.html +1 -0
  194. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sequence-full.html +1 -0
  195. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sequence-light.html +1 -0
  196. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-dark.html +1 -0
  197. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-full.html +1 -0
  198. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-light.html +1 -0
  199. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-slopegraph-dark.html +1 -0
  200. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-slopegraph-full.html +1 -0
  201. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-slopegraph-light.html +1 -0
  202. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-state-dark.html +1 -0
  203. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-state-full.html +1 -0
  204. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-dark.html +1 -0
  205. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-full.html +1 -0
  206. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-light.html +1 -0
  207. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-state-light.html +1 -0
  208. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-story-map-dark.html +1 -0
  209. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-story-map-full.html +1 -0
  210. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-story-map-light.html +1 -0
  211. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-streamgraph-dark.html +1 -0
  212. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-streamgraph-full.html +1 -0
  213. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-streamgraph-light.html +1 -0
  214. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-swimlane-dark.html +1 -0
  215. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-swimlane-full.html +1 -0
  216. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-swimlane-light.html +1 -0
  217. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-timeline-dark.html +1 -0
  218. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-timeline-full.html +1 -0
  219. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-timeline-light.html +1 -0
  220. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-dark.html +1 -0
  221. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-full.html +1 -0
  222. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-light.html +1 -0
  223. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-tree-dark.html +1 -0
  224. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-tree-full.html +1 -0
  225. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-tree-light.html +1 -0
  226. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-treemap-dark.html +1 -0
  227. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-treemap-full.html +1 -0
  228. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-treemap-light.html +1 -0
  229. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-uml-class-dark.html +1 -0
  230. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-uml-class-full.html +1 -0
  231. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-uml-class-light.html +1 -0
  232. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-venn-dark.html +1 -0
  233. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-venn-full.html +1 -0
  234. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-venn-light.html +1 -0
  235. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-wardley-dark.html +1 -0
  236. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-wardley-full.html +1 -0
  237. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-wardley-light.html +1 -0
  238. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-waterfall-dark.html +1 -0
  239. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-waterfall-full.html +1 -0
  240. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/examples/type-waterfall-light.html +1 -0
  241. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/fonts/OFL.txt +94 -0
  242. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/fonts/PretendardVariable.woff2 +0 -0
  243. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/fonts/provenance.json +22 -0
  244. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/icons.html +231 -0
  245. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/index.html +1 -0
  246. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/licenses/devicon-MIT.txt +20 -0
  247. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/licenses/diagram-design-MIT.txt +21 -0
  248. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/licenses/log-z-MIT.txt +21 -0
  249. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/licenses/simple-icons-CC0.md +30 -0
  250. package/assets/lithermes-plugin/skills/lit-diagram-drawer/assets/licenses/tabler-MIT.txt +21 -0
  251. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/01-service-architecture/after.html +1 -0
  252. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/01-service-architecture/brief.md +33 -0
  253. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/02-release-decision/after.html +1 -0
  254. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/02-release-decision/brief.md +18 -0
  255. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/03-data-retention/after.html +1 -0
  256. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/03-data-retention/brief.md +19 -0
  257. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/04-oauth-sequence/after.html +1 -0
  258. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/04-oauth-sequence/brief.md +17 -0
  259. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/05-review-lanes/after.html +1 -0
  260. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/05-review-lanes/brief.md +17 -0
  261. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/06-rollout-gates/after.html +1 -0
  262. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/06-rollout-gates/brief.md +17 -0
  263. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/07-deployment-boundary/after.html +1 -0
  264. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/07-deployment-boundary/brief.md +19 -0
  265. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/08-policy-traces/after.html +1 -0
  266. package/assets/lithermes-plugin/skills/lit-diagram-drawer/examples/08-policy-traces/brief.md +20 -0
  267. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/accessibility.md +37 -0
  268. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/export.md +29 -0
  269. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/import-drawio.md +21 -0
  270. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/import-excalidraw.md +14 -0
  271. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/import-mermaid.md +18 -0
  272. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/import-schema.md +28 -0
  273. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/korean-typography.md +34 -0
  274. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/motion.md +29 -0
  275. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/office-pptx-docx.md +40 -0
  276. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/output-spec.md +48 -0
  277. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/primitive-annotation.md +12 -0
  278. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/primitive-icons.md +21 -0
  279. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/primitive-sketchy.md +11 -0
  280. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/primitive-terminal.md +11 -0
  281. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/profiles.md +24 -0
  282. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/semantic-patterns.md +27 -0
  283. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/style-guide.md +67 -0
  284. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-architecture.md +51 -0
  285. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-bar.md +51 -0
  286. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-beeswarm.md +49 -0
  287. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-bubble.md +49 -0
  288. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-bump.md +49 -0
  289. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-catalog.json +1433 -0
  290. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-data-flow.md +51 -0
  291. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-datalake.md +49 -0
  292. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-db-schema.md +49 -0
  293. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-dependency.md +49 -0
  294. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-deployment.md +49 -0
  295. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-dp-integration.md +49 -0
  296. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-dp-security-matrix.md +49 -0
  297. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-er.md +49 -0
  298. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-fishbone.md +49 -0
  299. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-flowchart.md +49 -0
  300. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-gantt.md +49 -0
  301. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-heatmap.md +53 -0
  302. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-high-level-vertical.md +53 -0
  303. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-high-level.md +53 -0
  304. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-import-drawio.md +53 -0
  305. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-import-excalidraw.md +53 -0
  306. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-import-mermaid.md +53 -0
  307. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-it-state.md +54 -0
  308. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-journey.md +54 -0
  309. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-kanban.md +54 -0
  310. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-layers.md +54 -0
  311. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-line.md +54 -0
  312. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-loop-terminal.md +53 -0
  313. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-loop.md +54 -0
  314. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-marimekko.md +54 -0
  315. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-medallion.md +54 -0
  316. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-nested.md +59 -0
  317. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-org-chart.md +58 -0
  318. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-paved-road-animated.md +72 -0
  319. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-polar.md +67 -0
  320. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-policy-trace-animated.md +69 -0
  321. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-process.md +58 -0
  322. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-pyramid.md +59 -0
  323. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-quadrant-consultant.md +60 -0
  324. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-quadrant.md +57 -0
  325. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-queue-animated.md +63 -0
  326. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-radar.md +57 -0
  327. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-ridgeline.md +63 -0
  328. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-sankey.md +68 -0
  329. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-scatter.md +60 -0
  330. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-sequence-oauth.md +66 -0
  331. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-sequence.md +63 -0
  332. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-slopegraph.md +65 -0
  333. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-state-lifecycle.md +53 -0
  334. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-state.md +59 -0
  335. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-story-map.md +52 -0
  336. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-streamgraph.md +53 -0
  337. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-swimlane.md +52 -0
  338. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-timeline.md +52 -0
  339. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-tree-block-decomposition.md +57 -0
  340. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-tree.md +54 -0
  341. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-treemap.md +54 -0
  342. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-uml-class.md +52 -0
  343. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-venn.md +51 -0
  344. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-wardley.md +52 -0
  345. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/type-waterfall.md +54 -0
  346. package/assets/lithermes-plugin/skills/lit-diagram-drawer/references/verifier-guide.md +31 -0
  347. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/block-registry.mjs +43 -0
  348. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/browser-version.mjs +12 -0
  349. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/check-visible-text.py +12 -0
  350. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_brief.py +192 -0
  351. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_catalog.py +135 -0
  352. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_checks.py +123 -0
  353. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_cli.py +94 -0
  354. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_geometry.py +130 -0
  355. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_metrics.py +166 -0
  356. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_quality.py +293 -0
  357. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_quality_geometry.py +200 -0
  358. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_records.py +205 -0
  359. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/diagram_sequence.py +55 -0
  360. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/doctor.mjs +24 -0
  361. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/drawio_extract.py +209 -0
  362. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/drawio_source.py +188 -0
  363. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/excalidraw_extract.py +233 -0
  364. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/excalidraw_support.py +64 -0
  365. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/export.mjs +125 -0
  366. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/mermaid_extract.py +240 -0
  367. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/mermaid_source.py +39 -0
  368. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/office-safety.mjs +54 -0
  369. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/verify-all.py +12 -0
  370. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/verify-brief.py +12 -0
  371. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/verify-diagram.py +12 -0
  372. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/verify-motion.py +12 -0
  373. package/assets/lithermes-plugin/skills/lit-diagram-drawer/scripts/verify-type.py +12 -0
  374. package/assets/lithermes-plugin/skills/lit-docx/NOTICE +1 -0
  375. package/assets/lithermes-plugin/skills/lit-docx/SKILL.md +97 -0
  376. package/assets/lithermes-plugin/skills/lit-docx/references/frontmatter_schema.md +42 -0
  377. package/assets/lithermes-plugin/skills/lit-docx/references/journal_style_spec.md +17 -0
  378. package/assets/lithermes-plugin/skills/lit-docx/references/markdown_quality_checklist.md +37 -0
  379. package/assets/lithermes-plugin/skills/lit-docx/references/slop_phrase_list.yaml +58 -0
  380. package/assets/lithermes-plugin/skills/lit-docx/references/slop_rules.md +35 -0
  381. package/assets/lithermes-plugin/skills/lit-docx/scripts/clean_markdown.py +95 -0
  382. package/assets/lithermes-plugin/skills/lit-docx/scripts/convert_md_to_docx.py +1041 -0
  383. package/assets/lithermes-plugin/skills/lit-docx/scripts/convert_md_to_pdf.py +281 -0
  384. package/assets/lithermes-plugin/skills/lit-docx/scripts/convert_pdf.py +130 -0
  385. package/assets/lithermes-plugin/skills/lit-docx/scripts/edit_docx.py +297 -0
  386. package/assets/lithermes-plugin/skills/lit-docx/scripts/embed_images.py +78 -0
  387. package/assets/lithermes-plugin/skills/lit-docx/scripts/generate_docx_templates.py +491 -0
  388. package/assets/lithermes-plugin/skills/lit-docx/scripts/slop_lint.py +536 -0
  389. package/assets/lithermes-plugin/skills/lit-docx/scripts/visual_audit.py +41 -0
  390. package/assets/lithermes-plugin/skills/lit-docx/templates/docx/acs.docx +0 -0
  391. package/assets/lithermes-plugin/skills/lit-docx/templates/docx/elsevier.docx +0 -0
  392. package/assets/lithermes-plugin/skills/lit-docx/templates/docx/ieee.docx +0 -0
  393. package/assets/lithermes-plugin/skills/lit-docx/templates/docx/korean-generic.docx +0 -0
  394. package/assets/lithermes-plugin/skills/lit-docx/templates/docx/nature.docx +0 -0
  395. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/acs/README.md +5 -0
  396. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/acs/template.tex +37 -0
  397. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/elsevier/README.md +5 -0
  398. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/elsevier/template.tex +38 -0
  399. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/ieee/README.md +5 -0
  400. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/ieee/template.tex +37 -0
  401. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/korean-generic/README.md +5 -0
  402. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/korean-generic/template.tex +37 -0
  403. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/nature/README.md +5 -0
  404. package/assets/lithermes-plugin/skills/lit-docx/templates/latex/nature/template.tex +37 -0
  405. package/assets/lithermes-plugin/skills/lit-docx/templates/registry.yaml +1366 -0
  406. package/assets/lithermes-plugin/skills/lit-humanizer/NOTICE +170 -0
  407. package/assets/lithermes-plugin/skills/lit-humanizer/SKILL.md +125 -0
  408. package/assets/lithermes-plugin/skills/lit-humanizer/assets/report-skeleton.md +26 -0
  409. package/assets/lithermes-plugin/skills/lit-humanizer/assets/slide-text-skeleton.md +30 -0
  410. package/assets/lithermes-plugin/skills/lit-humanizer/examples/accessibility-note/after.md +7 -0
  411. package/assets/lithermes-plugin/skills/lit-humanizer/examples/accessibility-note/before.md +7 -0
  412. package/assets/lithermes-plugin/skills/lit-humanizer/examples/api-reference/after.md +9 -0
  413. package/assets/lithermes-plugin/skills/lit-humanizer/examples/api-reference/before.md +15 -0
  414. package/assets/lithermes-plugin/skills/lit-humanizer/examples/changelog/after.md +5 -0
  415. package/assets/lithermes-plugin/skills/lit-humanizer/examples/changelog/before.md +12 -0
  416. package/assets/lithermes-plugin/skills/lit-humanizer/examples/code-comments/after.md +10 -0
  417. package/assets/lithermes-plugin/skills/lit-humanizer/examples/code-comments/before.md +19 -0
  418. package/assets/lithermes-plugin/skills/lit-humanizer/examples/commit/after.md +5 -0
  419. package/assets/lithermes-plugin/skills/lit-humanizer/examples/commit/before.md +7 -0
  420. package/assets/lithermes-plugin/skills/lit-humanizer/examples/data-release/after.md +7 -0
  421. package/assets/lithermes-plugin/skills/lit-humanizer/examples/data-release/before.md +9 -0
  422. package/assets/lithermes-plugin/skills/lit-humanizer/examples/detector-validation/ko-metrics-golden.json +49 -0
  423. package/assets/lithermes-plugin/skills/lit-humanizer/examples/detector-validation/pos-real.txt +26 -0
  424. package/assets/lithermes-plugin/skills/lit-humanizer/examples/detector-validation/rule-cases.json +306 -0
  425. package/assets/lithermes-plugin/skills/lit-humanizer/examples/english-essay/after.md +5 -0
  426. package/assets/lithermes-plugin/skills/lit-humanizer/examples/english-essay/before.md +5 -0
  427. package/assets/lithermes-plugin/skills/lit-humanizer/examples/incident-update/after.md +7 -0
  428. package/assets/lithermes-plugin/skills/lit-humanizer/examples/incident-update/before.md +7 -0
  429. package/assets/lithermes-plugin/skills/lit-humanizer/examples/ko-essay/after.md +7 -0
  430. package/assets/lithermes-plugin/skills/lit-humanizer/examples/ko-essay/before.md +9 -0
  431. package/assets/lithermes-plugin/skills/lit-humanizer/examples/ko-report/after.md +9 -0
  432. package/assets/lithermes-plugin/skills/lit-humanizer/examples/ko-report/before.md +13 -0
  433. package/assets/lithermes-plugin/skills/lit-humanizer/examples/ko-slide/after.md +19 -0
  434. package/assets/lithermes-plugin/skills/lit-humanizer/examples/ko-slide/before.md +21 -0
  435. package/assets/lithermes-plugin/skills/lit-humanizer/examples/meeting-brief/after.md +9 -0
  436. package/assets/lithermes-plugin/skills/lit-humanizer/examples/meeting-brief/before.md +11 -0
  437. package/assets/lithermes-plugin/skills/lit-humanizer/examples/policy-faq/after.md +9 -0
  438. package/assets/lithermes-plugin/skills/lit-humanizer/examples/policy-faq/before.md +9 -0
  439. package/assets/lithermes-plugin/skills/lit-humanizer/examples/pr/after.md +15 -0
  440. package/assets/lithermes-plugin/skills/lit-humanizer/examples/pr/before.md +17 -0
  441. package/assets/lithermes-plugin/skills/lit-humanizer/examples/project-update/after.md +7 -0
  442. package/assets/lithermes-plugin/skills/lit-humanizer/examples/project-update/before.md +9 -0
  443. package/assets/lithermes-plugin/skills/lit-humanizer/examples/readme/after.md +12 -0
  444. package/assets/lithermes-plugin/skills/lit-humanizer/examples/readme/before.md +14 -0
  445. package/assets/lithermes-plugin/skills/lit-humanizer/examples/report/after.md +13 -0
  446. package/assets/lithermes-plugin/skills/lit-humanizer/examples/report/before.md +11 -0
  447. package/assets/lithermes-plugin/skills/lit-humanizer/examples/research-abstract/after.md +5 -0
  448. package/assets/lithermes-plugin/skills/lit-humanizer/examples/research-abstract/before.md +5 -0
  449. package/assets/lithermes-plugin/skills/lit-humanizer/examples/slides/after.md +19 -0
  450. package/assets/lithermes-plugin/skills/lit-humanizer/examples/slides/before.md +19 -0
  451. package/assets/lithermes-plugin/skills/lit-humanizer/examples/troubleshooting/after.md +11 -0
  452. package/assets/lithermes-plugin/skills/lit-humanizer/examples/troubleshooting/before.md +11 -0
  453. package/assets/lithermes-plugin/skills/lit-humanizer/references/README.md +16 -0
  454. package/assets/lithermes-plugin/skills/lit-humanizer/references/always-on-rule.md +9 -0
  455. package/assets/lithermes-plugin/skills/lit-humanizer/references/code-patterns.md +468 -0
  456. package/assets/lithermes-plugin/skills/lit-humanizer/references/deliverable-channels.md +111 -0
  457. package/assets/lithermes-plugin/skills/lit-humanizer/references/en-patterns-checklist.md +43 -0
  458. package/assets/lithermes-plugin/skills/lit-humanizer/references/en-patterns-content.md +243 -0
  459. package/assets/lithermes-plugin/skills/lit-humanizer/references/en-patterns-structure.md +375 -0
  460. package/assets/lithermes-plugin/skills/lit-humanizer/references/en-patterns.md +57 -0
  461. package/assets/lithermes-plugin/skills/lit-humanizer/references/ko-metrics.md +33 -0
  462. package/assets/lithermes-plugin/skills/lit-humanizer/references/ko-patterns-a-d.md +659 -0
  463. package/assets/lithermes-plugin/skills/lit-humanizer/references/ko-patterns-e-j.md +387 -0
  464. package/assets/lithermes-plugin/skills/lit-humanizer/references/ko-patterns.md +31 -0
  465. package/assets/lithermes-plugin/skills/lit-humanizer/references/rewrite-playbook.md +54 -0
  466. package/assets/lithermes-plugin/skills/lit-humanizer/references/taxonomy.md +153 -0
  467. package/assets/lithermes-plugin/skills/lit-humanizer/rules.json +884 -0
  468. package/assets/lithermes-plugin/skills/lit-humanizer/scripts/detect.py +17 -0
  469. package/assets/lithermes-plugin/skills/lit-humanizer/scripts/extract_office_text.py +114 -0
  470. package/assets/lithermes-plugin/skills/lit-humanizer/scripts/ko_metrics.py +35 -0
  471. package/assets/lithermes-plugin/skills/lit-pptx/NOTICE +1 -0
  472. package/assets/lithermes-plugin/skills/lit-pptx/SKILL.md +109 -0
  473. package/assets/lithermes-plugin/skills/lit-pptx/agents/analyst.md +49 -0
  474. package/assets/lithermes-plugin/skills/lit-pptx/agents/antithesis.md +65 -0
  475. package/assets/lithermes-plugin/skills/lit-pptx/agents/architect.md +44 -0
  476. package/assets/lithermes-plugin/skills/lit-pptx/agents/critic.md +42 -0
  477. package/assets/lithermes-plugin/skills/lit-pptx/agents/synthesizer.md +47 -0
  478. package/assets/lithermes-plugin/skills/lit-pptx/agents/thesis.md +33 -0
  479. package/assets/lithermes-plugin/skills/lit-pptx/assets/azure/circle-lg.png +0 -0
  480. package/assets/lithermes-plugin/skills/lit-pptx/assets/azure/circle-md.png +0 -0
  481. package/assets/lithermes-plugin/skills/lit-pptx/assets/azure/circle-sm.png +0 -0
  482. package/assets/lithermes-plugin/skills/lit-pptx/bin/office.mjs +77 -0
  483. package/assets/lithermes-plugin/skills/lit-pptx/fonts/PRETENDARD-OFL.txt +94 -0
  484. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-Black.otf +0 -0
  485. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-Bold.otf +0 -0
  486. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-ExtraBold.otf +0 -0
  487. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-ExtraLight.otf +0 -0
  488. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-Light.otf +0 -0
  489. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-Medium.otf +0 -0
  490. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-Regular.otf +0 -0
  491. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-SemiBold.otf +0 -0
  492. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/A2Z-Thin.otf +0 -0
  493. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/OFL.txt +94 -0
  494. package/assets/lithermes-plugin/skills/lit-pptx/fonts/a2z-font/SOURCE.md +29 -0
  495. package/assets/lithermes-plugin/skills/lit-pptx/pretendard-font/public/static/PretendardGOV-Bold.otf +0 -0
  496. package/assets/lithermes-plugin/skills/lit-pptx/pretendard-font/public/static/PretendardGOV-Regular.otf +0 -0
  497. package/assets/lithermes-plugin/skills/lit-pptx/references/anti-slop-checklist.md +71 -0
  498. package/assets/lithermes-plugin/skills/lit-pptx/references/authoring-guide.md +139 -0
  499. package/assets/lithermes-plugin/skills/lit-pptx/references/consensus-protocol.md +125 -0
  500. package/assets/lithermes-plugin/skills/lit-pptx/references/data-display-cookbook.md +45 -0
  501. package/assets/lithermes-plugin/skills/lit-pptx/references/design-system-azure.md +58 -0
  502. package/assets/lithermes-plugin/skills/lit-pptx/runtime/package-lock.json +750 -0
  503. package/assets/lithermes-plugin/skills/lit-pptx/runtime/package.json +15 -0
  504. package/assets/lithermes-plugin/skills/lit-pptx/runtime/requirements.in +7 -0
  505. package/assets/lithermes-plugin/skills/lit-pptx/runtime/requirements.lock +391 -0
  506. package/assets/lithermes-plugin/skills/lit-pptx/scripts/compile-deck.js +447 -0
  507. package/assets/lithermes-plugin/skills/lit-pptx/scripts/craft_extras.py +215 -0
  508. package/assets/lithermes-plugin/skills/lit-pptx/scripts/embed_fonts.py +199 -0
  509. package/assets/lithermes-plugin/skills/lit-pptx/scripts/integrity.py +60 -0
  510. package/assets/lithermes-plugin/skills/lit-pptx/scripts/inventory.py +64 -0
  511. package/assets/lithermes-plugin/skills/lit-pptx/scripts/learn_template.py +433 -0
  512. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/derive-palette.js +176 -0
  513. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/directive-parser.js +244 -0
  514. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/font-map.js +79 -0
  515. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/gen-bg.js +85 -0
  516. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/gen-gradient-assets.js +36 -0
  517. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/layout-resolver.js +736 -0
  518. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/markdown-loader.js +136 -0
  519. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/render-adapter-html.js +357 -0
  520. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +1864 -0
  521. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/slide-ast.js +539 -0
  522. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/spec-validator.js +94 -0
  523. package/assets/lithermes-plugin/skills/lit-pptx/scripts/lib/template-registry.js +355 -0
  524. package/assets/lithermes-plugin/skills/lit-pptx/scripts/qa_deck.py +791 -0
  525. package/assets/lithermes-plugin/skills/lit-pptx/scripts/validate_pptx.py +206 -0
  526. package/assets/lithermes-plugin/skills/lit-pptx/slide-formats/markdown-slide-spec-v1.md +251 -0
  527. package/assets/lithermes-plugin/skills/lit-pptx/slide-formats/markdown-slide-spec-v2.md +221 -0
  528. package/assets/lithermes-plugin/skills/lit-pptx/slide-formats/slide-ast-v1.schema.json +229 -0
  529. package/assets/lithermes-plugin/skills/lit-pptx/slide-formats/slide-ast-v2.schema.json +144 -0
  530. package/assets/lithermes-plugin/skills/lit-pptx/slide-formats/template-enrollment-contract.md +228 -0
  531. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/AZURE-A2Z/capabilities.yaml +146 -0
  532. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +384 -0
  533. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +37 -0
  534. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/AZURE-PRO/capabilities.yaml +154 -0
  535. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +405 -0
  536. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +37 -0
  537. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/capabilities.yaml +179 -0
  538. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/layout-mapping.yaml +299 -0
  539. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/template.yaml +45 -0
  540. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/capabilities.yaml +181 -0
  541. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/layout-mapping.yaml +299 -0
  542. package/assets/lithermes-plugin/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/template.yaml +44 -0
  543. package/assets/lithermes-plugin/skills/lit-scientific-visualization/SKILL.md +2 -0
  544. package/assets/lithermes-plugin/skills/lit-typographic-motion/SKILL.md +71 -0
  545. package/assets/lithermes-plugin/skills/lit-typographic-motion/bin/audio.py +45 -0
  546. package/assets/lithermes-plugin/skills/lit-typographic-motion/bin/motion.mjs +690 -0
  547. package/assets/lithermes-plugin/skills/lit-typographic-motion/bin/runtime.mjs +299 -0
  548. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/NOTICE +23 -0
  549. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/THIRD_PARTY_NOTICES +55 -0
  550. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/browser.mjs +169 -0
  551. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/completion.mjs +52 -0
  552. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/constants.mjs +162 -0
  553. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/director.mjs +33 -0
  554. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/encode.mjs +191 -0
  555. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/flash.mjs +163 -0
  556. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/frame.mjs +428 -0
  557. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/gate.mjs +483 -0
  558. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/look.mjs +223 -0
  559. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/page.js +622 -0
  560. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/presets.mjs +170 -0
  561. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/scenes.mjs +242 -0
  562. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/sound.mjs +382 -0
  563. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage-gate.mjs +97 -0
  564. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage-init.js +186 -0
  565. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage-kit.js +389 -0
  566. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage-qa.mjs +358 -0
  567. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage-worker.mjs +33 -0
  568. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stage.mjs +691 -0
  569. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stills.mjs +71 -0
  570. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/stroke.mjs +231 -0
  571. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/timeline.mjs +177 -0
  572. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/treatment.mjs +244 -0
  573. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/type.mjs +183 -0
  574. package/assets/lithermes-plugin/skills/lit-typographic-motion/engine/util.mjs +152 -0
  575. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/craft-loop.md +175 -0
  576. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/engine-contract.md +166 -0
  577. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/runtime.md +122 -0
  578. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/stage.md +261 -0
  579. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/style-bibles.md +122 -0
  580. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/treatment.md +164 -0
  581. package/assets/lithermes-plugin/skills/lit-typographic-motion/references/type-craft.md +92 -0
  582. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/fonts.json +154 -0
  583. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/licenses/CREDITS +20 -0
  584. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/licenses/EMS-OFL.txt +91 -0
  585. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/package-lock.json +88 -0
  586. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/package.json +12 -0
  587. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/requirements.in +1 -0
  588. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/requirements.lock +727 -0
  589. package/assets/lithermes-plugin/skills/lit-typographic-motion/runtime/word-timing.json +9 -0
  590. package/assets/lithermes-plugin/skills/litresearch/SKILL.md +19 -18
  591. package/assets/lithermes-plugin/skills/litwork/SKILL.md +28 -0
  592. package/assets/lithermes-plugin/skills/visual-qa/references/complete-contract.md +3 -3
  593. package/package.json +1 -1
  594. package/readme-assets/ab-simple/s11-ui-baseline-desktop.webp +0 -0
  595. package/readme-assets/ab-simple/s11-ui-lithermes-desktop.webp +0 -0
  596. package/readme-assets/ab-simple/s3-ui-baseline-desktop.webp +0 -0
  597. package/readme-assets/ab-simple/s3-ui-lithermes-desktop.webp +0 -0
  598. package/readme-assets/ab-simple/s4-ui-baseline-desktop.webp +0 -0
  599. package/readme-assets/ab-simple/s4-ui-lithermes-desktop.webp +0 -0
  600. package/readme-assets/ab-simple/s5-office-baseline-slides.webp +0 -0
  601. package/readme-assets/ab-simple/s5-office-lithermes-slides.webp +0 -0
  602. package/readme-assets/ab-simple/s7-lithermes-diagram.webp +0 -0
  603. package/readme-assets/ab-simple/s8-office-baseline-slides.webp +0 -0
  604. package/readme-assets/ab-simple/s8-office-lithermes-slides.webp +0 -0
  605. package/readme-assets/ab-simple/s9-office-lithermes-pages.webp +0 -0
  606. package/readme-assets/badge-version.svg +1 -1
  607. package/readme-assets/cover-motion-still.webp +0 -0
  608. package/readme-assets/cover-motion.webp +0 -0
  609. package/readme-assets/skills/autoconference.webp +0 -0
  610. package/readme-assets/skills/autoresearch.webp +0 -0
  611. package/readme-assets/skills/browser-drive.webp +0 -0
  612. package/readme-assets/skills/comment-checker.webp +0 -0
  613. package/readme-assets/skills/debugging.webp +0 -0
  614. package/readme-assets/skills/deep-interview.webp +0 -0
  615. package/readme-assets/skills/frontend-ui-ux.webp +0 -0
  616. package/readme-assets/skills/lit-burnoff-file.webp +0 -0
  617. package/readme-assets/skills/lit-burnoff.webp +0 -0
  618. package/readme-assets/skills/lit-code.webp +0 -0
  619. package/readme-assets/skills/lit-commit.webp +0 -0
  620. package/readme-assets/skills/lit-comprehend.webp +0 -0
  621. package/readme-assets/skills/lit-crucible.webp +0 -0
  622. package/readme-assets/skills/lit-diagram-drawer.webp +0 -0
  623. package/readme-assets/skills/lit-docx.webp +0 -0
  624. package/readme-assets/skills/lit-handoff.webp +0 -0
  625. package/readme-assets/skills/lit-humanizer.webp +0 -0
  626. package/readme-assets/skills/lit-init.webp +0 -0
  627. package/readme-assets/skills/lit-plan.webp +0 -0
  628. package/readme-assets/skills/lit-pptx.webp +0 -0
  629. package/readme-assets/skills/lit-recap.webp +0 -0
  630. package/readme-assets/skills/lit-scientific-visualization.webp +0 -0
  631. package/readme-assets/skills/lit-typographic-motion.webp +0 -0
  632. package/readme-assets/skills/litgoal.webp +0 -0
  633. package/readme-assets/skills/litresearch.webp +0 -0
  634. package/readme-assets/skills/litwork.webp +0 -0
  635. package/readme-assets/skills/lsp-setup.webp +0 -0
  636. package/readme-assets/skills/lsp.webp +0 -0
  637. package/readme-assets/skills/readme-studio.webp +0 -0
  638. package/readme-assets/skills/refactor.webp +0 -0
  639. package/readme-assets/skills/review-work.webp +0 -0
  640. package/readme-assets/skills/rules.webp +0 -0
  641. package/readme-assets/skills/start-work.webp +0 -0
  642. package/readme-assets/skills/structural-search.webp +0 -0
  643. package/readme-assets/skills/visual-qa.webp +0 -0
  644. package/readme-assets/skills/wikify.webp +0 -0
  645. package/src/cli.js +40 -1
  646. package/src/lib/check.js +21 -0
  647. package/src/lib/install.js +262 -7
  648. package/src/lib/skillPayload.js +3 -3
  649. package/assets/lithermes-plugin/skills/lit-korean/SKILL.md +0 -237
  650. package/assets/lithermes-plugin/skills/lit-korean/references/quick-rules.md +0 -24
  651. package/assets/lithermes-plugin/skills/lit-korean/references/safety-checklist.md +0 -23
  652. package/readme-assets/cover.webp +0 -0
@@ -0,0 +1,1041 @@
1
+ #!/usr/bin/env python3
2
+ """Convert Markdown to DOCX with proper styling.
3
+
4
+ Usage:
5
+ python convert_md_to_docx.py input.md output.docx [--template template.docx]
6
+ python convert_md_to_docx.py input.md output.docx --publisher elsevier
7
+
8
+ Features:
9
+ - Headings (H1-H6 → Word heading styles)
10
+ - Paragraphs with bold/italic/code formatting
11
+ - Bullet and numbered lists
12
+ - Tables
13
+ - Code blocks (monospace font)
14
+ - Images (if local)
15
+ - Links (as hyperlinks)
16
+ - [NEW in M1] --publisher NAME loads templates/registry.yaml and applies
17
+ journal design discipline: title block from YAML frontmatter, curly
18
+ quotes, en/em dashes, nbsp before units, ellipsis, heading auto-numbering,
19
+ booktabs tables, banned-font/style stripping, CJK font pairing.
20
+ """
21
+
22
+ from __future__ import annotations
23
+ import argparse
24
+ import re
25
+ import sys
26
+ from pathlib import Path
27
+ from typing import Any
28
+
29
+ try:
30
+ import markdown
31
+ from markdown.extensions.tables import TableExtension
32
+ from markdown.extensions.fenced_code import FencedCodeExtension
33
+ except ImportError:
34
+ print("Error: 'markdown' library not found. Install with: pip install markdown")
35
+ sys.exit(1)
36
+
37
+ try:
38
+ from docx import Document
39
+ from docx.shared import Pt, Inches, Cm, RGBColor
40
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
41
+ from docx.enum.style import WD_STYLE_TYPE
42
+ from docx.oxml.ns import qn
43
+ from docx.oxml import OxmlElement
44
+ except ImportError:
45
+ print("Error: 'python-docx' library not found. Install with: pip install python-docx")
46
+ sys.exit(1)
47
+
48
+ try:
49
+ from bs4 import BeautifulSoup, NavigableString
50
+ except ImportError:
51
+ print("Error: 'beautifulsoup4' library not found. Install with: pip install beautifulsoup4")
52
+ sys.exit(1)
53
+
54
+
55
+ # ===========================================================================
56
+ # Legacy HTML→DOCX helpers (unchanged from pre-M1 — preserved byte-for-byte)
57
+ # ===========================================================================
58
+
59
+
60
+ def create_hyperlink(paragraph, url: str, text: str):
61
+ """Add a hyperlink to a paragraph."""
62
+ part = paragraph.part
63
+ r_id = part.relate_to(url, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", is_external=True)
64
+
65
+ hyperlink = OxmlElement('w:hyperlink')
66
+ hyperlink.set(qn('r:id'), r_id)
67
+
68
+ new_run = OxmlElement('w:r')
69
+ rPr = OxmlElement('w:rPr')
70
+
71
+ # Blue color and underline for hyperlink
72
+ color = OxmlElement('w:color')
73
+ color.set(qn('w:val'), '0000FF')
74
+ rPr.append(color)
75
+
76
+ underline = OxmlElement('w:u')
77
+ underline.set(qn('w:val'), 'single')
78
+ rPr.append(underline)
79
+
80
+ new_run.append(rPr)
81
+
82
+ text_elem = OxmlElement('w:t')
83
+ text_elem.text = text
84
+ new_run.append(text_elem)
85
+
86
+ hyperlink.append(new_run)
87
+ paragraph._p.append(hyperlink)
88
+
89
+
90
+ def process_inline_elements(paragraph, element, md_path: Path):
91
+ """Process inline elements like bold, italic, code, links within a paragraph."""
92
+ if isinstance(element, NavigableString):
93
+ text = str(element)
94
+ if text.strip():
95
+ paragraph.add_run(text)
96
+ elif text:
97
+ paragraph.add_run(text)
98
+ return
99
+
100
+ if element.name == 'strong' or element.name == 'b':
101
+ run = paragraph.add_run(element.get_text())
102
+ run.bold = True
103
+ elif element.name == 'em' or element.name == 'i':
104
+ run = paragraph.add_run(element.get_text())
105
+ run.italic = True
106
+ elif element.name == 'code':
107
+ run = paragraph.add_run(element.get_text())
108
+ run.font.name = 'Courier New'
109
+ run.font.size = Pt(10)
110
+ elif element.name == 'a':
111
+ href = element.get('href', '')
112
+ text = element.get_text()
113
+ if href:
114
+ create_hyperlink(paragraph, href, text)
115
+ else:
116
+ paragraph.add_run(text)
117
+ elif element.name == 'img':
118
+ src = element.get('src', '')
119
+ if src and not src.startswith(('http://', 'https://', 'data:')):
120
+ img_path = (md_path.parent / src).resolve()
121
+ if img_path.exists():
122
+ try:
123
+ paragraph.add_run().add_picture(str(img_path), width=Inches(4))
124
+ except Exception:
125
+ paragraph.add_run(f"[Image: {src}]")
126
+ else:
127
+ paragraph.add_run(f"[Image not found: {src}]")
128
+ else:
129
+ paragraph.add_run(f"[Image: {src}]")
130
+ elif element.name == 'br':
131
+ paragraph.add_run('\n')
132
+ else:
133
+ # Recursively process children
134
+ for child in element.children:
135
+ process_inline_elements(paragraph, child, md_path)
136
+
137
+
138
+ def add_paragraph_with_formatting(doc: Document, element, md_path: Path, style: str = None):
139
+ """Add a paragraph with inline formatting."""
140
+ para = doc.add_paragraph(style=style)
141
+ for child in element.children:
142
+ process_inline_elements(para, child, md_path)
143
+ return para
144
+
145
+
146
+ def process_list(doc: Document, element, md_path: Path, ordered: bool = False, level: int = 0):
147
+ """Process ordered or unordered lists."""
148
+ for i, li in enumerate(element.find_all('li', recursive=False)):
149
+ # Create paragraph with list style
150
+ para = doc.add_paragraph(style='List Number' if ordered else 'List Bullet')
151
+
152
+ # Set indentation for nested lists
153
+ if level > 0:
154
+ para.paragraph_format.left_indent = Inches(0.5 * level)
155
+
156
+ # Process direct text content
157
+ for child in li.children:
158
+ if isinstance(child, NavigableString):
159
+ text = str(child).strip()
160
+ if text:
161
+ para.add_run(text)
162
+ elif child.name in ('ul', 'ol'):
163
+ # Nested list
164
+ process_list(doc, child, md_path, ordered=(child.name == 'ol'), level=level + 1)
165
+ elif child.name == 'p':
166
+ # Process paragraph content inline
167
+ for subchild in child.children:
168
+ process_inline_elements(para, subchild, md_path)
169
+ else:
170
+ process_inline_elements(para, child, md_path)
171
+
172
+
173
+ def process_table(doc: Document, element, md_path: Path):
174
+ """Process HTML table and create DOCX table."""
175
+ rows = element.find_all('tr')
176
+ if not rows:
177
+ return
178
+
179
+ # Count columns from first row
180
+ first_row = rows[0]
181
+ cols = len(first_row.find_all(['th', 'td']))
182
+
183
+ if cols == 0:
184
+ return
185
+
186
+ table = doc.add_table(rows=len(rows), cols=cols)
187
+ table.style = 'Table Grid'
188
+
189
+ for row_idx, tr in enumerate(rows):
190
+ cells = tr.find_all(['th', 'td'])
191
+ for col_idx, cell in enumerate(cells):
192
+ if col_idx < cols:
193
+ table_cell = table.rows[row_idx].cells[col_idx]
194
+ # Clear default paragraph
195
+ table_cell.text = ''
196
+ para = table_cell.paragraphs[0]
197
+ for child in cell.children:
198
+ process_inline_elements(para, child, md_path)
199
+
200
+ # Bold for header cells
201
+ if cell.name == 'th':
202
+ for run in para.runs:
203
+ run.bold = True
204
+
205
+
206
+ def process_code_block(doc: Document, element):
207
+ """Process code block with monospace formatting."""
208
+ code = element.find('code')
209
+ text = code.get_text() if code else element.get_text()
210
+
211
+ para = doc.add_paragraph()
212
+ run = para.add_run(text)
213
+ run.font.name = 'Courier New'
214
+ run.font.size = Pt(9)
215
+
216
+ # Light gray background (via shading)
217
+ shading = OxmlElement('w:shd')
218
+ shading.set(qn('w:fill'), 'F0F0F0')
219
+ para._p.get_or_add_pPr().append(shading)
220
+
221
+
222
+ def html_to_docx(html: str, doc: Document, md_path: Path):
223
+ """Convert HTML to DOCX elements."""
224
+ soup = BeautifulSoup(html, 'html.parser')
225
+
226
+ for element in soup.children:
227
+ if isinstance(element, NavigableString):
228
+ text = str(element).strip()
229
+ if text:
230
+ doc.add_paragraph(text)
231
+ continue
232
+
233
+ if element.name in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6'):
234
+ level = int(element.name[1])
235
+ heading = doc.add_heading(level=level)
236
+ for child in element.children:
237
+ process_inline_elements(heading, child, md_path)
238
+
239
+ elif element.name == 'p':
240
+ add_paragraph_with_formatting(doc, element, md_path)
241
+
242
+ elif element.name == 'ul':
243
+ process_list(doc, element, md_path, ordered=False)
244
+
245
+ elif element.name == 'ol':
246
+ process_list(doc, element, md_path, ordered=True)
247
+
248
+ elif element.name == 'table':
249
+ process_table(doc, element, md_path)
250
+
251
+ elif element.name == 'pre':
252
+ process_code_block(doc, element)
253
+
254
+ elif element.name == 'blockquote':
255
+ para = doc.add_paragraph(style='Quote')
256
+ for child in element.children:
257
+ if child.name == 'p':
258
+ for subchild in child.children:
259
+ process_inline_elements(para, subchild, md_path)
260
+ else:
261
+ process_inline_elements(para, child, md_path)
262
+
263
+ elif element.name == 'hr':
264
+ # Add a horizontal line
265
+ para = doc.add_paragraph()
266
+ para.add_run('─' * 50)
267
+ para.alignment = WD_ALIGN_PARAGRAPH.CENTER
268
+
269
+ elif element.name in ('div', 'section', 'article'):
270
+ # Recursively process container elements
271
+ html_to_docx(str(element), doc, md_path)
272
+
273
+
274
+ # ===========================================================================
275
+ # M1: Journal workflow — frontmatter, filters, design enforcement
276
+ # ===========================================================================
277
+
278
+
279
+ def _load_yaml():
280
+ try:
281
+ import yaml
282
+ return yaml
283
+ except ImportError:
284
+ print("Error: 'pyyaml' library required for --publisher. pip install pyyaml")
285
+ sys.exit(1)
286
+
287
+
288
+ def parse_frontmatter(md_text: str) -> tuple[dict, str]:
289
+ """Extract leading YAML frontmatter. Returns (frontmatter_dict, body)."""
290
+ if not md_text.startswith("---"):
291
+ return {}, md_text
292
+ # Find closing fence
293
+ lines = md_text.splitlines(keepends=True)
294
+ if len(lines) < 2:
295
+ return {}, md_text
296
+ end_idx = None
297
+ for i in range(1, len(lines)):
298
+ if lines[i].rstrip() == "---":
299
+ end_idx = i
300
+ break
301
+ if end_idx is None:
302
+ return {}, md_text
303
+ yaml_src = "".join(lines[1:end_idx])
304
+ body = "".join(lines[end_idx + 1:])
305
+ yaml = _load_yaml()
306
+ try:
307
+ data = yaml.safe_load(yaml_src) or {}
308
+ except Exception as exc:
309
+ print(f"Warning: could not parse YAML frontmatter: {exc}", file=sys.stderr)
310
+ return {}, md_text
311
+ if not isinstance(data, dict):
312
+ return {}, md_text
313
+ return data, body
314
+
315
+
316
+ def load_publisher(registry_path: Path, name: str) -> dict:
317
+ yaml = _load_yaml()
318
+ if not registry_path.exists():
319
+ raise SystemExit(f"Error: registry not found: {registry_path}")
320
+ with registry_path.open("r", encoding="utf-8") as fh:
321
+ data = yaml.safe_load(fh) or {}
322
+ pubs = data.get("publishers") or {}
323
+ if name not in pubs:
324
+ raise SystemExit(
325
+ f"Error: publisher {name!r} not in registry "
326
+ f"(known: {', '.join(sorted(pubs)) or 'none'})"
327
+ )
328
+ return pubs[name]
329
+
330
+
331
+ # ---------------------------------------------------------------------------
332
+ # Code-preserving filter helpers
333
+ # ---------------------------------------------------------------------------
334
+
335
+
336
+ _FENCE_RE = re.compile(r"(^```.*?^```)", re.MULTILINE | re.DOTALL)
337
+ _INLINE_CODE_RE = re.compile(r"(`[^`\n]+`)")
338
+
339
+
340
+ def _split_code_preserving(text: str) -> list[tuple[str, bool]]:
341
+ """Split text into (segment, is_code) tuples.
342
+
343
+ Fenced code blocks and inline backtick code are returned as is_code=True
344
+ and must never be touched by the micro-typography filters.
345
+ """
346
+ # First split on fenced code blocks
347
+ out: list[tuple[str, bool]] = []
348
+ pos = 0
349
+ for m in _FENCE_RE.finditer(text):
350
+ if m.start() > pos:
351
+ out.append((text[pos:m.start()], False))
352
+ out.append((m.group(0), True))
353
+ pos = m.end()
354
+ if pos < len(text):
355
+ out.append((text[pos:], False))
356
+ # Then split non-code segments on inline backtick code
357
+ refined: list[tuple[str, bool]] = []
358
+ for seg, is_code in out:
359
+ if is_code:
360
+ refined.append((seg, True))
361
+ continue
362
+ last = 0
363
+ for m in _INLINE_CODE_RE.finditer(seg):
364
+ if m.start() > last:
365
+ refined.append((seg[last:m.start()], False))
366
+ refined.append((m.group(0), True))
367
+ last = m.end()
368
+ if last < len(seg):
369
+ refined.append((seg[last:], False))
370
+ return refined
371
+
372
+
373
+ def _apply_to_noncode(text: str, fn) -> str:
374
+ parts = _split_code_preserving(text)
375
+ out = []
376
+ for seg, is_code in parts:
377
+ out.append(seg if is_code else fn(seg))
378
+ return "".join(out)
379
+
380
+
381
+ # ---------------------------------------------------------------------------
382
+ # Pre-MD micro-typography filters
383
+ # ---------------------------------------------------------------------------
384
+
385
+
386
+ _NUMRANGE_RE = re.compile(r"(\d)-(\d)")
387
+ _PAREN_DASH_RE = re.compile(r"(\w) - (\w)")
388
+
389
+
390
+ def fix_dashes(text: str, rules: dict | None = None) -> str:
391
+ """Numeric ranges → en-dash; parenthetical 'word - word' → em-dash.
392
+
393
+ rules is the design.micro_typography.dashes block (currently informational;
394
+ M1 hardcodes en-dash for numeric range and em-dash for parenthetical).
395
+ """
396
+ def _fn(seg: str) -> str:
397
+ seg = _NUMRANGE_RE.sub(lambda m: f"{m.group(1)}\u2013{m.group(2)}", seg)
398
+ seg = _PAREN_DASH_RE.sub(lambda m: f"{m.group(1)} \u2014 {m.group(2)}", seg)
399
+ return seg
400
+ return _apply_to_noncode(text, _fn)
401
+
402
+
403
+ def fix_quotes(text: str) -> str:
404
+ """ASCII "..." → "..."; '...' → '...' via left/right state machine."""
405
+ def _fn(seg: str) -> str:
406
+ out_chars = []
407
+ open_dq = True
408
+ open_sq = True
409
+ for ch in seg:
410
+ if ch == '"':
411
+ out_chars.append("\u201C" if open_dq else "\u201D")
412
+ open_dq = not open_dq
413
+ elif ch == "'":
414
+ # Keep apostrophe if surrounded by letters (e.g. "don't")
415
+ prev = out_chars[-1] if out_chars else ""
416
+ if prev.isalpha():
417
+ out_chars.append("\u2019")
418
+ else:
419
+ out_chars.append("\u2018" if open_sq else "\u2019")
420
+ open_sq = not open_sq
421
+ else:
422
+ out_chars.append(ch)
423
+ return "".join(out_chars)
424
+ return _apply_to_noncode(text, _fn)
425
+
426
+
427
+ _UNIT_GROUP = (
428
+ r"mg|g|kg|mL|L|\u03BCL|uL|nm|\u03BCm|um|mm|cm|m|km|K|\u00B0C|%|min|h|s|ms"
429
+ )
430
+ _UNIT_RE = re.compile(rf"(\d)(\s+)({_UNIT_GROUP})(?=\b|\W|$)")
431
+ _FIG_RE = re.compile(r"(Fig\.)\s(\d)")
432
+ _TABLE_RE = re.compile(r"(Table)\s(\d)")
433
+ _EQ_RE = re.compile(r"(Eq\.)\s(\d)")
434
+
435
+
436
+ def fix_unit_spacing(text: str) -> str:
437
+ """Insert U+00A0 between number and SI unit, and after Fig./Table/Eq."""
438
+ def _fn(seg: str) -> str:
439
+ seg = _UNIT_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(3)}", seg)
440
+ seg = _FIG_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(2)}", seg)
441
+ seg = _TABLE_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(2)}", seg)
442
+ seg = _EQ_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(2)}", seg)
443
+ return seg
444
+ return _apply_to_noncode(text, _fn)
445
+
446
+
447
+ def fix_ellipsis(text: str) -> str:
448
+ def _fn(seg: str) -> str:
449
+ return seg.replace("...", "\u2026")
450
+ return _apply_to_noncode(text, _fn)
451
+
452
+
453
+ def normalize_double_spaces(text: str) -> str:
454
+ def _fn(seg: str) -> str:
455
+ # Preserve leading indentation; collapse interior double spaces
456
+ lines = seg.split("\n")
457
+ cleaned = []
458
+ for line in lines:
459
+ stripped_left = line.lstrip(" ")
460
+ lead = line[: len(line) - len(stripped_left)]
461
+ cleaned.append(lead + re.sub(r" {2,}", " ", stripped_left))
462
+ return "\n".join(cleaned)
463
+ return _apply_to_noncode(text, _fn)
464
+
465
+
466
+ # ---------------------------------------------------------------------------
467
+ # Post-HTML (doc object) filters
468
+ # ---------------------------------------------------------------------------
469
+
470
+
471
+ def apply_heading_numbering(doc, design: dict) -> None:
472
+ def to_roman(value: int) -> str:
473
+ numerals = [
474
+ (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"),
475
+ (100, "C"), (90, "XC"), (50, "L"), (40, "XL"),
476
+ (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I"),
477
+ ]
478
+ out: list[str] = []
479
+ remaining = value
480
+ for arabic, roman in numerals:
481
+ while remaining >= arabic:
482
+ out.append(roman)
483
+ remaining -= arabic
484
+ return "".join(out)
485
+
486
+ def prefix_for(level: int, counters: list[int]) -> str | None:
487
+ key = f"h{level}"
488
+ cfg = (design.get("heading_hierarchy") or {}).get(key) or {}
489
+ numbering = cfg.get("numbering")
490
+ if numbering is None:
491
+ return None
492
+ numbering = str(numbering).strip()
493
+ if level == 1 and numbering.upper() == "I.":
494
+ return f"{to_roman(counters[0])}. "
495
+ if level == 1:
496
+ return f"{counters[0]}. "
497
+ if level == 2:
498
+ return f"{counters[0]}.{counters[1]}. "
499
+ if level == 3:
500
+ return f"{counters[0]}.{counters[1]}.{counters[2]}. "
501
+ return None
502
+
503
+ counters = [0, 0, 0]
504
+ for para in doc.paragraphs:
505
+ style_name = para.style.name if para.style else ""
506
+ level = 0
507
+ if style_name == "Heading 1":
508
+ level = 1
509
+ counters[0] += 1
510
+ counters[1] = 0
511
+ counters[2] = 0
512
+ elif style_name == "Heading 2":
513
+ level = 2
514
+ counters[1] += 1
515
+ counters[2] = 0
516
+ elif style_name == "Heading 3":
517
+ level = 3
518
+ counters[2] += 1
519
+ else:
520
+ continue
521
+ prefix = prefix_for(level, counters)
522
+ if prefix is None:
523
+ continue
524
+ current = para.text or ""
525
+ # Skip if already numbered (e.g. "1 Introduction" from the source)
526
+ if re.match(r"^(?:\d+(?:\.\d+)*\.?|[IVXLCDM]+\.?)\s", current):
527
+ continue
528
+ if para.runs:
529
+ para.runs[0].text = prefix + para.runs[0].text
530
+ else:
531
+ para.add_run(prefix)
532
+
533
+
534
+ def _set_cell_borders_nil(tcPr):
535
+ tcBorders = tcPr.find(qn("w:tcBorders"))
536
+ if tcBorders is None:
537
+ tcBorders = OxmlElement("w:tcBorders")
538
+ tcPr.append(tcBorders)
539
+ for side in ("top", "left", "bottom", "right", "insideH", "insideV"):
540
+ el = tcBorders.find(qn(f"w:{side}"))
541
+ if el is None:
542
+ el = OxmlElement(f"w:{side}")
543
+ tcBorders.append(el)
544
+ el.set(qn("w:val"), "nil")
545
+ el.set(qn("w:sz"), "0")
546
+
547
+
548
+ def apply_table_style(doc, design: dict) -> None:
549
+ """Override python-docx 'Table Grid' with booktabs: only horizontal rules.
550
+
551
+ Rules: top rule (table top), header-bottom rule, bottom rule (table bottom).
552
+ All vertical rules (left/right/insideV) set to nil.
553
+ """
554
+ for table in doc.tables:
555
+ table.style = None # detach Table Grid
556
+ if not table.rows or not table.columns:
557
+ continue
558
+ # Fixed page-width grid avoids Word compressing cells into narrow strips.
559
+ section = doc.sections[0]
560
+ available = section.page_width - section.left_margin - section.right_margin
561
+ weights = [
562
+ max(8, min(40, max(len(row.cells[index].text.strip()) for row in table.rows)))
563
+ for index in range(len(table.columns))
564
+ ]
565
+ table.autofit = False
566
+ assigned = 0
567
+ for index, column in enumerate(table.columns):
568
+ width = available - assigned if index == len(weights) - 1 else int(available * weights[index] / sum(weights))
569
+ column.width = width
570
+ for row in table.rows:
571
+ row.cells[index].width = width
572
+ assigned += width
573
+ for index, row in enumerate(table.rows):
574
+ tr_pr = row._tr.get_or_add_trPr()
575
+ if tr_pr.find(qn("w:cantSplit")) is None:
576
+ tr_pr.append(OxmlElement("w:cantSplit"))
577
+ if index == 0 and tr_pr.find(qn("w:tblHeader")) is None:
578
+ tr_pr.append(OxmlElement("w:tblHeader"))
579
+ tbl = table._tbl
580
+ tblPr = tbl.find(qn("w:tblPr"))
581
+ if tblPr is None:
582
+ tblPr = OxmlElement("w:tblPr")
583
+ tbl.insert(0, tblPr)
584
+ # Remove any existing tblBorders and add our booktabs set
585
+ existing = tblPr.find(qn("w:tblBorders"))
586
+ if existing is not None:
587
+ tblPr.remove(existing)
588
+ tblBorders = OxmlElement("w:tblBorders")
589
+
590
+ def _add_border(name: str, val: str, sz: str):
591
+ el = OxmlElement(f"w:{name}")
592
+ el.set(qn("w:val"), val)
593
+ el.set(qn("w:sz"), sz)
594
+ el.set(qn("w:space"), "0")
595
+ el.set(qn("w:color"), "000000")
596
+ tblBorders.append(el)
597
+
598
+ _add_border("top", "single", "12") # ~1.5pt
599
+ _add_border("bottom", "single", "12") # ~1.5pt
600
+ _add_border("left", "nil", "0")
601
+ _add_border("right", "nil", "0")
602
+ _add_border("insideH", "single", "6") # ~0.75pt (header-bottom)
603
+ _add_border("insideV", "nil", "0") # explicit no verticals
604
+ tblPr.append(tblBorders)
605
+
606
+ # Bold header row + add bottom border only to header cells so the
607
+ # thicker rule sits under the header (and horizontal rules between
608
+ # body rows are suppressed)
609
+ if table.rows:
610
+ header_row = table.rows[0]
611
+ for cell in header_row.cells:
612
+ for p in cell.paragraphs:
613
+ for r in p.runs:
614
+ r.bold = True
615
+ # Remove insideH to prevent inner body rules; header-bottom comes
616
+ # from a per-cell bottom border on the first row.
617
+ insideH = tblBorders.find(qn("w:insideH"))
618
+ if insideH is not None:
619
+ insideH.set(qn("w:val"), "nil")
620
+ for cell in header_row.cells:
621
+ tcPr = cell._tc.get_or_add_tcPr()
622
+ tcBorders = tcPr.find(qn("w:tcBorders"))
623
+ if tcBorders is None:
624
+ tcBorders = OxmlElement("w:tcBorders")
625
+ tcPr.append(tcBorders)
626
+ existing_bottom = tcBorders.find(qn("w:bottom"))
627
+ if existing_bottom is None:
628
+ existing_bottom = OxmlElement("w:bottom")
629
+ tcBorders.append(existing_bottom)
630
+ existing_bottom.set(qn("w:val"), "single")
631
+ existing_bottom.set(qn("w:sz"), "6")
632
+ existing_bottom.set(qn("w:space"), "0")
633
+ existing_bottom.set(qn("w:color"), "000000")
634
+
635
+
636
+ def strip_banned(doc, design: dict) -> None:
637
+ """Remove any banned font/style from runs and paragraphs."""
638
+ banned = design.get("banned") or {}
639
+ banned_fonts = set(banned.get("fonts") or [])
640
+ banned_styles = set(banned.get("styles") or [])
641
+ body_font = None
642
+ # body font is enforced on Normal style already, but we override raw runs too
643
+ for para in doc.paragraphs:
644
+ if para.style and para.style.name in banned_styles:
645
+ try:
646
+ para.style = doc.styles["Normal"]
647
+ except KeyError:
648
+ pass
649
+ for run in para.runs:
650
+ if run.font.name and run.font.name in banned_fonts:
651
+ run.font.name = None # inherit from style
652
+ # Also walk table cells
653
+ for table in doc.tables:
654
+ for row in table.rows:
655
+ for cell in row.cells:
656
+ for para in cell.paragraphs:
657
+ if para.style and para.style.name in banned_styles:
658
+ try:
659
+ para.style = doc.styles["Normal"]
660
+ except KeyError:
661
+ pass
662
+ for run in para.runs:
663
+ if run.font.name and run.font.name in banned_fonts:
664
+ run.font.name = None
665
+
666
+
667
+ def _set_run_fonts(run, latin: str, cjk: str | None) -> None:
668
+ rpr = run._element.get_or_add_rPr()
669
+ rfonts = rpr.find(qn("w:rFonts"))
670
+ if rfonts is None:
671
+ rfonts = OxmlElement("w:rFonts")
672
+ rpr.append(rfonts)
673
+ rfonts.set(qn("w:ascii"), latin)
674
+ rfonts.set(qn("w:hAnsi"), latin)
675
+ rfonts.set(qn("w:cs"), latin)
676
+ if cjk:
677
+ rfonts.set(qn("w:eastAsia"), cjk)
678
+
679
+
680
+ def apply_cjk_font_pairing(doc, font_cfg: dict) -> None:
681
+ body = font_cfg.get("body") or {}
682
+ body_cjk = font_cfg.get("body_cjk") or {}
683
+ latin = body.get("family")
684
+ cjk = body_cjk.get("family")
685
+ if not latin:
686
+ return
687
+
688
+ def _walk(paragraphs):
689
+ for para in paragraphs:
690
+ for run in para.runs:
691
+ # Only fix runs that already have a font set to something
692
+ # other than the registry-banned default; leaving run.font.name
693
+ # as None lets the style do its job. We still force eastAsia.
694
+ current_name = run.font.name
695
+ if current_name and current_name != "Courier New":
696
+ _set_run_fonts(run, latin, cjk)
697
+ elif not current_name:
698
+ # set only eastAsia pair to avoid losing style inheritance
699
+ rpr = run._element.get_or_add_rPr()
700
+ rfonts = rpr.find(qn("w:rFonts"))
701
+ if rfonts is None:
702
+ rfonts = OxmlElement("w:rFonts")
703
+ rpr.append(rfonts)
704
+ if cjk:
705
+ rfonts.set(qn("w:eastAsia"), cjk)
706
+
707
+ _walk(doc.paragraphs)
708
+ for table in doc.tables:
709
+ for row in table.rows:
710
+ for cell in row.cells:
711
+ _walk(cell.paragraphs)
712
+
713
+
714
+ # ---------------------------------------------------------------------------
715
+ # Title block builder
716
+ # ---------------------------------------------------------------------------
717
+
718
+
719
+ def _insert_paragraph_before(doc, before_p, style=None):
720
+ """Insert a new paragraph before the given paragraph element."""
721
+ new_p = OxmlElement("w:p")
722
+ before_p._p.addprevious(new_p)
723
+ from docx.text.paragraph import Paragraph
724
+ para = Paragraph(new_p, before_p._parent)
725
+ if style is not None:
726
+ try:
727
+ para.style = doc.styles[style]
728
+ except KeyError:
729
+ pass
730
+ return para
731
+
732
+
733
+ def inject_title_block(doc, frontmatter: dict, design: dict) -> None:
734
+ """Prepend title/authors/affiliations/abstract/keywords to the doc.
735
+
736
+ Builds the block at the top of the document body via the underlying
737
+ XML so it appears before any html_to_docx output. Called BEFORE
738
+ html_to_docx in M1's control flow so paragraphs just append normally.
739
+ """
740
+ tb = design.get("title_block") or {}
741
+ title = frontmatter.get("title")
742
+ if not title:
743
+ return
744
+
745
+ def _p_center(size: int, bold=False, italic=False, space_after=4):
746
+ p = doc.add_paragraph()
747
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
748
+ p.paragraph_format.first_line_indent = Cm(0)
749
+ p.paragraph_format.space_after = Pt(space_after)
750
+ return p
751
+
752
+ def _add_run(p, text: str, size: int, bold=False, italic=False, sup=False):
753
+ run = p.add_run(text)
754
+ run.font.size = Pt(size)
755
+ run.bold = bold
756
+ run.italic = italic
757
+ run.font.superscript = sup
758
+ return run
759
+
760
+ # Title
761
+ tp = _p_center(
762
+ tb.get("title", {}).get("size_pt", 18),
763
+ bold=True,
764
+ space_after=tb.get("title", {}).get("space_after_pt", 12),
765
+ )
766
+ _add_run(tp, str(title), tb.get("title", {}).get("size_pt", 18), bold=True)
767
+
768
+ # Authors
769
+ authors = frontmatter.get("authors") or []
770
+ if authors:
771
+ ap = _p_center(
772
+ tb.get("authors", {}).get("size_pt", 12),
773
+ space_after=tb.get("authors", {}).get("space_after_pt", 4),
774
+ )
775
+ sep = tb.get("author_separator", ", ")
776
+ corr_mark = tb.get("corresponding_marker", "*")
777
+ size = tb.get("authors", {}).get("size_pt", 12)
778
+ for i, author in enumerate(authors):
779
+ if not isinstance(author, dict):
780
+ continue
781
+ if i > 0:
782
+ _add_run(ap, sep, size)
783
+ name = str(author.get("name", "Author"))
784
+ _add_run(ap, name, size)
785
+ aff = author.get("affiliation")
786
+ if aff is not None:
787
+ if isinstance(aff, list):
788
+ aff_text = ",".join(str(a) for a in aff)
789
+ else:
790
+ aff_text = str(aff)
791
+ _add_run(ap, aff_text, size, sup=True)
792
+ if author.get("corresponding"):
793
+ _add_run(ap, corr_mark, size, sup=True)
794
+
795
+ # Affiliations
796
+ affs = frontmatter.get("affiliations")
797
+ if isinstance(affs, dict):
798
+ for key in sorted(affs.keys(), key=lambda k: str(k)):
799
+ fp = _p_center(
800
+ tb.get("affiliations", {}).get("size_pt", 10),
801
+ italic=True,
802
+ space_after=2,
803
+ )
804
+ _add_run(
805
+ fp,
806
+ f"{key} {affs[key]}",
807
+ tb.get("affiliations", {}).get("size_pt", 10),
808
+ italic=True,
809
+ )
810
+
811
+ # Corresponding email (if present, small italic line)
812
+ corr_email = frontmatter.get("corresponding_email")
813
+ if corr_email:
814
+ cp = _p_center(10, italic=True, space_after=8)
815
+ _add_run(cp, f"* Corresponding author: {corr_email}", 10, italic=True)
816
+
817
+ # Abstract
818
+ abstract = frontmatter.get("abstract")
819
+ if abstract:
820
+ lp = doc.add_paragraph()
821
+ lp.paragraph_format.first_line_indent = Cm(0)
822
+ lp.paragraph_format.space_after = Pt(4)
823
+ _add_run(
824
+ lp,
825
+ tb.get("abstract_label", "Abstract"),
826
+ tb.get("abstract_font_size_pt", 10),
827
+ bold=True,
828
+ )
829
+ body = doc.add_paragraph()
830
+ body.paragraph_format.first_line_indent = Cm(0)
831
+ body.paragraph_format.space_after = Pt(6)
832
+ _add_run(
833
+ body,
834
+ str(abstract),
835
+ tb.get("abstract_font_size_pt", 10),
836
+ )
837
+
838
+ # Keywords
839
+ keywords = frontmatter.get("keywords")
840
+ if keywords:
841
+ kp = doc.add_paragraph()
842
+ kp.paragraph_format.first_line_indent = Cm(0)
843
+ kp.paragraph_format.space_after = Pt(12)
844
+ _add_run(
845
+ kp,
846
+ tb.get("keywords_label", "Keywords") + ": ",
847
+ tb.get("abstract_font_size_pt", 10),
848
+ bold=True,
849
+ )
850
+ if isinstance(keywords, list):
851
+ sep = tb.get("keywords_separator", "; ")
852
+ text = sep.join(str(k) for k in keywords)
853
+ else:
854
+ text = str(keywords)
855
+ _add_run(kp, text, tb.get("abstract_font_size_pt", 10))
856
+
857
+
858
+ # ---------------------------------------------------------------------------
859
+ # Locale detection
860
+ # ---------------------------------------------------------------------------
861
+
862
+
863
+ _HANGUL_RE = re.compile(r"[\uac00-\ud7a3]")
864
+
865
+
866
+ def detect_locale(text: str) -> str:
867
+ total = len(text) or 1
868
+ hangul_count = len(_HANGUL_RE.findall(text))
869
+ ratio = hangul_count / total
870
+ if ratio > 0.05:
871
+ return "ko"
872
+ if ratio > 0.01:
873
+ return "mixed"
874
+ return "en"
875
+
876
+
877
+ # ===========================================================================
878
+ # Conversion entry point
879
+ # ===========================================================================
880
+
881
+
882
+ def convert_md_to_docx(
883
+ md_path: Path,
884
+ docx_path: Path,
885
+ template_path: Path = None,
886
+ publisher_name: str | None = None,
887
+ registry_path: Path | None = None,
888
+ locale: str = "auto",
889
+ ):
890
+ """Convert Markdown file to DOCX.
891
+
892
+ When publisher_name is None, behavior is byte-compatible with the pre-M1
893
+ script: read md, convert to HTML, html_to_docx, save. Regression-guarded.
894
+
895
+ When publisher_name is set, apply the full journal pipeline: registry
896
+ load, frontmatter parse, pre-MD filters, title-block injection, post-HTML
897
+ heading numbering, booktabs tables, banned stripping, CJK font pairing.
898
+ """
899
+ if publisher_name is None:
900
+ # --- Legacy code path (regression-critical: do not mutate) ---
901
+ md_text = md_path.read_text(encoding='utf-8')
902
+ md_converter = markdown.Markdown(extensions=[
903
+ 'tables',
904
+ 'fenced_code',
905
+ 'nl2br',
906
+ 'sane_lists',
907
+ ])
908
+ html = md_converter.convert(md_text)
909
+ if template_path and template_path.exists():
910
+ doc = Document(str(template_path))
911
+ else:
912
+ doc = Document()
913
+ html_to_docx(html, doc, md_path)
914
+ doc.save(str(docx_path))
915
+ print(f"Successfully converted {md_path} to {docx_path}")
916
+ return
917
+
918
+ # --- Journal workflow ---
919
+ script_dir = Path(__file__).resolve().parent
920
+ registry_path = registry_path or (script_dir.parent / "templates" / "registry.yaml")
921
+ publisher = load_publisher(Path(registry_path), publisher_name)
922
+ design = publisher["design"]
923
+ docx_font = publisher["docx"]["font"]
924
+
925
+ md_text = md_path.read_text(encoding="utf-8")
926
+ frontmatter, body = parse_frontmatter(md_text)
927
+
928
+ # Locale detection (informational in M1; Korean rules land in M6)
929
+ detected_locale = detect_locale(body) if locale == "auto" else locale
930
+
931
+ # Pre-MD micro-typography filters
932
+ dash_rules = design.get("micro_typography", {}).get("dashes")
933
+ body = fix_dashes(body, dash_rules)
934
+ body = fix_quotes(body)
935
+ body = fix_unit_spacing(body)
936
+ body = fix_ellipsis(body)
937
+ body = normalize_double_spaces(body)
938
+
939
+ # Load template if available
940
+ template_docx = script_dir.parent / "templates" / "docx" / f"{publisher_name}.docx"
941
+ if template_docx.exists():
942
+ doc = Document(str(template_docx))
943
+ # The template includes a self-describing sample title block and
944
+ # sample heading/body paragraph. Strip all existing body paragraphs
945
+ # and tables so the conversion output is the user's content only.
946
+ body_el = doc.element.body
947
+ sect_pr = body_el.find(qn("w:sectPr"))
948
+ for child in list(body_el):
949
+ if child is sect_pr:
950
+ continue
951
+ body_el.remove(child)
952
+ if sect_pr is None:
953
+ pass # keep original body even if no sectPr detected
954
+ elif template_path and template_path.exists():
955
+ doc = Document(str(template_path))
956
+ else:
957
+ doc = Document()
958
+
959
+ # Title block (built from frontmatter) before main content
960
+ if frontmatter.get("title"):
961
+ inject_title_block(doc, frontmatter, design)
962
+
963
+ # Main content
964
+ md_converter = markdown.Markdown(extensions=[
965
+ 'tables',
966
+ 'fenced_code',
967
+ 'nl2br',
968
+ 'sane_lists',
969
+ ])
970
+ html = md_converter.convert(body)
971
+ html_to_docx(html, doc, md_path)
972
+
973
+ # Post-HTML design enforcement
974
+ apply_heading_numbering(doc, design)
975
+ apply_table_style(doc, design)
976
+ strip_banned(doc, design)
977
+ apply_cjk_font_pairing(doc, docx_font)
978
+
979
+ doc.save(str(docx_path))
980
+ print(
981
+ f"Successfully converted {md_path} to {docx_path} "
982
+ f"[publisher={publisher_name}, locale={detected_locale}]"
983
+ )
984
+
985
+
986
+ def parse_args() -> argparse.Namespace:
987
+ parser = argparse.ArgumentParser(
988
+ description="Convert Markdown to DOCX with proper styling"
989
+ )
990
+ parser.add_argument("input", help="Input Markdown file")
991
+ parser.add_argument("output", help="Output DOCX file")
992
+ parser.add_argument(
993
+ "--template",
994
+ help="Optional DOCX template to use as base",
995
+ default=None,
996
+ )
997
+ parser.add_argument(
998
+ "--publisher",
999
+ help="Journal publisher profile from templates/registry.yaml (e.g. elsevier)",
1000
+ default=None,
1001
+ )
1002
+ parser.add_argument(
1003
+ "--registry",
1004
+ help="Path to templates/registry.yaml (defaults to the one in this skill)",
1005
+ default=None,
1006
+ )
1007
+ parser.add_argument(
1008
+ "--locale",
1009
+ choices=("auto", "en", "ko", "mixed"),
1010
+ default="auto",
1011
+ help="Force locale; 'auto' detects via Hangul codepoint ratio",
1012
+ )
1013
+ args = parser.parse_args()
1014
+ if args.publisher and args.template:
1015
+ parser.error("--publisher and --template are mutually exclusive")
1016
+ return args
1017
+
1018
+
1019
+ def main() -> int:
1020
+ args = parse_args()
1021
+
1022
+ md_path = Path(args.input).expanduser().resolve()
1023
+ docx_path = Path(args.output).expanduser().resolve()
1024
+ template_path = Path(args.template).expanduser().resolve() if args.template else None
1025
+ registry_path = Path(args.registry).expanduser().resolve() if args.registry else None
1026
+
1027
+ if not md_path.exists():
1028
+ print(f"Error: Input file not found: {md_path}")
1029
+ return 1
1030
+
1031
+ convert_md_to_docx(
1032
+ md_path, docx_path, template_path,
1033
+ publisher_name=args.publisher,
1034
+ registry_path=registry_path,
1035
+ locale=args.locale,
1036
+ )
1037
+ return 0
1038
+
1039
+
1040
+ if __name__ == "__main__":
1041
+ raise SystemExit(main())