learnforge 0.0.0-stage → 0.2.0

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 (464) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +21 -0
  3. package/README.md +142 -2
  4. package/demo/sample/README.md +8 -0
  5. package/demo/sample/src/backoff.ts +6 -0
  6. package/demo/sample/src/index.ts +12 -0
  7. package/demo/sample/src/queue.ts +58 -0
  8. package/demo/sample/src/worker.ts +20 -0
  9. package/dist/cli.js +3549 -0
  10. package/dist/web/assets/Map-CWWYq8VB.js +1 -0
  11. package/dist/web/assets/Practice-BrxN0TfX.js +25 -0
  12. package/dist/web/assets/_baseUniq-D3A4Knms.js +1 -0
  13. package/dist/web/assets/abap-DsBKuouk.js +1 -0
  14. package/dist/web/assets/actionscript-3-D_z4Izcz.js +1 -0
  15. package/dist/web/assets/ada-727ZlQH0.js +1 -0
  16. package/dist/web/assets/andromeeda-C3khCPGq.js +1 -0
  17. package/dist/web/assets/angular-html-LfdN0zeE.js +1 -0
  18. package/dist/web/assets/angular-ts-CKsD7JZE.js +1 -0
  19. package/dist/web/assets/apache-Dn00JSTd.js +1 -0
  20. package/dist/web/assets/apex-COJ4H7py.js +1 -0
  21. package/dist/web/assets/apl-B4CMkyY2.js +1 -0
  22. package/dist/web/assets/apl-BBq3IX1j.js +1 -0
  23. package/dist/web/assets/applescript-Bu5BbsvL.js +1 -0
  24. package/dist/web/assets/ara-7O62HKoU.js +1 -0
  25. package/dist/web/assets/architectureDiagram-UYN6MBPD-CtGxP8ms.js +36 -0
  26. package/dist/web/assets/asciiarmor-Df11BRmG.js +1 -0
  27. package/dist/web/assets/asciidoc-BPT9niGB.js +1 -0
  28. package/dist/web/assets/asm-Dhn9LcZ4.js +1 -0
  29. package/dist/web/assets/asn1-EdZsLKOL.js +1 -0
  30. package/dist/web/assets/asterisk-B-8jnY81.js +1 -0
  31. package/dist/web/assets/astro-CqkE3fuf.js +1 -0
  32. package/dist/web/assets/aurora-x-D-2ljcwZ.js +1 -0
  33. package/dist/web/assets/awk-eg146-Ew.js +1 -0
  34. package/dist/web/assets/ayu-dark-Cv9koXgw.js +1 -0
  35. package/dist/web/assets/ballerina-Du268qiB.js +1 -0
  36. package/dist/web/assets/bat-fje9CFhw.js +1 -0
  37. package/dist/web/assets/beancount-BwXTMy5W.js +1 -0
  38. package/dist/web/assets/berry-3xVqZejG.js +1 -0
  39. package/dist/web/assets/bibtex-xW4inM5L.js +1 -0
  40. package/dist/web/assets/bicep-DHo0CJ0O.js +1 -0
  41. package/dist/web/assets/blade-a8OxSdnT.js +1 -0
  42. package/dist/web/assets/blockDiagram-ZHA2E4KO-CQ2sgLCo.js +121 -0
  43. package/dist/web/assets/brainfuck-C4LP7Hcl.js +1 -0
  44. package/dist/web/assets/bsl-Dgyn0ogV.js +1 -0
  45. package/dist/web/assets/c-C3t2pwGQ.js +1 -0
  46. package/dist/web/assets/c4Diagram-6F5ED5ID-CWKXGBe-.js +10 -0
  47. package/dist/web/assets/cadence-DNquZEk8.js +1 -0
  48. package/dist/web/assets/cairo--RitsXJZ.js +1 -0
  49. package/dist/web/assets/catppuccin-frappe-CD_QflpE.js +1 -0
  50. package/dist/web/assets/catppuccin-latte-DRW-0cLl.js +1 -0
  51. package/dist/web/assets/catppuccin-macchiato-C-_shW-Y.js +1 -0
  52. package/dist/web/assets/catppuccin-mocha-LGGdnPYs.js +1 -0
  53. package/dist/web/assets/channel-Dh2DBgYr.js +1 -0
  54. package/dist/web/assets/chunk-5HRBRIJM-DFVbwlkG.js +1 -0
  55. package/dist/web/assets/chunk-7U56Z5CX-gak83OWB.js +220 -0
  56. package/dist/web/assets/chunk-ASOPGD6M-cNXbP4zQ.js +1 -0
  57. package/dist/web/assets/chunk-KFBOBJHC-yO5uhU2i.js +1 -0
  58. package/dist/web/assets/chunk-T2TOU4HS-BbXMDtlZ.js +164 -0
  59. package/dist/web/assets/chunk-TMUBEWPD-CxPE7zW_.js +1 -0
  60. package/dist/web/assets/clarity-BHOwM8T6.js +1 -0
  61. package/dist/web/assets/classDiagram-LNE6IOMH-BiiTLJy-.js +1 -0
  62. package/dist/web/assets/classDiagram-v2-MQ7JQ4JX-BiiTLJy-.js +1 -0
  63. package/dist/web/assets/clike-B9uivgTg.js +1 -0
  64. package/dist/web/assets/clojure-BMjYHr_A.js +1 -0
  65. package/dist/web/assets/clojure-DxSadP1t.js +1 -0
  66. package/dist/web/assets/clone-XVPeJFtd.js +1 -0
  67. package/dist/web/assets/cmake-BQqOBYOt.js +1 -0
  68. package/dist/web/assets/cmake-DbXoA79R.js +1 -0
  69. package/dist/web/assets/cobol-CWcv1MsR.js +1 -0
  70. package/dist/web/assets/cobol-PTqiYgYu.js +1 -0
  71. package/dist/web/assets/codeowners-Bp6g37R7.js +1 -0
  72. package/dist/web/assets/codeql-sacFqUAJ.js +1 -0
  73. package/dist/web/assets/coffee-dyiR41kL.js +1 -0
  74. package/dist/web/assets/coffeescript-S37ZYGWr.js +1 -0
  75. package/dist/web/assets/common-lisp-C7gG9l05.js +1 -0
  76. package/dist/web/assets/commonlisp-DBKNyK5s.js +1 -0
  77. package/dist/web/assets/coq-Dsg_Bt_b.js +1 -0
  78. package/dist/web/assets/cpp-BksuvNSY.js +1 -0
  79. package/dist/web/assets/crystal-DtDmRg-F.js +1 -0
  80. package/dist/web/assets/crystal-SjHAIU92.js +1 -0
  81. package/dist/web/assets/csharp-D9R-vmeu.js +1 -0
  82. package/dist/web/assets/css-BPhBrDlE.js +1 -0
  83. package/dist/web/assets/css-BnMrqG3P.js +1 -0
  84. package/dist/web/assets/csv-B0qRVHPH.js +1 -0
  85. package/dist/web/assets/cue-DtFQj3wx.js +1 -0
  86. package/dist/web/assets/cypher-C_CwsFkJ.js +1 -0
  87. package/dist/web/assets/cypher-m2LEI-9-.js +1 -0
  88. package/dist/web/assets/cytoscape.esm-DgFJg4rT.js +331 -0
  89. package/dist/web/assets/d-BoXegm-a.js +1 -0
  90. package/dist/web/assets/d-pRatUO7H.js +1 -0
  91. package/dist/web/assets/d3-scale-35hnzshu.js +1 -0
  92. package/dist/web/assets/dagre-4EVJKHTY-CBDUYbRw.js +4 -0
  93. package/dist/web/assets/dark-plus-C3mMm8J8.js +1 -0
  94. package/dist/web/assets/dart-B9wLZaAG.js +1 -0
  95. package/dist/web/assets/dax-ClGRhx96.js +1 -0
  96. package/dist/web/assets/desktop-DEIpsLCJ.js +1 -0
  97. package/dist/web/assets/diagram-QW4FP2JN-C7TmMevO.js +24 -0
  98. package/dist/web/assets/diff-BgYniUM_.js +1 -0
  99. package/dist/web/assets/diff-DbItnlRl.js +1 -0
  100. package/dist/web/assets/docker-COcR7UxN.js +1 -0
  101. package/dist/web/assets/dockerfile-BKs6k2Af.js +1 -0
  102. package/dist/web/assets/dotenv-BjQB5zDj.js +1 -0
  103. package/dist/web/assets/dracula-BzJJZx-M.js +1 -0
  104. package/dist/web/assets/dracula-soft-BXkSAIEj.js +1 -0
  105. package/dist/web/assets/dream-maker-C-nORZOA.js +1 -0
  106. package/dist/web/assets/dtd-DF_7sFjM.js +1 -0
  107. package/dist/web/assets/dylan-DwRh75JA.js +1 -0
  108. package/dist/web/assets/ebnf-CDyGwa7X.js +1 -0
  109. package/dist/web/assets/ecl-Cabwm37j.js +1 -0
  110. package/dist/web/assets/edge-D5gP-w-T.js +1 -0
  111. package/dist/web/assets/eiffel-CnydiIhH.js +1 -0
  112. package/dist/web/assets/elixir-CLiX3zqd.js +1 -0
  113. package/dist/web/assets/elm-CmHSxxaM.js +1 -0
  114. package/dist/web/assets/elm-vLlmbW-K.js +1 -0
  115. package/dist/web/assets/emacs-lisp-BX77sIaO.js +1 -0
  116. package/dist/web/assets/erDiagram-6RL3IURR-BrIhLTf-.js +51 -0
  117. package/dist/web/assets/erb-BYTLMnw6.js +1 -0
  118. package/dist/web/assets/erlang-B-DoSBHF.js +1 -0
  119. package/dist/web/assets/erlang-BNw1qcRV.js +1 -0
  120. package/dist/web/assets/everforest-dark-BgDCqdQA.js +1 -0
  121. package/dist/web/assets/everforest-light-C8M2exoo.js +1 -0
  122. package/dist/web/assets/factor-kuTfRLto.js +1 -0
  123. package/dist/web/assets/fcl-Kvtd6kyn.js +1 -0
  124. package/dist/web/assets/fennel-bCA53EVm.js +1 -0
  125. package/dist/web/assets/fish-w-ucz2PV.js +1 -0
  126. package/dist/web/assets/flowDiagram-7ASYPVHJ-xplSH1V5.js +160 -0
  127. package/dist/web/assets/fluent-Dayu4EKP.js +1 -0
  128. package/dist/web/assets/forth-Ffai-XNe.js +1 -0
  129. package/dist/web/assets/fortran-DYz_wnZ1.js +1 -0
  130. package/dist/web/assets/fortran-fixed-form-TqA4NnZg.js +1 -0
  131. package/dist/web/assets/fortran-free-form-DKXYxT9g.js +1 -0
  132. package/dist/web/assets/fsharp-XplgxFYe.js +1 -0
  133. package/dist/web/assets/ganttDiagram-NTVNEXSI-CTjkBoVW.js +257 -0
  134. package/dist/web/assets/gas-Bneqetm1.js +1 -0
  135. package/dist/web/assets/gdresource-BHYsBjWJ.js +1 -0
  136. package/dist/web/assets/gdscript-DfxzS6Rs.js +1 -0
  137. package/dist/web/assets/gdshader-SKMF96pI.js +1 -0
  138. package/dist/web/assets/genie-ajMbGru0.js +1 -0
  139. package/dist/web/assets/gherkin--30QC5Em.js +1 -0
  140. package/dist/web/assets/gherkin-heZmZLOM.js +1 -0
  141. package/dist/web/assets/git-commit-i4q6IMui.js +1 -0
  142. package/dist/web/assets/git-rebase-B-v9cOL2.js +1 -0
  143. package/dist/web/assets/gitGraph-YCYPL57B-CMCcQH9Z.js +127 -0
  144. package/dist/web/assets/gitGraphDiagram-NRZ2UAAF-I2RXCZiV.js +65 -0
  145. package/dist/web/assets/github-dark-DHJKELXO.js +1 -0
  146. package/dist/web/assets/github-dark-default-Cuk6v7N8.js +1 -0
  147. package/dist/web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
  148. package/dist/web/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
  149. package/dist/web/assets/github-light-DAi9KRSo.js +1 -0
  150. package/dist/web/assets/github-light-default-D7oLnXFd.js +1 -0
  151. package/dist/web/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
  152. package/dist/web/assets/gleam-B430Bg39.js +1 -0
  153. package/dist/web/assets/glimmer-js-D-cwc0-E.js +1 -0
  154. package/dist/web/assets/glimmer-ts-pgjy16dm.js +1 -0
  155. package/dist/web/assets/glsl-DBO2IWDn.js +1 -0
  156. package/dist/web/assets/gnuplot-CM8KxXT1.js +1 -0
  157. package/dist/web/assets/go-B1SYOhNW.js +1 -0
  158. package/dist/web/assets/graph-DfxUDGeH.js +1 -0
  159. package/dist/web/assets/graphql-cDcHW_If.js +1 -0
  160. package/dist/web/assets/groovy-D9Dt4D0W.js +1 -0
  161. package/dist/web/assets/groovy-DkBy-JyN.js +1 -0
  162. package/dist/web/assets/hack-D1yCygmZ.js +1 -0
  163. package/dist/web/assets/haml-B2EZWmdv.js +1 -0
  164. package/dist/web/assets/handlebars-BQGss363.js +1 -0
  165. package/dist/web/assets/haskell-BILxekzW.js +1 -0
  166. package/dist/web/assets/haskell-BWDZoCOh.js +1 -0
  167. package/dist/web/assets/haxe-C5wWYbrZ.js +1 -0
  168. package/dist/web/assets/haxe-H-WmDvRZ.js +1 -0
  169. package/dist/web/assets/hcl-HzYwdGDm.js +1 -0
  170. package/dist/web/assets/hjson-T-Tgc4AT.js +1 -0
  171. package/dist/web/assets/hlsl-ifBTmRxC.js +1 -0
  172. package/dist/web/assets/houston-DnULxvSX.js +1 -0
  173. package/dist/web/assets/html-C2L_23MC.js +1 -0
  174. package/dist/web/assets/html-derivative-CSfWNPLT.js +1 -0
  175. package/dist/web/assets/http-DBlCnlav.js +1 -0
  176. package/dist/web/assets/http-FRrOvY1W.js +1 -0
  177. package/dist/web/assets/hxml-TIA70rKU.js +1 -0
  178. package/dist/web/assets/hy-BMj5Y0dO.js +1 -0
  179. package/dist/web/assets/idl-BEugSyMb.js +1 -0
  180. package/dist/web/assets/imba-bv_oIlVt.js +1 -0
  181. package/dist/web/assets/index-4dQXSykb.js +1 -0
  182. package/dist/web/assets/index-BCcuEbgc.js +1 -0
  183. package/dist/web/assets/index-BN9_IkPV.js +1 -0
  184. package/dist/web/assets/index-BbAVe1TP.js +6 -0
  185. package/dist/web/assets/index-Bi0iU3Po.js +3 -0
  186. package/dist/web/assets/index-Biw9rLAa.css +1 -0
  187. package/dist/web/assets/index-BoyLgAJJ.js +13 -0
  188. package/dist/web/assets/index-BqXQJR28.js +1 -0
  189. package/dist/web/assets/index-BwoEv7R1.js +493 -0
  190. package/dist/web/assets/index-BzKIqhZn.js +1 -0
  191. package/dist/web/assets/index-C2PIUqbt.js +1 -0
  192. package/dist/web/assets/index-C7DbozeE.js +7 -0
  193. package/dist/web/assets/index-CDpPKe18.js +1 -0
  194. package/dist/web/assets/index-CTkcLj9F.js +1 -0
  195. package/dist/web/assets/index-CWD7Tiz8.js +1 -0
  196. package/dist/web/assets/index-Cm8ah4T0.js +1 -0
  197. package/dist/web/assets/index-D-vErHI8.js +1 -0
  198. package/dist/web/assets/index-D3sNRgEi.js +1 -0
  199. package/dist/web/assets/index-D91ZBf2I.js +1 -0
  200. package/dist/web/assets/index-D94n50FM.js +2 -0
  201. package/dist/web/assets/index-D9KG0kJs.js +1 -0
  202. package/dist/web/assets/index-DdahRhN3.js +1 -0
  203. package/dist/web/assets/index-Dl9E7_vZ.js +1 -0
  204. package/dist/web/assets/index-DnmHf2in.js +149 -0
  205. package/dist/web/assets/infoDiagram-A4XQUW5V-BcjfRCXi.js +2 -0
  206. package/dist/web/assets/ini-BjABl1g7.js +1 -0
  207. package/dist/web/assets/java-xI-RfyKK.js +1 -0
  208. package/dist/web/assets/javascript-qCveANmP.js +1 -0
  209. package/dist/web/assets/javascript-ySlJ1b_l.js +1 -0
  210. package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-BptiBwAt.woff2 +0 -0
  211. package/dist/web/assets/jetbrains-mono-greek-wght-normal-BW1JPxja.woff2 +0 -0
  212. package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-Com2F4yK.woff2 +0 -0
  213. package/dist/web/assets/jetbrains-mono-latin-wght-normal-Ajscav9D.woff2 +0 -0
  214. package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-By-yputv.woff2 +0 -0
  215. package/dist/web/assets/jinja-DGy0s7-h.js +1 -0
  216. package/dist/web/assets/jinja2-C4DGRd-O.js +1 -0
  217. package/dist/web/assets/jison-BqZprYcd.js +1 -0
  218. package/dist/web/assets/journeyDiagram-G5WM74LC-BrvwR6gO.js +139 -0
  219. package/dist/web/assets/json-BQoSv7ci.js +1 -0
  220. package/dist/web/assets/json5-w8dY5SsB.js +1 -0
  221. package/dist/web/assets/jsonc-TU54ms6u.js +1 -0
  222. package/dist/web/assets/jsonl-DREVFZK8.js +1 -0
  223. package/dist/web/assets/jsonnet-BfivnA6A.js +1 -0
  224. package/dist/web/assets/jssm-P4WzXJd0.js +1 -0
  225. package/dist/web/assets/jsx-BAng5TT0.js +1 -0
  226. package/dist/web/assets/julia-BBuGR-5E.js +1 -0
  227. package/dist/web/assets/julia-DuME0IfC.js +1 -0
  228. package/dist/web/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
  229. package/dist/web/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
  230. package/dist/web/assets/kanagawa-wave-DWedfzmr.js +1 -0
  231. package/dist/web/assets/kanban-definition-QRCXZQQD-Ds9WLUQu.js +88 -0
  232. package/dist/web/assets/katex-C5jXJg4s.js +257 -0
  233. package/dist/web/assets/kotlin-B5lbUyaz.js +1 -0
  234. package/dist/web/assets/kusto-mebxcVVE.js +1 -0
  235. package/dist/web/assets/laserwave-DUszq2jm.js +1 -0
  236. package/dist/web/assets/latex-C-cWTeAZ.js +1 -0
  237. package/dist/web/assets/layout-ktpd0Z4b.js +1 -0
  238. package/dist/web/assets/lean-XBlWyCtg.js +1 -0
  239. package/dist/web/assets/less-BfCpw3nA.js +1 -0
  240. package/dist/web/assets/light-plus-B7mTdjB0.js +1 -0
  241. package/dist/web/assets/liquid-D3W5UaiH.js +1 -0
  242. package/dist/web/assets/livescript-BwQOo05w.js +1 -0
  243. package/dist/web/assets/log-Cc5clBb7.js +1 -0
  244. package/dist/web/assets/logo-IuBKFhSY.js +1 -0
  245. package/dist/web/assets/lua-CvWAzNxB.js +1 -0
  246. package/dist/web/assets/lua-VAEuO923.js +1 -0
  247. package/dist/web/assets/luau-Du5NY7AG.js +1 -0
  248. package/dist/web/assets/make-Bvotw-X0.js +1 -0
  249. package/dist/web/assets/markdown-UIAJJxZW.js +1 -0
  250. package/dist/web/assets/marko-z0MBrx5-.js +1 -0
  251. package/dist/web/assets/material-theme-D5KoaKCx.js +1 -0
  252. package/dist/web/assets/material-theme-darker-BfHTSMKl.js +1 -0
  253. package/dist/web/assets/material-theme-lighter-B0m2ddpp.js +1 -0
  254. package/dist/web/assets/material-theme-ocean-CyktbL80.js +1 -0
  255. package/dist/web/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
  256. package/dist/web/assets/mathematica-DTrFuWx2.js +1 -0
  257. package/dist/web/assets/matlab-D9-PGadD.js +1 -0
  258. package/dist/web/assets/mbox-CNhZ1qSd.js +1 -0
  259. package/dist/web/assets/mdc-DB_EDNY_.js +1 -0
  260. package/dist/web/assets/mdx-sdHcTMYB.js +1 -0
  261. package/dist/web/assets/mermaid-Ci6OQyBP.js +1 -0
  262. package/dist/web/assets/mermaid.core-BGuQYGS_.js +190 -0
  263. package/dist/web/assets/min-C7naItsZ.js +1 -0
  264. package/dist/web/assets/min-dark-CafNBF8u.js +1 -0
  265. package/dist/web/assets/min-light-CTRr51gU.js +1 -0
  266. package/dist/web/assets/mindmap-definition-GWI6TPTV-BwBiBSTc.js +95 -0
  267. package/dist/web/assets/mipsasm-BC5c_5Pe.js +1 -0
  268. package/dist/web/assets/mirc-CjQqDB4T.js +1 -0
  269. package/dist/web/assets/mllike-CXdrOF99.js +1 -0
  270. package/dist/web/assets/modelica-Dc1JOy9r.js +1 -0
  271. package/dist/web/assets/mojo-Tz6hzZYG.js +1 -0
  272. package/dist/web/assets/monokai-D4h5O-jR.js +1 -0
  273. package/dist/web/assets/move-DB_GagMm.js +1 -0
  274. package/dist/web/assets/mscgen-BA5vi2Kp.js +1 -0
  275. package/dist/web/assets/mumps-BT43cFF4.js +1 -0
  276. package/dist/web/assets/narrat-DLbgOhZU.js +1 -0
  277. package/dist/web/assets/nextflow-B0XVJmRM.js +1 -0
  278. package/dist/web/assets/nginx-D_VnBJ67.js +1 -0
  279. package/dist/web/assets/nginx-DdIZxoE0.js +1 -0
  280. package/dist/web/assets/night-owl-C39BiMTA.js +1 -0
  281. package/dist/web/assets/nim-ZlGxZxc3.js +1 -0
  282. package/dist/web/assets/nix-shcSOmrb.js +1 -0
  283. package/dist/web/assets/nord-Ddv68eIx.js +1 -0
  284. package/dist/web/assets/nsis-LY0VT_u5.js +1 -0
  285. package/dist/web/assets/ntriples-BfvgReVJ.js +1 -0
  286. package/dist/web/assets/nushell-D4Tzg5kh.js +1 -0
  287. package/dist/web/assets/objective-c-Deuh7S70.js +1 -0
  288. package/dist/web/assets/objective-cpp-BUEGK8hf.js +1 -0
  289. package/dist/web/assets/ocaml-BNioltXt.js +1 -0
  290. package/dist/web/assets/octave-Ck1zUtKM.js +1 -0
  291. package/dist/web/assets/one-dark-pro-GBQ2dnAY.js +1 -0
  292. package/dist/web/assets/one-light-PoHY5YXO.js +1 -0
  293. package/dist/web/assets/oz-BzwKVEFT.js +1 -0
  294. package/dist/web/assets/pascal--L3eBynH.js +1 -0
  295. package/dist/web/assets/pascal-JqZropPD.js +1 -0
  296. package/dist/web/assets/perl-CHQXSrWU.js +1 -0
  297. package/dist/web/assets/perl-CdXCOZ3F.js +1 -0
  298. package/dist/web/assets/php-B5ebYQev.js +1 -0
  299. package/dist/web/assets/pieDiagram-YF2LJOPJ-DeXhe8wW.js +30 -0
  300. package/dist/web/assets/pig-CevX1Tat.js +1 -0
  301. package/dist/web/assets/plastic-3e1v2bzS.js +1 -0
  302. package/dist/web/assets/plsql-LKU2TuZ1.js +1 -0
  303. package/dist/web/assets/po-BFLt1xDp.js +1 -0
  304. package/dist/web/assets/poimandres-CS3Unz2-.js +1 -0
  305. package/dist/web/assets/polar-DKykz6zU.js +1 -0
  306. package/dist/web/assets/postcss-B3ZDOciz.js +1 -0
  307. package/dist/web/assets/powerquery-CSHBycmS.js +1 -0
  308. package/dist/web/assets/powershell-BIEUsx6d.js +1 -0
  309. package/dist/web/assets/powershell-CFHJl5sT.js +1 -0
  310. package/dist/web/assets/prisma-B48N-Iqd.js +1 -0
  311. package/dist/web/assets/prolog-BY-TUvya.js +1 -0
  312. package/dist/web/assets/properties-C78fOPTZ.js +1 -0
  313. package/dist/web/assets/proto-zocC4JxJ.js +1 -0
  314. package/dist/web/assets/protobuf-ChK-085T.js +1 -0
  315. package/dist/web/assets/pug-CM9l7STV.js +1 -0
  316. package/dist/web/assets/pug-DukmZTjD.js +1 -0
  317. package/dist/web/assets/puppet-Cza_XSSt.js +1 -0
  318. package/dist/web/assets/puppet-DMA9R1ak.js +1 -0
  319. package/dist/web/assets/purescript-Bg-kzb6g.js +1 -0
  320. package/dist/web/assets/python-BuPzkPfP.js +1 -0
  321. package/dist/web/assets/python-DhUJRlN_.js +1 -0
  322. package/dist/web/assets/q-pXgVlZs6.js +1 -0
  323. package/dist/web/assets/qml-D8XfuvdV.js +1 -0
  324. package/dist/web/assets/qmldir-C8lEn-DE.js +1 -0
  325. package/dist/web/assets/qss-DhMKtDLN.js +1 -0
  326. package/dist/web/assets/quadrantDiagram-OS5C2QUG-qIwp82jR.js +7 -0
  327. package/dist/web/assets/r-CwjWoCRV.js +1 -0
  328. package/dist/web/assets/r-DUYO_cvP.js +1 -0
  329. package/dist/web/assets/racket-CzouJOBO.js +1 -0
  330. package/dist/web/assets/raku-B1bQXN8T.js +1 -0
  331. package/dist/web/assets/razor-CNLDkMZG.js +1 -0
  332. package/dist/web/assets/red-bN70gL4F.js +1 -0
  333. package/dist/web/assets/reg-5LuOXUq_.js +1 -0
  334. package/dist/web/assets/regexp-DWJ3fJO_.js +1 -0
  335. package/dist/web/assets/rel-DJlmqQ1C.js +1 -0
  336. package/dist/web/assets/requirementDiagram-MIRIMTAZ-BMNoO9OJ.js +52 -0
  337. package/dist/web/assets/riscv-QhoSD0DR.js +1 -0
  338. package/dist/web/assets/rose-pine-CmCqftbK.js +1 -0
  339. package/dist/web/assets/rose-pine-dawn-Ds-gbosJ.js +1 -0
  340. package/dist/web/assets/rose-pine-moon-CjDtw9vr.js +1 -0
  341. package/dist/web/assets/rpm-CTu-6PCP.js +1 -0
  342. package/dist/web/assets/rst-4NLicBqY.js +1 -0
  343. package/dist/web/assets/ruby-BK5aLJev.js +1 -0
  344. package/dist/web/assets/ruby-DeZ3UC14.js +1 -0
  345. package/dist/web/assets/rust-Be6lgOlo.js +1 -0
  346. package/dist/web/assets/sankeyDiagram-Y46BX6SQ-BcWhv667.js +8 -0
  347. package/dist/web/assets/sas-B4kiWyti.js +1 -0
  348. package/dist/web/assets/sas-BmTFh92c.js +1 -0
  349. package/dist/web/assets/sass-BJ4Li9vH.js +1 -0
  350. package/dist/web/assets/scala-DQVVAn-B.js +1 -0
  351. package/dist/web/assets/scheme-BJGe-b2p.js +1 -0
  352. package/dist/web/assets/scheme-C41bIUwD.js +1 -0
  353. package/dist/web/assets/scss-C31hgJw-.js +1 -0
  354. package/dist/web/assets/sdbl-BLhTXw86.js +1 -0
  355. package/dist/web/assets/sequenceDiagram-G6AWOVSC-C4AgKjJQ.js +122 -0
  356. package/dist/web/assets/shaderlab-B7qAK45m.js +1 -0
  357. package/dist/web/assets/shell-CjFT_Tl9.js +1 -0
  358. package/dist/web/assets/shellscript-atvbtKCR.js +1 -0
  359. package/dist/web/assets/shellsession-C_rIy8kc.js +1 -0
  360. package/dist/web/assets/sieve-C3Gn_uJK.js +1 -0
  361. package/dist/web/assets/simple-mode-GW_nhZxv.js +1 -0
  362. package/dist/web/assets/slack-dark-BthQWCQV.js +1 -0
  363. package/dist/web/assets/slack-ochin-DqwNpetd.js +1 -0
  364. package/dist/web/assets/smalltalk-CnHTOXQT.js +1 -0
  365. package/dist/web/assets/smalltalk-DkLiglaE.js +1 -0
  366. package/dist/web/assets/snazzy-light-Bw305WKR.js +1 -0
  367. package/dist/web/assets/solarized-dark-DXbdFlpD.js +1 -0
  368. package/dist/web/assets/solarized-light-L9t79GZl.js +1 -0
  369. package/dist/web/assets/solidity-C1w2a3ep.js +1 -0
  370. package/dist/web/assets/solr-DehyRSwq.js +1 -0
  371. package/dist/web/assets/source-serif-4-cyrillic-ext-opsz-italic-Bl6DJqma.woff2 +0 -0
  372. package/dist/web/assets/source-serif-4-cyrillic-ext-opsz-normal-DIwfbPUE.woff2 +0 -0
  373. package/dist/web/assets/source-serif-4-cyrillic-opsz-italic-Dibx14aP.woff2 +0 -0
  374. package/dist/web/assets/source-serif-4-cyrillic-opsz-normal-C0olyEE-.woff2 +0 -0
  375. package/dist/web/assets/source-serif-4-greek-opsz-italic-CMW9dfKg.woff2 +0 -0
  376. package/dist/web/assets/source-serif-4-greek-opsz-normal-DrHU7SY7.woff2 +0 -0
  377. package/dist/web/assets/source-serif-4-latin-ext-opsz-italic-BhUEwDRF.woff2 +0 -0
  378. package/dist/web/assets/source-serif-4-latin-ext-opsz-normal-HoL-AExg.woff2 +0 -0
  379. package/dist/web/assets/source-serif-4-latin-opsz-italic-BOLXpvkj.woff2 +0 -0
  380. package/dist/web/assets/source-serif-4-latin-opsz-normal-BpEBLj1O.woff2 +0 -0
  381. package/dist/web/assets/source-serif-4-vietnamese-opsz-italic-C-k5pZlm.woff2 +0 -0
  382. package/dist/web/assets/source-serif-4-vietnamese-opsz-normal-BOyYyU_V.woff2 +0 -0
  383. package/dist/web/assets/soy-C-lX7w71.js +1 -0
  384. package/dist/web/assets/sparql-DkYu6x3z.js +1 -0
  385. package/dist/web/assets/sparql-bYkjHRlG.js +1 -0
  386. package/dist/web/assets/splunk-Cf8iN4DR.js +1 -0
  387. package/dist/web/assets/spreadsheet-BCZA_wO0.js +1 -0
  388. package/dist/web/assets/sql-COK4E0Yg.js +1 -0
  389. package/dist/web/assets/sql-D0XecflT.js +1 -0
  390. package/dist/web/assets/ssh-config-BknIz3MU.js +1 -0
  391. package/dist/web/assets/stata-DorPZHa4.js +1 -0
  392. package/dist/web/assets/stateDiagram-MAYHULR4-D13_SEW-.js +1 -0
  393. package/dist/web/assets/stateDiagram-v2-4JROLMXI-B54Ohb2s.js +1 -0
  394. package/dist/web/assets/stex-C3f8Ysf7.js +1 -0
  395. package/dist/web/assets/stylus-B533Al4x.js +1 -0
  396. package/dist/web/assets/stylus-BeQkCIfX.js +1 -0
  397. package/dist/web/assets/svelte-MSaWC3Je.js +1 -0
  398. package/dist/web/assets/swift-BSxZ-RaX.js +1 -0
  399. package/dist/web/assets/swift-BzpIVaGY.js +1 -0
  400. package/dist/web/assets/synthwave-84-CbfX1IO0.js +1 -0
  401. package/dist/web/assets/system-verilog-C7L56vO4.js +1 -0
  402. package/dist/web/assets/systemd-CUnW07Te.js +1 -0
  403. package/dist/web/assets/talonscript-C1XDQQGZ.js +1 -0
  404. package/dist/web/assets/tasl-CQjiPCtT.js +1 -0
  405. package/dist/web/assets/tcl-DQ1-QYvQ.js +1 -0
  406. package/dist/web/assets/tcl-DVfN8rqt.js +1 -0
  407. package/dist/web/assets/templ-dwX3ZSMB.js +1 -0
  408. package/dist/web/assets/terraform-BbSNqyBO.js +1 -0
  409. package/dist/web/assets/tex-rYs2v40G.js +1 -0
  410. package/dist/web/assets/textile-CnDTJFAw.js +1 -0
  411. package/dist/web/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  412. package/dist/web/assets/tiki-DGYXhP31.js +1 -0
  413. package/dist/web/assets/timeline-definition-U7ZMHBDA-D1EAZC5t.js +61 -0
  414. package/dist/web/assets/tokyo-night-DBQeEorK.js +1 -0
  415. package/dist/web/assets/toml-Bm5Em-hy.js +1 -0
  416. package/dist/web/assets/toml-CB2ApiWb.js +1 -0
  417. package/dist/web/assets/troff-wAsdV37c.js +1 -0
  418. package/dist/web/assets/ts-tags-CipyTH0X.js +1 -0
  419. package/dist/web/assets/tsv-B_m7g4N7.js +1 -0
  420. package/dist/web/assets/tsx-B6W0miNI.js +1 -0
  421. package/dist/web/assets/ttcn-CfJYG6tj.js +1 -0
  422. package/dist/web/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  423. package/dist/web/assets/turtle-B1tBg_DP.js +1 -0
  424. package/dist/web/assets/turtle-BMR_PYu6.js +1 -0
  425. package/dist/web/assets/twig-NC5TFiHP.js +1 -0
  426. package/dist/web/assets/typescript-Dj6nwHGl.js +1 -0
  427. package/dist/web/assets/typespec-BpWG_bgh.js +1 -0
  428. package/dist/web/assets/typst-BVUVsWT6.js +1 -0
  429. package/dist/web/assets/v-CAQ2eGtk.js +1 -0
  430. package/dist/web/assets/vala-BFOHcciG.js +1 -0
  431. package/dist/web/assets/vb-CdO5JTpU.js +1 -0
  432. package/dist/web/assets/vb-CmGdzxic.js +1 -0
  433. package/dist/web/assets/vbscript-BuJXcnF6.js +1 -0
  434. package/dist/web/assets/velocity-D8B20fx6.js +1 -0
  435. package/dist/web/assets/verilog-C6RDOZhf.js +1 -0
  436. package/dist/web/assets/verilog-CJaU5se_.js +1 -0
  437. package/dist/web/assets/vesper-BEBZ7ncR.js +1 -0
  438. package/dist/web/assets/vhdl-DYoNaHQp.js +1 -0
  439. package/dist/web/assets/vhdl-lSbBsy5d.js +1 -0
  440. package/dist/web/assets/viml-m4uW47V2.js +1 -0
  441. package/dist/web/assets/vitesse-black-Bkuqu6BP.js +1 -0
  442. package/dist/web/assets/vitesse-dark-D0r3Knsf.js +1 -0
  443. package/dist/web/assets/vitesse-light-CVO1_9PV.js +1 -0
  444. package/dist/web/assets/vue-BuYVFjOK.js +1 -0
  445. package/dist/web/assets/vue-html-xdeiXROB.js +1 -0
  446. package/dist/web/assets/vyper-nyqBNV6O.js +1 -0
  447. package/dist/web/assets/wasm-C6j12Q_x.js +1 -0
  448. package/dist/web/assets/wasm-CG6Dc4jp.js +1 -0
  449. package/dist/web/assets/webidl-ZXfAyPTL.js +1 -0
  450. package/dist/web/assets/wenyan-7A4Fjokl.js +1 -0
  451. package/dist/web/assets/wgsl-CB0Krxn9.js +1 -0
  452. package/dist/web/assets/wikitext-DCE3LsBG.js +1 -0
  453. package/dist/web/assets/wolfram-C3FkfJm5.js +1 -0
  454. package/dist/web/assets/xml-e3z08dGr.js +1 -0
  455. package/dist/web/assets/xquery-CQfU5ijd.js +1 -0
  456. package/dist/web/assets/xsl-Dd0NUgwM.js +1 -0
  457. package/dist/web/assets/xychartDiagram-6QU3TZC5-9fhTIPRM.js +7 -0
  458. package/dist/web/assets/yacas-BJ4BC0dw.js +1 -0
  459. package/dist/web/assets/yaml-CVw76BM1.js +1 -0
  460. package/dist/web/assets/z80-Hz9HOZM7.js +1 -0
  461. package/dist/web/assets/zenscript-HnGAYVZD.js +1 -0
  462. package/dist/web/assets/zig-BVz_zdnA.js +1 -0
  463. package/dist/web/index.html +22 -0
  464. package/package.json +80 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 (2026-11-10)
4
+
5
+ Learning features on top of 0.1:
6
+
7
+ - Review cards with spaced repetition (FSRS); quiz misses become cards on their own.
8
+ - Weak spots: wrong answers saved as the belief behind them; "Quiz my weak spots" aims new questions at them.
9
+ - My take first / Predict first on lenses, with a "where you differ" section.
10
+ - New lens kinds: Trace a run (step-through with variables) and History (from git log).
11
+ - Teach-back, Socratic tutor with a hint ladder, walkthrough with per-block checks, bug hunt.
12
+ - Map (import graph for TS/JS with tsconfig aliases, and Python), learning paths, glossary, margin notes.
13
+ - Today page, fading level and whole-repo heatmap in Progress, command palette (Ctrl/Cmd+K), `?` shortcuts.
14
+ - Lens freshness banner with refresh; markdown export of lenses and quizzes; JSON export of a project.
15
+ - Model replies checked against schemas with one retry; lens, walkthrough and path replies cached.
16
+ - Storage stays bounded: archive expiry, cache size cap, quiz attempt cap, capped histories, crash-file cleanup,
17
+ removed projects archived then expired; Settings > Storage with usage and "Clean up now".
18
+ - Jobs persist across restarts (capped), with a history in Settings.
19
+ - `--demo` flag: a sample repo with canned answers and temp data.
20
+
21
+ ## 0.1.0
22
+
23
+ Lenses, quizzes, practice, changes and progress over any folder. Claude Code, Codex and Copilot CLIs, or an API key.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 learnforge contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,143 @@
1
- # Temporary Holding Version
1
+ # learnforge
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Understand any codebase, and prove to yourself that you do.
4
+
5
+ AI makes code faster to write and easier to not understand. learnforge turns the model around: instead of
6
+ writing code for you, it helps you build the model of the code in your own head.
7
+
8
+ ```bash
9
+ npx learnforge ./my-repo
10
+ npx learnforge --demo # a sample repo and canned answers: see every page in a minute, no model needed
11
+ ```
12
+
13
+ | | |
14
+ |---|---|
15
+ | ![Open a folder](assets/screenshots/projects.png) | ![A lens over real code](assets/screenshots/lens.png) |
16
+ | ![The import graph](assets/screenshots/map.png) | ![Progress per file](assets/screenshots/progress.png) |
17
+
18
+ ## What it does
19
+
20
+ It is built on what makes learning stick: recall beats re-reading, spacing beats cramming, and
21
+ producing an answer before you see one beats reading the answer.
22
+
23
+ **Read, with a question**
24
+
25
+ | | |
26
+ |---|---|
27
+ | **Lenses** | See code through one question: *Explain*, *Data flow*, *State over time*, *Failure modes*, *Contracts*, *Concepts*, *The change*, *Trace a run* (a debugger without running: line by line with the variables), *History* (why it is like this, from git), or your own. Tick **My take first** to write your own guess before the lens; it opens with where you differ. On a diff, that becomes **Predict first**. A lens shows a banner when its code changes, with one-click refresh. |
28
+ | **Walkthrough** | The file in reading order (not file order), one block at a time, with a check question on each block before the next. |
29
+ | **Tutor** | A Socratic chat over the files. It answers with a question or a hint first and gives a bit more each turn; ask it to just tell you any time. Opens from any missed quiz question too. |
30
+ | **Map** | The import graph (TS/JS with tsconfig aliases, Python), sized by how many files import each one: where to start. |
31
+ | **Paths** | An ordered tour of the repo, 6-12 stops, each with the activity that fits. Stops tick off as you do them. |
32
+
33
+ **Prove it**
34
+
35
+ | | |
36
+ |---|---|
37
+ | **Quizzes** | Free-text questions about behaviour and reasons, not names. Mark each answer *sure* or *guess*. Graded with feedback that names the line and a good answer to compare with. |
38
+ | **Teach-back** | Explain the code in your own words. Graded 1-5: what you got right, what you missed, what is wrong. |
39
+ | **Practice** | The key logic is cut out of a copy of your file (4 levels). Write it back, with hints, then "check my work". |
40
+ | **Bug hunt** | Realistic bugs are planted in a copy of the file. Click the lines you suspect and say why; see found, missed and false alarms. |
41
+ | **Changes** | Two git refs, or HEAD vs your working tree. Read the diff, then predict, lens or quiz the change itself. |
42
+
43
+ **Keep it**
44
+
45
+ | | |
46
+ |---|---|
47
+ | **Review cards** | Spaced repetition (FSRS). Quiz misses become cards on their own; lens concepts and code lines can become cards in one click. |
48
+ | **Weak spots** | Wrong answers are saved as the belief behind them ("you think X, but Y"). *Quiz my weak spots* asks new questions aimed at exactly those; a right answer clears one. |
49
+ | **Today** | Each project opens on what to do now: due cards, weak spots, files that need a refresh, the next stop on your path, and one suggested 10-minute activity. |
50
+ | **Progress** | Per file: *seen*, *understood* (a check passed on the code as it is now), *fading* (no recall for a few weeks), *stale* (the code changed since). Table, or a heatmap of the whole repo. |
51
+ | **Library** | Everything made, searchable, plus a glossary built from every lens and your margin notes. Export a lens or quiz as markdown, or a whole project as JSON. |
52
+
53
+ `Ctrl/Cmd+K` jumps to any page, file or project, or starts an activity. `?` lists all shortcuts.
54
+
55
+ Context is what you pick: tick files in the tree, or add extra folders (docs, notes, design files) to a
56
+ project as context. The model reads only what you give it.
57
+
58
+ ## Model access
59
+
60
+ learnforge makes one model call per lens, quiz, grade, practice, tutor turn and so on (about 15 s to 2 min).
61
+ Replies are checked against a schema (one retry with the problems listed), and lens, walkthrough and path
62
+ replies are cached: the same lens on an unchanged file is free the second time.
63
+ It drives a coding CLI you already use, with that CLI's own login, so **learnforge never asks for or
64
+ stores a key**. Pick one in Settings; *Auto* takes the first one it finds, in this order:
65
+
66
+ | Provider | How learnforge runs it | Login |
67
+ |---|---|---|
68
+ | **Claude Code** (default) | `claude -p`, read-only tools (`Read`, `Grep`, `Glob`) | your Claude Code login |
69
+ | **OpenAI Codex** | `codex exec -`, `--sandbox read-only` | `codex login` |
70
+ | **GitHub Copilot** | `copilot -p -s`, only the `read` tool (shell and write denied) | your Copilot login, or `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` |
71
+ | **Anthropic API** | Messages API; the picked files go in the prompt | `ANTHROPIC_API_KEY` in the environment |
72
+
73
+ Each CLI runs with the project folder as its working directory. Model per provider is optional
74
+ (empty = the CLI's default). `LEARNFORGE_AGENT=fake` gives canned answers, to try the UI without a model.
75
+
76
+ ## Your files are safe
77
+
78
+ - learnforge never writes to your folders. Practice works on a copy.
79
+ - Everything it makes lives in `~/.learnforge` (change with `LEARNFORGE_HOME`), as plain JSON files, one
80
+ per item. Files, not SQLite: the data is small, you can read and back it up, and there is no native
81
+ module to build.
82
+
83
+ ```
84
+ ~/.learnforge/
85
+ settings.json projects.json jobs.json prune.json
86
+ projects/<id>/<lenses|quizzes|practice|cards|misconceptions|teachbacks|threads|walks|hunts|paths|notes>/<id>.json
87
+ projects/<id>/archive/... "Archive" moves items here
88
+ archive/projects/<id>/ a project you removed from the list
89
+ cache/<hash>.json saved model replies
90
+ ```
91
+
92
+ **It does not keep growing.** Every part that could grow has a limit (Settings > Storage shows the
93
+ sizes and has *Clean up now*):
94
+
95
+ | What | Limit (setting) |
96
+ |---|---|
97
+ | Archived items and removed projects | deleted after 30 days (`storage.archiveDays`; reopen a removed folder in time and its history comes back) |
98
+ | Model reply cache | 50 MB, least recently used goes first (`storage.cacheMB`) |
99
+ | Graded attempts per quiz | newest 20, the best one always kept (`storage.maxAttempts`) |
100
+ | Card review history, tutor messages, job history | 50 per card, 200 per chat, 100 jobs |
101
+ | Temp files left by a crash | removed after an hour |
102
+
103
+ Cleanup runs at start-up and every 6 hours, and only ever inside the learnforge folder.
104
+
105
+ - The server binds to `127.0.0.1` only. There is no login: it is a local, one-person tool.
106
+
107
+ ## CLI
108
+
109
+ ```
110
+ learnforge [folder] [--port 4711] [--host 127.0.0.1] [--no-open] [--demo]
111
+ ```
112
+
113
+ ## Develop
114
+
115
+ ```bash
116
+ npm install
117
+ npm run dev # API on :4711 (tsx watch) + Vite on :5173 with hot reload
118
+ npm test # core and API tests (vitest, fake model, temp git repos)
119
+ npm run typecheck
120
+ npm run build # dist/web (Vite) + dist/cli.js (tsup)
121
+
122
+ # Browser smoke test over every page (needs a Chromium; set CHROME or have one in ~/.cache/ms-playwright)
123
+ LEARNFORGE_HOME=$(mktemp -d) LEARNFORGE_AGENT=fake node dist/cli.js . --port 4799 --no-open &
124
+ node test/ui-smoke.mjs [--dark] [--shots DIR]
125
+ ```
126
+
127
+ Layout:
128
+
129
+ ```
130
+ src/cli.ts CLI: serves the API and the built web app
131
+ src/server/app.ts Hono routes under /api
132
+ src/core/ no HTTP here: workspace (files, git), graph (imports), store, storage (limits, cache),
133
+ prompts, schemas, services (model work), insights (cards, progress, today), jobs, agent adapters
134
+ demo/sample/ the small repo --demo opens
135
+ web/src/ React + Vite + Tailwind: pages/, components/, lib/
136
+ ```
137
+
138
+ Stack: TypeScript everywhere. Hono on Node 20+, zod, ts-fsrs. React 18, React Router, TanStack Query,
139
+ Tailwind, Shiki (code), CodeMirror (practice editor), Mermaid (diagrams), d3-force (map).
140
+
141
+ ## License
142
+
143
+ MIT
@@ -0,0 +1,8 @@
1
+ # tiny-queue
2
+
3
+ A small in-memory job queue with retries, used as the learnforge demo project.
4
+
5
+ - `src/queue.ts`: the queue (add, take, ack, fail with retry and backoff)
6
+ - `src/backoff.ts`: how long to wait before a retry
7
+ - `src/worker.ts`: runs jobs from the queue with a concurrency limit
8
+ - `src/index.ts`: wires it together
@@ -0,0 +1,6 @@
1
+ /** Wait before retry `attempt` (1-based): doubles each time, capped, with jitter so retries spread out. */
2
+ export function backoffMs(attempt: number, baseMs = 200, capMs = 10_000, random = Math.random): number {
3
+ const exp = Math.min(capMs, baseMs * 2 ** (attempt - 1));
4
+ // Full jitter: anywhere between half and all of the delay.
5
+ return Math.round(exp / 2 + random() * (exp / 2));
6
+ }
@@ -0,0 +1,12 @@
1
+ import { Queue } from "./queue.js";
2
+ import { drain } from "./worker.js";
3
+
4
+ const queue = new Queue<string>(3);
5
+ for (const url of ["a", "b", "flaky", "c"]) queue.add(url);
6
+
7
+ let flakyTries = 0;
8
+ await drain(queue, async (url) => {
9
+ if (url === "flaky" && ++flakyTries < 3) throw new Error("try again");
10
+ console.log("done", url);
11
+ });
12
+ console.log("dead letters:", queue.dead.length);
@@ -0,0 +1,58 @@
1
+ import { backoffMs } from "./backoff.js";
2
+
3
+ export interface Job<T> {
4
+ id: number;
5
+ payload: T;
6
+ attempts: number;
7
+ /** Not before this time (ms since epoch). */
8
+ runAt: number;
9
+ }
10
+
11
+ /**
12
+ * In-memory queue. take() hands out the oldest ready job and keeps it "in flight" until
13
+ * ack() or fail(). fail() puts it back with a backoff, or drops it after maxAttempts.
14
+ */
15
+ export class Queue<T> {
16
+ private ready: Job<T>[] = [];
17
+ private inFlight = new Map<number, Job<T>>();
18
+ private nextId = 1;
19
+ readonly dead: Job<T>[] = [];
20
+
21
+ constructor(private readonly maxAttempts = 3, private readonly now = () => Date.now()) {}
22
+
23
+ add(payload: T): number {
24
+ const job = { id: this.nextId++, payload, attempts: 0, runAt: this.now() };
25
+ this.ready.push(job);
26
+ return job.id;
27
+ }
28
+
29
+ take(): Job<T> | undefined {
30
+ const t = this.now();
31
+ const i = this.ready.findIndex((j) => j.runAt <= t);
32
+ if (i < 0) return undefined;
33
+ const [job] = this.ready.splice(i, 1);
34
+ job.attempts++;
35
+ this.inFlight.set(job.id, job);
36
+ return job;
37
+ }
38
+
39
+ ack(id: number): void {
40
+ this.inFlight.delete(id);
41
+ }
42
+
43
+ fail(id: number): void {
44
+ const job = this.inFlight.get(id);
45
+ if (!job) return;
46
+ this.inFlight.delete(id);
47
+ if (job.attempts >= this.maxAttempts) {
48
+ this.dead.push(job);
49
+ return;
50
+ }
51
+ job.runAt = this.now() + backoffMs(job.attempts);
52
+ this.ready.push(job);
53
+ }
54
+
55
+ get size(): number {
56
+ return this.ready.length + this.inFlight.size;
57
+ }
58
+ }
@@ -0,0 +1,20 @@
1
+ import type { Queue } from "./queue.js";
2
+
3
+ /** Pull jobs and run them, at most `concurrency` at a time, until the queue is empty. */
4
+ export async function drain<T>(queue: Queue<T>, handle: (payload: T) => Promise<void>, concurrency = 2): Promise<void> {
5
+ const running = new Set<Promise<void>>();
6
+ while (queue.size > 0) {
7
+ const job = running.size < concurrency ? queue.take() : undefined;
8
+ if (!job) {
9
+ // Nothing ready (or no free slot): wait for a running job, or a short tick for backoff.
10
+ await (running.size ? Promise.race(running) : new Promise((r) => setTimeout(r, 50)));
11
+ continue;
12
+ }
13
+ const p = handle(job.payload)
14
+ .then(() => queue.ack(job.id))
15
+ .catch(() => queue.fail(job.id))
16
+ .finally(() => running.delete(p));
17
+ running.add(p);
18
+ }
19
+ await Promise.all(running);
20
+ }