@qnroa/qtype 0.0.1 → 0.0.3

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 (468) hide show
  1. package/CHANGELOG.md +1 -3
  2. package/CHANGELOG.zh.md +1 -2
  3. package/README.md +88 -56
  4. package/README.zh.md +82 -62
  5. package/dist/cli/bootstrap.js +4 -115
  6. package/dist/cli/commands/check/index.js +11 -10
  7. package/dist/cli/commands/config/action.js +5 -9
  8. package/dist/cli/commands/content/lint/action.js +38 -44
  9. package/dist/cli/commands/content/search/action.js +44 -34
  10. package/dist/cli/commands/content/search/i18n.js +6 -0
  11. package/dist/cli/commands/content/search/index.js +19 -1
  12. package/dist/cli/commands/content/validate/action.js +28 -27
  13. package/dist/cli/commands/index.js +1 -3
  14. package/dist/cli/commands/pack/index.js +2 -1
  15. package/dist/cli/commands/publish/build/action.js +39 -11
  16. package/dist/cli/commands/repo/new/action.js +23 -4
  17. package/dist/cli/commands/repo/new/i18n.js +2 -2
  18. package/dist/cli/commands/repo/sync/action.js +24 -4
  19. package/dist/cli/commands/repo/templates.js +2 -1
  20. package/dist/cli/utils/material.js +49 -0
  21. package/dist/core/encrypt.js +24 -1
  22. package/dist/core/index.js +1 -0
  23. package/dist/core/parser/frontmatter.js +39 -34
  24. package/dist/core/parser/parseMaterial.js +174 -24
  25. package/dist/core/romanization/index.js +152 -0
  26. package/dist/core/schemas/both.js +52 -0
  27. package/dist/core/schemas/index.js +3 -0
  28. package/dist/core/schemas/repo.js +55 -0
  29. package/dist/core/schemas/user.js +19 -0
  30. package/dist/core/typing/engine/TypingInput.js +243 -0
  31. package/dist/core/typing/engine/chars.js +30 -0
  32. package/dist/core/typing/engine/feedback.js +15 -0
  33. package/dist/core/typing/engine/index.js +5 -0
  34. package/dist/core/typing/engine/settings.js +8 -0
  35. package/dist/core/typing/engine/stats.js +45 -0
  36. package/dist/core/typing/index.js +9 -1
  37. package/dist/view/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  38. package/dist/view/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  39. package/dist/view/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  40. package/dist/view/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  41. package/dist/view/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  42. package/dist/view/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  43. package/dist/view/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  44. package/dist/view/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  45. package/dist/view/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  46. package/dist/view/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  47. package/dist/view/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  48. package/dist/view/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  49. package/dist/view/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  50. package/dist/view/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  51. package/dist/view/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  52. package/dist/view/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  53. package/dist/view/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  54. package/dist/view/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  55. package/dist/view/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  56. package/dist/view/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  57. package/dist/view/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  58. package/dist/view/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  59. package/dist/view/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  60. package/dist/view/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  61. package/dist/view/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  62. package/dist/view/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  63. package/dist/view/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  64. package/dist/view/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  65. package/dist/view/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  66. package/dist/view/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  67. package/dist/view/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  68. package/dist/view/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  69. package/dist/view/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  70. package/dist/view/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  71. package/dist/view/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  72. package/dist/view/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  73. package/dist/view/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  74. package/dist/view/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  75. package/dist/view/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  76. package/dist/view/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  77. package/dist/view/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  78. package/dist/view/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  79. package/dist/view/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  80. package/dist/view/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  81. package/dist/view/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  82. package/dist/view/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  83. package/dist/view/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  84. package/dist/view/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  85. package/dist/view/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  86. package/dist/view/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  87. package/dist/view/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  88. package/dist/view/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  89. package/dist/view/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  90. package/dist/view/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  91. package/dist/view/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  92. package/dist/view/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  93. package/dist/view/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  94. package/dist/view/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  95. package/dist/view/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  96. package/dist/view/assets/abap-BdImnpbu.js +1 -0
  97. package/dist/view/assets/actionscript-3-B3316cI-.js +1 -0
  98. package/dist/view/assets/ada-bCR0ucgS.js +1 -0
  99. package/dist/view/assets/ahk-CsyLZFj1.js +1 -0
  100. package/dist/view/assets/ahk2-8Zs4aa1G.js +1 -0
  101. package/dist/view/assets/andromeeda-C4gqWexZ.js +1 -0
  102. package/dist/view/assets/angular-html-DA-rfuFy.js +1 -0
  103. package/dist/view/assets/angular-ts-BrjP3tb8.js +1 -0
  104. package/dist/view/assets/apache-Pmp26Uib.js +1 -0
  105. package/dist/view/assets/apex-DhZFqWV2.js +1 -0
  106. package/dist/view/assets/apl-CORt7UWP.js +1 -0
  107. package/dist/view/assets/applescript-Co6uUVPk.js +1 -0
  108. package/dist/view/assets/ara-BRHolxvo.js +1 -0
  109. package/dist/view/assets/asciidoc-CSVQ5wI8.js +1 -0
  110. package/dist/view/assets/asm-D_Q5rh1f.js +1 -0
  111. package/dist/view/assets/astro-HNnZUWAn.js +1 -0
  112. package/dist/view/assets/aurora-x-D-2ljcwZ.js +1 -0
  113. package/dist/view/assets/awk-DMzUqQB5.js +1 -0
  114. package/dist/view/assets/ayu-dark-DYE7WIF3.js +1 -0
  115. package/dist/view/assets/ayu-light-BA47KaF1.js +1 -0
  116. package/dist/view/assets/ayu-mirage-32ctXXKs.js +1 -0
  117. package/dist/view/assets/ballerina-BFfxhgS-.js +1 -0
  118. package/dist/view/assets/bat-CickPsom.js +1 -0
  119. package/dist/view/assets/beancount-k_qm7-4y.js +1 -0
  120. package/dist/view/assets/berry-uYugtg8r.js +1 -0
  121. package/dist/view/assets/bibtex-CHM0blh-.js +1 -0
  122. package/dist/view/assets/bicep-Bmn6On1c.js +1 -0
  123. package/dist/view/assets/bird2-Bx8U0n9b.js +1 -0
  124. package/dist/view/assets/blade-2xfisSek.js +1 -0
  125. package/dist/view/assets/bsl-DlhNcFeZ.js +1 -0
  126. package/dist/view/assets/c-BIGW1oBm.js +1 -0
  127. package/dist/view/assets/c3-Dp5svz6Z.js +1 -0
  128. package/dist/view/assets/cadence-Bv_4Rxtq.js +1 -0
  129. package/dist/view/assets/cairo-KRGpt6FW.js +1 -0
  130. package/dist/view/assets/catppuccin-frappe-CZL1YF0i.js +1 -0
  131. package/dist/view/assets/catppuccin-latte-DH-8KZSZ.js +1 -0
  132. package/dist/view/assets/catppuccin-macchiato-B7yYVSCf.js +1 -0
  133. package/dist/view/assets/catppuccin-mocha-Ct7hS0mc.js +1 -0
  134. package/dist/view/assets/chapel-DTp_pixX.js +1 -0
  135. package/dist/view/assets/clarity-Dn5IMItf.js +1 -0
  136. package/dist/view/assets/clojure-P80f7IUj.js +1 -0
  137. package/dist/view/assets/cmake-D1j8_8rp.js +1 -0
  138. package/dist/view/assets/cobol-nBiQ_Alo.js +1 -0
  139. package/dist/view/assets/codeowners-Bp6g37R7.js +1 -0
  140. package/dist/view/assets/codeql-DsOJ9woJ.js +1 -0
  141. package/dist/view/assets/coffee-Ch7k5sss.js +1 -0
  142. package/dist/view/assets/common-lisp-Cg-RD9OK.js +1 -0
  143. package/dist/view/assets/coq-C7JzOVbR.js +1 -0
  144. package/dist/view/assets/cpp-BMRokrvK.js +1 -0
  145. package/dist/view/assets/crystal-DGywbUpC.js +1 -0
  146. package/dist/view/assets/csharp-DSvCPggb.js +1 -0
  147. package/dist/view/assets/css-CLj8gQPS.js +1 -0
  148. package/dist/view/assets/csv-fuZLfV_i.js +1 -0
  149. package/dist/view/assets/cue-D82EKSYY.js +1 -0
  150. package/dist/view/assets/cypher-COkxafJQ.js +1 -0
  151. package/dist/view/assets/d-85-TOEBH.js +1 -0
  152. package/dist/view/assets/dark-plus-C3mMm8J8.js +1 -0
  153. package/dist/view/assets/dart-bE4Kk8sk.js +1 -0
  154. package/dist/view/assets/dax-CEL-wOlO.js +1 -0
  155. package/dist/view/assets/desktop-BmXAJ9_W.js +1 -0
  156. package/dist/view/assets/diff-D97Zzqfu.js +1 -0
  157. package/dist/view/assets/docker-BcOcwvcX.js +1 -0
  158. package/dist/view/assets/dotenv-Da5cRb03.js +1 -0
  159. package/dist/view/assets/dracula-BzJJZx-M.js +1 -0
  160. package/dist/view/assets/dracula-soft-BXkSAIEj.js +1 -0
  161. package/dist/view/assets/dream-maker-BtqSS_iP.js +1 -0
  162. package/dist/view/assets/edge-FbVlp4U3.js +1 -0
  163. package/dist/view/assets/elixir-CkH2-t6x.js +1 -0
  164. package/dist/view/assets/elm-DbKCFpqz.js +1 -0
  165. package/dist/view/assets/emacs-lisp-C_m_b--Z.js +1 -0
  166. package/dist/view/assets/erb-DXfck5VN.js +1 -0
  167. package/dist/view/assets/erlang-DsQrWhSR.js +1 -0
  168. package/dist/view/assets/everforest-dark-BgDCqdQA.js +1 -0
  169. package/dist/view/assets/everforest-light-C8M2exoo.js +1 -0
  170. package/dist/view/assets/fennel-BYunw83y.js +1 -0
  171. package/dist/view/assets/fish-BvzEVeQv.js +1 -0
  172. package/dist/view/assets/fluent-C4IJs8-o.js +1 -0
  173. package/dist/view/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
  174. package/dist/view/assets/fortran-free-form-BxgE0vQu.js +1 -0
  175. package/dist/view/assets/fsharp-CXgrBDvD.js +1 -0
  176. package/dist/view/assets/gdresource-TyuKm33G.js +1 -0
  177. package/dist/view/assets/gdscript-DqcFQ5yU.js +1 -0
  178. package/dist/view/assets/gdshader-DkwncUOv.js +1 -0
  179. package/dist/view/assets/genie-D0YGMca9.js +1 -0
  180. package/dist/view/assets/gherkin-DyxjwDmM.js +1 -0
  181. package/dist/view/assets/git-commit-F4YmCXRG.js +1 -0
  182. package/dist/view/assets/git-rebase-r7XF79zn.js +1 -0
  183. package/dist/view/assets/github-dark-DHJKELXO.js +1 -0
  184. package/dist/view/assets/github-dark-default-Cuk6v7N8.js +1 -0
  185. package/dist/view/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  186. package/dist/view/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  187. package/dist/view/assets/github-light-DAi9KRSo.js +1 -0
  188. package/dist/view/assets/github-light-default-D7oLnXFd.js +1 -0
  189. package/dist/view/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  190. package/dist/view/assets/gleam-BspZqrRM.js +1 -0
  191. package/dist/view/assets/glimmer-js-ByusRIyA.js +1 -0
  192. package/dist/view/assets/glimmer-ts-BfAWNZQY.js +1 -0
  193. package/dist/view/assets/glsl-DplSGwfg.js +1 -0
  194. package/dist/view/assets/gn-n2N0HUVH.js +1 -0
  195. package/dist/view/assets/gnuplot-DdkO51Og.js +1 -0
  196. package/dist/view/assets/go-C27-OAKa.js +1 -0
  197. package/dist/view/assets/graphql-ChdNCCLP.js +1 -0
  198. package/dist/view/assets/groovy-gcz8RCvz.js +1 -0
  199. package/dist/view/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
  200. package/dist/view/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
  201. package/dist/view/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
  202. package/dist/view/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
  203. package/dist/view/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
  204. package/dist/view/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
  205. package/dist/view/assets/hack-BWmVpMyf.js +1 -0
  206. package/dist/view/assets/haml-D5jkg6IW.js +1 -0
  207. package/dist/view/assets/handlebars-BpdQsYii.js +1 -0
  208. package/dist/view/assets/haskell-Df6bDoY_.js +1 -0
  209. package/dist/view/assets/haxe-CfZj7gIn.js +1 -0
  210. package/dist/view/assets/hcl-BWvSN4gD.js +1 -0
  211. package/dist/view/assets/hjson-D5-asLiD.js +1 -0
  212. package/dist/view/assets/hlsl-D3lLCCz7.js +1 -0
  213. package/dist/view/assets/horizon-BUw7H-hv.js +1 -0
  214. package/dist/view/assets/horizon-bright-CUuTKBJd.js +1 -0
  215. package/dist/view/assets/houston-DnULxvSX.js +1 -0
  216. package/dist/view/assets/html-derivative-DlHx6ybY.js +1 -0
  217. package/dist/view/assets/html-pp8916En.js +1 -0
  218. package/dist/view/assets/http-jrhK8wxY.js +1 -0
  219. package/dist/view/assets/hurl-irOxFIW8.js +1 -0
  220. package/dist/view/assets/hxml-2-FPmUDs.js +1 -0
  221. package/dist/view/assets/hy-DFXneXwc.js +1 -0
  222. package/dist/view/assets/imba-DGztddWO.js +1 -0
  223. package/dist/view/assets/index-BLryk3W4.css +1 -0
  224. package/dist/view/assets/index-ByMJp0a5.js +3 -0
  225. package/dist/view/assets/index-CRh4USfC.js +189 -0
  226. package/dist/view/assets/index-JNx7Ohoj.js +153 -0
  227. package/dist/view/assets/ini-BEwlwnbL.js +1 -0
  228. package/dist/view/assets/java-CylS5w8V.js +1 -0
  229. package/dist/view/assets/javascript-wDzz0qaB.js +1 -0
  230. package/dist/view/assets/jinja-f2NsQr07.js +1 -0
  231. package/dist/view/assets/jison-wvAkD_A8.js +1 -0
  232. package/dist/view/assets/json-Cp-IABpG.js +1 -0
  233. package/dist/view/assets/json5-C9tS-k6U.js +1 -0
  234. package/dist/view/assets/jsonc-Des-eS-w.js +1 -0
  235. package/dist/view/assets/jsonl-DcaNXYhu.js +1 -0
  236. package/dist/view/assets/jsonnet-DFQXde-d.js +1 -0
  237. package/dist/view/assets/jssm-C2t-YnRu.js +1 -0
  238. package/dist/view/assets/jsx-g9-lgVsj.js +1 -0
  239. package/dist/view/assets/julia-5Bft2YPA.js +1 -0
  240. package/dist/view/assets/just-Cwhn7H3k.js +1 -0
  241. package/dist/view/assets/kanagawa-dragon-BuwD2xS4.js +1 -0
  242. package/dist/view/assets/kanagawa-lotus-C3DzagqV.js +1 -0
  243. package/dist/view/assets/kanagawa-wave-DFGoQZhC.js +1 -0
  244. package/dist/view/assets/katex-BYZTj3zW.css +1 -0
  245. package/dist/view/assets/katex-C5jXJg4s.js +257 -0
  246. package/dist/view/assets/kdl-DV7GczEv.js +1 -0
  247. package/dist/view/assets/kotlin-BdnUsdx6.js +1 -0
  248. package/dist/view/assets/kusto-wEQ09or8.js +1 -0
  249. package/dist/view/assets/laserwave-DUszq2jm.js +1 -0
  250. package/dist/view/assets/latex-D5pSuvFb.js +1 -0
  251. package/dist/view/assets/lean-BZvkOJ9d.js +1 -0
  252. package/dist/view/assets/less-B1dDrJ26.js +1 -0
  253. package/dist/view/assets/light-plus-B7mTdjB0.js +1 -0
  254. package/dist/view/assets/liquid-C0sCDyMI.js +1 -0
  255. package/dist/view/assets/llvm-BZoOZj88.js +1 -0
  256. package/dist/view/assets/log-2UxHyX5q.js +1 -0
  257. package/dist/view/assets/logo-BtOb2qkB.js +1 -0
  258. package/dist/view/assets/lua-BaeVxFsk.js +1 -0
  259. package/dist/view/assets/luau-BnpPk5vE.js +1 -0
  260. package/dist/view/assets/make-CHLpvVh8.js +1 -0
  261. package/dist/view/assets/markdown-Cvjx9yec.js +1 -0
  262. package/dist/view/assets/marko-DjSrsDqO.js +1 -0
  263. package/dist/view/assets/material-theme-D5KoaKCx.js +1 -0
  264. package/dist/view/assets/material-theme-darker-BfHTSMKl.js +1 -0
  265. package/dist/view/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  266. package/dist/view/assets/material-theme-ocean-CyktbL80.js +1 -0
  267. package/dist/view/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  268. package/dist/view/assets/matlab-D7o27uSR.js +1 -0
  269. package/dist/view/assets/mdc-D1_yUvq7.js +1 -0
  270. package/dist/view/assets/mdx-Cmh6b_Ma.js +1 -0
  271. package/dist/view/assets/mermaid-CQcHuHx7.js +1 -0
  272. package/dist/view/assets/min-dark-CafNBF8u.js +1 -0
  273. package/dist/view/assets/min-light-CTRr51gU.js +1 -0
  274. package/dist/view/assets/mipsasm-CKIfxQSi.js +1 -0
  275. package/dist/view/assets/mojo-DJz3ZmWd.js +1 -0
  276. package/dist/view/assets/monokai-BRVnQi9A.js +1 -0
  277. package/dist/view/assets/moonbit-CHtswR0a.js +1 -0
  278. package/dist/view/assets/move-el3G9tDJ.js +1 -0
  279. package/dist/view/assets/narrat-DRg8JJMk.js +1 -0
  280. package/dist/view/assets/nextflow-C-mBbutL.js +1 -0
  281. package/dist/view/assets/nextflow-groovy-vE_lwT2v.js +1 -0
  282. package/dist/view/assets/nginx-BpAMiNFr.js +1 -0
  283. package/dist/view/assets/night-owl-C39BiMTA.js +1 -0
  284. package/dist/view/assets/night-owl-light-CMTm3GFP.js +1 -0
  285. package/dist/view/assets/nim-BIad80T-.js +1 -0
  286. package/dist/view/assets/nix-CwoSXNpI.js +1 -0
  287. package/dist/view/assets/nord-Ddv68eIx.js +1 -0
  288. package/dist/view/assets/nsis-BlV79W_Q.js +1 -0
  289. package/dist/view/assets/nushell-D3jzshHO.js +1 -0
  290. package/dist/view/assets/objective-c-DXmwc3jG.js +1 -0
  291. package/dist/view/assets/objective-cpp-CLxacb5B.js +1 -0
  292. package/dist/view/assets/ocaml-C0hk2d4L.js +1 -0
  293. package/dist/view/assets/odin-BBf5iR-q.js +1 -0
  294. package/dist/view/assets/one-dark-pro-DVMEJ2y_.js +1 -0
  295. package/dist/view/assets/one-light-C3Wv6jpd.js +1 -0
  296. package/dist/view/assets/openscad-C4EeE6gA.js +1 -0
  297. package/dist/view/assets/org-DM6o9KBp.js +1 -0
  298. package/dist/view/assets/pascal-D93ZcfNL.js +1 -0
  299. package/dist/view/assets/perl-B9cMNwum.js +1 -0
  300. package/dist/view/assets/php-Csjmro_R.js +1 -0
  301. package/dist/view/assets/pkl-u5AG7uiY.js +1 -0
  302. package/dist/view/assets/plastic-3e1v2bzS.js +1 -0
  303. package/dist/view/assets/plsql-ChMvpjG-.js +1 -0
  304. package/dist/view/assets/po-BTJTHyun.js +1 -0
  305. package/dist/view/assets/poimandres-CS3Unz2-.js +1 -0
  306. package/dist/view/assets/polar-C0HS_06l.js +1 -0
  307. package/dist/view/assets/postcss-CXtECtnM.js +1 -0
  308. package/dist/view/assets/powerquery-CEu0bR-o.js +1 -0
  309. package/dist/view/assets/powershell-BmBUJMz7.js +1 -0
  310. package/dist/view/assets/prisma-Vru482bI.js +1 -0
  311. package/dist/view/assets/prolog-CbFg5uaA.js +1 -0
  312. package/dist/view/assets/proto-C7zT0LnQ.js +1 -0
  313. package/dist/view/assets/pug-DKIMFp6K.js +1 -0
  314. package/dist/view/assets/puppet-BMWR74SV.js +1 -0
  315. package/dist/view/assets/purescript-CklMAg4u.js +1 -0
  316. package/dist/view/assets/python-B6aJPvgy.js +1 -0
  317. package/dist/view/assets/qml-3beO22l8.js +1 -0
  318. package/dist/view/assets/qmldir-C8lEn-DE.js +1 -0
  319. package/dist/view/assets/qss-IeuSbFQv.js +1 -0
  320. package/dist/view/assets/r-Cf5RLm7j.js +1 -0
  321. package/dist/view/assets/racket-BqYA7rlc.js +1 -0
  322. package/dist/view/assets/raku-DXvB9xmW.js +1 -0
  323. package/dist/view/assets/razor-BjBPvh-w.js +1 -0
  324. package/dist/view/assets/rbs-CpoqiR4B.js +1 -0
  325. package/dist/view/assets/red-hvxz__6c.js +1 -0
  326. package/dist/view/assets/reg-C-SQnVFl.js +1 -0
  327. package/dist/view/assets/regexp-CDVJQ6XC.js +1 -0
  328. package/dist/view/assets/rel-C3B-1QV4.js +1 -0
  329. package/dist/view/assets/riscv-BM1_JUlF.js +1 -0
  330. package/dist/view/assets/ron-D8l8udqQ.js +1 -0
  331. package/dist/view/assets/rose-pine-5qJOZa0Y.js +1 -0
  332. package/dist/view/assets/rose-pine-dawn-zx0QlTCp.js +1 -0
  333. package/dist/view/assets/rose-pine-moon-C9pEdX9L.js +1 -0
  334. package/dist/view/assets/rosmsg-BJDFO7_C.js +1 -0
  335. package/dist/view/assets/rst-bs7f0vWN.js +1 -0
  336. package/dist/view/assets/ruby-C0TQ7zu5.js +1 -0
  337. package/dist/view/assets/rust-B1yitclQ.js +1 -0
  338. package/dist/view/assets/sas-DEy46yEz.js +1 -0
  339. package/dist/view/assets/sass-Cj5Yp3dK.js +1 -0
  340. package/dist/view/assets/scala-CqE71os6.js +1 -0
  341. package/dist/view/assets/scheme-C98Dy4si.js +1 -0
  342. package/dist/view/assets/scss-D5BDwBP9.js +1 -0
  343. package/dist/view/assets/sdbl-DVxCFoDh.js +1 -0
  344. package/dist/view/assets/shaderlab-Dg9Lc6iA.js +1 -0
  345. package/dist/view/assets/shellscript-Yzrsuije.js +1 -0
  346. package/dist/view/assets/shellsession-BADoaaVG.js +1 -0
  347. package/dist/view/assets/slack-dark-BthQWCQV.js +1 -0
  348. package/dist/view/assets/slack-ochin-DqwNpetd.js +1 -0
  349. package/dist/view/assets/smalltalk-BOQMe2GC.js +1 -0
  350. package/dist/view/assets/smithy-cds9vsN8.js +1 -0
  351. package/dist/view/assets/snazzy-light-Bw305WKR.js +1 -0
  352. package/dist/view/assets/solarized-dark-CpvCGNkr.js +1 -0
  353. package/dist/view/assets/solarized-light-Dlz6yCKv.js +1 -0
  354. package/dist/view/assets/solidity-DijEV5ha.js +1 -0
  355. package/dist/view/assets/soy-8wufbnw4.js +1 -0
  356. package/dist/view/assets/sparql-rVzFXLq3.js +1 -0
  357. package/dist/view/assets/splunk-BtCnVYZw.js +1 -0
  358. package/dist/view/assets/sql-CRqJ_cUM.js +1 -0
  359. package/dist/view/assets/ssh-config-_ykCGR6B.js +1 -0
  360. package/dist/view/assets/stata-DI20mbqo.js +1 -0
  361. package/dist/view/assets/stylus-BEDo0Tqx.js +1 -0
  362. package/dist/view/assets/surrealql-Cjom0U5J.js +1 -0
  363. package/dist/view/assets/svelte-Cy7k_4gC.js +1 -0
  364. package/dist/view/assets/swift-C2oV4EkX.js +1 -0
  365. package/dist/view/assets/synthwave-84-CbfX1IO0.js +1 -0
  366. package/dist/view/assets/system-verilog-0hqHdDBg.js +1 -0
  367. package/dist/view/assets/systemd-4A_iFExJ.js +1 -0
  368. package/dist/view/assets/talonscript-CkByrt1z.js +1 -0
  369. package/dist/view/assets/tasl-QIJgUcNo.js +1 -0
  370. package/dist/view/assets/tcl-dwOrl1Do.js +1 -0
  371. package/dist/view/assets/templ-DhtptRzy.js +1 -0
  372. package/dist/view/assets/terraform-BETggiCN.js +1 -0
  373. package/dist/view/assets/tex-D96PA37w.js +1 -0
  374. package/dist/view/assets/tokyo-night-hegEt444.js +1 -0
  375. package/dist/view/assets/toml-vGWfd6FD.js +1 -0
  376. package/dist/view/assets/ts-tags-D351s5mN.js +1 -0
  377. package/dist/view/assets/tsv-B_m7g4N7.js +1 -0
  378. package/dist/view/assets/tsx-COt5Ahok.js +1 -0
  379. package/dist/view/assets/turtle-BsS91CYL.js +1 -0
  380. package/dist/view/assets/twig-27uCiNez.js +1 -0
  381. package/dist/view/assets/typescript-BPQ3VLAy.js +1 -0
  382. package/dist/view/assets/typespec-CAFt9gP4.js +1 -0
  383. package/dist/view/assets/typst-BUadGCkm.js +1 -0
  384. package/dist/view/assets/v-BGw2Nkan.js +1 -0
  385. package/dist/view/assets/vala-CsfeWuGM.js +1 -0
  386. package/dist/view/assets/vb-Cu-pLBUe.js +1 -0
  387. package/dist/view/assets/verilog-nZwndyjY.js +1 -0
  388. package/dist/view/assets/vesper-DRje8inN.js +1 -0
  389. package/dist/view/assets/vhdl-CeAyd5Ju.js +1 -0
  390. package/dist/view/assets/viml-CJc9bBzg.js +1 -0
  391. package/dist/view/assets/vitesse-black-Bkuqu6BP.js +1 -0
  392. package/dist/view/assets/vitesse-dark-D0r3Knsf.js +1 -0
  393. package/dist/view/assets/vitesse-light-CVO1_9PV.js +1 -0
  394. package/dist/view/assets/vue-BqiEGhQt.js +1 -0
  395. package/dist/view/assets/vue-html-AaS7Mt5G.js +1 -0
  396. package/dist/view/assets/vue-vine-BoDAl6tE.js +1 -0
  397. package/dist/view/assets/vyper-CDx5xZoG.js +1 -0
  398. package/dist/view/assets/wasm-CG6Dc4jp.js +1 -0
  399. package/dist/view/assets/wasm-MzD3tlZU.js +1 -0
  400. package/dist/view/assets/wenyan-BV7otONQ.js +1 -0
  401. package/dist/view/assets/wgsl-Dx-B1_4e.js +1 -0
  402. package/dist/view/assets/wikitext-BhOHFoWU.js +1 -0
  403. package/dist/view/assets/wit-5i3qLPDT.js +1 -0
  404. package/dist/view/assets/wolfram-lXgVvXCa.js +1 -0
  405. package/dist/view/assets/xml-sdJ4AIDG.js +1 -0
  406. package/dist/view/assets/xsl-CtQFsRM5.js +1 -0
  407. package/dist/view/assets/yaml-Buea-lGh.js +1 -0
  408. package/dist/view/assets/zenscript-DVFEvuxE.js +1 -0
  409. package/dist/view/assets/zig-VOosw3JB.js +1 -0
  410. package/dist/view/index.html +10 -2
  411. package/docs/README.md +21 -15
  412. package/docs/README.zh.md +15 -9
  413. package/docs/en/authoring.md +85 -80
  414. package/docs/en/cli-reference.md +110 -72
  415. package/docs/en/deployment.md +183 -0
  416. package/docs/en/getting-started.md +112 -0
  417. package/docs/en/material-types.md +241 -0
  418. package/docs/en/settings.md +133 -0
  419. package/docs/en/shortcuts.md +89 -0
  420. package/docs/en/typing-rules.md +208 -0
  421. package/docs/zh/authoring.md +74 -69
  422. package/docs/zh/cli-reference.md +92 -58
  423. package/docs/zh/deployment.md +179 -0
  424. package/docs/zh/getting-started.md +104 -0
  425. package/docs/zh/material-types.md +769 -0
  426. package/docs/zh/settings.md +120 -0
  427. package/docs/zh/shortcuts.md +83 -0
  428. package/docs/zh/typing-rules.md +191 -0
  429. package/package.json +13 -11
  430. package/templates/en/QTYPE.md +155 -495
  431. package/templates/en/README.md +11 -11
  432. package/templates/en/TODO.md +1 -1
  433. package/templates/en/material/article.md +20 -0
  434. package/templates/en/material/assets/article/sunrise.svg +12 -0
  435. package/templates/en/material/assets/code/tree.svg +19 -0
  436. package/templates/en/material/assets/qa/login-flow.svg +17 -0
  437. package/templates/en/material/assets/sentence/pangram.svg +6 -0
  438. package/templates/en/material/assets/snippet/moon.svg +8 -0
  439. package/templates/en/material/assets/word/apple.svg +5 -0
  440. package/templates/en/material/code.md +55 -0
  441. package/templates/en/material/qa.md +33 -0
  442. package/templates/en/material/sentence.md +18 -0
  443. package/templates/en/material/snippet.md +17 -0
  444. package/templates/en/material/word.md +20 -0
  445. package/templates/zh/QTYPE.md +191 -473
  446. package/templates/zh/README.md +6 -6
  447. package/templates/zh/index.md +1 -1
  448. package/templates/zh/material/article.md +18 -0
  449. package/templates/zh/material/assets/article/sunrise.svg +12 -0
  450. package/templates/zh/material/assets/code/tree.svg +19 -0
  451. package/templates/zh/material/assets/qa/login-flow.svg +17 -0
  452. package/templates/zh/material/assets/sentence/pangram.svg +6 -0
  453. package/templates/zh/material/assets/snippet/moon.svg +8 -0
  454. package/templates/zh/material/assets/word/apple.svg +5 -0
  455. package/templates/zh/material/code.md +55 -0
  456. package/templates/zh/material/qa.md +33 -0
  457. package/templates/zh/material/sentence.md +19 -0
  458. package/templates/zh/material/snippet.md +20 -0
  459. package/templates/zh/material/word.md +20 -0
  460. package/dist/cli/commands/check/action.js +0 -56
  461. package/dist/cli/commands/check/i18n.js +0 -26
  462. package/dist/cli/commands/plugin/i18n.js +0 -28
  463. package/dist/cli/commands/plugin/index.js +0 -41
  464. package/dist/core/typing/engine.js +0 -112
  465. package/dist/view/assets/index-DBABH3dG.js +0 -111
  466. package/dist/view/assets/index-RTLZ-zOC.css +0 -1
  467. package/templates/en/material/example.md +0 -47
  468. package/templates/zh/material/example.md +0 -47
@@ -15,604 +15,264 @@ The whole document is organized into four modules: **Concepts / Format / Operati
15
15
  - The user picks **topics** or **drops materials**. You **read, distill, cut into cards, file, and maintain**.
16
16
  - You are not a Q&A bot — you are the **author of a typing-practice card library**. Every card must be something a real person can actually type.
17
17
  - `raw/` is where the user drops source material (optional dir). **Never modify its contents**.
18
- - Each `.md` file under `material/` is one deck, **fully maintained by you** (except cards marked as hand-edited).
19
- - Cards are not arbitrary Q&A pairs — they are **strings a human can type on an OS keyboard** (or via Chinese IME).
18
+ - Each `.md` file under `material/` is one material, **fully maintained by you** (except hand-edited cards).
19
+ - Cards are **strings a human can type on an OS keyboard** (or via Chinese IME).
20
20
 
21
21
  ### Terminology
22
22
 
23
23
  | Term | Definition |
24
24
  |---|---|
25
- | Repo | A standalone qtype directory (e.g. `my-typing-deck/`) |
26
- | Deck | A single `.md` file under `material/`, containing many cards |
27
- | Card | One `## Q:` + `## A:` unit, preceded by a frontmatter block |
28
- | Tag | Category marker on a card or deck; used for filtering and index grouping |
29
- | Word card | `type: word`; drills spelling and word form; requires `phonetic` and `gloss` |
30
- | Sentence card | `type: sentence`; drills continuous typing of a sentence; requires `translation` |
31
- | Normal card | `type: normal` (default); Q is a prompt, A is the answer; most free-form |
32
- | Raw material | Source file under `raw/` (optional); used by ingest to derive cards |
33
- | Log | `log.md`, append-only timeline |
34
- | Review progress | Local practice progress produced by the Web UI (not the Agent's concern) |
25
+ | Repo | A standalone qtype directory |
26
+ | Material | One `.md` file under `material/`, containing many cards |
27
+ | Card | One `#` H1 with its body |
28
+ | Tag | Material-level classification marker |
29
+ | type | Material's kind, deciding card internal shape: `word` / `sentence` / `article` / `snippet` / `qa` / `code` |
35
30
 
36
31
  ### Directory Layout
37
32
 
38
33
  ```
39
34
  <repo-root>/
40
- ├── QTYPE.md # this file (rules and operations; language chosen at repo creation)
41
- ├── AGENTS.md # symlink → QTYPE.md
42
- ├── CLAUDE.md # symlink → QTYPE.md
43
- ├── GEMINI.md # symlink → QTYPE.md
44
- ├── README.md # repo intro (maintained by human)
45
- ├── TODO.md # backlog (maintained by todo command)
46
- ├── index.md # table of contents of all decks, grouped by tag
47
- ├── log.md # append-only timeline
48
- ├── qtype.config.json # user-tunable settings (theme, target WPM, hint mode, ...)
49
- ├── material/ # decks you write
35
+ ├── QTYPE.md
36
+ ├── AGENTS.md, CLAUDE.md, GEMINI.md # symlinks → QTYPE.md
37
+ ├── README.md
38
+ ├── TODO.md
39
+ ├── index.md
40
+ ├── log.md
41
+ ├── qtype.config.json
42
+ ├── material/
50
43
  │ ├── .gitkeep
51
- │ ├── <slug>.md # one deck per file
52
- │ └── assets/ # images / audio referenced by decks
53
- └── <deck-slug>/
54
- │ └── xxx.png
55
- └── raw/ # (optional) source materials dropped by the user
44
+ │ ├── <slug>.md
45
+ │ └── assets/<material-slug>/
46
+ └── raw/
56
47
  ├── .gitkeep
57
48
  ├── YYYY-MM-DD-<slug>.md
58
- └── assets/
59
- └── <raw-slug>/
49
+ └── assets/<raw-slug>/
60
50
  ```
61
51
 
62
- Rules:
63
-
64
- - Under `material/`, all deck files are **flat**. Only one subdirectory is allowed: `assets/` (for images and other binaries referenced by decks).
65
- - Under `raw/`, all source files are **flat**. Only one subdirectory is allowed: `assets/`.
66
- - `material/assets/<deck-slug>/` and `raw/assets/<raw-slug>/`: grouped by the owning md file's slug, to avoid global name collisions.
67
- - **On first operation, sanity-check the skeleton**: the user normally initializes. If the Agent enters a repo and finds `material/` / `index.md` / `log.md` missing, create them by spec. When creating `material/` or `raw/`, drop a `.gitkeep`.
68
- - `raw/` is optional — if the user never drops materials, don't create it.
69
- - Only create the directories and files specified here. **Never** create anything outside the rules.
70
-
71
52
  ---
72
53
 
73
54
  ## Format
74
55
 
75
- ### Naming
76
-
77
- **Deck filename**
78
-
79
- - Path: `material/<slug>.md`.
80
- - `<slug>`: kebab-case of the topic, lowercase, ASCII letters and hyphens, ≤ 60 chars. For Chinese topics use an English translation or pinyin.
81
- - On collision, append `-2` / `-3`.
82
- - Examples: `gre-vocab-list-3.md`, `react-hooks-quiz.md`, `toefl-idioms.md`.
83
-
84
- **Raw filename**
85
-
86
- - Path: `raw/YYYY-MM-DD-<slug>.md`.
87
- - `YYYY-MM-DD`: the date the material was collected into this repo.
88
- - `<slug>`: kebab-case of the source title.
89
- - Untitled paste: `YYYY-MM-DD-note-<N>.md`.
90
-
91
- **Assets naming**
92
-
93
- - `material/assets/<deck-slug>/` and `raw/assets/<raw-slug>/`: grouped by the owning file's slug; consistent slug means one directory.
56
+ ### Material-level frontmatter
94
57
 
95
- ### Links
96
-
97
- **Use Markdown links only, never Wikilinks.**
98
-
99
- | Context | Path form | Example |
100
- |---|---|---|
101
- | Deck references another deck | `./<slug>.md` | `[GRE Frequent](./gre-vocab-list-3.md)` |
102
- | Deck references a raw file | `../raw/<file>.md` | `[Source](../raw/2026-08-14-mdn-closures.md)` |
103
- | Deck references image in material/assets | `./assets/<deck-slug>/<file>` | `![Diagram](./assets/react-hooks-quiz/lifecycle.png)` |
104
- | Deck references image in raw/assets | `../raw/assets/<raw-slug>/<file>` | `![Original](../raw/assets/2026-08-14-mdn-closures/scope.png)` |
105
- | index.md / log.md reference a deck | From repo root | `material/gre-vocab-list-3.md` |
106
-
107
- Rules:
108
-
109
- - **Never** use `[[wikilink]]` syntax.
110
- - **Never** use absolute paths. Every link must start with `./` or `../`.
111
- - Link targets must actually exist.
112
-
113
- ### Deck-level frontmatter
114
-
115
- Each deck file begins with one YAML frontmatter block describing the whole deck:
58
+ Each material begins with one YAML frontmatter block. **It decides the shape of every card in the file**:
116
59
 
117
60
  ```yaml
118
61
  ---
119
- title: <deck title>
120
- language: <target language ISO code, e.g. en / zh / ja>
62
+ title: <material title>
63
+ type: word | sentence | article | snippet | qa | code
121
64
  tags: [<tag-1>, <tag-2>]
122
65
  created: YYYY-MM-DD
123
66
  updated: YYYY-MM-DD
124
67
  ---
125
68
  ```
126
69
 
127
- Fields:
128
-
129
- - `title`: deck title. Human-readable; can contain non-ASCII.
130
- - `language`: the primary language of the answer text (drives IME hint and input expectations). Common values: `en`, `zh`, `ja`, `mixed`.
131
- - `tags`: array or space-separated string. At least one; used for grouping in `index.md`.
132
- - `created` / `updated`: dates. Bump `updated` on any content change.
70
+ - `title`: human-readable
71
+ - `type`: **required**. Decides how every card is parsed and rendered
72
+ - `tags`: array or space-separated
73
+ - `created` / `updated`: dates. Bump `updated` on any content change
133
74
 
134
- Directly after the deck frontmatter comes the first card's own frontmatter (separated by a `---` line). No deck-level body prose — put commentary in README or the index.
75
+ **One material, one type. All cards in a file share the same shape.**
135
76
 
136
- ### Card frontmatter
137
-
138
- Each card starts with its own frontmatter block. Fields:
139
-
140
- | Field | Values | Applies to | Notes |
141
- |---|---|---|---|
142
- | `type` | `normal` \| `word` \| `sentence` | All | Default `normal`. |
143
- | `tags` | Array or space-separated string | Optional | Card-level tags; can overlap with deck tags. |
144
- | `difficulty` | Integer 1..5 | Optional | 1=trivial, 5=hardest. Default 3. |
145
- | `hint` | `none` \| `ghost` | Optional | Overrides the global hint mode. Omit = follow global. |
146
- | `phonetic` | IPA string, `/…/` or `[…]` | Word cards | e.g. `/əˈbæn.dən/`. |
147
- | `gloss` | Native-language gloss (typically simplified Chinese) | Word cards | e.g. `抛弃, 放弃`. |
148
- | `translation` | Translation of the sentence | Sentence cards | Meaning-preserving; not word-for-word. |
149
-
150
- Rules:
151
-
152
- - Word cards **must** have `phonetic` and `gloss`.
153
- - Sentence cards **must** have `translation`.
154
- - Normal cards may omit all optional fields.
155
- - Fields not listed above are not allowed — this keeps the format stable.
77
+ There is **no card-level frontmatter**. All per-card info lives in markdown structure.
156
78
 
157
79
  ### Card structure
158
80
 
159
- A card consists of frontmatter, a `## Q:` line, and a `## A:` line:
160
-
161
- ```md
162
- ---
163
- type: word
164
- phonetic: /əˈbæn.dən/
165
- gloss: 抛弃, 放弃
166
- tags: [gre]
167
- difficulty: 2
168
- ---
169
- ## Q: abandon
170
- ## A: abandon
171
- ```
172
-
173
- Rules:
174
-
175
- - `## Q:` — the prompt. Shown to the user during practice.
176
- - `## A:` — **the exact text the user is expected to type**.
177
- - Cards are separated by a blank line + `---` + a blank line (i.e. the start of the next card's frontmatter).
178
- - The deck frontmatter's closing `---` is followed immediately by the first card's opening frontmatter — no prose between them.
179
-
180
- **Answer-text constraints (contents of `## A:`)**:
181
-
182
- - Only characters typable via the OS keyboard (including Chinese IME) are allowed. Emojis, zero-width chars, and most exotic Unicode are rejected.
183
- - Full-width Chinese punctuation is auto-normalized by the tool (smart quotes → straight quotes, em-dash → double hyphen, etc.). Write punctuation naturally.
184
- - Length **should** stay under 200 characters — longer answers hurt the practice UX. Split into multiple cards.
185
- - Spaces, newlines (Enter), and Tab characters are allowed. Newlines inside an answer must be real newlines (a blank line would break Markdown parsing — use a soft break or no break).
186
-
187
- ### Card examples
81
+ **H1 (`#`) splits cards.** Each H1 starts a new card. The next H1 is the next card. **No `---` between cards.**
188
82
 
189
- **Word card**
83
+ **Six card shapes, keyed by material `type`**:
190
84
 
191
- ```md
192
- ---
193
- type: word
194
- phonetic: /əˈbæn.dən/
195
- gloss: 抛弃, 放弃
196
- tags: [gre]
197
- difficulty: 2
198
- ---
199
- ## Q: abandon
200
- ## A: abandon
201
- ```
85
+ #### type: word
202
86
 
203
- **Sentence card**
87
+ Word / short phrase. H1 = typing target; H2/H3/H4 are optional annotation slots at fixed positions.
204
88
 
205
89
  ```md
206
- ---
207
- type: sentence
208
- translation: 熟能生巧。
209
- tags: [idiom]
210
- difficulty: 3
211
- ---
212
- ## Q: Practice makes perfect.
213
- ## A: Practice makes perfect.
214
- ```
90
+ # abandon
91
+ ## /əˈbæn.dən/
92
+ ### to give up, forsake
93
+ #### ![](./assets/vocab/abandon.jpg)
215
94
 
216
- **Normal card**
95
+ # ephemeral
96
+ ## /əˈfem(ə)rəl/
97
+ ### short-lived
217
98
 
218
- ```md
219
- ---
220
- type: normal
221
- tags: [js, closures]
222
- difficulty: 4
223
- ---
224
- ## Q: What is a closure in JavaScript?
225
- ## A: A function bundled with its lexical scope, letting it access variables from where it was defined.
99
+ # barebones
226
100
  ```
227
101
 
228
- For normal cards, the A section is **what the user types**; Q is the prompt. A can be a code snippet, a phrase, a full sentence — subject to the answer-text constraints.
102
+ | Level | Content | Optional |
103
+ |---|---|---|
104
+ | **H1** | Typing target (the word) | Required |
105
+ | **H2** | Phonetic / pinyin | Optional |
106
+ | **H3** | Gloss / definition | Optional |
107
+ | **H4** | Image, in `![](url)` markdown | Optional |
229
108
 
230
- ### `index.md` format
109
+ #### type: sentence
231
110
 
232
- `index.md` lives at repo root, grouped by tag. It **must** be updated after every ingest / update / quiz-gen.
111
+ Single sentence. **Same shape as word.** H1 = typing target (full sentence).
233
112
 
234
113
  ```md
235
- ---
236
- updated: YYYY-MM-DD
237
- ---
238
-
239
- # Index
240
-
241
- ## <tag-1>
242
-
243
- | Deck | Cards | Language | Summary | Updated |
244
- |---|---|---|---|---|
245
- | [Title 1](material/<file-1>.md) | 32 | en | one-line summary | YYYY-MM-DD |
246
- | [Title 2](material/<file-2>.md) | 25 | zh | one-line summary | YYYY-MM-DD |
247
-
248
- ## <tag-2>
114
+ # Practice makes perfect.
115
+ ### With enough practice you master anything.
249
116
 
250
- | Deck | Cards | Language | Summary | Updated |
251
- |---|---|---|---|---|
252
- | [Title 3](material/<file-3>.md) | 40 | mixed | one-line summary | YYYY-MM-DD |
117
+ # The unexamined life is not worth living.
118
+ ### Reflect on your life to give it depth.
253
119
  ```
254
120
 
255
- Rules:
121
+ #### type: article
256
122
 
257
- - One `##` heading per tag. **A deck can appear under multiple tags** if it has multiple `tags` values — list it in every relevant section.
258
- - Under each tag, **only one markdown table** — nothing else.
259
- - Link paths start from the repo root (`index.md` is at the root).
260
- - Summary ≤ 60 characters; one line describing the deck's topic.
261
- - `Cards` reflects the actual card count in the deck file.
262
-
263
- ### `log.md` format
264
-
265
- `log.md` lives at repo root, chronologically appended (new entries at the end). **Never delete entries.** Every operation **must** append one entry.
123
+ Prose. **H1 = title (not typed). The body under H1 is the typing target.**
266
124
 
267
125
  ```md
268
- ---
269
- updated: YYYY-MM-DD
270
- ---
271
-
272
- # Log
273
-
274
- ## [YYYY-MM-DD] ingest | <source title or new deck name>
275
- - created: [Deck A](material/<A>.md) — N cards
276
- - updated: [Deck B](material/<B>.md) — appended M cards
277
-
278
- ## [YYYY-MM-DD] quiz-gen | <topic>
279
- - created: [Deck C](material/<C>.md) — N cards
280
-
281
- ## [YYYY-MM-DD] update | <deck name>
282
- - appended: N
283
- - fixed: M
126
+ # Morning ritual
284
127
 
285
- ## [YYYY-MM-DD] cascade | <triggering deck>
286
- - affected: [Deck X](material/<X>.md), [Deck Y](material/<Y>.md)
128
+ Wake up early. Drink a glass of water. Start typing for ten minutes.
129
+ Consistency beats intensity that's how habits compound over time.
287
130
 
288
- ## [YYYY-MM-DD] check | N issues, M auto-fixed
131
+ # 200-word self-intro
289
132
 
290
- ## [YYYY-MM-DD] level-up | <merge/split description>
133
+ Hello, my name is Alice. I'm a software engineer based in Shanghai.
291
134
  ```
292
135
 
293
- Rules:
294
-
295
- - Every ingest / update / quiz-gen / cascade / check / level-up appends one entry.
296
- - Heading format: `## [YYYY-MM-DD] <op> | <note>`.
297
- - Entries are **append-only**; do not delete or modify existing ones.
298
- - `grep "^## \[" log.md` scans all entries.
299
-
300
- ---
301
-
302
- ## Operations
303
-
304
- ### Ingest
305
-
306
- **Turn source material into a stack of typable cards.**
307
-
308
- Trigger: the user says "ingest <path-or-url>", "make cards from this article", "process this word list".
309
-
310
- **Step 1: fetch (drop source into raw/)**
311
-
312
- Four cases:
313
-
314
- Case A: input is a URL
315
- - Use whatever web-fetching tool is available; convert to markdown. If none is available, ask the user to paste the content.
316
- - Save to `raw/YYYY-MM-DD-<slug>.md`.
317
- - Write frontmatter: `source: <URL>` + `collected: YYYY-MM-DD`.
318
-
319
- Case B: input is a local file (`ingest /path/to/wordlist.pdf`)
320
- - Convert to markdown, copy to `raw/YYYY-MM-DD-<slug>.md`.
321
- - Write frontmatter: `source: <original path>` + `collected: YYYY-MM-DD`.
322
-
323
- Case C: input is pasted text
324
- - Save to `raw/YYYY-MM-DD-note-<N>.md`.
325
- - Write frontmatter: `source: pasted text` + `collected: YYYY-MM-DD`.
136
+ Images (`![](url)`) may appear in the body — they render but are **stripped from the typing text**.
326
137
 
327
- Case D: input is a topic description ("give me 20 high-frequency GRE words from memory")
328
- - **Skip fetch**; go straight to Step 2 (this is the quiz-gen path — see Quiz-gen).
138
+ #### type: snippet
329
139
 
330
- **Step 2: cut into cards**
140
+ Short composition. **Structurally identical to article** (H1 = title, not typed; body below H1 = typing target). The difference is purely visual: snippet renders **vertically centered with centered text alignment**, so it reads like a poster — good for poems, aphorisms, slogans, short standalone passages.
331
141
 
332
- Read the source and split by material type:
333
-
334
- - **Word list** → one word card per entry. Grab IPA from the material; if absent, look up an authoritative source; if unknown, leave blank and report in log. Gloss goes in simplified Chinese (or the configured native language).
335
- - **Sentence / example collection** → one sentence card per line. Translation from the material or a natural translation.
336
- - **Article / tutorial / code snippet** → extract key points as normal cards. Q is the question, A is a concise answer. Avoid answers > 200 chars — split if longer.
337
-
338
- **Step 3: decide which deck it belongs to**
339
-
340
- - Scan `material/` for existing decks on the closest topic:
341
- - Same topic, existing deck has < 50 cards → append to it.
342
- - Same topic, existing deck has ≥ 50 cards → create a follow-on deck (e.g. `gre-vocab-list-4.md`).
343
- - No matching deck → create `material/<slug>.md` with a fresh deck frontmatter.
344
- - **One deck, one topic.** Never mix TypeScript with English vocabulary in one file.
345
-
346
- **Step 4: verify typability**
347
-
348
- For each new card's `## A:`:
349
-
350
- - Scan characters; reject emojis, zero-widths, control chars (except Tab / Enter).
351
- - Full-width punctuation is auto-normalized by the tool — write naturally.
352
- - Length > 200 chars → split into multiple cards, giving each Q a different angle.
353
- - On word cards, A must equal the target word from Q (this drills spelling, not meaning).
354
-
355
- **Step 5: update index.md and log.md**
356
-
357
- - index.md: add rows for new decks; on appended decks, bump `Cards` and `updated`. See Index format.
358
- - log.md: append one ingest entry. See Log format.
359
-
360
- **Step 6: tell the user**
361
-
362
- Briefly report in the conversation what was created / appended / total card count. The user reviews via `git diff` and commits.
363
-
364
- **The Agent does not run `git add` / `git commit` / `git push`.**
365
-
366
- **Don't**:
367
-
368
- - **Don't** "preview and wait for confirmation" — write by the rules directly.
369
- - **Don't** ingest multiple sources at once — one at a time, so topic judgments don't interfere.
370
- - **Don't** mix topics in one deck — create more decks instead.
371
-
372
- ### Update
373
-
374
- **Fix or extend an existing deck.**
375
-
376
- Trigger: the user says "add a few cards on X to `<deck>`", "fix the IPA on the abandon card in `<deck>`", "merge these cards into `<deck>`".
377
-
378
- **Steps**
379
-
380
- 1. **Read the target deck**: locate cards to change or the position to append.
381
- 2. **Apply changes**:
382
- - **Append**: add new cards to the end of the file, following the format.
383
- - **Fix**: only touch the specified field or the specified card's Q/A/frontmatter. **Don't touch** anything not asked for.
384
- - **Delete**: only when explicitly requested; do not proactively tidy.
385
- 3. **Verify typability**: same as Ingest Step 4.
386
- 4. **Bump the deck frontmatter `updated`**.
387
- 5. **Update index.md** if card count changed.
388
- 6. **Append log.md**: `## [YYYY-MM-DD] update | <deck name>` with counts.
389
-
390
- **Don't**:
391
-
392
- - **Don't** modify hand-edited cards — see the rules section on `<!-- hand-edited -->`.
393
- - **Don't** re-tidy sections that weren't asked to be touched.
394
- - **Don't** rewrite the whole deck unless the user explicitly asks.
395
-
396
- ### Cascade
397
-
398
- **After a big change, check related decks.**
399
-
400
- Trigger: automatic when an Ingest or Update involves **many cards** (≥ 10), a **topic-scope change** (e.g. a deck goes from "GRE list" to "GRE + TOEFL mixed"), or **terminology renames**.
401
-
402
- **Steps**
403
-
404
- 1. **Scan index.md**: find decks sharing tags or with related topics.
405
- 2. **Check each one** for:
406
- - Terminology consistency — did the new deck adopt a new term the old decks should follow?
407
- - Duplicate cards — remove duplicates from whichever deck has the lower quality version.
408
- - IPA / gloss / translation conflicts — the same word/sentence should have consistent fields across decks.
409
- 3. **Fix conflicts**: prefer "newer wins" or "higher quality wins". Touch **only** conflicting items — do not retidy.
410
- 4. **Bump `updated` on every deck you touched**.
411
- 5. **Append log.md**: `## [YYYY-MM-DD] cascade | <triggering deck>` with the affected list.
412
-
413
- Cascade completes **before the triggering operation returns**, not later.
414
-
415
- ### Quiz-gen
416
-
417
- **Fabricate a stack of cards from a topic description.**
142
+ ```md
143
+ # Quiet Night Thought
418
144
 
419
- Trigger: the user says "quiz-gen JavaScript closures", "give me 30 GRE high-frequency words", "make a React hooks quiz deck".
145
+ Bright moonlight before my bed
146
+ Could it be frost on the ground?
147
+ I lift my head to look at the moon,
148
+ Then lower it, thinking of home.
420
149
 
421
- **Steps**
150
+ # Simplicity is the ultimate sophistication.
422
151
 
423
- 1. **Confirm topic and count**: default 25 cards; use whatever count the user specifies.
424
- 2. **Choose card type**:
425
- - Vocabulary → mostly word cards.
426
- - Sentences for language learning → mostly sentence cards.
427
- - Programming / concept knowledge → normal cards (Q is question, A is a short answer).
428
- 3. **Follow Ingest Steps 2–6**: cut cards → decide deck (usually new) → verify typability → update index / log.
429
- 4. **In log, use `quiz-gen` (not `ingest`)** and mark source as "from training memory".
152
+ Attributed to Leonardo da Vinci.
153
+ ```
430
154
 
431
- **Rules**
155
+ Pick article vs snippet by tone: paragraphs meant for flow reading with surrounding context → article; short, standalone, needs breathing room → snippet.
432
156
 
433
- - Content must be accurate. If unsure (e.g. IPA of a rare word), leave blank with a note — do not fabricate.
434
- - One topic, one deck per invocation.
157
+ #### type: qa
435
158
 
436
- ### Check
159
+ Q&A. **H1 = card name, `## Q` = prompt, `## A` = typing target.**
437
160
 
438
- **When the user's `qtype check` fails, the Agent fixes.**
161
+ ```md
162
+ # Closures
439
163
 
440
- Trigger: the user runs `qtype check` (see CLI section) and hands the error list to the Agent.
164
+ ## Q
165
+ What is a closure in JavaScript? Give a practical example.
441
166
 
442
- **Agent handling**:
167
+ ## A
168
+ A closure is a function combined with its lexical scope. When the inner function is referenced from outside, its captured variables are kept alive. The classic example is a counter factory.
169
+ ```
443
170
 
444
- **Deterministic (auto-fix)**:
171
+ #### type: code
445
172
 
446
- - **Illegal characters** in answer text (emoji / zero-width / control) strip or drop the card.
447
- - **Frontmatter errors**: field name misspelled, wrong type, missing required field → fix it.
448
- - **Word card missing phonetic/gloss, sentence card missing translation** → fill it in (if unknown, place `TODO` and report).
449
- - **Answer > 200 chars** → split into multiple cards, giving each Q a different angle.
450
- - **index.md inconsistency**: deck file exists but not in index → add row; card count changed → update.
451
- - **Broken internal link**: target missing → search `material/` for a same-named file; unique match → repair; otherwise report.
173
+ Coding problem. **Same shape as qa**, with A containing a fenced code block the code inside is the typing target.
452
174
 
453
- **Heuristic (report only)**:
175
+ ````md
176
+ # Two Sum
454
177
 
455
- - **Duplicate cards**: same Q + A across decks. Report; the user decides whether to merge.
456
- - **Deck too large**: > 100 cards recommend split.
457
- - **Deck too small**: < 5 cards → recommend merge.
458
- - **Orphan deck**: the deck's tag appears only on this one deck in index.md. Might be a new topic, might be miscategorized. Report.
178
+ ## Q
179
+ Given `nums` and `target`, return the indices of the two numbers that add up to target.
459
180
 
460
- **Report & log**: give the user a fix report, then append `## [YYYY-MM-DD] check | N issues, M auto-fixed`.
181
+ ## A
182
+ ```py
183
+ class Solution:
184
+ def twoSum(self, nums, target):
185
+ seen = {}
186
+ for i, x in enumerate(nums):
187
+ if target - x in seen:
188
+ return [seen[target - x], i]
189
+ seen[x] = i
190
+ ```
191
+ ````
461
192
 
462
- ### Level-up
193
+ The code fence's language tag drives Shiki syntax highlighting (`ts` / `py` / `go` / ...).
463
194
 
464
- **Restructure a scatter of small decks into a coherent series.**
195
+ ### Universal rules
465
196
 
466
- Trigger: the user says "merge these decks", "split this deck into beginner/advanced", "organize the GRE lists into list 1 / 2 / 3".
197
+ - Authors don't need to remember low-level micro-conventions ("phonetic must be inline code" none of that). Structure is enough.
198
+ - Typing targets may include spaces, newlines (Enter), Tab
199
+ - Target length **should** stay ≤ 200 chars per card — split longer content
200
+ - Only OS-keyboard-typable characters. Emoji, zero-widths, control chars (except Tab / Enter) are rejected
201
+ - Full-width Chinese punctuation is auto-normalized by the tool
467
202
 
468
- **Steps**
203
+ ### Rich rendering (display side, never typed)
469
204
 
470
- 1. **Read all involved decks**: full frontmatter + all cards.
471
- 2. **Decide split strategy**:
472
- - **Merge**: many small decks → one large deck (by topic, difficulty, or tag).
473
- - **Split**: one large deck → several smaller ones (by difficulty tier, by subtopic).
474
- - **Reorder**: rearrange cards within a deck — e.g. by ascending `difficulty`, alphabetical, or learning order.
475
- 3. **Write new deck files** using the deck naming rules (e.g. `gre-vocab-list-1.md`).
476
- 4. **Delete or empty old deck files**: post-merge originals get removed; post-split originals get removed. Use `rm` — do not proactively `git rm`.
477
- 5. **Update index.md and log.md**: adjust rows and links; append `## [YYYY-MM-DD] level-up | <description>`.
478
- 6. **Preserve card content**: don't change Q / A / IPA / gloss / translation — level-up is a reorganization, not a content edit. Hand-edited cards (see rules) migrate as-is.
205
+ Display-side slots (`## Q` prompts, article / snippet bodies, gloss) support three kinds of rich content beyond plain markdown:
479
206
 
480
- **Don't**:
207
+ - **Mermaid diagrams**: ` ```mermaid ` fences; `publish build` pre-renders to SVG
208
+ - **Math**: inline `$…$`, block `$$…$$`; KaTeX lazy-loads (~280KB)
209
+ - **Standard markdown**: code blocks, images, bold, italic
481
210
 
482
- - **Don't** modify card content during level-up. Use Update for content changes.
483
- - **Don't** delete user data on a hunch — if unsure whether an old file should be removed, ask.
211
+ Example put the equation in `## Q`, keep `## A` typable:
484
212
 
213
+ ```md
214
+ ---
215
+ type: qa
216
+ tags: [math]
485
217
  ---
486
218
 
487
- ## Rules
488
-
489
- ### Prohibitions
490
-
491
- The following are **strictly forbidden**:
492
-
493
- 1. **Never modify raw/ contents.** Files under `raw/` are read-only by default. Moving, renaming, or deleting requires explicit user instruction.
494
- 2. **Never write untypable characters.** Emojis, zero-widths, control characters (except Tab and Enter) in an answer are forbidden. If unsure, prefer ASCII or omit.
495
- 3. **Never write over-long answers.** `## A:` should be ≤ 200 characters. Longer → split. Don't make the user type for ten minutes.
496
- 4. **Never mix topics in one deck.** One deck, one topic. TypeScript and English vocabulary do not co-exist in a single file. Create more decks instead.
497
- 5. **Never modify hand-edited cards.** A card whose body contains the HTML comment `<!-- hand-edited -->` is read-only to the Agent. To change it, ask the user first. Cascade skips these.
498
- 6. **Never use Wikilinks.** `[[foo]]` is banned. Use `[text](./path.md)`.
499
- 7. **Never use absolute paths.** All links must be relative, starting with `./` or `../`.
500
- 8. **Never run `git commit` / `push`.** The user decides commits.
501
- 9. **Never create directories outside the rules.** Under `material/`, only flat `.md` files and an `assets/` subdirectory are allowed. Under `raw/`, likewise. Structures like `material/words/` or `material/2026/` are forbidden.
502
- 10. **Never fabricate IPA / gloss / translation.** For uncertain fields, leave them blank and report in log — do not invent.
503
-
504
- ### Content language
505
-
506
- - Deck `title`, `index.md` summaries, `log.md` entries: **primarily the repo language (e.g. Chinese), with technical terms in their original form**.
507
- - Word card `gloss`: **the native language** (usually simplified Chinese; the repo may specify otherwise).
508
- - Sentence card `translation`: translation into the user's native language (default simplified Chinese). Meaning-preserving, not word-for-word.
509
- - The card `## A:` answer text itself: **in the deck's target language**, preserved verbatim from the source (English words stay English, Japanese sentences stay Japanese).
510
-
511
- ### Card count guidance
512
-
513
- - **20–50 cards per deck** is the sweet spot.
514
- - < 5: too thin — consider merging (Level-up).
515
- - \> 100: too thick — consider splitting (Level-up).
516
- - A single Ingest / Quiz-gen usually produces ~25 cards. Beyond that, quality degrades.
517
-
518
- ### Difficulty scale
519
-
520
- `difficulty` semantics (default 3):
521
-
522
- | Value | Meaning |
523
- |---|---|
524
- | 1 | Trivial recognition, no thought (common words, common-sense facts) |
525
- | 2 | Read at a glance, no recall needed (common phrases, basic grammar) |
526
- | 3 | Brief recall required (default, most cards) |
527
- | 4 | Real thought or a longer answer (concept explanations, sentence composition) |
528
- | 5 | Hard — long answers or complex concepts (small code snippets, long-sentence dictation) |
219
+ # Gaussian integral
529
220
 
530
- ### Quick reference
221
+ ## Q
222
+ Evaluate the integral:
531
223
 
532
- **Ingest a source**:
224
+ $$\int_{-\infty}^{\infty} e^{-x^2}\,dx = ?$$
533
225
 
534
- ```
535
- raw/YYYY-MM-DD-<slug>.md ← write source (flat, optional)
536
- material/<slug>.md ← write or append to deck
537
- index.md ← update row (cards / updated)
538
- log.md ← append ## [date] ingest | title
226
+ ## A
227
+ sqrt(pi)
539
228
  ```
540
229
 
541
- **Update a deck**:
230
+ **Rendering happens only on the display side. Typing targets (`## A` / word H1 / etc.) still must be plain keyboard-typable text.**
542
231
 
543
- ```
544
- material/<slug>.md ← append/fix cards, bump updated
545
- index.md ← update cards & updated
546
- log.md ← append ## [date] update | deck name
547
- ```
548
-
549
- **Quiz-gen from a topic**:
550
-
551
- ```
552
- material/<slug>.md ← create new deck
553
- index.md ← add row
554
- log.md ← append ## [date] quiz-gen | topic
555
- ```
556
-
557
- **Check errors reported by user**:
232
+ ### Naming
558
233
 
559
- ```
560
- classify errors, auto-fix or report
561
- auto-fix: chars / frontmatter / length / index consistency
562
- report only: duplicates / oversized / undersized / orphans
563
- log.md ← append ## [date] check | N issues
564
- ```
234
+ Material files: `material/<slug>.md`
235
+ - kebab-case, ASCII lowercase + hyphens, ≤ 60 chars
236
+ - Chinese topics: use English translation or pinyin
237
+ - Collision: append `-2` / `-3`
565
238
 
566
- **Level-up restructure**:
239
+ ### Links
567
240
 
568
- ```
569
- read old decks decide merge/split/reorder
570
- write new material/*.md
571
- rm old files
572
- index.md ← rows added/removed
573
- log.md ← append ## [date] level-up | description
574
- ```
241
+ - **Markdown link syntax only**, no Wikilinks
242
+ - No absolute paths start with `./` or `../`
243
+ - Targets must actually exist
575
244
 
576
245
  ---
577
246
 
578
- ## CLI Commands (for the user, not for you)
247
+ ## Operations
579
248
 
580
- The following commands are run **by the user** in a terminal. Don't try to invoke them; but recognize them when the user reports errors.
249
+ Ingest, Update, Quiz-gen, Cascade, Check, Level-up semantics as before. Key change: **decide the material's `type` first, then write cards in that shape**.
581
250
 
582
- | Command | Purpose |
583
- |---|---|
584
- | `qtype check` | Validate the repo: scans for **untypable characters**, **missing/malformed frontmatter**, **over-long answers**, **index inconsistencies** (fatal) + duplicate cards / oversized / undersized decks (warnings). **Writes no files.** |
585
- | `qtype publish build` | Build the repo into a static site in `dist/`. |
586
- | `qtype publish serve` | Local server for the practice UI in the browser. Supports Chinese IME, target-WPM cursor, blind / ghost hint modes. |
587
- | `qtype publish init --ci github` | Generate a GitHub Actions workflow. |
251
+ ### Deciding `type`
588
252
 
589
- **Notes**:
253
+ - Vocabulary, terms → **word**
254
+ - Individual sentences, quotes → **sentence**
255
+ - Paragraphs, essays, poems → **article**
256
+ - Concept questions, interviews → **qa**
257
+ - Coding problems, snippets → **code**
590
258
 
591
- - After ingest / update / quiz-gen, you don't need to run these; CI runs them on commit.
592
- - User reports "check says card XXX has illegal characters" — locate the card and fix per the Check section.
593
- - User reports "publish serve won't let me practice this card" — usually A contains untypable chars or exceeds the length cap — fix via Check.
259
+ **One material, one type.** Mixed content multiple materials.
594
260
 
595
261
  ---
596
262
 
597
- ## Publish output (background only)
598
-
599
- `qtype publish build` produces roughly:
600
-
601
- ```
602
- dist/
603
- ├── index.html ← SPA shell
604
- ├── material/<slug>.html ← one shell per deck (<noscript> plain-HTML fallback embedded)
605
- ├── _app/ ← view bundle
606
- │ └── app.js + chunks/...
607
- └── _data/
608
- └── repo.json ← single data snapshot (decks / cards / metadata)
609
- ```
610
-
611
- The Web UI supports: Chinese IME input (diffs against the target after commit), three card types (`type: normal | word | sentence`), target-speed cursor, blind / ghost hints, full-width punctuation auto-normalization, space / Enter / Tab characters.
263
+ ## Rules
612
264
 
613
- **Fatal errors**: the build aborts (no files emitted) if:
265
+ ### Prohibitions
614
266
 
615
- - Any card's answer contains untypable characters.
616
- - Any card's frontmatter is missing a required field or has a wrong type.
617
- - Any deck's frontmatter is missing `title` / `language` / `tags`.
618
- - A word card is missing `phonetic` / `gloss`, or a sentence card is missing `translation`.
267
+ 1. **Never modify raw/** read-only by default
268
+ 2. **Never write untypable characters** emojis, zero-widths, control chars (except Tab & Enter)
269
+ 3. **Never write over-long answers** target text 200 chars per card; split if longer
270
+ 4. **One topic per material** no mixing
271
+ 5. **Never modify hand-edited cards** — cards containing `<!-- hand-edited -->` are read-only to the Agent
272
+ 6. **No Wikilinks**
273
+ 7. **No absolute paths**
274
+ 8. **Never `git commit` / `push`** — the user commits
275
+ 9. **No unspec'd directories** — flat `material/` + `assets/` only
276
+ 10. **Never fabricate IPA / gloss / translation** — leave blank, report in log
277
+ 11. **One `type` per material** — no mixing
278
+ 12. **No card-level frontmatter** — per-card info lives in markdown structure