@litfamily/litclaude 1.0.10 → 1.0.13

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 (718) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +436 -45
  3. package/README_ko-KR.md +403 -17
  4. package/bin/install-ownership.mjs +155 -18
  5. package/bin/litclaude-ai.js +91 -9
  6. package/docs/ab/S11-baseline-desktop.webp +0 -0
  7. package/docs/ab/S11-baseline-phone.webp +0 -0
  8. package/docs/ab/S11-litclaude-desktop.webp +0 -0
  9. package/docs/ab/S11-litclaude-phone.webp +0 -0
  10. package/docs/ab/S3-baseline-desktop.webp +0 -0
  11. package/docs/ab/S3-baseline-phone.webp +0 -0
  12. package/docs/ab/S3-litclaude-desktop.webp +0 -0
  13. package/docs/ab/S3-litclaude-phone.webp +0 -0
  14. package/docs/ab/S4-baseline-desktop.webp +0 -0
  15. package/docs/ab/S4-baseline-phone.webp +0 -0
  16. package/docs/ab/S4-litclaude-desktop.webp +0 -0
  17. package/docs/ab/S4-litclaude-phone.webp +0 -0
  18. package/docs/ab/S5-baseline-pages.webp +0 -0
  19. package/docs/ab/S5-baseline-slides.webp +0 -0
  20. package/docs/ab/S5-litclaude-pages.webp +0 -0
  21. package/docs/ab/S5-litclaude-slides.webp +0 -0
  22. package/docs/ab/S7-litclaude-diagram.webp +0 -0
  23. package/docs/ab/S8-baseline-slides.webp +0 -0
  24. package/docs/ab/S8-litclaude-slides.webp +0 -0
  25. package/docs/ab/S9-litclaude-pages.webp +0 -0
  26. package/docs/agents.md +10 -7
  27. package/docs/assets/cover-motion-still.webp +0 -0
  28. package/docs/assets/cover-motion.webp +0 -0
  29. package/docs/assets/readme/badge-version.svg +1 -1
  30. package/docs/assets/skills/autoconference.webp +0 -0
  31. package/docs/assets/skills/automatic-checks.webp +0 -0
  32. package/docs/assets/skills/autoresearch.webp +0 -0
  33. package/docs/assets/skills/browser-drive.webp +0 -0
  34. package/docs/assets/skills/debugging.webp +0 -0
  35. package/docs/assets/skills/deep-interview.webp +0 -0
  36. package/docs/assets/skills/frontend-ui-ux.webp +0 -0
  37. package/docs/assets/skills/lit-burnoff-file.webp +0 -0
  38. package/docs/assets/skills/lit-burnoff.webp +0 -0
  39. package/docs/assets/skills/lit-code.webp +0 -0
  40. package/docs/assets/skills/lit-commit.webp +0 -0
  41. package/docs/assets/skills/lit-comprehend.webp +0 -0
  42. package/docs/assets/skills/lit-crucible.webp +0 -0
  43. package/docs/assets/skills/lit-diagram-drawer.webp +0 -0
  44. package/docs/assets/skills/lit-docx.webp +0 -0
  45. package/docs/assets/skills/lit-handoff.webp +0 -0
  46. package/docs/assets/skills/lit-humanizer.webp +0 -0
  47. package/docs/assets/skills/lit-init.webp +0 -0
  48. package/docs/assets/skills/lit-loop.webp +0 -0
  49. package/docs/assets/skills/lit-plan.webp +0 -0
  50. package/docs/assets/skills/lit-pptx.webp +0 -0
  51. package/docs/assets/skills/lit-recap.webp +0 -0
  52. package/docs/assets/skills/lit-scientific-visualization.webp +0 -0
  53. package/docs/assets/skills/lit-team.webp +0 -0
  54. package/docs/assets/skills/lit-typographic-motion.webp +0 -0
  55. package/docs/assets/skills/litgoal.webp +0 -0
  56. package/docs/assets/skills/litresearch.webp +0 -0
  57. package/docs/assets/skills/litwork.webp +0 -0
  58. package/docs/assets/skills/lsp-setup.webp +0 -0
  59. package/docs/assets/skills/readme-studio.webp +0 -0
  60. package/docs/assets/skills/refactor.webp +0 -0
  61. package/docs/assets/skills/review-work.webp +0 -0
  62. package/docs/assets/skills/start-work.webp +0 -0
  63. package/docs/assets/skills/structural-search.webp +0 -0
  64. package/docs/assets/skills/visual-qa.webp +0 -0
  65. package/docs/assets/skills/wikify.webp +0 -0
  66. package/docs/hooks.md +185 -41
  67. package/docs/migration.md +6 -3
  68. package/docs/privacy.md +6 -1
  69. package/package.json +4 -2
  70. package/plugins/litclaude/.claude-plugin/plugin.json +1 -1
  71. package/plugins/litclaude/agents/korean-prose-editor.md +1 -0
  72. package/plugins/litclaude/agents/korean-style-analyzer.md +1 -0
  73. package/plugins/litclaude/agents/meaning-preservation-auditor.md +1 -0
  74. package/plugins/litclaude/agents/native-flow-reviewer.md +1 -0
  75. package/plugins/litclaude/agents/polish-orchestrator.md +1 -0
  76. package/plugins/litclaude/bin/litclaude-hook.js +347 -35
  77. package/plugins/litclaude/bin/litclaude-hud.js +29 -1
  78. package/plugins/litclaude/bin/litclaude-mcp.js +1 -1
  79. package/plugins/litclaude/bundled-rules/lit-humanizer.md +14 -0
  80. package/plugins/litclaude/commands/korean-ai-slop-remover.md +2 -2
  81. package/plugins/litclaude/commands/lit-comprehend.md +11 -11
  82. package/plugins/litclaude/commands/lit-humanizer.md +75 -0
  83. package/plugins/litclaude/commands/lit-korean.md +4 -130
  84. package/plugins/litclaude/commands/litresearch.md +12 -10
  85. package/plugins/litclaude/hooks/hooks.json +1 -1
  86. package/plugins/litclaude/lib/canonical-runtime-commitments.mjs +2 -2
  87. package/plugins/litclaude/lib/canonical-skill-catalog.mjs +5 -1
  88. package/plugins/litclaude/lib/canonical-skill-resources.mjs +618 -13
  89. package/plugins/litclaude/lib/deliverable-hedge-guard.mjs +256 -350
  90. package/plugins/litclaude/lib/hud-accent-palette.mjs +33 -0
  91. package/plugins/litclaude/lib/interface-mode.mjs +33 -0
  92. package/plugins/litclaude/lib/interface-probe-gate.mjs +125 -0
  93. package/plugins/litclaude/lib/jev-skill-hint.mjs +445 -0
  94. package/plugins/litclaude/lib/motion-render-gate.mjs +164 -0
  95. package/plugins/litclaude/lib/mutated-file-paths.mjs +32 -1
  96. package/plugins/litclaude/lib/office-runtime-lock/package-lock.json +745 -0
  97. package/plugins/litclaude/lib/office-runtime-lock/package.json +12 -0
  98. package/plugins/litclaude/lib/office-runtime-lock/requirements.lock +15 -0
  99. package/plugins/litclaude/lib/office-runtime.mjs +255 -0
  100. package/plugins/litclaude/lib/office_data.py +493 -0
  101. package/plugins/litclaude/lib/office_runtime_bootstrap.py +61 -0
  102. package/plugins/litclaude/lib/ooxml_integrity.py +199 -0
  103. package/plugins/litclaude/lib/rename-aliases.mjs +3 -1
  104. package/plugins/litclaude/lib/render_pages.py +105 -0
  105. package/plugins/litclaude/skills/autoconference/SKILL.md +2 -0
  106. package/plugins/litclaude/skills/browser-drive/SKILL.md +19 -6
  107. package/plugins/litclaude/skills/browser-drive/scripts/capability-probe.mjs +44 -8
  108. package/plugins/litclaude/skills/frontend-ui-ux/ATTRIBUTION.md +26 -0
  109. package/plugins/litclaude/skills/frontend-ui-ux/SKILL.md +50 -16
  110. package/plugins/litclaude/skills/frontend-ui-ux/examples/phase-3-readme-ab/README.md +9 -0
  111. package/plugins/litclaude/skills/frontend-ui-ux/references/complete-contract.md +32 -6
  112. package/plugins/litclaude/skills/frontend-ui-ux/references/craft-floor.md +257 -0
  113. package/plugins/litclaude/skills/frontend-ui-ux/references/default-editorial-pixel.json +6 -0
  114. package/plugins/litclaude/skills/frontend-ui-ux/references/interaction-motion.md +34 -88
  115. package/plugins/litclaude/skills/frontend-ui-ux/references/motion-guide.md +130 -0
  116. package/plugins/litclaude/skills/frontend-ui-ux/references/slop-register.md +150 -0
  117. package/plugins/litclaude/skills/frontend-ui-ux/references/visual-reconstruction.md +39 -85
  118. package/plugins/litclaude/skills/frontend-ui-ux/scripts/interface-probe-page.mjs +1534 -0
  119. package/plugins/litclaude/skills/frontend-ui-ux/scripts/interface-probe-rules.mjs +141 -0
  120. package/plugins/litclaude/skills/frontend-ui-ux/scripts/interface-probe-server.mjs +57 -0
  121. package/plugins/litclaude/skills/frontend-ui-ux/scripts/interface-probe-static.mjs +129 -0
  122. package/plugins/litclaude/skills/frontend-ui-ux/scripts/interface-probe.mjs +316 -0
  123. package/plugins/litclaude/skills/lit-comprehend/SKILL.md +34 -43
  124. package/plugins/litclaude/skills/lit-comprehend/references/artifact-template.md +5 -44
  125. package/plugins/litclaude/skills/lit-comprehend/scripts/verify-explainer.mjs +6 -16
  126. package/plugins/litclaude/skills/lit-diagram-drawer/NOTICE +33 -0
  127. package/plugins/litclaude/skills/lit-diagram-drawer/SKILL.md +123 -0
  128. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-architecture-dark.html +1 -0
  129. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-architecture-full.html +1 -0
  130. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-architecture-light.html +1 -0
  131. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bar-dark.html +1 -0
  132. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bar-full.html +1 -0
  133. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bar-light.html +1 -0
  134. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-beeswarm-dark.html +1 -0
  135. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-beeswarm-full.html +1 -0
  136. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-beeswarm-light.html +1 -0
  137. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bubble-dark.html +1 -0
  138. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bubble-full.html +1 -0
  139. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bubble-light.html +1 -0
  140. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bump-dark.html +1 -0
  141. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bump-full.html +1 -0
  142. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-bump-light.html +1 -0
  143. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-data-flow-dark.html +1 -0
  144. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-data-flow-full.html +1 -0
  145. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-data-flow-light.html +1 -0
  146. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-datalake-dark.html +1 -0
  147. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-datalake-full.html +1 -0
  148. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-datalake-light.html +1 -0
  149. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-db-schema-dark.html +1 -0
  150. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-db-schema-full.html +1 -0
  151. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-db-schema-light.html +1 -0
  152. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dependency-dark.html +1 -0
  153. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dependency-full.html +1 -0
  154. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dependency-light.html +1 -0
  155. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-deployment-dark.html +1 -0
  156. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-deployment-full.html +1 -0
  157. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-deployment-light.html +1 -0
  158. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dp-integration-dark.html +1 -0
  159. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dp-integration-full.html +1 -0
  160. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dp-integration-light.html +1 -0
  161. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-dark.html +1 -0
  162. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-full.html +1 -0
  163. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-dp-security-matrix-light.html +1 -0
  164. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-er-dark.html +1 -0
  165. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-er-full.html +1 -0
  166. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-er-light.html +1 -0
  167. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-fishbone-dark.html +1 -0
  168. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-fishbone-full.html +1 -0
  169. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-fishbone-light.html +1 -0
  170. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-flowchart-dark.html +1 -0
  171. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-flowchart-full.html +1 -0
  172. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-flowchart-light.html +1 -0
  173. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-gantt-dark.html +1 -0
  174. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-gantt-full.html +1 -0
  175. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-gantt-light.html +1 -0
  176. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-heatmap-dark.html +1 -0
  177. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-heatmap-full.html +1 -0
  178. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-heatmap-light.html +1 -0
  179. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-high-level-dark.html +1 -0
  180. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-high-level-full.html +1 -0
  181. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-high-level-light.html +1 -0
  182. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-dark.html +1 -0
  183. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-full.html +1 -0
  184. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-high-level-vertical-light.html +1 -0
  185. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-drawio-dark.html +1 -0
  186. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-drawio-full.html +1 -0
  187. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-drawio-light.html +1 -0
  188. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-dark.html +1 -0
  189. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-full.html +1 -0
  190. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-excalidraw-light.html +1 -0
  191. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-dark.html +1 -0
  192. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-full.html +1 -0
  193. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-import-mermaid-light.html +1 -0
  194. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-it-state-dark.html +1 -0
  195. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-it-state-full.html +1 -0
  196. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-it-state-light.html +1 -0
  197. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-journey-dark.html +1 -0
  198. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-journey-full.html +1 -0
  199. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-journey-light.html +1 -0
  200. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-kanban-dark.html +1 -0
  201. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-kanban-full.html +1 -0
  202. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-kanban-light.html +1 -0
  203. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-layers-dark.html +1 -0
  204. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-layers-full.html +1 -0
  205. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-layers-light.html +1 -0
  206. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-line-dark.html +1 -0
  207. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-line-full.html +1 -0
  208. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-line-light.html +1 -0
  209. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-loop-dark.html +1 -0
  210. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-loop-full.html +1 -0
  211. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-loop-light.html +1 -0
  212. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-dark.html +1 -0
  213. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-full.html +1 -0
  214. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-loop-terminal-light.html +1 -0
  215. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-marimekko-dark.html +1 -0
  216. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-marimekko-full.html +1 -0
  217. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-marimekko-light.html +1 -0
  218. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-medallion-dark.html +1 -0
  219. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-medallion-full.html +1 -0
  220. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-medallion-light.html +1 -0
  221. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-nested-dark.html +1 -0
  222. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-nested-full.html +1 -0
  223. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-nested-light.html +1 -0
  224. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-org-chart-dark.html +1 -0
  225. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-org-chart-full.html +1 -0
  226. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-org-chart-light.html +1 -0
  227. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-dark.html +1 -0
  228. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-full.html +1 -0
  229. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-paved-road-animated-light.html +1 -0
  230. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-polar-dark.html +1 -0
  231. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-polar-full.html +1 -0
  232. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-polar-light.html +1 -0
  233. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-dark.html +1 -0
  234. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-full.html +1 -0
  235. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-policy-trace-animated-light.html +1 -0
  236. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-process-dark.html +1 -0
  237. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-process-full.html +1 -0
  238. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-process-light.html +1 -0
  239. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-pyramid-dark.html +1 -0
  240. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-pyramid-full.html +1 -0
  241. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-pyramid-light.html +1 -0
  242. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-dark.html +1 -0
  243. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-full.html +1 -0
  244. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-quadrant-consultant-light.html +1 -0
  245. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-quadrant-dark.html +1 -0
  246. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-quadrant-full.html +1 -0
  247. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-quadrant-light.html +1 -0
  248. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-queue-animated-dark.html +1 -0
  249. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-queue-animated-full.html +1 -0
  250. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-queue-animated-light.html +1 -0
  251. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-radar-dark.html +1 -0
  252. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-radar-full.html +1 -0
  253. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-radar-light.html +1 -0
  254. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-ridgeline-dark.html +1 -0
  255. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-ridgeline-full.html +1 -0
  256. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-ridgeline-light.html +1 -0
  257. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sankey-dark.html +1 -0
  258. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sankey-full.html +1 -0
  259. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sankey-light.html +1 -0
  260. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-scatter-dark.html +1 -0
  261. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-scatter-full.html +1 -0
  262. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-scatter-light.html +1 -0
  263. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sequence-dark.html +1 -0
  264. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sequence-full.html +1 -0
  265. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sequence-light.html +1 -0
  266. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-dark.html +1 -0
  267. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-full.html +1 -0
  268. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-sequence-oauth-light.html +1 -0
  269. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-slopegraph-dark.html +1 -0
  270. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-slopegraph-full.html +1 -0
  271. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-slopegraph-light.html +1 -0
  272. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-state-dark.html +1 -0
  273. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-state-full.html +1 -0
  274. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-dark.html +1 -0
  275. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-full.html +1 -0
  276. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-state-lifecycle-light.html +1 -0
  277. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-state-light.html +1 -0
  278. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-story-map-dark.html +1 -0
  279. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-story-map-full.html +1 -0
  280. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-story-map-light.html +1 -0
  281. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-streamgraph-dark.html +1 -0
  282. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-streamgraph-full.html +1 -0
  283. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-streamgraph-light.html +1 -0
  284. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-swimlane-dark.html +1 -0
  285. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-swimlane-full.html +1 -0
  286. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-swimlane-light.html +1 -0
  287. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-timeline-dark.html +1 -0
  288. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-timeline-full.html +1 -0
  289. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-timeline-light.html +1 -0
  290. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-dark.html +1 -0
  291. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-full.html +1 -0
  292. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-tree-block-decomposition-light.html +1 -0
  293. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-tree-dark.html +1 -0
  294. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-tree-full.html +1 -0
  295. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-tree-light.html +1 -0
  296. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-treemap-dark.html +1 -0
  297. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-treemap-full.html +1 -0
  298. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-treemap-light.html +1 -0
  299. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-uml-class-dark.html +1 -0
  300. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-uml-class-full.html +1 -0
  301. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-uml-class-light.html +1 -0
  302. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-venn-dark.html +1 -0
  303. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-venn-full.html +1 -0
  304. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-venn-light.html +1 -0
  305. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-wardley-dark.html +1 -0
  306. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-wardley-full.html +1 -0
  307. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-wardley-light.html +1 -0
  308. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-waterfall-dark.html +1 -0
  309. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-waterfall-full.html +1 -0
  310. package/plugins/litclaude/skills/lit-diagram-drawer/assets/examples/type-waterfall-light.html +1 -0
  311. package/plugins/litclaude/skills/lit-diagram-drawer/assets/fonts/OFL.txt +94 -0
  312. package/plugins/litclaude/skills/lit-diagram-drawer/assets/fonts/PretendardVariable.woff2 +0 -0
  313. package/plugins/litclaude/skills/lit-diagram-drawer/assets/fonts/provenance.json +22 -0
  314. package/plugins/litclaude/skills/lit-diagram-drawer/assets/icons.html +231 -0
  315. package/plugins/litclaude/skills/lit-diagram-drawer/assets/index.html +1 -0
  316. package/plugins/litclaude/skills/lit-diagram-drawer/assets/licenses/devicon-MIT.txt +20 -0
  317. package/plugins/litclaude/skills/lit-diagram-drawer/assets/licenses/diagram-design-MIT.txt +21 -0
  318. package/plugins/litclaude/skills/lit-diagram-drawer/assets/licenses/log-z-MIT.txt +21 -0
  319. package/plugins/litclaude/skills/lit-diagram-drawer/assets/licenses/simple-icons-CC0.md +30 -0
  320. package/plugins/litclaude/skills/lit-diagram-drawer/assets/licenses/tabler-MIT.txt +21 -0
  321. package/plugins/litclaude/skills/lit-diagram-drawer/examples/01-service-architecture/after.html +1 -0
  322. package/plugins/litclaude/skills/lit-diagram-drawer/examples/01-service-architecture/brief.md +33 -0
  323. package/plugins/litclaude/skills/lit-diagram-drawer/examples/02-release-decision/after.html +1 -0
  324. package/plugins/litclaude/skills/lit-diagram-drawer/examples/02-release-decision/brief.md +18 -0
  325. package/plugins/litclaude/skills/lit-diagram-drawer/examples/03-data-retention/after.html +1 -0
  326. package/plugins/litclaude/skills/lit-diagram-drawer/examples/03-data-retention/brief.md +19 -0
  327. package/plugins/litclaude/skills/lit-diagram-drawer/examples/04-oauth-sequence/after.html +1 -0
  328. package/plugins/litclaude/skills/lit-diagram-drawer/examples/04-oauth-sequence/brief.md +17 -0
  329. package/plugins/litclaude/skills/lit-diagram-drawer/examples/05-review-lanes/after.html +1 -0
  330. package/plugins/litclaude/skills/lit-diagram-drawer/examples/05-review-lanes/brief.md +17 -0
  331. package/plugins/litclaude/skills/lit-diagram-drawer/examples/06-rollout-gates/after.html +1 -0
  332. package/plugins/litclaude/skills/lit-diagram-drawer/examples/06-rollout-gates/brief.md +17 -0
  333. package/plugins/litclaude/skills/lit-diagram-drawer/examples/07-deployment-boundary/after.html +1 -0
  334. package/plugins/litclaude/skills/lit-diagram-drawer/examples/07-deployment-boundary/brief.md +19 -0
  335. package/plugins/litclaude/skills/lit-diagram-drawer/examples/08-policy-traces/after.html +1 -0
  336. package/plugins/litclaude/skills/lit-diagram-drawer/examples/08-policy-traces/brief.md +20 -0
  337. package/plugins/litclaude/skills/lit-diagram-drawer/references/accessibility.md +37 -0
  338. package/plugins/litclaude/skills/lit-diagram-drawer/references/export.md +29 -0
  339. package/plugins/litclaude/skills/lit-diagram-drawer/references/import-drawio.md +21 -0
  340. package/plugins/litclaude/skills/lit-diagram-drawer/references/import-excalidraw.md +14 -0
  341. package/plugins/litclaude/skills/lit-diagram-drawer/references/import-mermaid.md +18 -0
  342. package/plugins/litclaude/skills/lit-diagram-drawer/references/import-schema.md +28 -0
  343. package/plugins/litclaude/skills/lit-diagram-drawer/references/korean-typography.md +34 -0
  344. package/plugins/litclaude/skills/lit-diagram-drawer/references/motion.md +29 -0
  345. package/plugins/litclaude/skills/lit-diagram-drawer/references/office-pptx-docx.md +42 -0
  346. package/plugins/litclaude/skills/lit-diagram-drawer/references/output-spec.md +48 -0
  347. package/plugins/litclaude/skills/lit-diagram-drawer/references/primitive-annotation.md +12 -0
  348. package/plugins/litclaude/skills/lit-diagram-drawer/references/primitive-icons.md +21 -0
  349. package/plugins/litclaude/skills/lit-diagram-drawer/references/primitive-sketchy.md +11 -0
  350. package/plugins/litclaude/skills/lit-diagram-drawer/references/primitive-terminal.md +11 -0
  351. package/plugins/litclaude/skills/lit-diagram-drawer/references/profiles.md +24 -0
  352. package/plugins/litclaude/skills/lit-diagram-drawer/references/semantic-patterns.md +27 -0
  353. package/plugins/litclaude/skills/lit-diagram-drawer/references/style-guide.md +67 -0
  354. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-architecture.md +51 -0
  355. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-bar.md +51 -0
  356. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-beeswarm.md +49 -0
  357. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-bubble.md +49 -0
  358. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-bump.md +49 -0
  359. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-catalog.json +1433 -0
  360. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-data-flow.md +51 -0
  361. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-datalake.md +49 -0
  362. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-db-schema.md +49 -0
  363. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-dependency.md +49 -0
  364. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-deployment.md +49 -0
  365. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-dp-integration.md +49 -0
  366. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-dp-security-matrix.md +49 -0
  367. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-er.md +49 -0
  368. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-fishbone.md +49 -0
  369. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-flowchart.md +49 -0
  370. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-gantt.md +49 -0
  371. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-heatmap.md +53 -0
  372. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-high-level-vertical.md +53 -0
  373. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-high-level.md +53 -0
  374. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-import-drawio.md +53 -0
  375. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-import-excalidraw.md +53 -0
  376. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-import-mermaid.md +53 -0
  377. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-it-state.md +54 -0
  378. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-journey.md +54 -0
  379. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-kanban.md +54 -0
  380. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-layers.md +54 -0
  381. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-line.md +54 -0
  382. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-loop-terminal.md +53 -0
  383. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-loop.md +54 -0
  384. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-marimekko.md +54 -0
  385. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-medallion.md +54 -0
  386. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-nested.md +59 -0
  387. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-org-chart.md +58 -0
  388. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-paved-road-animated.md +72 -0
  389. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-polar.md +67 -0
  390. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-policy-trace-animated.md +69 -0
  391. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-process.md +58 -0
  392. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-pyramid.md +59 -0
  393. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-quadrant-consultant.md +60 -0
  394. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-quadrant.md +57 -0
  395. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-queue-animated.md +63 -0
  396. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-radar.md +57 -0
  397. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-ridgeline.md +63 -0
  398. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-sankey.md +68 -0
  399. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-scatter.md +60 -0
  400. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-sequence-oauth.md +66 -0
  401. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-sequence.md +63 -0
  402. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-slopegraph.md +65 -0
  403. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-state-lifecycle.md +53 -0
  404. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-state.md +59 -0
  405. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-story-map.md +52 -0
  406. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-streamgraph.md +53 -0
  407. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-swimlane.md +52 -0
  408. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-timeline.md +52 -0
  409. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-tree-block-decomposition.md +57 -0
  410. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-tree.md +54 -0
  411. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-treemap.md +54 -0
  412. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-uml-class.md +52 -0
  413. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-venn.md +51 -0
  414. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-wardley.md +52 -0
  415. package/plugins/litclaude/skills/lit-diagram-drawer/references/type-waterfall.md +54 -0
  416. package/plugins/litclaude/skills/lit-diagram-drawer/references/verifier-guide.md +66 -0
  417. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/block-registry.mjs +43 -0
  418. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/brief-contract.mjs +94 -0
  419. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/check-visible-text.mjs +15 -0
  420. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/diagram-metrics.mjs +223 -0
  421. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/doctor.mjs +35 -0
  422. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/drawio-extract.mjs +635 -0
  423. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/excalidraw-extract.mjs +319 -0
  424. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/export.mjs +116 -0
  425. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/mermaid-extract.mjs +438 -0
  426. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/office-safety.mjs +54 -0
  427. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/renderer.mjs +33 -0
  428. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/verify-all.mjs +58 -0
  429. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/verify-brief.mjs +22 -0
  430. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/verify-coverage.mjs +56 -0
  431. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/verify-diagram.mjs +27 -0
  432. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/verify-motion.mjs +12 -0
  433. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/verify-type.mjs +48 -0
  434. package/plugins/litclaude/skills/lit-diagram-drawer/scripts/visual-quality.mjs +376 -0
  435. package/plugins/litclaude/skills/lit-docx/NOTICE +33 -0
  436. package/plugins/litclaude/skills/lit-docx/SKILL.md +170 -0
  437. package/plugins/litclaude/skills/lit-docx/references/frontmatter_schema.md +42 -0
  438. package/plugins/litclaude/skills/lit-docx/references/journal_style_spec.md +17 -0
  439. package/plugins/litclaude/skills/lit-docx/references/markdown_quality_checklist.md +37 -0
  440. package/plugins/litclaude/skills/lit-docx/references/slop_phrase_list.yaml +58 -0
  441. package/plugins/litclaude/skills/lit-docx/references/slop_rules.md +35 -0
  442. package/plugins/litclaude/skills/lit-docx/scripts/clean_markdown.py +95 -0
  443. package/plugins/litclaude/skills/lit-docx/scripts/convert_md_to_docx.py +1194 -0
  444. package/plugins/litclaude/skills/lit-docx/scripts/convert_md_to_pdf.py +290 -0
  445. package/plugins/litclaude/skills/lit-docx/scripts/convert_pdf.py +139 -0
  446. package/plugins/litclaude/skills/lit-docx/scripts/edit_docx.py +306 -0
  447. package/plugins/litclaude/skills/lit-docx/scripts/embed_images.py +78 -0
  448. package/plugins/litclaude/skills/lit-docx/scripts/generate_docx_templates.py +500 -0
  449. package/plugins/litclaude/skills/lit-docx/scripts/qa_docx.py +177 -0
  450. package/plugins/litclaude/skills/lit-docx/scripts/slop_lint.py +561 -0
  451. package/plugins/litclaude/skills/lit-docx/scripts/visual_audit.py +48 -0
  452. package/plugins/litclaude/skills/lit-docx/templates/docx/acs.docx +0 -0
  453. package/plugins/litclaude/skills/lit-docx/templates/docx/elsevier.docx +0 -0
  454. package/plugins/litclaude/skills/lit-docx/templates/docx/ieee.docx +0 -0
  455. package/plugins/litclaude/skills/lit-docx/templates/docx/korean-generic.docx +0 -0
  456. package/plugins/litclaude/skills/lit-docx/templates/docx/nature.docx +0 -0
  457. package/plugins/litclaude/skills/lit-docx/templates/latex/acs/README.md +5 -0
  458. package/plugins/litclaude/skills/lit-docx/templates/latex/acs/template.tex +37 -0
  459. package/plugins/litclaude/skills/lit-docx/templates/latex/elsevier/README.md +5 -0
  460. package/plugins/litclaude/skills/lit-docx/templates/latex/elsevier/template.tex +38 -0
  461. package/plugins/litclaude/skills/lit-docx/templates/latex/ieee/README.md +5 -0
  462. package/plugins/litclaude/skills/lit-docx/templates/latex/ieee/template.tex +37 -0
  463. package/plugins/litclaude/skills/lit-docx/templates/latex/korean-generic/README.md +5 -0
  464. package/plugins/litclaude/skills/lit-docx/templates/latex/korean-generic/template.tex +37 -0
  465. package/plugins/litclaude/skills/lit-docx/templates/latex/nature/README.md +5 -0
  466. package/plugins/litclaude/skills/lit-docx/templates/latex/nature/template.tex +37 -0
  467. package/plugins/litclaude/skills/lit-docx/templates/registry.yaml +1366 -0
  468. package/plugins/litclaude/skills/lit-humanizer/NOTICE +160 -0
  469. package/plugins/litclaude/skills/lit-humanizer/SKILL.md +164 -0
  470. package/plugins/litclaude/skills/lit-humanizer/assets/always-on-rule.md +9 -0
  471. package/plugins/litclaude/skills/lit-humanizer/assets/report-skeleton.md +25 -0
  472. package/plugins/litclaude/skills/lit-humanizer/assets/slide-text-skeleton.md +28 -0
  473. package/plugins/litclaude/skills/lit-humanizer/bench/prompts.md +73 -0
  474. package/plugins/litclaude/skills/lit-humanizer/examples/accessibility-note/after.md +7 -0
  475. package/plugins/litclaude/skills/lit-humanizer/examples/accessibility-note/before.md +7 -0
  476. package/plugins/litclaude/skills/lit-humanizer/examples/api-reference/after.md +9 -0
  477. package/plugins/litclaude/skills/lit-humanizer/examples/api-reference/before.md +15 -0
  478. package/plugins/litclaude/skills/lit-humanizer/examples/changelog/after.md +5 -0
  479. package/plugins/litclaude/skills/lit-humanizer/examples/changelog/before.md +12 -0
  480. package/plugins/litclaude/skills/lit-humanizer/examples/code-comments/after.md +10 -0
  481. package/plugins/litclaude/skills/lit-humanizer/examples/code-comments/before.md +19 -0
  482. package/plugins/litclaude/skills/lit-humanizer/examples/commit/after.md +5 -0
  483. package/plugins/litclaude/skills/lit-humanizer/examples/commit/before.md +7 -0
  484. package/plugins/litclaude/skills/lit-humanizer/examples/data-release/after.md +7 -0
  485. package/plugins/litclaude/skills/lit-humanizer/examples/data-release/before.md +9 -0
  486. package/plugins/litclaude/skills/lit-humanizer/examples/english-essay/after.md +5 -0
  487. package/plugins/litclaude/skills/lit-humanizer/examples/english-essay/before.md +5 -0
  488. package/plugins/litclaude/skills/lit-humanizer/examples/incident-update/after.md +7 -0
  489. package/plugins/litclaude/skills/lit-humanizer/examples/incident-update/before.md +7 -0
  490. package/plugins/litclaude/skills/lit-humanizer/examples/ko-essay/after.md +7 -0
  491. package/plugins/litclaude/skills/lit-humanizer/examples/ko-essay/before.md +9 -0
  492. package/plugins/litclaude/skills/lit-humanizer/examples/ko-report/after.md +9 -0
  493. package/plugins/litclaude/skills/lit-humanizer/examples/ko-report/before.md +13 -0
  494. package/plugins/litclaude/skills/lit-humanizer/examples/ko-slide/after.md +19 -0
  495. package/plugins/litclaude/skills/lit-humanizer/examples/ko-slide/before.md +21 -0
  496. package/plugins/litclaude/skills/lit-humanizer/examples/meeting-brief/after.md +9 -0
  497. package/plugins/litclaude/skills/lit-humanizer/examples/meeting-brief/before.md +11 -0
  498. package/plugins/litclaude/skills/lit-humanizer/examples/policy-faq/after.md +9 -0
  499. package/plugins/litclaude/skills/lit-humanizer/examples/policy-faq/before.md +9 -0
  500. package/plugins/litclaude/skills/lit-humanizer/examples/pr/after.md +15 -0
  501. package/plugins/litclaude/skills/lit-humanizer/examples/pr/before.md +17 -0
  502. package/plugins/litclaude/skills/lit-humanizer/examples/project-update/after.md +7 -0
  503. package/plugins/litclaude/skills/lit-humanizer/examples/project-update/before.md +9 -0
  504. package/plugins/litclaude/skills/lit-humanizer/examples/readme/after.md +12 -0
  505. package/plugins/litclaude/skills/lit-humanizer/examples/readme/before.md +14 -0
  506. package/plugins/litclaude/skills/lit-humanizer/examples/report/after.md +13 -0
  507. package/plugins/litclaude/skills/lit-humanizer/examples/report/before.md +11 -0
  508. package/plugins/litclaude/skills/lit-humanizer/examples/research-abstract/after.md +5 -0
  509. package/plugins/litclaude/skills/lit-humanizer/examples/research-abstract/before.md +5 -0
  510. package/plugins/litclaude/skills/lit-humanizer/examples/slides/after.md +19 -0
  511. package/plugins/litclaude/skills/lit-humanizer/examples/slides/before.md +19 -0
  512. package/plugins/litclaude/skills/lit-humanizer/examples/troubleshooting/after.md +11 -0
  513. package/plugins/litclaude/skills/lit-humanizer/examples/troubleshooting/before.md +11 -0
  514. package/plugins/litclaude/skills/lit-humanizer/motion-guide.md +123 -0
  515. package/plugins/litclaude/skills/lit-humanizer/references/code-patterns.md +468 -0
  516. package/plugins/litclaude/skills/lit-humanizer/references/deliverable-channels.md +111 -0
  517. package/plugins/litclaude/skills/lit-humanizer/references/en-patterns-checklist.md +43 -0
  518. package/plugins/litclaude/skills/lit-humanizer/references/en-patterns-content.md +243 -0
  519. package/plugins/litclaude/skills/lit-humanizer/references/en-patterns-structure.md +375 -0
  520. package/plugins/litclaude/skills/lit-humanizer/references/en-patterns.md +57 -0
  521. package/plugins/litclaude/skills/lit-humanizer/references/ko-metrics.md +33 -0
  522. package/plugins/litclaude/skills/lit-humanizer/references/ko-patterns-a-d.md +659 -0
  523. package/plugins/litclaude/skills/lit-humanizer/references/ko-patterns-e-j.md +387 -0
  524. package/plugins/litclaude/skills/lit-humanizer/references/ko-patterns.md +31 -0
  525. package/plugins/litclaude/skills/lit-humanizer/references/rewrite-playbook.md +54 -0
  526. package/plugins/litclaude/skills/lit-humanizer/references/taxonomy.md +153 -0
  527. package/plugins/litclaude/skills/lit-humanizer/rules.json +884 -0
  528. package/plugins/litclaude/skills/lit-humanizer/scripts/artifact-text.mjs +38 -0
  529. package/plugins/litclaude/skills/lit-humanizer/scripts/core.mjs +207 -0
  530. package/plugins/litclaude/skills/lit-humanizer/scripts/detect.mjs +64 -0
  531. package/plugins/litclaude/skills/lit-humanizer/scripts/extract_office_text.py +112 -0
  532. package/plugins/litclaude/skills/lit-humanizer/scripts/ko-metrics.mjs +124 -0
  533. package/plugins/litclaude/skills/lit-humanizer/scripts/scan-input.mjs +29 -0
  534. package/plugins/litclaude/skills/lit-loop/SKILL.md +30 -1
  535. package/plugins/litclaude/skills/lit-plan/SKILL.md +4 -1
  536. package/plugins/litclaude/skills/lit-pptx/NOTICE +38 -0
  537. package/plugins/litclaude/skills/lit-pptx/SKILL.md +207 -0
  538. package/plugins/litclaude/skills/lit-pptx/assets/azure/circle-lg.png +0 -0
  539. package/plugins/litclaude/skills/lit-pptx/assets/azure/circle-md.png +0 -0
  540. package/plugins/litclaude/skills/lit-pptx/assets/azure/circle-sm.png +0 -0
  541. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/A2Z-Black.otf +0 -0
  542. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/A2Z-Bold.otf +0 -0
  543. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/A2Z-Light.otf +0 -0
  544. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/A2Z-Medium.otf +0 -0
  545. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/A2Z-Regular.otf +0 -0
  546. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/OFL.txt +94 -0
  547. package/plugins/litclaude/skills/lit-pptx/fonts/a2z/SOURCE.md +29 -0
  548. package/plugins/litclaude/skills/lit-pptx/fonts/pretendard/OFL.txt +94 -0
  549. package/plugins/litclaude/skills/lit-pptx/fonts/pretendard/Pretendard-Bold.otf +0 -0
  550. package/plugins/litclaude/skills/lit-pptx/fonts/pretendard/Pretendard-Regular.otf +0 -0
  551. package/plugins/litclaude/skills/lit-pptx/fonts/provenance.json +78 -0
  552. package/plugins/litclaude/skills/lit-pptx/references/agents/analyst.md +49 -0
  553. package/plugins/litclaude/skills/lit-pptx/references/agents/antithesis.md +59 -0
  554. package/plugins/litclaude/skills/lit-pptx/references/agents/architect.md +44 -0
  555. package/plugins/litclaude/skills/lit-pptx/references/agents/critic.md +42 -0
  556. package/plugins/litclaude/skills/lit-pptx/references/agents/synthesizer.md +47 -0
  557. package/plugins/litclaude/skills/lit-pptx/references/agents/thesis.md +33 -0
  558. package/plugins/litclaude/skills/lit-pptx/references/anti-slop-checklist.md +81 -0
  559. package/plugins/litclaude/skills/lit-pptx/references/authoring-guide.md +173 -0
  560. package/plugins/litclaude/skills/lit-pptx/references/consensus-protocol.md +125 -0
  561. package/plugins/litclaude/skills/lit-pptx/references/data-display-cookbook.md +45 -0
  562. package/plugins/litclaude/skills/lit-pptx/references/design-system-azure.md +58 -0
  563. package/plugins/litclaude/skills/lit-pptx/references/interview-protocol.md +113 -0
  564. package/plugins/litclaude/skills/lit-pptx/references/stages/autopilot.md +48 -0
  565. package/plugins/litclaude/skills/lit-pptx/references/stages/interview.md +52 -0
  566. package/plugins/litclaude/skills/lit-pptx/references/stages/plan.md +42 -0
  567. package/plugins/litclaude/skills/lit-pptx/scripts/compile-deck.js +414 -0
  568. package/plugins/litclaude/skills/lit-pptx/scripts/craft_extras.py +373 -0
  569. package/plugins/litclaude/skills/lit-pptx/scripts/deck_craft.py +321 -0
  570. package/plugins/litclaude/skills/lit-pptx/scripts/embed_fonts.py +215 -0
  571. package/plugins/litclaude/skills/lit-pptx/scripts/forbidden-terms.json +55 -0
  572. package/plugins/litclaude/skills/lit-pptx/scripts/layout_inventory.py +418 -0
  573. package/plugins/litclaude/skills/lit-pptx/scripts/learn_template.py +446 -0
  574. package/plugins/litclaude/skills/lit-pptx/scripts/lib/derive-palette.js +176 -0
  575. package/plugins/litclaude/skills/lit-pptx/scripts/lib/directive-parser.js +244 -0
  576. package/plugins/litclaude/skills/lit-pptx/scripts/lib/font-map.js +79 -0
  577. package/plugins/litclaude/skills/lit-pptx/scripts/lib/gen-bg.js +86 -0
  578. package/plugins/litclaude/skills/lit-pptx/scripts/lib/gen-gradient-assets.js +37 -0
  579. package/plugins/litclaude/skills/lit-pptx/scripts/lib/layout-resolver.js +768 -0
  580. package/plugins/litclaude/skills/lit-pptx/scripts/lib/markdown-loader.js +136 -0
  581. package/plugins/litclaude/skills/lit-pptx/scripts/lib/render-adapter-html.js +356 -0
  582. package/plugins/litclaude/skills/lit-pptx/scripts/lib/render-adapter-pptx.js +2094 -0
  583. package/plugins/litclaude/skills/lit-pptx/scripts/lib/runtime-require.js +28 -0
  584. package/plugins/litclaude/skills/lit-pptx/scripts/lib/slide-ast.js +561 -0
  585. package/plugins/litclaude/skills/lit-pptx/scripts/lib/spec-validator.js +94 -0
  586. package/plugins/litclaude/skills/lit-pptx/scripts/lib/template-registry.js +394 -0
  587. package/plugins/litclaude/skills/lit-pptx/scripts/package.json +4 -0
  588. package/plugins/litclaude/skills/lit-pptx/scripts/qa_deck.py +766 -0
  589. package/plugins/litclaude/skills/lit-pptx/scripts/validate_pptx.py +215 -0
  590. package/plugins/litclaude/skills/lit-pptx/specs/markdown-slide-spec-v1.md +251 -0
  591. package/plugins/litclaude/skills/lit-pptx/specs/markdown-slide-spec-v2.md +214 -0
  592. package/plugins/litclaude/skills/lit-pptx/specs/slide-ast-v1.schema.json +229 -0
  593. package/plugins/litclaude/skills/lit-pptx/specs/slide-ast-v2.schema.json +144 -0
  594. package/plugins/litclaude/skills/lit-pptx/specs/template-enrollment-contract.md +382 -0
  595. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/AZURE-A2Z/capabilities.yaml +146 -0
  596. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/AZURE-A2Z/layout-mapping.yaml +454 -0
  597. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/AZURE-A2Z/template.yaml +37 -0
  598. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/AZURE-PRO/capabilities.yaml +154 -0
  599. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/AZURE-PRO/layout-mapping.yaml +475 -0
  600. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/AZURE-PRO/template.yaml +37 -0
  601. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/capabilities.yaml +179 -0
  602. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/layout-mapping.yaml +299 -0
  603. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/BOILERPLATE-A2Z/template.yaml +45 -0
  604. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/capabilities.yaml +181 -0
  605. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/layout-mapping.yaml +299 -0
  606. package/plugins/litclaude/skills/lit-pptx/templates/enrolled/BOILERPLATE-PRETENDARD/template.yaml +44 -0
  607. package/plugins/litclaude/skills/lit-scientific-visualization/SKILL.md +1 -0
  608. package/plugins/litclaude/skills/lit-typographic-motion/SKILL.md +131 -0
  609. package/plugins/litclaude/skills/lit-typographic-motion/engine/NOTICE +23 -0
  610. package/plugins/litclaude/skills/lit-typographic-motion/engine/THIRD_PARTY_NOTICES +56 -0
  611. package/plugins/litclaude/skills/lit-typographic-motion/engine/audio/beat_grid.py +56 -0
  612. package/plugins/litclaude/skills/lit-typographic-motion/engine/audio/requirements.lock +1084 -0
  613. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/constants.mjs +211 -0
  614. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/contrast.mjs +90 -0
  615. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/events.mjs +46 -0
  616. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/flash.mjs +211 -0
  617. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/gate-rules.mjs +550 -0
  618. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/presets.mjs +123 -0
  619. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/text.mjs +100 -0
  620. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/timeline.mjs +142 -0
  621. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/util.mjs +167 -0
  622. package/plugins/litclaude/skills/lit-typographic-motion/engine/core/voices.mjs +19 -0
  623. package/plugins/litclaude/skills/lit-typographic-motion/engine/models/word-timing.json +198 -0
  624. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/analysis.mjs +108 -0
  625. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/brief.mjs +158 -0
  626. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/chrome.mjs +330 -0
  627. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/coverage.mjs +83 -0
  628. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/done.mjs +104 -0
  629. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/encode.mjs +104 -0
  630. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/frame-worker.mjs +36 -0
  631. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/look.mjs +128 -0
  632. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/pipeline.mjs +592 -0
  633. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/png.mjs +112 -0
  634. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/report.mjs +66 -0
  635. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/runtime.mjs +330 -0
  636. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/session.mjs +145 -0
  637. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/sound-cli.mjs +60 -0
  638. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/sound.mjs +641 -0
  639. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/stage-capture.mjs +178 -0
  640. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/stage-gate.mjs +122 -0
  641. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/stage-qa.mjs +295 -0
  642. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/stage-serve.mjs +278 -0
  643. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/stage.mjs +503 -0
  644. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/stills.mjs +100 -0
  645. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/treatment.mjs +343 -0
  646. package/plugins/litclaude/skills/lit-typographic-motion/engine/node/ws-server.mjs +132 -0
  647. package/plugins/litclaude/skills/lit-typographic-motion/engine/package-lock.json +25 -0
  648. package/plugins/litclaude/skills/lit-typographic-motion/engine/package.json +10 -0
  649. package/plugins/litclaude/skills/lit-typographic-motion/engine/stage/init.js +288 -0
  650. package/plugins/litclaude/skills/lit-typographic-motion/engine/stage/qa.js +157 -0
  651. package/plugins/litclaude/skills/lit-typographic-motion/engine/stage/stage-kit.js +701 -0
  652. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/boot.mjs +123 -0
  653. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/engine.mjs +281 -0
  654. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/gl.mjs +319 -0
  655. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/glsl-common.mjs +78 -0
  656. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/index.html +6 -0
  657. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/lines.mjs +112 -0
  658. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/passes/crt.mjs +98 -0
  659. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/passes/dither.mjs +49 -0
  660. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/passes/glitch.mjs +77 -0
  661. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/passes/swiss-grid.mjs +61 -0
  662. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/passes/terminal-ui.mjs +88 -0
  663. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/passes/tidal-gradient.mjs +86 -0
  664. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/post.mjs +165 -0
  665. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scale.mjs +15 -0
  666. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scene.mjs +82 -0
  667. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/end-card.mjs +30 -0
  668. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/index.mjs +16 -0
  669. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/karaoke-line.mjs +47 -0
  670. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/kinetic-list.mjs +45 -0
  671. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/number-counter.mjs +29 -0
  672. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/signature.mjs +73 -0
  673. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/scenes/title-slam.mjs +73 -0
  674. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/stroke.mjs +236 -0
  675. package/plugins/litclaude/skills/lit-typographic-motion/engine/web/type.mjs +180 -0
  676. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w100-400.ttf +0 -0
  677. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w100-700.ttf +0 -0
  678. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w100-900.ttf +0 -0
  679. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w125-400.ttf +0 -0
  680. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w125-700.ttf +0 -0
  681. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w125-900.ttf +0 -0
  682. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w75-400.ttf +0 -0
  683. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w75-700.ttf +0 -0
  684. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/Archivo-w75-900.ttf +0 -0
  685. package/plugins/litclaude/skills/lit-typographic-motion/fonts/archivo/OFL.txt +93 -0
  686. package/plugins/litclaude/skills/lit-typographic-motion/fonts/manifest.json +437 -0
  687. package/plugins/litclaude/skills/lit-typographic-motion/fonts/silkscreen/OFL.txt +93 -0
  688. package/plugins/litclaude/skills/lit-typographic-motion/fonts/silkscreen/Silkscreen-Bold.ttf +0 -0
  689. package/plugins/litclaude/skills/lit-typographic-motion/fonts/silkscreen/Silkscreen-Regular.ttf +0 -0
  690. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/CREDITS +42 -0
  691. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/EMSAllure.svg +216 -0
  692. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/EMSFelix.svg +216 -0
  693. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/EMSOsmotron.svg +216 -0
  694. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/EMSReadability.svg +216 -0
  695. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/EMSTech.svg +217 -0
  696. package/plugins/litclaude/skills/lit-typographic-motion/fonts/stroke/OFL.txt +91 -0
  697. package/plugins/litclaude/skills/lit-typographic-motion/fonts/vt323/OFL.txt +93 -0
  698. package/plugins/litclaude/skills/lit-typographic-motion/fonts/vt323/VT323-Regular.ttf +0 -0
  699. package/plugins/litclaude/skills/lit-typographic-motion/references/brief-schema.md +91 -0
  700. package/plugins/litclaude/skills/lit-typographic-motion/references/craft-loop.md +69 -0
  701. package/plugins/litclaude/skills/lit-typographic-motion/references/engine-contract.md +104 -0
  702. package/plugins/litclaude/skills/lit-typographic-motion/references/look.md +106 -0
  703. package/plugins/litclaude/skills/lit-typographic-motion/references/runtime.md +65 -0
  704. package/plugins/litclaude/skills/lit-typographic-motion/references/sound.md +83 -0
  705. package/plugins/litclaude/skills/lit-typographic-motion/references/stage.md +192 -0
  706. package/plugins/litclaude/skills/lit-typographic-motion/references/style-bibles.md +117 -0
  707. package/plugins/litclaude/skills/lit-typographic-motion/references/treatment.md +114 -0
  708. package/plugins/litclaude/skills/lit-typographic-motion/references/type-craft.md +79 -0
  709. package/plugins/litclaude/skills/lit-typographic-motion/scripts/motion-doctor.mjs +78 -0
  710. package/plugins/litclaude/skills/lit-typographic-motion/scripts/motion-runtime.mjs +67 -0
  711. package/plugins/litclaude/skills/lit-typographic-motion/scripts/motion.mjs +132 -0
  712. package/plugins/litclaude/skills/litresearch/SKILL.md +54 -18
  713. package/scripts/doctor.mjs +5 -0
  714. package/scripts/postinstall.mjs +1 -0
  715. package/plugins/litclaude/skills/lit-korean/SKILL.md +0 -327
  716. /package/plugins/litclaude/skills/{lit-korean/references/fidelity-checklist.md → lit-humanizer/references/litclaude-fidelity-checklist.md} +0 -0
  717. /package/plugins/litclaude/skills/{lit-korean/references/rewrite-rules.md → lit-humanizer/references/litclaude-rewrite-rules.md} +0 -0
  718. /package/plugins/litclaude/skills/{lit-korean/references/style-patterns.md → lit-humanizer/references/litclaude-style-patterns.md} +0 -0
@@ -0,0 +1,1194 @@
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 os as _os
24
+ import sys as _sys
25
+
26
+ _sys.dont_write_bytecode = True # the installed skill directory stays read-only
27
+ _sys.path.insert(0, _os.path.join(_os.path.dirname(_os.path.abspath(__file__)), "..", "..", "..", "lib"))
28
+ from office_runtime_bootstrap import ensure_runtime # noqa: E402
29
+ from office_data import DataError, resolve_text # noqa: E402
30
+
31
+ ensure_runtime(["docx", "markdown", "bs4", "yaml"])
32
+
33
+ import argparse
34
+ import re
35
+ import sys
36
+ from pathlib import Path
37
+ from typing import Any
38
+
39
+ try:
40
+ import markdown
41
+ from markdown.extensions.tables import TableExtension
42
+ from markdown.extensions.fenced_code import FencedCodeExtension
43
+ except ImportError:
44
+ print("Error: 'markdown' library not found. Install with: pip install markdown")
45
+ sys.exit(1)
46
+
47
+ try:
48
+ from docx import Document
49
+ from docx.shared import Pt, Inches, Cm, RGBColor
50
+ from docx.enum.text import WD_ALIGN_PARAGRAPH
51
+ from docx.enum.style import WD_STYLE_TYPE
52
+ from docx.oxml.ns import qn
53
+ from docx.oxml import OxmlElement
54
+ except ImportError:
55
+ print("Error: 'python-docx' library not found. Install with: pip install python-docx")
56
+ sys.exit(1)
57
+
58
+ try:
59
+ from bs4 import BeautifulSoup, NavigableString
60
+ except ImportError:
61
+ print("Error: 'beautifulsoup4' library not found. Install with: pip install beautifulsoup4")
62
+ sys.exit(1)
63
+
64
+
65
+ # ===========================================================================
66
+ # Legacy HTML→DOCX helpers (unchanged from pre-M1 — preserved byte-for-byte)
67
+ # ===========================================================================
68
+
69
+
70
+ def create_hyperlink(paragraph, url: str, text: str):
71
+ """Add a hyperlink to a paragraph."""
72
+ part = paragraph.part
73
+ r_id = part.relate_to(url, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", is_external=True)
74
+
75
+ hyperlink = OxmlElement('w:hyperlink')
76
+ hyperlink.set(qn('r:id'), r_id)
77
+
78
+ new_run = OxmlElement('w:r')
79
+ rPr = OxmlElement('w:rPr')
80
+
81
+ # Blue color and underline for hyperlink
82
+ color = OxmlElement('w:color')
83
+ color.set(qn('w:val'), '0000FF')
84
+ rPr.append(color)
85
+
86
+ underline = OxmlElement('w:u')
87
+ underline.set(qn('w:val'), 'single')
88
+ rPr.append(underline)
89
+
90
+ new_run.append(rPr)
91
+
92
+ text_elem = OxmlElement('w:t')
93
+ text_elem.text = text
94
+ new_run.append(text_elem)
95
+
96
+ hyperlink.append(new_run)
97
+ paragraph._p.append(hyperlink)
98
+
99
+
100
+ def process_inline_elements(paragraph, element, md_path: Path):
101
+ """Process inline elements like bold, italic, code, links within a paragraph."""
102
+ if isinstance(element, NavigableString):
103
+ text = str(element)
104
+ if text.strip():
105
+ paragraph.add_run(text)
106
+ elif text:
107
+ paragraph.add_run(text)
108
+ return
109
+
110
+ if element.name == 'strong' or element.name == 'b':
111
+ run = paragraph.add_run(element.get_text())
112
+ run.bold = True
113
+ elif element.name == 'em' or element.name == 'i':
114
+ run = paragraph.add_run(element.get_text())
115
+ run.italic = True
116
+ elif element.name == 'code':
117
+ run = paragraph.add_run(element.get_text())
118
+ run.font.name = 'Courier New'
119
+ run.font.size = Pt(10)
120
+ elif element.name == 'a':
121
+ href = element.get('href', '')
122
+ text = element.get_text()
123
+ if href:
124
+ create_hyperlink(paragraph, href, text)
125
+ else:
126
+ paragraph.add_run(text)
127
+ elif element.name == 'img':
128
+ src = element.get('src', '')
129
+ if src and not src.startswith(('http://', 'https://', 'data:')):
130
+ img_path = (md_path.parent / src).resolve()
131
+ if img_path.exists():
132
+ try:
133
+ paragraph.add_run().add_picture(str(img_path), width=Inches(4))
134
+ except Exception:
135
+ paragraph.add_run(f"[Image: {src}]")
136
+ else:
137
+ paragraph.add_run(f"[Image not found: {src}]")
138
+ else:
139
+ paragraph.add_run(f"[Image: {src}]")
140
+ elif element.name == 'br':
141
+ paragraph.add_run('\n')
142
+ else:
143
+ # Recursively process children
144
+ for child in element.children:
145
+ process_inline_elements(paragraph, child, md_path)
146
+
147
+
148
+ def add_paragraph_with_formatting(doc: Document, element, md_path: Path, style: str = None):
149
+ """Add a paragraph with inline formatting."""
150
+ para = doc.add_paragraph(style=style)
151
+ for child in element.children:
152
+ process_inline_elements(para, child, md_path)
153
+ return para
154
+
155
+
156
+ def process_list(doc: Document, element, md_path: Path, ordered: bool = False, level: int = 0):
157
+ """Process ordered or unordered lists."""
158
+ for i, li in enumerate(element.find_all('li', recursive=False)):
159
+ # Create paragraph with list style
160
+ para = doc.add_paragraph(style='List Number' if ordered else 'List Bullet')
161
+
162
+ # Set indentation for nested lists
163
+ if level > 0:
164
+ para.paragraph_format.left_indent = Inches(0.5 * level)
165
+
166
+ # Process direct text content
167
+ for child in li.children:
168
+ if isinstance(child, NavigableString):
169
+ text = str(child).strip()
170
+ if text:
171
+ para.add_run(text)
172
+ elif child.name in ('ul', 'ol'):
173
+ # Nested list
174
+ process_list(doc, child, md_path, ordered=(child.name == 'ol'), level=level + 1)
175
+ elif child.name == 'p':
176
+ # Process paragraph content inline
177
+ for subchild in child.children:
178
+ process_inline_elements(para, subchild, md_path)
179
+ else:
180
+ process_inline_elements(para, child, md_path)
181
+
182
+
183
+ def process_table(doc: Document, element, md_path: Path):
184
+ """Process HTML table and create DOCX table."""
185
+ rows = element.find_all('tr')
186
+ if not rows:
187
+ return
188
+
189
+ # Count columns from first row
190
+ first_row = rows[0]
191
+ cols = len(first_row.find_all(['th', 'td']))
192
+
193
+ if cols == 0:
194
+ return
195
+
196
+ table = doc.add_table(rows=len(rows), cols=cols)
197
+ table.style = 'Table Grid'
198
+
199
+ for row_idx, tr in enumerate(rows):
200
+ cells = tr.find_all(['th', 'td'])
201
+ for col_idx, cell in enumerate(cells):
202
+ if col_idx < cols:
203
+ table_cell = table.rows[row_idx].cells[col_idx]
204
+ # Clear default paragraph
205
+ table_cell.text = ''
206
+ para = table_cell.paragraphs[0]
207
+ for child in cell.children:
208
+ process_inline_elements(para, child, md_path)
209
+
210
+ # Bold for header cells
211
+ if cell.name == 'th':
212
+ for run in para.runs:
213
+ run.bold = True
214
+
215
+ shape_table(doc, table, [[c.get_text(" ", strip=True) for c in tr.find_all(['th', 'td'])] for tr in rows])
216
+
217
+
218
+ # A cell reads as a number when, after signs and units, only digits remain.
219
+ NUMERIC_CELL = re.compile(r"^[+\-−±▲▼△▽]?\s*[\d.,]+\s*(?:%p?|배|x|pt|[가-힣]{1,3}|[A-Za-z]{1,3})?$")
220
+
221
+
222
+ def shape_table(doc, table, texts: list[list[str]]) -> None:
223
+ """Give a table readable columns and keep it whole on the page.
224
+
225
+ Column widths follow the longest cell of each column (Hangul counted wider)
226
+ with a floor, so a short column never squeezes a long one into one word per
227
+ line. The header row repeats on a new page, a row never splits across pages,
228
+ and columns of numbers are right-aligned.
229
+ """
230
+ if not texts or not texts[0]:
231
+ return
232
+ cols = len(table.columns)
233
+ section = doc.sections[-1]
234
+ usable = section.page_width - section.left_margin - section.right_margin
235
+
236
+ def width_of(text: str) -> float:
237
+ # Hangul runs a little over twice as wide as Latin; +3 covers the cell padding.
238
+ return sum(2.3 if "\uac00" <= ch <= "\ud7a3" else 1.0 for ch in text) + 3.0
239
+
240
+ want = []
241
+ for ci in range(cols):
242
+ column = [row[ci] for row in texts if ci < len(row)]
243
+ want.append(max([width_of(t) for t in column] + [4.0]))
244
+ # Each column first gets its natural width (about 0.085 in per Latin character at
245
+ # body size, capped at 45% of the line); columns that hit the cap share what is left.
246
+ unit = Inches(0.085)
247
+ cap = usable * 0.45
248
+ natural = [min(w * unit, cap) for w in want]
249
+ capped = [ci for ci in range(cols) if want[ci] * unit > cap]
250
+ spare = usable - sum(natural)
251
+ if spare > 0 and capped:
252
+ for ci in capped:
253
+ natural[ci] += spare / len(capped)
254
+ elif spare > 0:
255
+ natural = [w + spare / cols for w in natural]
256
+ scale = usable / sum(natural)
257
+ widths = [int(w * scale) for w in natural]
258
+
259
+ table.autofit = False
260
+ for ci, column in enumerate(table.columns):
261
+ column.width = widths[ci]
262
+ for ri, row in enumerate(table.rows):
263
+ tr_pr = row._tr.get_or_add_trPr()
264
+ # Schema order puts cantSplit before trHeight and tblHeader after it.
265
+ tr_pr.insert(0, OxmlElement("w:cantSplit"))
266
+ if ri == 0:
267
+ header = OxmlElement("w:tblHeader")
268
+ tr_pr.append(header)
269
+ for ci, cell in enumerate(row.cells):
270
+ if ci < cols:
271
+ cell.width = widths[ci]
272
+ for paragraph in cell.paragraphs:
273
+ # Body line spacing (1.6 in some profiles) makes every row a double row.
274
+ paragraph.paragraph_format.line_spacing = 1.15
275
+ paragraph.paragraph_format.space_after = Pt(0)
276
+ paragraph.paragraph_format.first_line_indent = Cm(0)
277
+
278
+ for ci in range(cols):
279
+ data = [row[ci] for row in texts[1:] if ci < len(row) and row[ci].strip()]
280
+ if data and all(NUMERIC_CELL.match(t.strip()) for t in data):
281
+ for row in table.rows:
282
+ for paragraph in row.cells[ci].paragraphs:
283
+ paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
284
+
285
+
286
+ def process_code_block(doc: Document, element):
287
+ """Process code block with monospace formatting."""
288
+ code = element.find('code')
289
+ text = code.get_text() if code else element.get_text()
290
+
291
+ para = doc.add_paragraph()
292
+ run = para.add_run(text)
293
+ run.font.name = 'Courier New'
294
+ run.font.size = Pt(9)
295
+
296
+ # Light gray background (via shading)
297
+ shading = OxmlElement('w:shd')
298
+ shading.set(qn('w:fill'), 'F0F0F0')
299
+ para._p.get_or_add_pPr().append(shading)
300
+
301
+
302
+ def html_to_docx(html: str, doc: Document, md_path: Path):
303
+ """Convert HTML to DOCX elements."""
304
+ soup = BeautifulSoup(html, 'html.parser')
305
+
306
+ for element in soup.children:
307
+ if isinstance(element, NavigableString):
308
+ text = str(element).strip()
309
+ if text:
310
+ doc.add_paragraph(text)
311
+ continue
312
+
313
+ if element.name in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6'):
314
+ level = int(element.name[1])
315
+ heading = doc.add_heading(level=level)
316
+ for child in element.children:
317
+ process_inline_elements(heading, child, md_path)
318
+
319
+ elif element.name == 'p':
320
+ add_paragraph_with_formatting(doc, element, md_path)
321
+
322
+ elif element.name == 'ul':
323
+ process_list(doc, element, md_path, ordered=False)
324
+
325
+ elif element.name == 'ol':
326
+ process_list(doc, element, md_path, ordered=True)
327
+
328
+ elif element.name == 'table':
329
+ process_table(doc, element, md_path)
330
+
331
+ elif element.name == 'pre':
332
+ process_code_block(doc, element)
333
+
334
+ elif element.name == 'blockquote':
335
+ para = doc.add_paragraph(style='Quote')
336
+ for child in element.children:
337
+ if child.name == 'p':
338
+ for subchild in child.children:
339
+ process_inline_elements(para, subchild, md_path)
340
+ else:
341
+ process_inline_elements(para, child, md_path)
342
+
343
+ elif element.name == 'hr':
344
+ # Add a horizontal line
345
+ para = doc.add_paragraph()
346
+ para.add_run('─' * 50)
347
+ para.alignment = WD_ALIGN_PARAGRAPH.CENTER
348
+
349
+ elif element.name in ('div', 'section', 'article'):
350
+ # Recursively process container elements
351
+ html_to_docx(str(element), doc, md_path)
352
+
353
+
354
+ # ===========================================================================
355
+ # M1: Journal workflow — frontmatter, filters, design enforcement
356
+ # ===========================================================================
357
+
358
+
359
+ def _load_yaml():
360
+ try:
361
+ import yaml
362
+ return yaml
363
+ except ImportError:
364
+ print("Error: 'pyyaml' library required for --publisher. pip install pyyaml")
365
+ sys.exit(1)
366
+
367
+
368
+ def parse_frontmatter(md_text: str) -> tuple[dict, str]:
369
+ """Extract leading YAML frontmatter. Returns (frontmatter_dict, body)."""
370
+ if not md_text.startswith("---"):
371
+ return {}, md_text
372
+ # Find closing fence
373
+ lines = md_text.splitlines(keepends=True)
374
+ if len(lines) < 2:
375
+ return {}, md_text
376
+ end_idx = None
377
+ for i in range(1, len(lines)):
378
+ if lines[i].rstrip() == "---":
379
+ end_idx = i
380
+ break
381
+ if end_idx is None:
382
+ return {}, md_text
383
+ yaml_src = "".join(lines[1:end_idx])
384
+ body = "".join(lines[end_idx + 1:])
385
+ yaml = _load_yaml()
386
+ try:
387
+ data = yaml.safe_load(yaml_src) or {}
388
+ except Exception as exc:
389
+ print(f"Warning: could not parse YAML frontmatter: {exc}", file=sys.stderr)
390
+ return {}, md_text
391
+ if not isinstance(data, dict):
392
+ return {}, md_text
393
+ return data, body
394
+
395
+
396
+ def load_publisher(registry_path: Path, name: str) -> dict:
397
+ yaml = _load_yaml()
398
+ if not registry_path.exists():
399
+ raise SystemExit(f"Error: registry not found: {registry_path}")
400
+ with registry_path.open("r", encoding="utf-8") as fh:
401
+ data = yaml.safe_load(fh) or {}
402
+ pubs = data.get("publishers") or {}
403
+ if name not in pubs:
404
+ raise SystemExit(
405
+ f"Error: publisher {name!r} not in registry "
406
+ f"(known: {', '.join(sorted(pubs)) or 'none'})"
407
+ )
408
+ return pubs[name]
409
+
410
+
411
+ # ---------------------------------------------------------------------------
412
+ # Code-preserving filter helpers
413
+ # ---------------------------------------------------------------------------
414
+
415
+
416
+ _FENCE_RE = re.compile(r"(^```.*?^```)", re.MULTILINE | re.DOTALL)
417
+ _INLINE_CODE_RE = re.compile(r"(`[^`\n]+`)")
418
+
419
+
420
+ def _split_code_preserving(text: str) -> list[tuple[str, bool]]:
421
+ """Split text into (segment, is_code) tuples.
422
+
423
+ Fenced code blocks and inline backtick code are returned as is_code=True
424
+ and must never be touched by the micro-typography filters.
425
+ """
426
+ # First split on fenced code blocks
427
+ out: list[tuple[str, bool]] = []
428
+ pos = 0
429
+ for m in _FENCE_RE.finditer(text):
430
+ if m.start() > pos:
431
+ out.append((text[pos:m.start()], False))
432
+ out.append((m.group(0), True))
433
+ pos = m.end()
434
+ if pos < len(text):
435
+ out.append((text[pos:], False))
436
+ # Then split non-code segments on inline backtick code
437
+ refined: list[tuple[str, bool]] = []
438
+ for seg, is_code in out:
439
+ if is_code:
440
+ refined.append((seg, True))
441
+ continue
442
+ last = 0
443
+ for m in _INLINE_CODE_RE.finditer(seg):
444
+ if m.start() > last:
445
+ refined.append((seg[last:m.start()], False))
446
+ refined.append((m.group(0), True))
447
+ last = m.end()
448
+ if last < len(seg):
449
+ refined.append((seg[last:], False))
450
+ return refined
451
+
452
+
453
+ def _apply_to_noncode(text: str, fn) -> str:
454
+ parts = _split_code_preserving(text)
455
+ out = []
456
+ for seg, is_code in parts:
457
+ out.append(seg if is_code else fn(seg))
458
+ return "".join(out)
459
+
460
+
461
+ # ---------------------------------------------------------------------------
462
+ # Pre-MD micro-typography filters
463
+ # ---------------------------------------------------------------------------
464
+
465
+
466
+ _NUMRANGE_RE = re.compile(r"(\d)-(\d)")
467
+ _PAREN_DASH_RE = re.compile(r"(\w) - (\w)")
468
+
469
+
470
+ def fix_dashes(text: str, rules: dict | None = None) -> str:
471
+ """Numeric ranges → en-dash; parenthetical 'word - word' → em-dash.
472
+
473
+ rules is the design.micro_typography.dashes block (currently informational;
474
+ M1 hardcodes en-dash for numeric range and em-dash for parenthetical).
475
+ """
476
+ def _fn(seg: str) -> str:
477
+ seg = _NUMRANGE_RE.sub(lambda m: f"{m.group(1)}\u2013{m.group(2)}", seg)
478
+ seg = _PAREN_DASH_RE.sub(lambda m: f"{m.group(1)} \u2014 {m.group(2)}", seg)
479
+ return seg
480
+ return _apply_to_noncode(text, _fn)
481
+
482
+
483
+ def fix_quotes(text: str) -> str:
484
+ """ASCII "..." → "..."; '...' → '...' via left/right state machine."""
485
+ def _fn(seg: str) -> str:
486
+ out_chars = []
487
+ open_dq = True
488
+ open_sq = True
489
+ for ch in seg:
490
+ if ch == '"':
491
+ out_chars.append("\u201C" if open_dq else "\u201D")
492
+ open_dq = not open_dq
493
+ elif ch == "'":
494
+ # Keep apostrophe if surrounded by letters (e.g. "don't")
495
+ prev = out_chars[-1] if out_chars else ""
496
+ if prev.isalpha():
497
+ out_chars.append("\u2019")
498
+ else:
499
+ out_chars.append("\u2018" if open_sq else "\u2019")
500
+ open_sq = not open_sq
501
+ else:
502
+ out_chars.append(ch)
503
+ return "".join(out_chars)
504
+ return _apply_to_noncode(text, _fn)
505
+
506
+
507
+ _UNIT_GROUP = (
508
+ r"mg|g|kg|mL|L|\u03BCL|uL|nm|\u03BCm|um|mm|cm|m|km|K|\u00B0C|%|min|h|s|ms"
509
+ )
510
+ _UNIT_RE = re.compile(rf"(\d)(\s+)({_UNIT_GROUP})(?=\b|\W|$)")
511
+ _FIG_RE = re.compile(r"(Fig\.)\s(\d)")
512
+ _TABLE_RE = re.compile(r"(Table)\s(\d)")
513
+ _EQ_RE = re.compile(r"(Eq\.)\s(\d)")
514
+
515
+
516
+ def fix_unit_spacing(text: str) -> str:
517
+ """Insert U+00A0 between number and SI unit, and after Fig./Table/Eq."""
518
+ def _fn(seg: str) -> str:
519
+ seg = _UNIT_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(3)}", seg)
520
+ seg = _FIG_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(2)}", seg)
521
+ seg = _TABLE_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(2)}", seg)
522
+ seg = _EQ_RE.sub(lambda m: f"{m.group(1)}\u00A0{m.group(2)}", seg)
523
+ return seg
524
+ return _apply_to_noncode(text, _fn)
525
+
526
+
527
+ def fix_ellipsis(text: str) -> str:
528
+ def _fn(seg: str) -> str:
529
+ return seg.replace("...", "\u2026")
530
+ return _apply_to_noncode(text, _fn)
531
+
532
+
533
+ def normalize_double_spaces(text: str) -> str:
534
+ def _fn(seg: str) -> str:
535
+ # Preserve leading indentation; collapse interior double spaces
536
+ lines = seg.split("\n")
537
+ cleaned = []
538
+ for line in lines:
539
+ stripped_left = line.lstrip(" ")
540
+ lead = line[: len(line) - len(stripped_left)]
541
+ cleaned.append(lead + re.sub(r" {2,}", " ", stripped_left))
542
+ return "\n".join(cleaned)
543
+ return _apply_to_noncode(text, _fn)
544
+
545
+
546
+ # ---------------------------------------------------------------------------
547
+ # Post-HTML (doc object) filters
548
+ # ---------------------------------------------------------------------------
549
+
550
+
551
+ def apply_heading_numbering(doc, design: dict) -> None:
552
+ def to_roman(value: int) -> str:
553
+ numerals = [
554
+ (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"),
555
+ (100, "C"), (90, "XC"), (50, "L"), (40, "XL"),
556
+ (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I"),
557
+ ]
558
+ out: list[str] = []
559
+ remaining = value
560
+ for arabic, roman in numerals:
561
+ while remaining >= arabic:
562
+ out.append(roman)
563
+ remaining -= arabic
564
+ return "".join(out)
565
+
566
+ def prefix_for(level: int, counters: list[int]) -> str | None:
567
+ key = f"h{level}"
568
+ cfg = (design.get("heading_hierarchy") or {}).get(key) or {}
569
+ numbering = cfg.get("numbering")
570
+ if numbering is None:
571
+ return None
572
+ numbering = str(numbering).strip()
573
+ if level == 1 and numbering.upper() == "I.":
574
+ return f"{to_roman(counters[0])}. "
575
+ if level == 1:
576
+ return f"{counters[0]}. "
577
+ if level == 2:
578
+ return f"{counters[0]}.{counters[1]}. "
579
+ if level == 3:
580
+ return f"{counters[0]}.{counters[1]}.{counters[2]}. "
581
+ return None
582
+
583
+ counters = [0, 0, 0]
584
+ for para in doc.paragraphs:
585
+ style_name = para.style.name if para.style else ""
586
+ level = 0
587
+ if style_name == "Heading 1":
588
+ level = 1
589
+ counters[0] += 1
590
+ counters[1] = 0
591
+ counters[2] = 0
592
+ elif style_name == "Heading 2":
593
+ level = 2
594
+ counters[1] += 1
595
+ counters[2] = 0
596
+ elif style_name == "Heading 3":
597
+ level = 3
598
+ counters[2] += 1
599
+ else:
600
+ continue
601
+ prefix = prefix_for(level, counters)
602
+ if prefix is None:
603
+ continue
604
+ current = para.text or ""
605
+ # Skip if already numbered (e.g. "1 Introduction" from the source)
606
+ if re.match(r"^(?:\d+(?:\.\d+)*\.?|[IVXLCDM]+\.?)\s", current):
607
+ continue
608
+ if para.runs:
609
+ para.runs[0].text = prefix + para.runs[0].text
610
+ else:
611
+ para.add_run(prefix)
612
+
613
+
614
+ def _set_cell_borders_nil(tcPr):
615
+ tcBorders = tcPr.find(qn("w:tcBorders"))
616
+ if tcBorders is None:
617
+ tcBorders = OxmlElement("w:tcBorders")
618
+ tcPr.append(tcBorders)
619
+ for side in ("top", "left", "bottom", "right", "insideH", "insideV"):
620
+ el = tcBorders.find(qn(f"w:{side}"))
621
+ if el is None:
622
+ el = OxmlElement(f"w:{side}")
623
+ tcBorders.append(el)
624
+ el.set(qn("w:val"), "nil")
625
+ el.set(qn("w:sz"), "0")
626
+
627
+
628
+ def apply_table_style(doc, design: dict) -> None:
629
+ """Override python-docx 'Table Grid' with booktabs: only horizontal rules.
630
+
631
+ Rules: top rule (table top), header-bottom rule, bottom rule (table bottom).
632
+ All vertical rules (left/right/insideV) set to nil.
633
+ """
634
+ for table in doc.tables:
635
+ table.style = None # detach Table Grid
636
+ tbl = table._tbl
637
+ tblPr = tbl.find(qn("w:tblPr"))
638
+ if tblPr is None:
639
+ tblPr = OxmlElement("w:tblPr")
640
+ tbl.insert(0, tblPr)
641
+ # Remove any existing tblBorders and add our booktabs set
642
+ existing = tblPr.find(qn("w:tblBorders"))
643
+ if existing is not None:
644
+ tblPr.remove(existing)
645
+ tblBorders = OxmlElement("w:tblBorders")
646
+
647
+ def _add_border(name: str, val: str, sz: str):
648
+ el = OxmlElement(f"w:{name}")
649
+ el.set(qn("w:val"), val)
650
+ el.set(qn("w:sz"), sz)
651
+ el.set(qn("w:space"), "0")
652
+ el.set(qn("w:color"), "000000")
653
+ tblBorders.append(el)
654
+
655
+ _add_border("top", "single", "12") # ~1.5pt
656
+ _add_border("bottom", "single", "12") # ~1.5pt
657
+ _add_border("left", "nil", "0")
658
+ _add_border("right", "nil", "0")
659
+ _add_border("insideH", "single", "6") # ~0.75pt (header-bottom)
660
+ _add_border("insideV", "nil", "0") # explicit no verticals
661
+ tblPr.append(tblBorders)
662
+
663
+ # Bold header row + add bottom border only to header cells so the
664
+ # thicker rule sits under the header (and horizontal rules between
665
+ # body rows are suppressed)
666
+ if table.rows:
667
+ header_row = table.rows[0]
668
+ for cell in header_row.cells:
669
+ for p in cell.paragraphs:
670
+ for r in p.runs:
671
+ r.bold = True
672
+ # Remove insideH to prevent inner body rules; header-bottom comes
673
+ # from a per-cell bottom border on the first row.
674
+ insideH = tblBorders.find(qn("w:insideH"))
675
+ if insideH is not None:
676
+ insideH.set(qn("w:val"), "nil")
677
+ for cell in header_row.cells:
678
+ tcPr = cell._tc.get_or_add_tcPr()
679
+ tcBorders = tcPr.find(qn("w:tcBorders"))
680
+ if tcBorders is None:
681
+ tcBorders = OxmlElement("w:tcBorders")
682
+ tcPr.append(tcBorders)
683
+ existing_bottom = tcBorders.find(qn("w:bottom"))
684
+ if existing_bottom is None:
685
+ existing_bottom = OxmlElement("w:bottom")
686
+ tcBorders.append(existing_bottom)
687
+ existing_bottom.set(qn("w:val"), "single")
688
+ existing_bottom.set(qn("w:sz"), "6")
689
+ existing_bottom.set(qn("w:space"), "0")
690
+ existing_bottom.set(qn("w:color"), "000000")
691
+
692
+
693
+ def strip_banned(doc, design: dict) -> None:
694
+ """Remove any banned font/style from runs and paragraphs."""
695
+ banned = design.get("banned") or {}
696
+ banned_fonts = set(banned.get("fonts") or [])
697
+ banned_styles = set(banned.get("styles") or [])
698
+ body_font = None
699
+ # body font is enforced on Normal style already, but we override raw runs too
700
+ for para in doc.paragraphs:
701
+ if para.style and para.style.name in banned_styles:
702
+ try:
703
+ para.style = doc.styles["Normal"]
704
+ except KeyError:
705
+ pass
706
+ for run in para.runs:
707
+ if run.font.name and run.font.name in banned_fonts:
708
+ run.font.name = None # inherit from style
709
+ # Also walk table cells
710
+ for table in doc.tables:
711
+ for row in table.rows:
712
+ for cell in row.cells:
713
+ for para in cell.paragraphs:
714
+ if para.style and para.style.name in banned_styles:
715
+ try:
716
+ para.style = doc.styles["Normal"]
717
+ except KeyError:
718
+ pass
719
+ for run in para.runs:
720
+ if run.font.name and run.font.name in banned_fonts:
721
+ run.font.name = None
722
+
723
+
724
+ def _set_run_fonts(run, latin: str, cjk: str | None) -> None:
725
+ rpr = run._element.get_or_add_rPr()
726
+ rfonts = rpr.find(qn("w:rFonts"))
727
+ if rfonts is None:
728
+ rfonts = OxmlElement("w:rFonts")
729
+ rpr.append(rfonts)
730
+ rfonts.set(qn("w:ascii"), latin)
731
+ rfonts.set(qn("w:hAnsi"), latin)
732
+ rfonts.set(qn("w:cs"), latin)
733
+ if cjk:
734
+ rfonts.set(qn("w:eastAsia"), cjk)
735
+
736
+
737
+ def apply_cjk_font_pairing(doc, font_cfg: dict) -> None:
738
+ body = font_cfg.get("body") or {}
739
+ body_cjk = font_cfg.get("body_cjk") or {}
740
+ latin = body.get("family")
741
+ cjk = body_cjk.get("family")
742
+ if not latin:
743
+ return
744
+
745
+ def _walk(paragraphs):
746
+ for para in paragraphs:
747
+ for run in para.runs:
748
+ # Only fix runs that already have a font set to something
749
+ # other than the registry-banned default; leaving run.font.name
750
+ # as None lets the style do its job. We still force eastAsia.
751
+ current_name = run.font.name
752
+ if current_name and current_name != "Courier New":
753
+ _set_run_fonts(run, latin, cjk)
754
+ elif not current_name:
755
+ # set only eastAsia pair to avoid losing style inheritance
756
+ rpr = run._element.get_or_add_rPr()
757
+ rfonts = rpr.find(qn("w:rFonts"))
758
+ if rfonts is None:
759
+ rfonts = OxmlElement("w:rFonts")
760
+ rpr.append(rfonts)
761
+ if cjk:
762
+ rfonts.set(qn("w:eastAsia"), cjk)
763
+
764
+ _walk(doc.paragraphs)
765
+ for table in doc.tables:
766
+ for row in table.rows:
767
+ for cell in row.cells:
768
+ _walk(cell.paragraphs)
769
+
770
+
771
+ # ---------------------------------------------------------------------------
772
+ # Title block builder
773
+ # ---------------------------------------------------------------------------
774
+
775
+
776
+ def _insert_paragraph_before(doc, before_p, style=None):
777
+ """Insert a new paragraph before the given paragraph element."""
778
+ new_p = OxmlElement("w:p")
779
+ before_p._p.addprevious(new_p)
780
+ from docx.text.paragraph import Paragraph
781
+ para = Paragraph(new_p, before_p._parent)
782
+ if style is not None:
783
+ try:
784
+ para.style = doc.styles[style]
785
+ except KeyError:
786
+ pass
787
+ return para
788
+
789
+
790
+ def inject_title_block(doc, frontmatter: dict, design: dict) -> None:
791
+ """Prepend title/authors/affiliations/abstract/keywords to the doc.
792
+
793
+ Builds the block at the top of the document body via the underlying
794
+ XML so it appears before any html_to_docx output. Called BEFORE
795
+ html_to_docx in M1's control flow so paragraphs just append normally.
796
+ """
797
+ tb = design.get("title_block") or {}
798
+ title = frontmatter.get("title")
799
+ if not title:
800
+ return
801
+
802
+ def _p_center(size: int, bold=False, italic=False, space_after=4):
803
+ p = doc.add_paragraph()
804
+ p.alignment = WD_ALIGN_PARAGRAPH.CENTER
805
+ p.paragraph_format.first_line_indent = Cm(0)
806
+ p.paragraph_format.space_after = Pt(space_after)
807
+ return p
808
+
809
+ def _add_run(p, text: str, size: int, bold=False, italic=False, sup=False):
810
+ run = p.add_run(text)
811
+ run.font.size = Pt(size)
812
+ run.bold = bold
813
+ run.italic = italic
814
+ run.font.superscript = sup
815
+ return run
816
+
817
+ # Title
818
+ tp = _p_center(
819
+ tb.get("title", {}).get("size_pt", 18),
820
+ bold=True,
821
+ space_after=tb.get("title", {}).get("space_after_pt", 12),
822
+ )
823
+ _add_run(tp, str(title), tb.get("title", {}).get("size_pt", 18), bold=True)
824
+
825
+ # Report-style frontmatter: a subtitle and one author / organisation / date line
826
+ # when there is no journal author list.
827
+ if frontmatter.get("subtitle"):
828
+ sp = _p_center(13, space_after=6)
829
+ _add_run(sp, str(frontmatter["subtitle"]), 13)
830
+ if not frontmatter.get("authors"):
831
+ meta = [str(v) for v in (frontmatter.get("author"), frontmatter.get("organization"), frontmatter.get("date")) if v]
832
+ if meta:
833
+ mp = _p_center(10.5, space_after=14)
834
+ _add_run(mp, " · ".join(meta), 10.5)
835
+
836
+ # Authors
837
+ authors = frontmatter.get("authors") or []
838
+ if authors:
839
+ ap = _p_center(
840
+ tb.get("authors", {}).get("size_pt", 12),
841
+ space_after=tb.get("authors", {}).get("space_after_pt", 4),
842
+ )
843
+ sep = tb.get("author_separator", ", ")
844
+ corr_mark = tb.get("corresponding_marker", "*")
845
+ size = tb.get("authors", {}).get("size_pt", 12)
846
+ for i, author in enumerate(authors):
847
+ if not isinstance(author, dict):
848
+ continue
849
+ if i > 0:
850
+ _add_run(ap, sep, size)
851
+ name = str(author.get("name", "Author"))
852
+ _add_run(ap, name, size)
853
+ aff = author.get("affiliation")
854
+ if aff is not None:
855
+ if isinstance(aff, list):
856
+ aff_text = ",".join(str(a) for a in aff)
857
+ else:
858
+ aff_text = str(aff)
859
+ _add_run(ap, aff_text, size, sup=True)
860
+ if author.get("corresponding"):
861
+ _add_run(ap, corr_mark, size, sup=True)
862
+
863
+ # Affiliations
864
+ affs = frontmatter.get("affiliations")
865
+ if isinstance(affs, dict):
866
+ for key in sorted(affs.keys(), key=lambda k: str(k)):
867
+ fp = _p_center(
868
+ tb.get("affiliations", {}).get("size_pt", 10),
869
+ italic=True,
870
+ space_after=2,
871
+ )
872
+ _add_run(
873
+ fp,
874
+ f"{key} {affs[key]}",
875
+ tb.get("affiliations", {}).get("size_pt", 10),
876
+ italic=True,
877
+ )
878
+
879
+ # Corresponding email (if present, small italic line)
880
+ corr_email = frontmatter.get("corresponding_email")
881
+ if corr_email:
882
+ cp = _p_center(10, italic=True, space_after=8)
883
+ _add_run(cp, f"* Corresponding author: {corr_email}", 10, italic=True)
884
+
885
+ # Abstract
886
+ abstract = frontmatter.get("abstract")
887
+ if abstract:
888
+ lp = doc.add_paragraph()
889
+ lp.paragraph_format.first_line_indent = Cm(0)
890
+ lp.paragraph_format.space_after = Pt(4)
891
+ _add_run(
892
+ lp,
893
+ tb.get("abstract_label", "Abstract"),
894
+ tb.get("abstract_font_size_pt", 10),
895
+ bold=True,
896
+ )
897
+ body = doc.add_paragraph()
898
+ body.paragraph_format.first_line_indent = Cm(0)
899
+ body.paragraph_format.space_after = Pt(6)
900
+ _add_run(
901
+ body,
902
+ str(abstract),
903
+ tb.get("abstract_font_size_pt", 10),
904
+ )
905
+
906
+ # Keywords
907
+ keywords = frontmatter.get("keywords")
908
+ if keywords:
909
+ kp = doc.add_paragraph()
910
+ kp.paragraph_format.first_line_indent = Cm(0)
911
+ kp.paragraph_format.space_after = Pt(12)
912
+ _add_run(
913
+ kp,
914
+ tb.get("keywords_label", "Keywords") + ": ",
915
+ tb.get("abstract_font_size_pt", 10),
916
+ bold=True,
917
+ )
918
+ if isinstance(keywords, list):
919
+ sep = tb.get("keywords_separator", "; ")
920
+ text = sep.join(str(k) for k in keywords)
921
+ else:
922
+ text = str(keywords)
923
+ _add_run(kp, text, tb.get("abstract_font_size_pt", 10))
924
+
925
+
926
+ # ---------------------------------------------------------------------------
927
+ # Locale detection
928
+ # ---------------------------------------------------------------------------
929
+
930
+
931
+ _HANGUL_RE = re.compile(r"[\uac00-\ud7a3]")
932
+
933
+
934
+ def detect_locale(text: str) -> str:
935
+ total = len(text) or 1
936
+ hangul_count = len(_HANGUL_RE.findall(text))
937
+ ratio = hangul_count / total
938
+ if ratio > 0.05:
939
+ return "ko"
940
+ if ratio > 0.01:
941
+ return "mixed"
942
+ return "en"
943
+
944
+
945
+ # ===========================================================================
946
+ # Conversion entry point
947
+ # ===========================================================================
948
+
949
+
950
+ NOTICE_FILL = "FDECEA"
951
+ NOTICE_INK = RGBColor(0xA2, 0x1B, 0x12)
952
+
953
+
954
+ def _shade(element, fill: str) -> None:
955
+ shd = OxmlElement("w:shd")
956
+ shd.set(qn("w:val"), "clear")
957
+ shd.set(qn("w:color"), "auto")
958
+ shd.set(qn("w:fill"), fill)
959
+ element.append(shd)
960
+
961
+
962
+ def add_notice(doc, text: str) -> None:
963
+ """The frontmatter `notice:` (e.g. "예시 데이터 — 수치는 가정입니다") as a tag in
964
+ every page header, so an example document cannot be mistaken for a sourced one
965
+ on any page it is printed from. A profile whose title page has its own, empty
966
+ header (korean-generic) gets a tinted band under the title block instead."""
967
+ if doc.sections[0].different_first_page_header_footer:
968
+ band = doc.add_paragraph()
969
+ band_run = band.add_run(str(text))
970
+ band_run.bold = True
971
+ band_run.font.size = Pt(10.5)
972
+ band_run.font.color.rgb = NOTICE_INK
973
+ band.paragraph_format.space_before = Pt(4)
974
+ band.paragraph_format.space_after = Pt(14)
975
+ _shade(band._p.get_or_add_pPr(), NOTICE_FILL)
976
+ for index, section in enumerate(doc.sections):
977
+ if index and section.header.is_linked_to_previous:
978
+ continue
979
+ header = section.header
980
+ tag = header.paragraphs[0] if header.paragraphs and not header.paragraphs[0].text.strip() else header.add_paragraph()
981
+ tag_run = tag.add_run(f"\u00a0{text}\u00a0")
982
+ tag_run.bold = True
983
+ tag_run.font.size = Pt(9)
984
+ tag_run.font.color.rgb = NOTICE_INK
985
+ _shade(tag_run._r.get_or_add_rPr(), NOTICE_FILL)
986
+
987
+
988
+ def add_plain_title_block(doc, front: dict) -> None:
989
+ """Title, optional subtitle, and one line of author / organisation / date,
990
+ left-aligned above the body, for the plain (non-publisher) profile."""
991
+ title = doc.add_paragraph()
992
+ run = title.add_run(str(front["title"]))
993
+ run.bold = True
994
+ run.font.size = Pt(22)
995
+ title.paragraph_format.space_after = Pt(4)
996
+ if front.get("subtitle"):
997
+ sub_p = doc.add_paragraph()
998
+ sub_run = sub_p.add_run(str(front["subtitle"]))
999
+ sub_run.font.size = Pt(13)
1000
+ sub_run.font.color.rgb = RGBColor(0x55, 0x5F, 0x6D)
1001
+ sub_p.paragraph_format.space_after = Pt(4)
1002
+ authors = front.get("authors") or front.get("author")
1003
+ if isinstance(authors, list):
1004
+ authors = ", ".join(str(a.get("name", a)) if isinstance(a, dict) else str(a) for a in authors)
1005
+ meta = [str(v) for v in (authors, front.get("organization"), front.get("date")) if v]
1006
+ if meta:
1007
+ meta_p = doc.add_paragraph()
1008
+ meta_run = meta_p.add_run(" · ".join(meta))
1009
+ meta_run.font.size = Pt(10.5)
1010
+ meta_run.font.color.rgb = RGBColor(0x55, 0x5F, 0x6D)
1011
+ meta_p.paragraph_format.space_after = Pt(18)
1012
+ if front.get("notice"):
1013
+ add_notice(doc, front["notice"])
1014
+
1015
+
1016
+ def read_source(md_path: Path) -> str:
1017
+ """The Markdown source, with {{ … }} numbers filled from its `data:` files
1018
+ (lib/office_data.py computes derived values and runs the declared checks)."""
1019
+ text = md_path.read_text(encoding="utf-8")
1020
+ try:
1021
+ return resolve_text(text, md_path.parent)[0]
1022
+ except DataError as exc:
1023
+ raise SystemExit(f"Data error: {exc}") from exc
1024
+
1025
+
1026
+ def convert_md_to_docx(
1027
+ md_path: Path,
1028
+ docx_path: Path,
1029
+ template_path: Path = None,
1030
+ publisher_name: str | None = None,
1031
+ registry_path: Path | None = None,
1032
+ locale: str = "auto",
1033
+ ):
1034
+ """Convert Markdown file to DOCX.
1035
+
1036
+ When publisher_name is None, behavior is byte-compatible with the pre-M1
1037
+ script: read md, convert to HTML, html_to_docx, save. Regression-guarded.
1038
+
1039
+ When publisher_name is set, apply the full journal pipeline: registry
1040
+ load, frontmatter parse, pre-MD filters, title-block injection, post-HTML
1041
+ heading numbering, booktabs tables, banned stripping, CJK font pairing.
1042
+ """
1043
+ if publisher_name is None:
1044
+ # --- Legacy code path (regression-critical: do not mutate) ---
1045
+ md_text = read_source(md_path)
1046
+ # A frontmatter block is a title page request, not body text: strip it and
1047
+ # set a plain title block. Markdown without frontmatter converts as before.
1048
+ plain_front = {}
1049
+ if md_text.startswith("---"):
1050
+ plain_front, md_text = parse_frontmatter(md_text)
1051
+ md_converter = markdown.Markdown(extensions=[
1052
+ 'tables',
1053
+ 'fenced_code',
1054
+ 'nl2br',
1055
+ 'sane_lists',
1056
+ ])
1057
+ html = md_converter.convert(md_text)
1058
+ if template_path and template_path.exists():
1059
+ doc = Document(str(template_path))
1060
+ else:
1061
+ doc = Document()
1062
+ if plain_front.get("title"):
1063
+ add_plain_title_block(doc, plain_front)
1064
+ html_to_docx(html, doc, md_path)
1065
+ doc.save(str(docx_path))
1066
+ print(f"Successfully converted {md_path} to {docx_path}")
1067
+ return
1068
+
1069
+ # --- Journal workflow ---
1070
+ script_dir = Path(__file__).resolve().parent
1071
+ registry_path = registry_path or (script_dir.parent / "templates" / "registry.yaml")
1072
+ publisher = load_publisher(Path(registry_path), publisher_name)
1073
+ design = publisher["design"]
1074
+ docx_font = publisher["docx"]["font"]
1075
+
1076
+ md_text = read_source(md_path)
1077
+ frontmatter, body = parse_frontmatter(md_text)
1078
+
1079
+ # Locale detection (informational in M1; Korean rules land in M6)
1080
+ detected_locale = detect_locale(body) if locale == "auto" else locale
1081
+
1082
+ # Pre-MD micro-typography filters
1083
+ dash_rules = design.get("micro_typography", {}).get("dashes")
1084
+ body = fix_dashes(body, dash_rules)
1085
+ body = fix_quotes(body)
1086
+ body = fix_unit_spacing(body)
1087
+ body = fix_ellipsis(body)
1088
+ body = normalize_double_spaces(body)
1089
+
1090
+ # Load template if available
1091
+ template_docx = script_dir.parent / "templates" / "docx" / f"{publisher_name}.docx"
1092
+ if template_docx.exists():
1093
+ doc = Document(str(template_docx))
1094
+ # The template includes a self-describing sample title block and
1095
+ # sample heading/body paragraph. Strip all existing body paragraphs
1096
+ # and tables so the conversion output is the user's content only.
1097
+ body_el = doc.element.body
1098
+ sect_pr = body_el.find(qn("w:sectPr"))
1099
+ for child in list(body_el):
1100
+ if child is sect_pr:
1101
+ continue
1102
+ body_el.remove(child)
1103
+ if sect_pr is None:
1104
+ pass # keep original body even if no sectPr detected
1105
+ elif template_path and template_path.exists():
1106
+ doc = Document(str(template_path))
1107
+ else:
1108
+ doc = Document()
1109
+
1110
+ # Title block (built from frontmatter) before main content
1111
+ if frontmatter.get("title"):
1112
+ inject_title_block(doc, frontmatter, design)
1113
+ if frontmatter.get("notice"):
1114
+ add_notice(doc, frontmatter["notice"])
1115
+
1116
+ # Main content
1117
+ md_converter = markdown.Markdown(extensions=[
1118
+ 'tables',
1119
+ 'fenced_code',
1120
+ 'nl2br',
1121
+ 'sane_lists',
1122
+ ])
1123
+ html = md_converter.convert(body)
1124
+ html_to_docx(html, doc, md_path)
1125
+
1126
+ # Post-HTML design enforcement
1127
+ apply_heading_numbering(doc, design)
1128
+ apply_table_style(doc, design)
1129
+ strip_banned(doc, design)
1130
+ apply_cjk_font_pairing(doc, docx_font)
1131
+
1132
+ doc.save(str(docx_path))
1133
+ print(
1134
+ f"Successfully converted {md_path} to {docx_path} "
1135
+ f"[publisher={publisher_name}, locale={detected_locale}]"
1136
+ )
1137
+
1138
+
1139
+ def parse_args() -> argparse.Namespace:
1140
+ parser = argparse.ArgumentParser(
1141
+ description="Convert Markdown to DOCX with proper styling"
1142
+ )
1143
+ parser.add_argument("input", help="Input Markdown file")
1144
+ parser.add_argument("output", help="Output DOCX file")
1145
+ parser.add_argument(
1146
+ "--template",
1147
+ help="Optional DOCX template to use as base",
1148
+ default=None,
1149
+ )
1150
+ parser.add_argument(
1151
+ "--publisher",
1152
+ help="Journal publisher profile from templates/registry.yaml (e.g. elsevier)",
1153
+ default=None,
1154
+ )
1155
+ parser.add_argument(
1156
+ "--registry",
1157
+ help="Path to templates/registry.yaml (defaults to the one in this skill)",
1158
+ default=None,
1159
+ )
1160
+ parser.add_argument(
1161
+ "--locale",
1162
+ choices=("auto", "en", "ko", "mixed"),
1163
+ default="auto",
1164
+ help="Force locale; 'auto' detects via Hangul codepoint ratio",
1165
+ )
1166
+ args = parser.parse_args()
1167
+ if args.publisher and args.template:
1168
+ parser.error("--publisher and --template are mutually exclusive")
1169
+ return args
1170
+
1171
+
1172
+ def main() -> int:
1173
+ args = parse_args()
1174
+
1175
+ md_path = Path(args.input).expanduser().resolve()
1176
+ docx_path = Path(args.output).expanduser().resolve()
1177
+ template_path = Path(args.template).expanduser().resolve() if args.template else None
1178
+ registry_path = Path(args.registry).expanduser().resolve() if args.registry else None
1179
+
1180
+ if not md_path.exists():
1181
+ print(f"Error: Input file not found: {md_path}")
1182
+ return 1
1183
+
1184
+ convert_md_to_docx(
1185
+ md_path, docx_path, template_path,
1186
+ publisher_name=args.publisher,
1187
+ registry_path=registry_path,
1188
+ locale=args.locale,
1189
+ )
1190
+ return 0
1191
+
1192
+
1193
+ if __name__ == "__main__":
1194
+ raise SystemExit(main())