scriptorium 0.6.1 → 0.7.2

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 (358) hide show
  1. checksums.yaml +4 -4
  2. data/assets/icons/social/reddit.png +0 -0
  3. data/assets/icons/social/x-logo.png +0 -0
  4. data/assets/imagenotfound.jpg +0 -0
  5. data/bin/sblog +84 -5
  6. data/bin/scriptorium +1 -0
  7. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +0 -1
  8. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +0 -29
  9. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +0 -19
  10. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +1 -1
  11. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +1 -1
  12. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +1 -1
  13. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +0 -10
  14. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +1 -4
  15. data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
  16. data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
  17. data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
  18. data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
  19. data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
  20. data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
  21. data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
  22. data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
  23. data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
  24. data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
  25. data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
  26. data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
  27. data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
  28. data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
  29. data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
  30. data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
  31. data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
  32. data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
  33. data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
  34. data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
  35. data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
  36. data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
  37. data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
  38. data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
  39. data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
  40. data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
  41. data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
  42. data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
  43. data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
  44. data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
  45. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
  46. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
  47. data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
  48. data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
  49. data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
  50. data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
  51. data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
  52. data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
  53. data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
  54. data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
  55. data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
  56. data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
  57. data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
  58. data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
  59. data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
  60. data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
  61. data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
  62. data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
  63. data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
  64. data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
  65. data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
  66. data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
  67. data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
  68. data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
  69. data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
  70. data/doc/imported/0018-ruby-puns/post.html +46 -0
  71. data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
  72. data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
  73. data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
  74. data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
  75. data/doc/imported/0020-fffff/metadata.txt +7 -0
  76. data/doc/imported/0020-fffff/post.html +24 -0
  77. data/doc/imported/0020-fffff/source.lt3 +12 -0
  78. data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
  79. data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
  80. data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
  81. data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
  82. data/doc/imported/0023-doctor-sleep/post.html +63 -0
  83. data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
  84. data/doc/imported/0024-just-a-test/metadata.txt +7 -0
  85. data/doc/imported/0024-just-a-test/post.html +24 -0
  86. data/doc/imported/0024-just-a-test/source.lt3 +12 -0
  87. data/doc/imported/import_summary.txt +98 -0
  88. data/doc/livetext-informal-spec.txt +65 -0
  89. data/doc/myuserdoc/ch-0.lt3 +31 -0
  90. data/doc/myuserdoc/ch-1.lt3 +37 -0
  91. data/doc/myuserdoc/ch-10.lt3 +22 -0
  92. data/doc/myuserdoc/ch-2.lt3 +37 -0
  93. data/doc/myuserdoc/ch-3.lt3 +19 -0
  94. data/doc/myuserdoc/ch-4.lt3 +43 -0
  95. data/doc/myuserdoc/ch-5.lt3 +22 -0
  96. data/doc/myuserdoc/ch-6.lt3 +19 -0
  97. data/doc/myuserdoc/ch-7.lt3 +16 -0
  98. data/doc/myuserdoc/ch-8.lt3 +13 -0
  99. data/doc/myuserdoc/ch-9.lt3 +19 -0
  100. data/doc/myuserdoc/tweak.rb +18 -0
  101. data/doc/{userdoc-toc.txt → myuserdoc/userdoc-toc.txt} +27 -27
  102. data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
  103. data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
  104. data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
  105. data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
  106. data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
  107. data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
  108. data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
  109. data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
  110. data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
  111. data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
  112. data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
  113. data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
  114. data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
  115. data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
  116. data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
  117. data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
  118. data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
  119. data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
  120. data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
  121. data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
  122. data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
  123. data/doc/old-posts/0024-just-a-test.lt3 +12 -0
  124. data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
  125. data/doc/old-repo +1 -0
  126. data/doc/reddit_integration.md +2 -2
  127. data/doc/user.lt3 +0 -3
  128. data/lib/scriptorium/api.rb +1811 -78
  129. data/lib/scriptorium/banner_svg.rb +55 -68
  130. data/lib/scriptorium/contract.rb +3 -2
  131. data/lib/scriptorium/exceptions.rb +133 -102
  132. data/lib/scriptorium/helpers.rb +282 -82
  133. data/lib/scriptorium/post.rb +81 -17
  134. data/lib/scriptorium/reddit.rb +1 -1
  135. data/lib/scriptorium/repo.rb +478 -164
  136. data/lib/scriptorium/standard_files.rb +30 -396
  137. data/lib/scriptorium/support/common_js/clipboard.js +35 -0
  138. data/lib/scriptorium/support/common_js/content-loader.js +187 -0
  139. data/lib/scriptorium/support/common_js/navigation.js +52 -0
  140. data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
  141. data/lib/scriptorium/support/config/reddit_template.txt +17 -0
  142. data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/social.txt +1 -0
  143. data/lib/scriptorium/support/highlight/css.txt +2 -0
  144. data/lib/scriptorium/support/highlight/custom.css +119 -0
  145. data/lib/scriptorium/support/highlight/js.txt +1 -0
  146. data/lib/scriptorium/support/post_index/config.txt +15 -0
  147. data/lib/scriptorium/support/post_index/style.css +55 -0
  148. data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
  149. data/{test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 → lib/scriptorium/support/templates/initial_post.lt3} +5 -5
  150. data/lib/scriptorium/support/templates/post.lt3 +104 -0
  151. data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt → lib/scriptorium/support/theme/header.lt3} +1 -1
  152. data/lib/scriptorium/theme.rb +83 -70
  153. data/lib/scriptorium/version.rb +2 -2
  154. data/lib/scriptorium/view.rb +194 -149
  155. data/lib/scriptorium.rb +24 -1
  156. data/lib/skeleton.rb +4 -1
  157. data/scriptorium.gemspec +2 -1
  158. data/test/WEB_INTEGRATION_README.md +196 -0
  159. data/test/all +40 -0
  160. data/test/banner_svg/unit.rb +267 -35
  161. data/test/config/deployment.txt +5 -0
  162. data/test/integration/integration_test.rb +7 -7
  163. data/test/integration/preview_flow_test.rb +94 -0
  164. data/test/livetext_plugin_test.rb +453 -182
  165. data/test/manual/banner-tests/test01.html +82 -18
  166. data/test/manual/banner-tests/test02.html +82 -18
  167. data/test/manual/banner-tests/test03.html +82 -18
  168. data/test/manual/banner-tests/test04.html +89 -25
  169. data/test/manual/banner-tests/test05.html +89 -25
  170. data/test/manual/banner-tests/test06.html +89 -25
  171. data/test/manual/banner-tests/test07.html +89 -25
  172. data/test/manual/banner-tests/test08.html +82 -18
  173. data/test/manual/banner-tests/test09.html +82 -18
  174. data/test/manual/banner-tests/test10.html +82 -18
  175. data/test/manual/banner-tests/test11.html +82 -18
  176. data/test/manual/banner-tests/test12.html +82 -18
  177. data/test/manual/banner-tests/test13.html +82 -18
  178. data/test/manual/banner-tests/test14.html +82 -18
  179. data/test/manual/banner-tests/test15.html +82 -18
  180. data/test/manual/banner-tests/test16.html +82 -18
  181. data/test/manual/banner-tests/test17.html +82 -18
  182. data/test/manual/banner-tests/test18.html +90 -26
  183. data/test/manual/banner-tests/test19.html +90 -26
  184. data/test/manual/banner-tests/test20.html +90 -26
  185. data/test/manual/banner-tests/test21.html +90 -26
  186. data/test/manual/banner-tests/test22.html +90 -26
  187. data/test/manual/banner-tests/test23.html +90 -26
  188. data/test/manual/banner-tests/test24.html +90 -26
  189. data/test/manual/banner-tests/test25.html +89 -25
  190. data/test/manual/banner_environment.rb +15 -2
  191. data/test/manual/codemirror_demo.html +773 -0
  192. data/test/manual/create_posts_for_web.rb +114 -0
  193. data/test/manual/preview_manual_test.rb +129 -0
  194. data/test/manual/test_banner_features.rb +14 -14
  195. data/test/manual/test_banner_integration.rb +115 -0
  196. data/test/manual/test_banner_radial.rb +87 -0
  197. data/test/manual/test_syntax_highlighting.rb +60 -40
  198. data/test/support/preview_utils.rb +88 -0
  199. data/test/test_gem_assets.rb +48 -0
  200. data/test/test_helpers.rb +10 -0
  201. data/test/tui_editor_integration_test.rb +15 -15
  202. data/test/tui_integration_test.rb +687 -441
  203. data/test/unit/api.rb +757 -37
  204. data/test/unit/asset_management.rb +195 -221
  205. data/test/unit/backup_test.rb +451 -0
  206. data/test/unit/contract_test.rb +1 -23
  207. data/test/unit/core.rb +415 -61
  208. data/test/unit/deploy_config_test.rb +248 -0
  209. data/test/unit/deploy_test.rb +312 -21
  210. data/test/unit/edit_post_test.rb +168 -0
  211. data/test/unit/gem_asset_management.rb +36 -42
  212. data/test/unit/livetext_basic.rb +23 -35
  213. data/test/unit/livetext_compatibility.rb +7 -14
  214. data/test/unit/parse_cmd_test.rb +260 -0
  215. data/test/unit/{symlink_test.rb → permalink_copy_test.rb} +47 -49
  216. data/test/unit/post.rb +91 -26
  217. data/test/unit/post_index_config_test.rb +258 -0
  218. data/test/unit/post_state_helpers_test.rb +137 -0
  219. data/test/unit/read_commented_file_test.rb +8 -6
  220. data/test/unit/repo.rb +75 -54
  221. data/test/unit/social_test.rb +41 -44
  222. data/test/unit/syntax_highlighting.rb +70 -0
  223. data/test/unit/theme_management_test.rb +91 -0
  224. data/test/unit/view.rb +79 -12
  225. data/test/unit/widgets.rb +8 -8
  226. data/test/web_integration_test.rb +231 -0
  227. data/test/web_test_helper.rb +218 -0
  228. data/test/web_workflow_test.rb +527 -0
  229. data/ui/tui/bin/scriptorium +885 -415
  230. data/ui/web/app/app.rb +1398 -176
  231. data/ui/web/app/assets/livetext_mode.js +244 -0
  232. data/ui/web/app/error_helpers.rb +16 -16
  233. data/ui/web/app/views/advanced_config.erb +8 -2
  234. data/ui/web/app/views/asset_management.erb +56 -0
  235. data/ui/web/app/views/backup_management.erb +238 -0
  236. data/ui/web/app/views/config_widget.erb +232 -0
  237. data/ui/web/app/views/dashboard.erb +64 -72
  238. data/ui/web/app/views/deploy_config.erb +3 -0
  239. data/ui/web/app/views/edit_pages.erb +170 -2
  240. data/ui/web/app/views/edit_post.erb +130 -9
  241. data/ui/web/app/views/edit_theme.erb +73 -0
  242. data/ui/web/app/views/edit_theme_file.erb +74 -0
  243. data/ui/web/app/views/theme_management.erb +130 -0
  244. data/ui/web/app/views/view_dashboard.erb +666 -25
  245. data/ui/web/app/views/widgets.erb +249 -0
  246. data/ui/web/bin/scriptorium-web +35 -24
  247. data/ui/web/tmp/timing.log +17 -0
  248. data/ui/web/tmp/web_server.log +0 -5
  249. metadata +190 -116
  250. data/assets/back-icon.png +0 -0
  251. data/assets/icons/facebook.svg +0 -1
  252. data/assets/icons/github.svg +0 -1
  253. data/assets/icons/instagram.svg +0 -1
  254. data/assets/icons/reddit.svg +0 -1
  255. data/assets/icons/x.svg +0 -1
  256. data/assets/icons/youtube.svg +0 -1
  257. data/bin/scriptorium +0 -1511
  258. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +0 -34
  259. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +0 -50
  260. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +0 -73
  261. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +0 -70
  262. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +0 -110
  263. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +0 -73
  264. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +0 -124
  265. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +0 -46
  266. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +0 -97
  267. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +0 -211
  268. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +0 -141
  269. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +0 -211
  270. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +0 -134
  271. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +0 -41
  272. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +0 -49
  273. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +0 -46
  274. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +0 -41
  275. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +0 -41
  276. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +0 -256
  277. data/lib/scriptorium/syntax_highlighter.rb +0 -234
  278. data/test/manual/deploy_symlink_demo.rb +0 -142
  279. data/test/manual/symlink_demo.rb +0 -117
  280. data/test/manual/test2.rb +0 -12
  281. data/test/manual/test_banner_from_file.rb +0 -150
  282. data/test/manual/test_banner_in_header.rb +0 -35
  283. data/test/manual/test_code_highlighting.rb +0 -68
  284. data/test/manual/test_complex_header.rb +0 -74
  285. data/test/manual/test_empty_header.rb +0 -32
  286. data/test/manual/test_radial_custom.rb +0 -58
  287. data/test/manual/test_radial_large_radius.rb +0 -52
  288. data/test/manual/test_svg_debug.rb +0 -47
  289. data/test/pages-demo/config/currentview.txt +0 -1
  290. data/test/pages-demo/views/demo/config/common.js +0 -57
  291. data/test/pages-demo/views/demo/config/footer.txt +0 -1
  292. data/test/pages-demo/views/demo/config/global-head.txt +0 -8
  293. data/test/pages-demo/views/demo/config/header.txt +0 -1
  294. data/test/pages-demo/views/demo/config/layout.txt +0 -1
  295. data/test/pages-demo/views/demo/config/left.txt +0 -1
  296. data/test/pages-demo/views/demo/config/main.txt +0 -1
  297. data/test/pages-demo/views/demo/config/right.txt +0 -1
  298. data/test/pages-demo/views/demo/config.txt +0 -3
  299. data/test/pages-demo/views/demo/output/panes/footer.html +0 -1
  300. data/test/pages-demo/views/demo/output/panes/header.html +0 -1
  301. data/test/pages-demo/views/demo/output/panes/left.html +0 -1
  302. data/test/pages-demo/views/demo/output/panes/main.html +0 -1
  303. data/test/pages-demo/views/demo/output/panes/right.html +0 -1
  304. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +0 -5
  305. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +0 -4
  306. data/test/scriptorium-TEST-1754622690-146/config/common.js +0 -57
  307. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +0 -1
  308. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +0 -9
  309. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +0 -1
  310. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +0 -4
  311. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +0 -3
  312. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +0 -8
  313. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +0 -6
  314. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +0 -1
  315. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +0 -1
  316. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +0 -1
  317. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +0 -1
  318. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +0 -14
  319. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +0 -13
  320. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +0 -1
  321. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +0 -5
  322. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +0 -4
  323. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +0 -57
  324. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +0 -5
  325. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +0 -2
  326. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +0 -9
  327. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +0 -4
  328. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +0 -5
  329. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +0 -3
  330. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +0 -5
  331. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +0 -3
  332. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +0 -7
  333. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +0 -3
  334. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +0 -3
  335. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +0 -3
  336. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +0 -3
  337. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +0 -3
  338. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +0 -3
  339. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +0 -1
  340. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +0 -1
  341. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +0 -1
  342. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +0 -1
  343. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +0 -1
  344. data/ui/web/tmp/web_server.pid +0 -1
  345. /data/{test/pages-demo/views/demo/config/bootstrap_css.txt → lib/scriptorium/support/bootstrap/css.txt} +0 -0
  346. /data/{test/pages-demo/views/demo/config/bootstrap_js.txt → lib/scriptorium/support/bootstrap/js.txt} +0 -0
  347. /data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/reddit.txt +0 -0
  348. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout → lib/scriptorium/support/templates}/layout.txt +0 -0
  349. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt → lib/scriptorium/support/theme/footer.lt3} +0 -0
  350. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt → lib/scriptorium/support/theme/left.lt3} +0 -0
  351. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt → lib/scriptorium/support/theme/main.lt3} +0 -0
  352. /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt → lib/scriptorium/support/theme/right.lt3} +0 -0
  353. /data/test/manual/banner-tests/{config.txt → svg.txt} +0 -0
  354. /data/test/manual/{test6.rb → test_advanced_widgets.rb} +0 -0
  355. /data/test/manual/{test1.rb → test_basic_posts.rb} +0 -0
  356. /data/test/manual/{test4.rb → test_layout_widgets.rb} +0 -0
  357. /data/test/manual/{test5.rb → test_pagination.rb} +0 -0
  358. /data/test/manual/{test3.rb → test_random_posts.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da71d5ae85fa244b22a3d7a1ab3868eed54e00c31251cc44eedd06a9763c435c
4
- data.tar.gz: 2dd03471532a10fb6a770ac042df3c2ad773eab34dc5f7577ae485841764c802
3
+ metadata.gz: a813abb831e8491645c51b9a63776c7dc6f6a9b43f1650a03ca165b8e1bd36f5
4
+ data.tar.gz: c244c1b74da19acac42e0cc8688c408e9ca75f9521be0c5a06bd4b5496d1620a
5
5
  SHA512:
6
- metadata.gz: 3f91b41df916bb566d83b231cefc24e3ca3a848b4dfa3111a84cfa8835ab5b59148a2ce2299cbba5889a13870c020211cdbd79b0de9f35c264ee260de643aed8
7
- data.tar.gz: 9905b42d39ccf0841d29ab3aa9efe4183855147883e2cdce83346afa6b4db6b33c079fb0196578a701285eaacbb23305c401088c950350d566be6273cd5f4559
6
+ metadata.gz: f4b7bcbd38cbf68d68efa0656260593c442aa72048b40b4bd866a292501c64f89058f13032753c67347997152348c9d2e3ed863b1c0751953a0bd73030d7becc
7
+ data.tar.gz: c8f12b213efa96276f9fd99f792bf9ba6693861a7b9b217bedec196a88e258e5f4103ab22cd6f86627afb17d5063d7f30a343b8fe58768c5873b05900c0aab1b
Binary file
Binary file
Binary file
data/bin/sblog CHANGED
@@ -1,11 +1,90 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'scriptorium'
4
- require 'rubytext'
3
+ require 'optparse'
4
+ require 'fileutils'
5
5
 
6
- puts "sblog: Attempting .new"
6
+ class ScriptoriumLauncher
7
+ def initialize
8
+ @script_dir = File.dirname(__FILE__)
9
+ @project_root = File.join(@script_dir, '..')
10
+ @tui_path = File.join(@project_root, 'ui', 'tui', 'bin', 'scriptorium')
11
+ @web_path = File.join(@project_root, 'ui', 'web', 'bin', 'scriptorium-web')
12
+ end
7
13
 
8
- $blog = Scriptorium.new
14
+ def run
15
+ command = ARGV.first
9
16
 
10
- puts
17
+ case command
18
+ when nil, 'tui'
19
+ launch_tui
20
+ when 'web'
21
+ launch_web(ARGV[1..-1])
22
+ when 'help', '--help', '-h'
23
+ show_help
24
+ else
25
+ puts "Unknown command: #{command}"
26
+ puts "Run 'sblog help' for usage information"
27
+ exit 1
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def launch_tui
34
+ exec(@tui_path, *ARGV)
35
+ end
36
+
37
+ def launch_web(args)
38
+ if args.empty?
39
+ exec(@web_path, 'start')
40
+ else
41
+ exec(@web_path, *args)
42
+ end
43
+ end
44
+
45
+ def show_help
46
+ puts <<~HELP
47
+ Scriptorium - A command-line blogging system
48
+
49
+ FLAGS:
50
+ --test - Use test repository (scriptorium-TEST)
51
+ - Default: production repository (~/.scriptorium)
52
+
53
+ USAGE:
54
+ sblog # Launch TUI (default)
55
+ sblog --test # Launch TUI in test mode
56
+ sblog tui # Launch TUI explicitly
57
+ sblog tui --test # Launch TUI in test mode
58
+ sblog web # Launch web app
59
+ sblog web --test # Launch web app in test mode
60
+ sblog web start # Start web server
61
+ sblog web start --test # Start web server in test mode
62
+ sblog web stop # Stop web server
63
+ sblog web status # Check web server status
64
+ sblog help # Show this help
65
+
66
+ INTERFACES:
67
+ TUI (Text User Interface):
68
+ - Command-line interface
69
+ - Full-featured management
70
+ - Preferred for daily use
71
+ - Runs in terminal
72
+
73
+ Web:
74
+ - Browser-based interface
75
+ - Visual management tools
76
+ - Good for occasional use
77
+ - Runs in web browser
78
+
79
+ EXAMPLES:
80
+ sblog # Start TUI
81
+ sblog new post "Title" # Create new post via TUI
82
+ sblog web start # Start web server
83
+ sblog web # Open web interface
84
+ HELP
85
+ end
86
+ end
87
+
88
+ # Run the launcher
89
+ ScriptoriumLauncher.new.run
11
90
 
data/bin/scriptorium ADDED
@@ -0,0 +1 @@
1
+ /Users/Hal/Dropbox/topx/git/scriptorium/ui/tui/bin/scriptorium
@@ -52,7 +52,6 @@
52
52
 
53
53
  4. Some of my priorities are: - This must be useful, easy, flexible, and intuitive FOR ME. (It is possible no one else will ever use it.) - I believe in "convention over configuration" as DHH said. - Other mantras are: Abstract away complexity; hide unnecessary detail; take reasonable defaults; balance the tradeoff between ease of use and feature richness; wrap things as needed to simplify them; etc. - I am using a tool of my own called Livetext; more details on that later. It is a tool for processing its input format and generating arbitrary output (usually HTML in this case) as well as side effects. It has "dot" commands; includes; raw copy of files, variables and functions (both predefined and user-defined); user-defined dot commands; and a rudimentary plugin system. - I avoid Javascript when I can, and like to "hide" CSS mostly (at a high level). In output, I prefer CSS inline rather than in files (usually). - I believe that extensibilty is good in general. I believe that the 90% most common tasks should become trivial; hard things should be easy, but some very advanced things may be impossible; as in, if you want to do this sort of esoteric or arcane task, this probably isn't your tool."
54
54
 
55
- 5. Scriptorium is far less mature than Runeblog was, but is being rewritten to be FAR more sturdy and robust. The basics of the API are in place; we can create a repo, create a view, add posts to a view, modify a layout, add a "Links" widget, generate a front page. There is currently no UI, no deployment, etc. There are unit tests of about 770 assertions, as well as manual and semi-manual tests I am using Bootstrap a little (for widgets and the navbar); that is a fairly complex piece. I haven't added the navbar piece yet; that will come soon. Some next things I want to accomplish: a "convenience module" API; a TUI; a curses UI; at least two new widgets; better features in the Livetext "Scriptorium plugin"; etc. Probably will encapsulate the API soon so as to start UI development.
56
55
 
57
56
  **ASST:**
58
57
  [See above content] 2025-07-30 16:30:00 - TUI Test Refactoring Learnings
@@ -1,31 +1,2 @@
1
1
  # Anti-Amnesia: Scriptorium Conventions and Decisions
2
2
 
3
- ## Runeblog TUI Post Creation Pattern
4
- **Date**: 2025-07-27
5
- **Context**: Understanding how Runeblog handled draft-to-post conversion
6
- **Decision**: Runeblog automatically converted drafts to posts after editing, without a separate "finish draft" step. This provides a fast workflow: edit → save → post (local), with deployment making it public.
7
-
8
- ## Scriptorium Setup vs Runeblog
9
- **Date**: 2025-07-27
10
- **Context**: Comparing setup approaches between Scriptorium and Runeblog
11
- **Decision**: Runeblog had a `get_started` method that ran automatically when creating a new repository. Scriptorium should follow this pattern for better user experience.
12
-
13
- ## Editor Discovery Implementation
14
- **Date**: 2025-07-27
15
- **Context**: Implementing editor discovery for TUI setup
16
- **Decision**: Created a `which()` helper method that uses `File.which` (Ruby 3.2+) or falls back to `system("which")`. Prioritized editors for "get in, get out" single-file editing: nano, vim, emacs, vi, micro, subl, ed.
17
-
18
- ## File Operation Consistency
19
- **Date**: 2025-07-27
20
- **Context**: Ensuring consistent file operations across the project
21
- **Decision**: Replaced `File.read` calls with the project's `read_file` helper for centralized error handling. This maintains consistency with the project's file operation patterns.
22
-
23
- ## Automatic Setup Implementation
24
- **Date**: 2025-07-27
25
- **Context**: Implementing Runeblog-style automatic setup when creating new repositories
26
- **Decision**:
27
- - Removed `setup` command from TUI (no longer needed)
28
- - Modified `discover_repo` to call `create_new_repo` when no repository exists
29
- - `create_new_repo` automatically calls `get_started` after creating repository
30
- - This follows Runeblog's pattern: create repo → immediate setup → ready to use
31
- - User experience: "Create new repository?" → "Yes" → automatic editor selection → ready to blog
@@ -41,24 +41,5 @@ ruby --version # Shows ruby 3.2.3
41
41
  - **The fix is temporary** - needs to be done each time Cursor opens a new terminal
42
42
  - **Permanent fix** would be to ensure rbenv init is in shell startup files
43
43
 
44
- ### After Fix
45
- - **Ruby version**: Now correctly shows 3.2.3
46
- - **Tests can load**: livetext gem dependency resolved
47
- - **New issue discovered**: Syntax error in `temp_smart_concatenated_test.rb`
48
-
49
- ### Test Results After Fix
50
- - **Core unit tests**: ✅ All passing (82 runs, 113 assertions)
51
- - **Repo unit tests**: ✅ All passing (20 runs, 59 assertions)
52
- - **View unit tests**: ✅ All passing (25 runs, 43 assertions)
53
- - **Post unit tests**: ✅ All passing (36 runs, 45 assertions)
54
- - **Total core tests**: ✅ 163 runs, 260 assertions, 0 failures
55
-
56
- ### Remaining Issues
57
- - **test_experimental.rb**: Has duplicate method extraction causing syntax errors
58
- - **temp_smart_concatenated_test.rb**: Generated file has duplicate `test_stats_command` methods
59
- - **test/all script**: Fails due to experimental test file issues
60
-
61
44
  ### Next Steps
62
- - Fix test_experimental.rb duplicate method extraction
63
45
  - Consider permanent rbenv integration for Cursor
64
- - Run full test suite once experimental issues are resolved
@@ -37,4 +37,4 @@ I once referred to this as "digital dementia" :) are you able to assess your own
37
37
  The "digital dementia" analogy is spot-on - like human memory, AI performance can degrade with information overload, and AI is not always the best judge of its own cognitive state.
38
38
 
39
39
  ### Anti-Amnesia Value
40
- This reinforces why the anti-amnesia documentation approach is valuable - it creates persistent, reliable reference that doesn't degrade with conversation length and helps maintain consistency across sessions.
40
+ This reinforces why the anti-amnesia documentation approach is valuable - it creates persistent, reliable reference that doesn't degrade with conversation length and helps maintain consistency across sessions.
@@ -43,4 +43,4 @@ This clarification helps users understand how to capture entire messages vs. ind
43
43
 
44
44
  - Anti-amnesia interface design
45
45
  - Message capture mechanisms
46
- - User interface documentation
46
+ - User interface documentation
@@ -155,4 +155,4 @@ Potential improvements identified:
155
155
  - Python script is executable (`chmod +x scripts/reddit_autopost.py`)
156
156
  - Credentials file should be added to `.gitignore` for security
157
157
  - Integration follows existing Scriptorium patterns and conventions
158
- - Error handling matches existing exception patterns in the codebase
158
+ - Error handling matches existing exception patterns in the codebase
@@ -33,13 +33,3 @@ The assistant was unable to break out of this pattern and make actual progress.
33
33
  3. **User Intervention**: The AI should recognize when it needs to ask the user for help or a different approach
34
34
  4. **Problem Restatement**: The AI should be able to step back and restate the problem in different terms
35
35
 
36
- ## Related Bug
37
- The actual bug being investigated was:
38
- - `test_072_create_post_with_generation_default` fails because `post.published` is being set to a timestamp during generation
39
- - The assistant identified that `write_post_metadata` writes ALL `post.*` keys from the `vars` hash
40
- - But the assistant could not determine where `post.published` was being set to a timestamp in the `vars` hash
41
-
42
- ## Status
43
- - **Loop Issue**: Documented for future reference
44
- - **Original Bug**: Still unsolved
45
- - **User Response**: User correctly identified the loop and requested documentation
@@ -23,8 +23,5 @@ Renamed the file to use the correct current timestamp:
23
23
  - Use `date +%Y%m%d-%H%M%S` format for consistent timestamping
24
24
  - Verify timestamp accuracy before creating files
25
25
 
26
- ## Files Modified
27
- - `doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md` - Renamed with correct timestamp
28
-
29
26
  ## Key Takeaway
30
- Always use current timestamps when creating anti-amnesia files to maintain accurate chronological order and prevent confusion.
27
+ Always use current timestamps when creating anti-amnesia files to maintain accurate chronological order and prevent confusion.
@@ -0,0 +1,172 @@
1
+ # CodeMirror Integration and Web Test Framework
2
+
3
+ **Date**: 2024-12-19 16:00:00
4
+
5
+ ## CodeMirror Integration
6
+
7
+ ### Overview
8
+ Integrated CodeMirror code editor into the web interface for enhanced post and page editing with LiveText syntax highlighting.
9
+
10
+ ### Files Created/Modified
11
+
12
+ #### `test/manual/codemirror_demo.html`
13
+ - Standalone HTML demo showcasing CodeMirror with custom LiveText syntax highlighting
14
+ - Includes macro toolbar with buttons for common editing tasks
15
+ - Demonstrates LiveText-specific syntax rules (non-terminating markers, bracketed formatting, etc.)
16
+ - Features responsive SVG banner generation and theme switching
17
+
18
+ #### `ui/web/app/assets/livetext_mode.js`
19
+ - Custom CodeMirror mode definition for LiveText syntax
20
+ - Handles LiveText-specific constructs:
21
+ - Variables (`$foo`, `$foo.bar`) - stops at invalid characters
22
+ - Functions (`$$max`, `$$link:param`, `$$index[param]`)
23
+ - Markers (`*`, `_`, `` ` ``, `~`) - non-terminating, space/comma/period terminated
24
+ - Bracketed formatting (`*[bold text]`)
25
+ - Dot commands (`.h1`, `.list`, `.banner`, etc.)
26
+ - Block structures:
27
+ - `.raw`...`__RAW__` (plain text)
28
+ - `.comment`...`.end` (plain text)
29
+ - `.def`/`.func`...`.end` (Ruby code)
30
+ - `.code ruby`/`elixir`/`bash`...`.end` (language-specific highlighting)
31
+
32
+ #### `ui/web/app/views/edit_post.erb`
33
+ - Integrated CodeMirror for post editing
34
+ - Replaces textarea with enhanced editor
35
+ - Includes LiveText syntax highlighting
36
+ - Form submission syncs CodeMirror content back to hidden textarea
37
+
38
+ #### `ui/web/app/views/edit_pages.erb`
39
+ - Integrated CodeMirror for page editing
40
+ - Similar functionality to edit_post.erb
41
+ - Button-triggered save with explicit content syncing
42
+
43
+ #### `ui/web/app/app.rb`
44
+ - Added `/web_assets/*` route to serve CodeMirror assets
45
+ - Fixed post creation workflow to redirect to edit page
46
+ - Enhanced error handling and debugging
47
+
48
+ ### Key Features
49
+ - **Syntax Highlighting**: Custom LiveText mode with accurate tokenization
50
+ - **Macro System**: Toolbar buttons for common editing tasks
51
+ - **Responsive Design**: Adapts to different screen sizes
52
+ - **Theme Support**: Light/dark mode switching
53
+ - **Content Syncing**: Seamless integration with existing form submission
54
+
55
+ ## Web Test Framework
56
+
57
+ ### Overview
58
+ Comprehensive automated testing framework for web interface functionality, covering complete user workflows.
59
+
60
+ ### Files Created
61
+
62
+ #### `test/web_test_helper.rb`
63
+ - Shared helper module for web integration tests
64
+ - Provides methods for:
65
+ - Starting/stopping web server
66
+ - Making HTTP requests (GET, POST)
67
+ - Asserting response types (success, redirect)
68
+ - Managing test repository
69
+ - Silent operation (no debug output)
70
+
71
+ #### `test/web_integration_test.rb`
72
+ - Basic web integration tests
73
+ - Verifies core functionality and test mode
74
+ - Tests repository creation, view management, basic navigation
75
+
76
+ #### `test/web_workflow_test.rb`
77
+ - Comprehensive workflow tests covering:
78
+ - **Post Creation**: Create post via web interface, verify redirect to edit page
79
+ - **Post Editing**: Edit post content, save, verify file content matches
80
+ - **Publish/Unpublish**: Toggle post status, verify API response and HTML display
81
+ - **Delete/Restore**: Delete post (strikethrough), restore (normal display)
82
+ - **Asset Management**: Upload and manage assets
83
+ - **View Configuration**: Configure view settings
84
+ - **Deployment**: Deploy configuration workflow
85
+ - **Error Handling**: Edge cases and error conditions
86
+
87
+ #### `test/web_test_mode_simple_test.rb`
88
+ - Simple test to verify web app test mode functionality
89
+ - Uses curl-based verification of test repository usage
90
+
91
+ ### Test Coverage
92
+
93
+ #### API Level Testing
94
+ - HTTP status codes (200, 302, 303, 404, 500)
95
+ - JSON response validation
96
+ - Redirect behavior verification
97
+ - Error handling and edge cases
98
+
99
+ #### UI Level Testing
100
+ - HTML content verification
101
+ - Visual state changes (published/unpublished status)
102
+ - Strikethrough styling for deleted posts
103
+ - Form submission and content persistence
104
+
105
+ #### Workflow Testing
106
+ - Complete user journeys from start to finish
107
+ - Cross-page navigation and state persistence
108
+ - File system verification (actual file content)
109
+ - Database/metadata verification
110
+
111
+ ### Key Features
112
+ - **Fully Automated**: No manual intervention required
113
+ - **Silent Operation**: No debug output, only errors shown
114
+ - **Comprehensive Coverage**: Tests both API and UI layers
115
+ - **Real File Verification**: Checks actual file content, not just responses
116
+ - **Test Mode Support**: Uses separate test repository (`ui/web/scriptorium-TEST`)
117
+ - **Parallel Safe**: Each test creates fresh test environment
118
+
119
+ ### Integration
120
+ - Added to `test/all` for inclusion in full test suite
121
+ - Follows existing project testing patterns (Minitest)
122
+ - Uses same helper patterns as TUI integration tests
123
+ - Maintains consistency with project coding standards
124
+
125
+ ## Benefits
126
+
127
+ ### CodeMirror Integration
128
+ - Enhanced editing experience with syntax highlighting
129
+ - Reduced editing errors through visual feedback
130
+ - Familiar code editor interface for users
131
+ - Extensible macro system for common tasks
132
+
133
+ ### Web Test Framework
134
+ - Catches regressions in web interface functionality
135
+ - Verifies complete user workflows, not just individual components
136
+ - Provides confidence in web interface reliability
137
+ - Enables safe refactoring and feature additions
138
+ - Documents expected behavior through test cases
139
+
140
+ ## Usage
141
+
142
+ ### Running Web Tests
143
+ ```bash
144
+ # Run all web tests
145
+ ruby test/web_workflow_test.rb
146
+ ruby test/web_integration_test.rb
147
+
148
+ # Run specific test
149
+ ruby test/web_workflow_test.rb -n test_004_post_editing_workflow
150
+
151
+ # Run as part of full test suite
152
+ ruby test/all
153
+ ```
154
+
155
+ ### CodeMirror Demo
156
+ Open `test/manual/codemirror_demo.html` in browser to see LiveText syntax highlighting and macro functionality.
157
+
158
+ ## Technical Notes
159
+
160
+ ### LiveText Syntax Rules
161
+ - Markers are non-terminating (unlike Markdown)
162
+ - Single vs. double markers differ only in termination (space vs. comma/period)
163
+ - Bracketed formatting allows multi-word formatting
164
+ - Variables and functions have specific naming rules
165
+ - Block structures have different body processing rules
166
+
167
+ ### Test Architecture
168
+ - Uses `WebTestHelper` module for shared functionality
169
+ - Each test creates fresh test environment
170
+ - Tests verify both API responses and HTML content
171
+ - File system verification ensures actual persistence
172
+ - Silent operation focuses on genuine errors only
@@ -0,0 +1,126 @@
1
+ # Backup/Restore System Implementation
2
+
3
+ ## Overview
4
+ Implemented a comprehensive backup and restore system for Scriptorium repositories with full/incremental backups, hybrid restore strategies, and 30-day retention.
5
+
6
+ ## Architecture
7
+
8
+ ### Storage Structure
9
+ ```
10
+ repo/backups/
11
+ ├── manifest.txt # Backup registry
12
+ └── data/ # Backup content
13
+ ├── 20250902-120000-full/
14
+ ├── 20250902-130000-incr/
15
+ └── 20250902-140000-incr/
16
+ ```
17
+
18
+ ### Manifest Format
19
+ ```
20
+ 20250902-120000-full Initial full backup
21
+ 20250902-130000-incr Added new post
22
+ 20250902-140000-incr Updated existing post
23
+ ```
24
+
25
+ ### Flat File Structure
26
+ Each backup directory contains files with full relative paths:
27
+ ```
28
+ data/20250902-120000-full/
29
+ ├── posts/0001/source.lt3
30
+ ├── posts/0001/meta.txt
31
+ ├── views/sample/config.txt
32
+ └── config/repo.txt
33
+ ```
34
+
35
+ ## Core Features
36
+
37
+ ### Backup Types
38
+ - **Full Backup**: Complete repository snapshot
39
+ - **Incremental Backup**: Only changed files since last backup
40
+
41
+ ### Change Detection
42
+ - Uses `File.mtime` to identify modified files
43
+ - 1-second sleep before backup creation ensures distinct timestamps
44
+ - Compares file modification times against last backup timestamp
45
+
46
+ ### Restore Strategies
47
+ - **`:safe`** (default): Creates pre-restore backup, then restores
48
+ - **`:merge`**: Overlays backup content on existing files
49
+ - **`:destroy`**: Clears repository and restores from backup
50
+
51
+ ### Dependency Management
52
+ - Always preserves most recent full backup (30-day retention)
53
+ - Restore finds most recent full backup before target
54
+ - Applies all subsequent incremental backups up to target
55
+ - Handles missing dependencies gracefully
56
+
57
+ ## API Methods
58
+
59
+ ### `create_backup(type: :full|:incr, description: nil)`
60
+ - Creates timestamped backup directory
61
+ - Records entry in manifest.txt
62
+ - Handles both full and incremental backups
63
+
64
+ ### `list_backups()`
65
+ - Returns array of backup info: `{timestamp, type, description}`
66
+ - Parses manifest.txt entries
67
+
68
+ ### `restore_backup(timestamp, strategy: :safe)`
69
+ - Implements hybrid restore strategies
70
+ - Finds dependency chain (full + incrementals)
71
+ - Preserves existing files in merge mode
72
+
73
+ ### `delete_backup(timestamp)`
74
+ - Removes backup directory and manifest entry
75
+ - Enforces retention policy (keeps most recent full)
76
+
77
+ ## Key Implementation Details
78
+
79
+ ### Timestamp Precision
80
+ - Uses `Time.now.strftime("%Y%m%d-%H%M%S")` for directory names
81
+ - 1-second sleep before backup creation prevents sub-second conflicts
82
+ - Temporary directory creation + rename ensures atomic operations
83
+
84
+ ### Error Handling
85
+ - Contract system validation (enabled in tests)
86
+ - Graceful handling of missing dependencies
87
+ - Clear error messages for invalid operations
88
+
89
+ ### Test Coverage
90
+ - 16 comprehensive tests covering all scenarios
91
+ - Tests for full/incremental backups, restore strategies, edge cases
92
+ - 100% pass rate with proper contract system integration
93
+
94
+ ## Usage Examples
95
+
96
+ ```ruby
97
+ # Create full backup
98
+ api.create_backup(type: :full, description: "Before major changes")
99
+
100
+ # Create incremental backup
101
+ api.create_backup(type: :incr, description: "Added new post")
102
+
103
+ # List available backups
104
+ backups = api.list_backups
105
+
106
+ # Restore with safe strategy (default)
107
+ api.restore_backup("20250902-120000-full")
108
+
109
+ # Restore with merge strategy
110
+ api.restore_backup("20250902-130000-incr", strategy: :merge)
111
+
112
+ # Delete old backup
113
+ api.delete_backup("20250902-120000-full")
114
+ ```
115
+
116
+ ## Files Modified
117
+ - `lib/scriptorium/api.rb`: Core backup/restore implementation
118
+ - `test/unit/backup_test.rb`: Comprehensive test suite
119
+ - `test/all`: Added backup tests to full test suite
120
+
121
+ ## Status
122
+ ✅ **Complete and Production Ready**
123
+ - All 16 tests passing
124
+ - Full test suite integration
125
+ - Comprehensive error handling
126
+ - 30-day retention policy implemented
@@ -0,0 +1,66 @@
1
+ # Backup Metadata Implementation - 2025-09-07 20:33:39
2
+
3
+ ## Overview
4
+ Added per-backup metadata storage to track version information and backup statistics for better debugging, compatibility checking, and audit trails.
5
+
6
+ ## Changes Made
7
+
8
+ ### 1. Backup Location Change
9
+ - **Changed backup storage location** from `repo/backups/` to `backup-scriptorium/` (parallel to repo)
10
+ - **Test repositories** use `backup-scriptorium-TEST/`
11
+ - **Updated `get_backup_directory()` method** to handle both production and test environments
12
+ - **Made method public** (was private) to allow direct access without `api.send()`
13
+
14
+ ### 2. Per-Backup Metadata File
15
+ - **Added `backup-info.txt`** to each backup directory (both full and incremental)
16
+ - **Contains essential metadata**:
17
+ - Scriptorium version (from `Scriptorium::VERSION`)
18
+ - LiveText version (from `livetext -v` command)
19
+ - Ruby version (from `RUBY_VERSION`)
20
+ - Backup type (full/incremental)
21
+ - Backup name (timestamp-type)
22
+ - Repository path (which repo was backed up)
23
+ - File count (number of files backed up)
24
+ - Total size (backup size in bytes)
25
+ - Platform (OS and Ruby engine)
26
+ - Git commit (first 8 characters, if available)
27
+
28
+ ### 3. Implementation Details
29
+ - **`create_backup_info()` method** - Creates the metadata file
30
+ - **`get_livetext_version()` method** - Gets LiveText version via command line
31
+ - **`get_git_commit_hash()` method** - Gets git commit hash if available
32
+ - **`count_files_in_backup()` method** - Counts files in backup directory
33
+ - **`calculate_directory_size()` method** - Calculates total backup size
34
+ - **Called after backup creation** but before final directory rename
35
+
36
+ ### 4. Test Updates
37
+ - **Added backup info file assertions** to both full and incremental backup tests
38
+ - **Verifies file existence** and content validation
39
+ - **All 16 backup tests pass** with new functionality
40
+
41
+ ## Benefits
42
+ - **Restore validation** - Check compatibility before restoring
43
+ - **Debugging** - Know exactly what versions were used
44
+ - **Migration help** - Understand what needs updating
45
+ - **Audit trail** - Track backup environment over time
46
+ - **Better error diagnosis** - Version mismatch detection
47
+
48
+ ## Files Modified
49
+ - `lib/scriptorium/api.rb` - Added backup metadata functionality
50
+ - `test/unit/backup_test.rb` - Added backup info file tests
51
+
52
+ ## Example Backup Info File
53
+ ```
54
+ # Scriptorium Backup Information
55
+ # Generated: 2025-09-07 20:32:33
56
+ scriptorium_version: 0.6.1
57
+ livetext_version: 0.9.60
58
+ ruby_version: 3.2.3
59
+ backup_type: full
60
+ backup_name: 20250907-203233-full
61
+ repository_path: test/scriptorium-TEST
62
+ file_count: 110
63
+ total_size: 138338
64
+ platform: x86_64-darwin22 ruby
65
+ git_commit: 3b5bcc67
66
+ ```
@@ -0,0 +1,7 @@
1
+ num 0001
2
+ title Elixir Conf 2014
3
+ date 2014-07-29
4
+ pubdate 2014-07-29
5
+ views computing austin
6
+ tags
7
+ pinned
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Elixir Conf 2014</title>
6
+ <meta name="generator" content="Scriptorium Import">
7
+ <meta property="og:title" content="Elixir Conf 2014">
8
+ <meta property="og:locale" content="en_US">
9
+ <meta property="og:type" content="article">
10
+ <meta property="article:published_time" content="2014-07-29">
11
+ </head>
12
+ <body>
13
+ <article>
14
+ <header>
15
+ <h1>Elixir Conf 2014</h1>
16
+ <time datetime="2014-07-29">July 29, 2014</time>
17
+ </header>
18
+
19
+ <div class="content">
20
+ <p>
21
+ Last week in Austin, I attended the world's first Elixir conference. It was very
22
+ energizing!
23
+ With only 105 people attending, the vibe was that of a Ruby conference 10 or more
24
+ years ago. Jose Valim, the language creator, was there; two Erlang heavyweights
25
+ were also in attendance -- Robert Virding and Francesco Cesarini.
26
+
27
+ <p>
28
+ There were many Rubyists there, of course, but I will only mention myself, Dave
29
+ Thomas, and Jim Freeze. The three of us were also at the first Ruby conference
30
+ in 2001.
31
+
32
+ <p>
33
+ This will be an exciting ride. I'll keep you informed.
34
+ </div>
35
+ </article>
36
+ </body>
37
+ </html>
@@ -0,0 +1,22 @@
1
+ .h1 Elixir Conf 2014
2
+
3
+ .set post.num = 0001
4
+ .set post.slug = elixir-conf-2014
5
+ .set post.date = 2014-07-29
6
+ .set post.title = Elixir Conf 2014
7
+ .set post.tags =
8
+ .set post.views = computing austin
9
+ .set post.published = yes
10
+ .set post.deployed = no
11
+
12
+ Last week in Austin, I attended the world's first Elixir conference. It was very
13
+ energizing!
14
+ With only 105 people attending, the vibe was that of a Ruby conference 10 or more
15
+ years ago. Jose Valim, the language creator, was there; two Erlang heavyweights
16
+ were also in attendance -- Robert Virding and Francesco Cesarini.
17
+
18
+ There were many Rubyists there, of course, but I will only mention myself, Dave
19
+ Thomas, and Jim Freeze. The three of us were also at the first Ruby conference
20
+ in 2001.
21
+
22
+ This will be an exciting ride. I'll keep you informed.