unaltraweb 0.3.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 (444) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/Makefile +412 -0
  4. data/README.md +226 -0
  5. data/_config.yml +842 -0
  6. data/_data/i18n/ca.yml +278 -0
  7. data/_data/i18n/en.yml +278 -0
  8. data/_data/i18n/es.yml +278 -0
  9. data/_includes/audio.liquid +30 -0
  10. data/_includes/bib_search.liquid +5 -0
  11. data/_includes/blog-list.liquid +66 -0
  12. data/_includes/book-citation.liquid +33 -0
  13. data/_includes/citation.liquid +26 -0
  14. data/_includes/custom_head.liquid +3 -0
  15. data/_includes/custom_scripts.liquid +5 -0
  16. data/_includes/cv/list.liquid +5 -0
  17. data/_includes/cv/list_groups.liquid +51 -0
  18. data/_includes/cv/map.liquid +29 -0
  19. data/_includes/cv/nested_list.liquid +16 -0
  20. data/_includes/cv/time_table.liquid +118 -0
  21. data/_includes/cv-download-card.liquid +26 -0
  22. data/_includes/developer-mode-switcher.liquid +24 -0
  23. data/_includes/disqus.liquid +13 -0
  24. data/_includes/distill_scripts.liquid +298 -0
  25. data/_includes/documentation-download-detail.liquid +76 -0
  26. data/_includes/documentation-downloads.liquid +71 -0
  27. data/_includes/documentation-profile-attributes.liquid +4 -0
  28. data/_includes/documentation-section-toc.liquid +9 -0
  29. data/_includes/documentation-sidebar.liquid +112 -0
  30. data/_includes/figure.liquid +87 -0
  31. data/_includes/footer.liquid +66 -0
  32. data/_includes/giscus.liquid +25 -0
  33. data/_includes/head.liquid +220 -0
  34. data/_includes/header.liquid +544 -0
  35. data/_includes/latest_posts.liquid +61 -0
  36. data/_includes/localized-date.liquid +5 -0
  37. data/_includes/manual-bibliography.liquid +2 -0
  38. data/_includes/manual-featured-readings.liquid +12 -0
  39. data/_includes/manual-other-readings.liquid +12 -0
  40. data/_includes/manual-page-toc.liquid +11 -0
  41. data/_includes/manual-sidebar.liquid +58 -0
  42. data/_includes/manual-teachers.liquid +74 -0
  43. data/_includes/metadata.liquid +278 -0
  44. data/_includes/news.liquid +48 -0
  45. data/_includes/newsletter.liquid +68 -0
  46. data/_includes/page-hero.liquid +96 -0
  47. data/_includes/page-link.liquid +8 -0
  48. data/_includes/pagination.liquid +22 -0
  49. data/_includes/post-reading-time.liquid +29 -0
  50. data/_includes/previous-next.liquid +37 -0
  51. data/_includes/profile-card.liquid +49 -0
  52. data/_includes/profile-feature-matrix.liquid +75 -0
  53. data/_includes/profile-highlights.liquid +122 -0
  54. data/_includes/project-grid.liquid +26 -0
  55. data/_includes/project-resource-link.liquid +45 -0
  56. data/_includes/project-resources.liquid +21 -0
  57. data/_includes/projects.liquid +38 -0
  58. data/_includes/projects_horizontal.liquid +37 -0
  59. data/_includes/publications-metrics-summary.liquid +69 -0
  60. data/_includes/publications-summary.liquid +127 -0
  61. data/_includes/reading-biblio-controls.liquid +65 -0
  62. data/_includes/reading-cover-card.liquid +93 -0
  63. data/_includes/reading-rating.liquid +11 -0
  64. data/_includes/recommended-readings.liquid +30 -0
  65. data/_includes/related_posts.liquid +39 -0
  66. data/_includes/repository/repo.liquid +48 -0
  67. data/_includes/repository/repo_trophies.liquid +44 -0
  68. data/_includes/repository/repo_user.liquid +35 -0
  69. data/_includes/resume/awards.liquid +19 -0
  70. data/_includes/resume/basics.liquid +28 -0
  71. data/_includes/resume/certificates.liquid +35 -0
  72. data/_includes/resume/education.liquid +54 -0
  73. data/_includes/resume/interests.liquid +34 -0
  74. data/_includes/resume/languages.liquid +31 -0
  75. data/_includes/resume/projects.liquid +32 -0
  76. data/_includes/resume/publications.liquid +28 -0
  77. data/_includes/resume/references.liquid +31 -0
  78. data/_includes/resume/skills.liquid +33 -0
  79. data/_includes/resume/volunteer.liquid +52 -0
  80. data/_includes/resume/work.liquid +52 -0
  81. data/_includes/scripts.liquid +364 -0
  82. data/_includes/search-data.js.liquid +341 -0
  83. data/_includes/selected_papers.liquid +3 -0
  84. data/_includes/t.liquid +31 -0
  85. data/_includes/team-grid.liquid +172 -0
  86. data/_includes/video.liquid +97 -0
  87. data/_layouts/about.liquid +93 -0
  88. data/_layouts/archive.liquid +45 -0
  89. data/_layouts/bib.liquid +677 -0
  90. data/_layouts/book-review.liquid +225 -0
  91. data/_layouts/book-shelf.liquid +66 -0
  92. data/_layouts/cv.liquid +127 -0
  93. data/_layouts/default.liquid +70 -0
  94. data/_layouts/distill.liquid +132 -0
  95. data/_layouts/documentation-download-detail.liquid +5 -0
  96. data/_layouts/documentation-home.liquid +100 -0
  97. data/_layouts/documentation-page.liquid +45 -0
  98. data/_layouts/manual-bib.liquid +73 -0
  99. data/_layouts/manual-chapter.liquid +99 -0
  100. data/_layouts/manual-featured-bib.liquid +100 -0
  101. data/_layouts/manual-home.liquid +120 -0
  102. data/_layouts/none.liquid +1 -0
  103. data/_layouts/outputs.liquid +29 -0
  104. data/_layouts/page.liquid +52 -0
  105. data/_layouts/post.liquid +95 -0
  106. data/_layouts/profile.liquid +36 -0
  107. data/_layouts/profiles.liquid +36 -0
  108. data/_layouts/project.liquid +7 -0
  109. data/_layouts/repositories.liquid +58 -0
  110. data/_layouts/theses.liquid +126 -0
  111. data/_plugins/bibliography_profiles.rb +164 -0
  112. data/_plugins/callouts.rb +104 -0
  113. data/_plugins/code_blocks.rb +277 -0
  114. data/_plugins/computation_figure_images.rb +266 -0
  115. data/_plugins/computation_sources.rb +42 -0
  116. data/_plugins/content_search_index.rb +210 -0
  117. data/_plugins/details.rb +23 -0
  118. data/_plugins/external-posts.rb +124 -0
  119. data/_plugins/figure_captions.rb +800 -0
  120. data/_plugins/file-exists.rb +22 -0
  121. data/_plugins/google-scholar-citations.rb +86 -0
  122. data/_plugins/hide-custom-bibtex.rb +18 -0
  123. data/_plugins/inspirehep-citations.rb +57 -0
  124. data/_plugins/localized_visual_sources.rb +145 -0
  125. data/_plugins/manual_release_metadata.rb +47 -0
  126. data/_plugins/mermaid_mmd_images.rb +233 -0
  127. data/_plugins/profile-pages.rb +28 -0
  128. data/_plugins/remove-accents.rb +32 -0
  129. data/_plugins/reproducible_build_time.rb +55 -0
  130. data/_plugins/search-data.rb +83 -0
  131. data/_plugins/theme-cache-bust.rb +56 -0
  132. data/_plugins/vega_visual_images.rb +290 -0
  133. data/_plugins/web_capture_images.rb +154 -0
  134. data/_sass/_base.scss +2133 -0
  135. data/_sass/_blog.scss +67 -0
  136. data/_sass/_callouts.scss +100 -0
  137. data/_sass/_custom.scss +437 -0
  138. data/_sass/_cv.scss +274 -0
  139. data/_sass/_developer.scss +97 -0
  140. data/_sass/_distill.scss +185 -0
  141. data/_sass/_documentation.scss +2220 -0
  142. data/_sass/_layout.scss +218 -0
  143. data/_sass/_manual.scss +2691 -0
  144. data/_sass/_profile.scss +323 -0
  145. data/_sass/_projects.scss +163 -0
  146. data/_sass/_reading.scss +465 -0
  147. data/_sass/_site-custom.scss +3 -0
  148. data/_sass/_tabs.scss +48 -0
  149. data/_sass/_team.scss +230 -0
  150. data/_sass/_themes.scss +254 -0
  151. data/_sass/_typograms.scss +132 -0
  152. data/_sass/_variables.scss +52 -0
  153. data/_sass/font-awesome/_animated.scss +152 -0
  154. data/_sass/font-awesome/_bordered-pulled.scss +20 -0
  155. data/_sass/font-awesome/_core.scss +49 -0
  156. data/_sass/font-awesome/_fixed-width.scss +7 -0
  157. data/_sass/font-awesome/_functions.scss +57 -0
  158. data/_sass/font-awesome/_icons.scss +13 -0
  159. data/_sass/font-awesome/_list.scss +18 -0
  160. data/_sass/font-awesome/_mixins.scss +65 -0
  161. data/_sass/font-awesome/_rotated-flipped.scss +31 -0
  162. data/_sass/font-awesome/_screen-reader.scss +14 -0
  163. data/_sass/font-awesome/_shims.scss +1578 -0
  164. data/_sass/font-awesome/_sizing.scss +16 -0
  165. data/_sass/font-awesome/_stacked.scss +32 -0
  166. data/_sass/font-awesome/_variables.scss +5044 -0
  167. data/_sass/font-awesome/brands.scss +30 -0
  168. data/_sass/font-awesome/fontawesome.scss +21 -0
  169. data/_sass/font-awesome/regular.scss +27 -0
  170. data/_sass/font-awesome/solid.scss +27 -0
  171. data/_sass/font-awesome/v4-shims.scss +11 -0
  172. data/_sass/tabler-icons/tabler-icons-filled.scss +1646 -0
  173. data/_sass/tabler-icons/tabler-icons-outline.scss +9859 -0
  174. data/_sass/tabler-icons/tabler-icons.scss +11463 -0
  175. data/_scripts/cronitor-analytics-setup.js +9 -0
  176. data/_scripts/giscus-setup.js +48 -0
  177. data/_scripts/google-analytics-setup.js +9 -0
  178. data/_scripts/open-panel-analytics-setup.js +14 -0
  179. data/_scripts/photoswipe-setup.js +11 -0
  180. data/assets/audio/epicaly-short-113909.mp3 +0 -0
  181. data/assets/bibliography/2018-12-22-distill.bib +7 -0
  182. data/assets/css/academicons.min.css +1 -0
  183. data/assets/css/bootstrap-toc.min.css +4 -0
  184. data/assets/css/bootstrap.min.css +7 -0
  185. data/assets/css/bootstrap.min.css.map +1 -0
  186. data/assets/css/jekyll-pygments-themes-github.css +209 -0
  187. data/assets/css/jekyll-pygments-themes-native.css +232 -0
  188. data/assets/css/jupyter-grade3.css +3758 -0
  189. data/assets/css/jupyter-monokai.css +3758 -0
  190. data/assets/css/jupyter.css +383 -0
  191. data/assets/css/main.scss +36 -0
  192. data/assets/css/mdb.min.css +48 -0
  193. data/assets/css/mdb.min.css.map +1 -0
  194. data/assets/css/scholar-icons.css +386 -0
  195. data/assets/fonts/academicons.ttf +0 -0
  196. data/assets/fonts/academicons.woff +0 -0
  197. data/assets/fonts/scholar-icons.ttf +0 -0
  198. data/assets/fonts/scholar-icons.woff +0 -0
  199. data/assets/fonts/tabler-icons-filled.ttf +0 -0
  200. data/assets/fonts/tabler-icons-filled.woff +0 -0
  201. data/assets/fonts/tabler-icons-filled.woff2 +0 -0
  202. data/assets/fonts/tabler-icons-outline.ttf +0 -0
  203. data/assets/fonts/tabler-icons-outline.woff +0 -0
  204. data/assets/fonts/tabler-icons-outline.woff2 +0 -0
  205. data/assets/fonts/tabler-icons.ttf +0 -0
  206. data/assets/fonts/tabler-icons.woff +0 -0
  207. data/assets/fonts/tabler-icons.woff2 +0 -0
  208. data/assets/html/relativity.html +15 -0
  209. data/assets/img/1.jpg +0 -0
  210. data/assets/img/10.jpg +0 -0
  211. data/assets/img/11.jpg +0 -0
  212. data/assets/img/12.jpg +0 -0
  213. data/assets/img/2.jpg +0 -0
  214. data/assets/img/3.jpg +0 -0
  215. data/assets/img/4.jpg +0 -0
  216. data/assets/img/5.jpg +0 -0
  217. data/assets/img/6.jpg +0 -0
  218. data/assets/img/7.jpg +0 -0
  219. data/assets/img/8.jpg +0 -0
  220. data/assets/img/9.jpg +0 -0
  221. data/assets/img/book_covers/the_godfather.jpg +0 -0
  222. data/assets/img/brand/dosquartsdedocs-logo-cafe.svg +31 -0
  223. data/assets/img/brand/dosquartsdedocs-logo-footer-cafe.svg +31 -0
  224. data/assets/img/brand/dosquartsdedocs-logo-white.svg +31 -0
  225. data/assets/img/brand/dosquartsdedocs-logo.svg +31 -0
  226. data/assets/img/prof_pic.jpg +0 -0
  227. data/assets/img/prof_pic_color.png +0 -0
  228. data/assets/img/profile-placeholder.svg +8 -0
  229. data/assets/img/publication_preview/brownian-motion.gif +0 -0
  230. data/assets/img/publication_preview/goodchild1992-gis-cover.jpg +0 -0
  231. data/assets/img/publication_preview/gutierrez2020-jtrg-preview.jpg +0 -0
  232. data/assets/img/publication_preview/harvey1989-postmodernity-cover.jpg +0 -0
  233. data/assets/img/publication_preview/tobler1970-economic-geography-cover.jpg +0 -0
  234. data/assets/img/publication_preview/tuan1977-space-place-cover.jpg +0 -0
  235. data/assets/img/publication_preview/wave-mechanics.gif +0 -0
  236. data/assets/img/publication_preview/zaragozi2025-rooftop-pv-preview.jpg +0 -0
  237. data/assets/img/rhino.png +0 -0
  238. data/assets/img/team/aaron-gutierrez.png +0 -0
  239. data/assets/img/team/alba-font.png +0 -0
  240. data/assets/img/team/alba-viana.png +0 -0
  241. data/assets/img/team/alejandro-gonzalez.png +0 -0
  242. data/assets/img/team/ana-pastor.png +0 -0
  243. data/assets/img/team/antoni-domenech.png +0 -0
  244. data/assets/img/team/benito-zaragozi.png +0 -0
  245. data/assets/img/team/cinta-sanz.png +0 -0
  246. data/assets/img/team/daniel-miravet.png +0 -0
  247. data/assets/img/team/eugenia-altamirano.png +0 -0
  248. data/assets/img/team/fiammetta-brandajs.png +0 -0
  249. data/assets/img/team/francesc-gonzalez.png +0 -0
  250. data/assets/img/team/isabel-paulino.png +0 -0
  251. data/assets/img/team/joan-borras.png +0 -0
  252. data/assets/img/team/julie-wilson.png +0 -0
  253. data/assets/img/team/liliana-sole.png +0 -0
  254. data/assets/img/team/maria-casado.png +0 -0
  255. data/assets/img/team/maria-medina.png +0 -0
  256. data/assets/img/team/marta-nello.png +0 -0
  257. data/assets/img/team/mogrify +1 -0
  258. data/assets/img/team/oscar-saladie.png +0 -0
  259. data/assets/img/team/paolo-russo.png +0 -0
  260. data/assets/img/team/raquel-santos.png +0 -0
  261. data/assets/img/team/salvador-anton.png +0 -0
  262. data/assets/img/team/sunsi-huertas.png +0 -0
  263. data/assets/img/team/user-placeholder.png +0 -0
  264. data/assets/img/team/wilbert-den-hoed.png +0 -0
  265. data/assets/img/team/xavier-delclos.png +0 -0
  266. data/assets/img/template_error.png +0 -0
  267. data/assets/js/bibsearch.js +70 -0
  268. data/assets/js/bootstrap-toc.min.js +5 -0
  269. data/assets/js/bootstrap.bundle.min.js +7 -0
  270. data/assets/js/bootstrap.bundle.min.js.map +1 -0
  271. data/assets/js/callouts.js +115 -0
  272. data/assets/js/chartjs-setup.js +14 -0
  273. data/assets/js/common.js +117 -0
  274. data/assets/js/content-search-match.js +159 -0
  275. data/assets/js/content-search.js +441 -0
  276. data/assets/js/copy_code.js +60 -0
  277. data/assets/js/custom.js +6 -0
  278. data/assets/js/developer-mode.js +103 -0
  279. data/assets/js/diff2html-setup.js +20 -0
  280. data/assets/js/distillpub/overrides.js +27 -0
  281. data/assets/js/distillpub/template.v2.js +9616 -0
  282. data/assets/js/distillpub/template.v2.js.map +1 -0
  283. data/assets/js/distillpub/transforms.v2.js +14557 -0
  284. data/assets/js/distillpub/transforms.v2.js.map +1 -0
  285. data/assets/js/documentation.js +435 -0
  286. data/assets/js/echarts-setup.js +29 -0
  287. data/assets/js/highlight-search-term.js +110 -0
  288. data/assets/js/jupyter_new_tab.js +18 -0
  289. data/assets/js/leaflet-setup.js +22 -0
  290. data/assets/js/manual.js +308 -0
  291. data/assets/js/masonry.js +12 -0
  292. data/assets/js/mathjax-setup.js +46 -0
  293. data/assets/js/mermaid-setup.js +37 -0
  294. data/assets/js/newsletter.js +105 -0
  295. data/assets/js/no_defer.js +24 -0
  296. data/assets/js/plotly-setup.js +52 -0
  297. data/assets/js/profile-nav.js +92 -0
  298. data/assets/js/progress-bar.js +73 -0
  299. data/assets/js/pseudocode-setup.js +18 -0
  300. data/assets/js/search/base-styles.min.js +286 -0
  301. data/assets/js/search/command-score.min.js +7 -0
  302. data/assets/js/search/hotkeys-js/hotkeys.esm.min.js +18 -0
  303. data/assets/js/search/lit/decorators.min.js +7 -0
  304. data/assets/js/search/lit/directives/class-map.min.js +7 -0
  305. data/assets/js/search/lit/directives/join.min.js +7 -0
  306. data/assets/js/search/lit/directives/live.min.js +7 -0
  307. data/assets/js/search/lit/directives/ref.min.js +7 -0
  308. data/assets/js/search/lit/directives/repeat.min.js +7 -0
  309. data/assets/js/search/lit/directives/unsafe-html.min.js +7 -0
  310. data/assets/js/search/lit/index.min.js +7 -0
  311. data/assets/js/search/lit-element/lit-element.min.js +12 -0
  312. data/assets/js/search/lit-html/directives/class-map.min.js +22 -0
  313. data/assets/js/search/lit-html/directives/join.min.js +12 -0
  314. data/assets/js/search/lit-html/directives/live.min.js +28 -0
  315. data/assets/js/search/lit-html/directives/ref.min.js +32 -0
  316. data/assets/js/search/lit-html/directives/repeat.min.js +27 -0
  317. data/assets/js/search/lit-html/directives/unsafe-html.min.js +22 -0
  318. data/assets/js/search/lit-html/is-server.min.js +12 -0
  319. data/assets/js/search/lit-html/lit-html.min.js +12 -0
  320. data/assets/js/search/ninja-action.min.js +101 -0
  321. data/assets/js/search/ninja-footer.min.js +62 -0
  322. data/assets/js/search/ninja-header.min.js +78 -0
  323. data/assets/js/search/ninja-keys.min.js +39 -0
  324. data/assets/js/search/reactive-element/decorators/custom-element.min.js +12 -0
  325. data/assets/js/search/reactive-element/decorators/event-options.min.js +12 -0
  326. data/assets/js/search/reactive-element/decorators/property.min.js +22 -0
  327. data/assets/js/search/reactive-element/decorators/query-all.min.js +17 -0
  328. data/assets/js/search/reactive-element/decorators/query-assigned-elements.min.js +17 -0
  329. data/assets/js/search/reactive-element/decorators/query-assigned-nodes.min.js +17 -0
  330. data/assets/js/search/reactive-element/decorators/query-async.min.js +17 -0
  331. data/assets/js/search/reactive-element/decorators/query.min.js +17 -0
  332. data/assets/js/search/reactive-element/decorators/state.min.js +27 -0
  333. data/assets/js/search/reactive-element/reactive-element.min.js +17 -0
  334. data/assets/js/search-setup.js +17 -0
  335. data/assets/js/shortcut-key.js +11 -0
  336. data/assets/js/tabs.min.js +5 -0
  337. data/assets/js/theme.js +314 -0
  338. data/assets/js/tooltips-setup.js +3 -0
  339. data/assets/js/typograms.js +1341 -0
  340. data/assets/js/vanilla-back-to-top.min.js +1 -0
  341. data/assets/js/vega-setup.js +24 -0
  342. data/assets/js/venobox-setup.js +5 -0
  343. data/assets/js/wechat.js +14 -0
  344. data/assets/js/zoom.js +15 -0
  345. data/assets/json/resume.json +98 -0
  346. data/assets/json/table_data.json +128 -0
  347. data/assets/jupyter/blog.ipynb +48 -0
  348. data/assets/pdf/example_pdf.pdf +0 -0
  349. data/assets/plotly/demo.html +72 -0
  350. data/assets/video/pexels-engin-akyurt-6069112-960x540-30fps.mp4 +0 -0
  351. data/assets/webfonts/fa-brands-400.ttf +0 -0
  352. data/assets/webfonts/fa-brands-400.woff2 +0 -0
  353. data/assets/webfonts/fa-regular-400.ttf +0 -0
  354. data/assets/webfonts/fa-regular-400.woff2 +0 -0
  355. data/assets/webfonts/fa-solid-900.ttf +0 -0
  356. data/assets/webfonts/fa-solid-900.woff2 +0 -0
  357. data/assets/webfonts/fa-v4compatibility.ttf +0 -0
  358. data/assets/webfonts/fa-v4compatibility.woff2 +0 -0
  359. data/docs/Gemfile +5 -0
  360. data/docs/_config.yml +83 -0
  361. data/docs/_documentation/en/01-quick-start.md +115 -0
  362. data/docs/_documentation/en/02-tools.md +146 -0
  363. data/docs/_documentation/en/03-usage.md +107 -0
  364. data/docs/_documentation/en/04-jekyll-basics.md +51 -0
  365. data/docs/_documentation/en/05-pages-collections.md +68 -0
  366. data/docs/_documentation/en/06-github-web-editing.md +92 -0
  367. data/docs/_documentation/en/10-profiles.md +125 -0
  368. data/docs/_documentation/en/11-unaltreselfie.md +39 -0
  369. data/docs/_documentation/en/12-unaltreprojecte.md +38 -0
  370. data/docs/_documentation/en/13-unaltremanual.md +237 -0
  371. data/docs/_documentation/en/14-unaltredocs.md +92 -0
  372. data/docs/_documentation/en/15-profile-checklist.md +39 -0
  373. data/docs/_documentation/en/20-syntax.md +353 -0
  374. data/docs/_documentation/en/21-themes.md +103 -0
  375. data/docs/_documentation/en/22-feature-reference.md +56 -0
  376. data/docs/_documentation/en/23-front-matter.md +51 -0
  377. data/docs/_documentation/en/24-data-files.md +28 -0
  378. data/docs/_documentation/en/30-customization.md +448 -0
  379. data/docs/_documentation/en/31-template.md +55 -0
  380. data/docs/_documentation/en/32-development.md +108 -0
  381. data/docs/_documentation/en/33-reusable-workflows.md +136 -0
  382. data/docs/_documentation/en/40-distribution.md +164 -0
  383. data/docs/_documentation/en/41-bibliometrics.md +137 -0
  384. data/docs/_documentation/en/42-docker-image.md +185 -0
  385. data/docs/_documentation/en/50-faq.md +33 -0
  386. data/docs/_pages/ca/index.md +35 -0
  387. data/docs/_pages/en/index.md +35 -0
  388. data/docs/_pages/es/index.md +35 -0
  389. data/docs/agents/action-prompts/00-start-site-session.txt +10 -0
  390. data/docs/agents/action-prompts/05-create-new-web.txt +5 -0
  391. data/docs/agents/action-prompts/10-content-update.txt +9 -0
  392. data/docs/agents/action-prompts/15-edit-default-content.txt +8 -0
  393. data/docs/agents/action-prompts/20-manual-teaching-materials.txt +18 -0
  394. data/docs/agents/action-prompts/22-manual-style-audit.txt +14 -0
  395. data/docs/agents/action-prompts/23-manual-structure-audit.txt +17 -0
  396. data/docs/agents/action-prompts/25-translation-prepublish.txt +8 -0
  397. data/docs/agents/action-prompts/30-project-site-update.txt +7 -0
  398. data/docs/agents/action-prompts/40-documentation-update.txt +7 -0
  399. data/docs/agents/action-prompts/50-bibliography-entry.txt +7 -0
  400. data/docs/agents/action-prompts/60-bibliometrics-refresh.txt +7 -0
  401. data/docs/agents/action-prompts/70-build-and-review.txt +12 -0
  402. data/docs/agents/manual-authoring-components.md +255 -0
  403. data/docs/agents/mcp-contract.md +162 -0
  404. data/docs/agents/quarto-computation-adoption.md +102 -0
  405. data/docs/assets/img/unaltraweb-docs-hero.svg +36 -0
  406. data/lib/unaltraweb/version.rb +8 -0
  407. data/lib/unaltraweb.rb +31 -0
  408. data/requirements.txt +5 -0
  409. data/scripts/biblio/fetch_scimago_csv.sh +126 -0
  410. data/scripts/biblio/metrics_common.py +154 -0
  411. data/scripts/biblio/metrics_merge_meta.py +73 -0
  412. data/scripts/biblio/metrics_update.py +826 -0
  413. data/scripts/computations/python/Dockerfile +37 -0
  414. data/scripts/computations/r/Dockerfile +31 -0
  415. data/scripts/computations/render.py +1267 -0
  416. data/scripts/cv/render_pdf_preview.sh +36 -0
  417. data/scripts/deploy/publish_branch.sh +80 -0
  418. data/scripts/generate_logo_variants.py +47 -0
  419. data/scripts/manual/Dockerfile +31 -0
  420. data/scripts/manual/build_pdf.py +1780 -0
  421. data/scripts/manual/filters/bibliography.lua +164 -0
  422. data/scripts/manual/filters/code-blocks.lua +102 -0
  423. data/scripts/manual/filters/figure-captions.lua +35 -0
  424. data/scripts/manual/publish_release.sh +281 -0
  425. data/scripts/manual/templates/manual.tex +494 -0
  426. data/scripts/manual/verify_release_assets.py +650 -0
  427. data/scripts/test_gem_build.py +128 -0
  428. data/scripts/test_reproducible_jekyll_build.py +191 -0
  429. data/scripts/test_wheel_install.py +282 -0
  430. data/scripts/unaltraweb-docker-mount.sh +36 -0
  431. data/scripts/unaltraweb-mcp-bootstrap.sh +105 -0
  432. data/scripts/unaltraweb-mcp-cleanup.sh +73 -0
  433. data/scripts/unaltraweb-mcp-project-id.sh +34 -0
  434. data/scripts/validate_distribution.py +563 -0
  435. data/scripts/validate_workflows.py +1285 -0
  436. data/scripts/web_captures/Dockerfile +31 -0
  437. data/scripts/web_captures/capture.mjs +157 -0
  438. data/scripts/web_captures/package-lock.json +56 -0
  439. data/scripts/web_captures/package.json +9 -0
  440. data/scripts/web_captures/render.py +867 -0
  441. data/src/unaltraweb_mcp/component-contract.json +153 -0
  442. data/src/unaltraweb_mcp/component-contract.schema.json +87 -0
  443. data/src/unaltraweb_mcp/docker_mount.py +19 -0
  444. metadata +861 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8881f6168982bd26668967e8c6d5baa8b7a02cb3bc6427edf7fdd89169fd8e36
4
+ data.tar.gz: 47457791441af3403defd6e99e621ebde05ada5e5adb50f80ce141db3a80e72c
5
+ SHA512:
6
+ metadata.gz: b870af22e7562818aa3b1a3c45911daaf273cd34ca9f523e05fb995f71f62c44f8222cc9d3457e420683c563c0d675ea6869165d8d6df0100058e4b7d07e9f27
7
+ data.tar.gz: 6c50e56046cb84a0ea06e7690177be1709265a5f4d5422c3605ab600e45ff5926ec776b1c28b8a3b7d27a01b8503c513d3d74f24608514e34a8fc5746b17472b
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Maruan Al-Shedivat.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,412 @@
1
+ PYTHON ?= python3
2
+ override PROJECT := $${MCP_CONSUMER_WORKSPACE:?MCP_CONSUMER_WORKSPACE is required}
3
+ override PROJECT_ROOT := $(PROJECT)
4
+ MCP_RUNTIME_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.3.0
5
+ MCP_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-mcp:0.3.0
6
+ MCP_DOCKER_BUILD_NETWORK ?= default
7
+ INIT_SITE_PROFILE ?= unaltreselfie
8
+ NEW_WEB_PROFILE ?= unaltreselfie
9
+ SITE_PROFILE ?=
10
+ SITE_TITLE ?=
11
+ BASEURL ?=
12
+ URL ?=
13
+ DEFAULT_LANG ?=
14
+ LANGUAGES ?=
15
+ METRICS_ARGS ?=
16
+ SCIMAGO_INPUT ?=
17
+ COMPUTE_PYTHON_IMAGE ?=
18
+ COMPUTE_R_IMAGE ?=
19
+ COMPUTE_SOURCE ?=
20
+ COMPUTE_CONFIRM_OVERWRITE ?= 0
21
+ COMPUTE_STALE_ONLY ?= 0
22
+ COMPUTE_MODE ?=
23
+ COMPUTE_SCRIPT := $(CURDIR)/scripts/computations/render.py
24
+ DOCKER_MOUNT_SCRIPT := $(CURDIR)/scripts/unaltraweb-docker-mount.sh
25
+ COMPUTE_PYTHON_LOCAL_IMAGE ?= unaltraweb-compute-python:dev
26
+ COMPUTE_R_LOCAL_IMAGE ?= unaltraweb-compute-r:dev
27
+ COMPUTE_DOCKER_BUILD_NETWORK ?= default
28
+ COMPUTE_CPUS ?= 4
29
+ COMPUTE_MEMORY ?= 8g
30
+ COMPUTE_PIDS_LIMIT ?= 512
31
+ RSTUDIO_PORT ?= 8787
32
+ WEB_CAPTURE_SOURCE ?=
33
+ WEB_CAPTURE_BASE_URL ?=
34
+ WEB_CAPTURE_DOCKER_NETWORK ?=
35
+ WEB_CAPTURE_SERVICE_HOST ?=
36
+ WEB_CAPTURE_CONFIRM_OVERWRITE ?= 0
37
+ WEB_CAPTURE_SCRIPT := $(CURDIR)/scripts/web_captures/render.py
38
+ WEB_CAPTURE_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-web-capture:0.3.0
39
+ WEB_CAPTURE_DEV_IMAGE ?= unaltraweb-web-capture:dev
40
+ WEB_CAPTURE_DOCKER_BUILD_NETWORK ?= default
41
+ VEGAVISUALS_CLI ?=
42
+ DOCKER_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb:0.3.0
43
+ MANUAL_PDF_IMAGE ?= ghcr.io/dosquartsdedocs/unaltraweb-manual-pdf:0.3.0
44
+ MANUAL_PDF_DEV_IMAGE ?= unaltraweb-manual-pdf:dev
45
+ MANUAL_PDF_LANG ?=
46
+ MANUAL_PDF_PUBLISH_DRY_RUN ?= 1
47
+ MANUAL_RELEASE_SELECTOR ?= latest
48
+ MANUAL_RELEASE_DRY_RUN ?= 1
49
+ MANUAL_RELEASE_CONFIRM_PREPARE ?= 0
50
+ override MANUAL_RELEASE_SELECTOR := $(value MANUAL_RELEASE_SELECTOR)
51
+ override MANUAL_RELEASE_DRY_RUN := $(value MANUAL_RELEASE_DRY_RUN)
52
+ override MANUAL_RELEASE_CONFIRM_PREPARE := $(value MANUAL_RELEASE_CONFIRM_PREPARE)
53
+ export MANUAL_RELEASE_SELECTOR
54
+ UNALTRAWEB_WORKER_ROLE ?=
55
+ UNALTRAWEB_WORKER_PROJECT ?=
56
+ UNALTRAWEB_WORKER_TOKEN ?=
57
+ WORKER_LABEL_ARGS = $(if $(strip $(UNALTRAWEB_WORKER_TOKEN)),--label "io.context.mcp-factory=unaltraweb" --label "io.context.mcp-role=$(UNALTRAWEB_WORKER_ROLE)" --label "io.context.mcp-project=$(UNALTRAWEB_WORKER_PROJECT)" --label "io.context.mcp-worker-token=$(UNALTRAWEB_WORKER_TOKEN)",)
58
+ DOCS_CONTAINER ?= unaltraweb-docs-local
59
+ DOCS_HOST ?= 0.0.0.0
60
+ DOCS_PORT ?= 4000
61
+ PUBLISH_REMOTE ?= origin
62
+ PUBLISH_BRANCH ?= gh-pages
63
+ PUBLISH_SOURCE ?= tmp/docs-site
64
+ PUBLISH_WORKTREE ?= tmp/publish-$(PUBLISH_BRANCH)
65
+ PUBLISH_DRY_RUN ?= 0
66
+ LOCAL_UID ?= $(shell id -u)
67
+ LOCAL_GID ?= $(shell id -g)
68
+
69
+ ifneq ($(filter mcp-stdio,$(MAKECMDGOALS)),)
70
+ ifneq ($(origin MCP_CONSUMER_WORKSPACE),environment)
71
+ ifneq ($(origin MCP_CONSUMER_WORKSPACE),environment override)
72
+ $(error MCP_CONSUMER_WORKSPACE must be inherited through the process environment)
73
+ endif
74
+ endif
75
+ endif
76
+
77
+ SCIMAGO_ARGS :=
78
+ ifneq ($(strip $(SCIMAGO_INPUT)),)
79
+ SCIMAGO_ARGS += --input "$(SCIMAGO_INPUT)"
80
+ endif
81
+
82
+ .PHONY: distribution-check distribution-release-check distribution-doctor workflow-check wheel-check gem-check reproducible-site-check docs-build docs-serve docs-publish docs-down metrics-scimago-fetch metrics-update metrics-update-all metrics-check manual-pdf-image manual-pdf-image-dev manual-pdf-preflight manual-pdf-status manual-pdf-check manual-pdf-build manual-pdf-publish manual-pdf-sync manual-release-status manual-release-check manual-release-prepare manual-compute-status manual-compute-check manual-compute-render manual-compute-render-figures manual-compute-image-python manual-compute-image-r manual-compute-images manual-compute-rstudio compute-base-image-python compute-base-image-r web-capture-status web-capture-check web-capture-render web-capture-image visualization-status visualization-check visualization-render
83
+ .PHONY: mcp-runtime-image mcp-image mcp-build mcp-check mcp-smoke mcp-smoke-prebuilt mcp-stdio mcp-down mcp-down-all mcp-list-tools mcp-starter-templates mcp-new-web mcp-initialize-site mcp-site-context mcp-profile-check mcp-manual-source-quality-check mcp-manual-editorial-quality-check mcp-manual-authoring-capabilities mcp-manual-computation-status mcp-manual-computation-check mcp-manual-computation-render mcp-manual-computation-render-figures mcp-web-capture-status mcp-web-capture-check mcp-web-capture-render mcp-manual-pdf-status mcp-manual-pdf-build mcp-manual-pdf-publish mcp-manual-release-status mcp-manual-release-check mcp-manual-release-prepare mcp-profile-prune-plan mcp-profile-prune mcp-content-inventory mcp-language-policy mcp-content-approval-inventory mcp-translation-plan mcp-bibliography-inventory mcp-bibliometrics-check mcp-build-health
84
+
85
+ REPOSITORY_CONTEXT_TARGETS := distribution-doctor manual-compute-status manual-compute-check manual-compute-render manual-compute-render-figures manual-compute-image-python manual-compute-image-r manual-compute-images manual-compute-rstudio web-capture-status web-capture-check web-capture-render visualization-status visualization-check visualization-render manual-pdf-preflight manual-pdf-status manual-pdf-check manual-pdf-build manual-pdf-publish manual-pdf-sync manual-release-status manual-release-check manual-release-prepare metrics-scimago-fetch metrics-update metrics-update-all metrics-check
86
+ $(REPOSITORY_CONTEXT_TARGETS): override PROJECT = $${MCP_CONSUMER_WORKSPACE:-$$PWD}
87
+ $(REPOSITORY_CONTEXT_TARGETS): override PROJECT_ROOT = $${MCP_CONSUMER_WORKSPACE:-$$PWD}
88
+
89
+ distribution-check: ## Validate component/version parity, release selections, and the wheel boundary
90
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) scripts/validate_distribution.py
91
+
92
+ distribution-release-check: ## Require every selected component to be ready for coordinated publication
93
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) scripts/validate_distribution.py --require-release-ready
94
+
95
+ distribution-doctor: ## Inspect the selected distribution and PROJECT without network access
96
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli doctor --project "$(PROJECT)"
97
+
98
+ workflow-check: ## Validate GitHub Actions syntax and publication safety gates
99
+ @$(PYTHON) scripts/validate_workflows.py
100
+
101
+ wheel-check: ## Build and exercise a clean factory-free wheel install
102
+ @$(PYTHON) scripts/test_wheel_install.py
103
+
104
+ gem-check: ## Build the gem and verify its package-owned contract files
105
+ @$(PYTHON) scripts/test_gem_build.py
106
+
107
+ reproducible-site-check: ## Build the same fixed-epoch Jekyll fixture twice and compare every output
108
+ @DOCKER_IMAGE="$(DOCKER_IMAGE)" $(PYTHON) scripts/test_reproducible_jekyll_build.py
109
+
110
+ mcp-runtime-image: ## Build the reusable Jekyll runtime used by the MCP
111
+ docker build --network "$(MCP_DOCKER_BUILD_NETWORK)" -t "$(MCP_RUNTIME_IMAGE)" .
112
+
113
+ mcp-image: mcp-runtime-image ## Build the Dockerized FastMCP control plane
114
+ docker build --network "$(MCP_DOCKER_BUILD_NETWORK)" --build-arg "UNALTRAWEB_RUNTIME_IMAGE=$(MCP_RUNTIME_IMAGE)" -t "$(MCP_IMAGE)" -f Dockerfile.mcp .
115
+
116
+ mcp-build: mcp-image ## Prepare the Docker images used by MCP sessions, builds, and previews
117
+
118
+ mcp-check: mcp-image ## Verify the Dockerized MCP CLI contract
119
+ docker run --rm --entrypoint unaltraweb-mcp "$(MCP_IMAGE)" version
120
+
121
+ mcp-smoke: mcp-build ## Build and prove a real MCP stdio connection
122
+ @$(MAKE) --silent --no-print-directory mcp-smoke-prebuilt MCP_IMAGE="$(MCP_IMAGE)"
123
+
124
+ mcp-smoke-prebuilt: ## Prove a real MCP stdio connection using the selected prebuilt MCP image
125
+ docker run --rm --user "$(LOCAL_UID):$(LOCAL_GID)" -e HOME=/tmp --entrypoint python3 "$(MCP_IMAGE)" /opt/unaltraweb/test/mcp_smoke.py
126
+ @mkdir -p "$(CURDIR)/tmp/mcp-preview-smoke"
127
+ @docker_socket="$${UNALTRAWEB_DOCKER_SOCKET:-/var/run/docker.sock}"; socket_group=$$(stat -c '%g' "$$docker_socket"); \
128
+ image_id=$$(docker image inspect --format '{{.Id}}' "$(MCP_IMAGE)"); \
129
+ socket_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$docker_socket" /var/run/docker.sock); \
130
+ project_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$(CURDIR)/tmp/mcp-preview-smoke" /workspace); \
131
+ docker run --rm --user "$(LOCAL_UID):$(LOCAL_GID)" --group-add "$$socket_group" \
132
+ -e HOME=/tmp -e "UNALTRAWEB_DOCKER_ROOT=$(CURDIR)/tmp/mcp-preview-smoke" \
133
+ -e "UNALTRAWEB_PROJECT_USER=$(LOCAL_UID):$(LOCAL_GID)" -e "UNALTRAWEB_MCP_IMAGE=$$image_id" \
134
+ --mount "$$socket_mount" \
135
+ --mount "$$project_mount" -w /workspace \
136
+ --entrypoint python3 "$$image_id" /opt/unaltraweb/test/mcp_preview_smoke.py
137
+
138
+ mcp-stdio: ## Serve MCP_CONSUMER_WORKSPACE through the Dockerized stdio MCP
139
+ @test -n "$${MCP_CONSUMER_WORKSPACE:-}" || { printf '%s\n' 'MCP_CONSUMER_WORKSPACE is required' >&2; exit 2; }
140
+ @exec "$(CURDIR)/scripts/unaltraweb-mcp-bootstrap.sh" --image "$(MCP_IMAGE)"
141
+
142
+ mcp-down: ## Remove MCP resources owned by MCP_CONSUMER_WORKSPACE or MCP_PROJECT_ID
143
+ @exec "$(CURDIR)/scripts/unaltraweb-mcp-cleanup.sh"
144
+
145
+ mcp-down-all: ## Remove all MCP resources owned by this factory (maintainers only)
146
+ @containers="$$(docker ps -aq --filter "label=io.context.mcp-factory=unaltraweb")" || exit $$?; \
147
+ if [ -n "$$containers" ]; then docker rm -f $$containers || exit $$?; fi; \
148
+ networks="$$(docker network ls -q --filter "label=io.context.mcp-factory=unaltraweb")" || exit $$?; \
149
+ if [ -n "$$networks" ]; then docker network rm $$networks; fi
150
+
151
+ mcp-list-tools: ## List MCP resources, prompts, and tools exposed by this factory
152
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp list-tools
153
+
154
+ mcp-starter-templates: ## List starter website templates available to initialize PROJECT
155
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp starter-templates
156
+
157
+ mcp-new-web: ## Create PROJECT from the package-owned scaffold for NEW_WEB_PROFILE
158
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" new-web --site-profile "$(NEW_WEB_PROFILE)" --title "$(SITE_TITLE)" --baseurl "$(BASEURL)" --url "$(URL)" --default-lang "$(DEFAULT_LANG)" --languages "$(LANGUAGES)"
159
+
160
+ mcp-initialize-site: ## Compatibility alias for package-owned website creation
161
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp initialize-site --site-profile "$(INIT_SITE_PROFILE)" --title "$(SITE_TITLE)" --baseurl "$(BASEURL)" --url "$(URL)" --default-lang "$(DEFAULT_LANG)" --languages "$(LANGUAGES)"
162
+
163
+ mcp-site-context: ## Print JSON site context for PROJECT
164
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp site-context
165
+
166
+ mcp-profile-check: ## Print JSON profile contract checks for PROJECT
167
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp profile-check
168
+
169
+ mcp-manual-source-quality-check: ## Print JSON manual source hygiene checks for PROJECT
170
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-source-quality-check
171
+
172
+ mcp-manual-editorial-quality-check: ## Print JSON publishable-prose checks for PROJECT
173
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-editorial-quality-check
174
+
175
+ mcp-manual-authoring-capabilities: ## Print supported manual component syntax and compatibility
176
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-authoring-capabilities
177
+
178
+ mcp-manual-computation-status: ## Inspect executable manual sources and generated artefacts
179
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-computation-status --source "$(COMPUTE_SOURCE)"
180
+
181
+ mcp-manual-computation-check: ## Fail when executable manual results are stale
182
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-computation-check --source "$(COMPUTE_SOURCE)"
183
+
184
+ mcp-manual-computation-render: ## Execute and publish versioned manual computation outputs
185
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-computation-render --source "$(COMPUTE_SOURCE)" $(if $(filter 1 true TRUE yes YES y Y,$(COMPUTE_CONFIRM_OVERWRITE)),--confirm-overwrite,) $(if $(filter 1 true TRUE yes YES y Y,$(COMPUTE_STALE_ONLY)),--stale-only,)
186
+
187
+ mcp-manual-computation-render-figures: ## Render all stale figure-only computation outputs without touching fresh or unmanaged files
188
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-computation-render-figures
189
+
190
+ mcp-web-capture-status: ## Inspect web capture recipes and generated artefacts
191
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp web-capture-status --source "$(WEB_CAPTURE_SOURCE)"
192
+
193
+ mcp-web-capture-check: ## Fail when web capture artefacts are stale
194
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp web-capture-check --source "$(WEB_CAPTURE_SOURCE)"
195
+
196
+ mcp-web-capture-render: ## Start an isolated preview and publish annotated SVG artefacts
197
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp web-capture-render --source "$(WEB_CAPTURE_SOURCE)" $(if $(filter 1 true TRUE yes YES y Y,$(WEB_CAPTURE_CONFIRM_OVERWRITE)),--confirm-overwrite,)
198
+
199
+ mcp-manual-pdf-status: ## Inspect manual PDF state for PROJECT
200
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-pdf-status --language "$(MANUAL_PDF_LANG)"
201
+
202
+ mcp-manual-pdf-build: ## Build the manual PDF for PROJECT
203
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-pdf-build --language "$(MANUAL_PDF_LANG)"
204
+
205
+ mcp-manual-pdf-publish: ## Dry-run manual PDF publication for PROJECT
206
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-pdf-publish --language "$(MANUAL_PDF_LANG)"
207
+
208
+ mcp-manual-release-status: ## Inspect local manual release readiness without publishing
209
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-release-status
210
+
211
+ mcp-manual-release-check: ## Require a current verified local manual release candidate
212
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-release-check
213
+
214
+ mcp-manual-release-prepare: ## Dry-run local manual release preparation unless explicitly confirmed
215
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp manual-release-prepare $(if $(filter 0 false FALSE no NO n N,$(MANUAL_RELEASE_DRY_RUN)),--apply,) $(if $(filter 1 true TRUE yes YES y Y,$(MANUAL_RELEASE_CONFIRM_PREPARE)),--confirm-prepare,)
216
+
217
+ mcp-profile-prune-plan: ## Print JSON dry-run prune candidates for the active or selected profile
218
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp profile-prune-plan --site-profile "$(SITE_PROFILE)"
219
+
220
+ mcp-profile-prune: ## Dry-run profile prune; use the MCP tool with confirm_prune for destructive runs
221
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp profile-prune --site-profile "$(SITE_PROFILE)"
222
+
223
+ mcp-content-inventory: ## Print JSON content inventory for PROJECT
224
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp content-inventory
225
+
226
+ mcp-language-policy: ## Print JSON default language and translation workflow settings for PROJECT
227
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp language-policy
228
+
229
+ mcp-content-approval-inventory: ## Print JSON editorial approval state for PROJECT content
230
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp content-approval-inventory
231
+
232
+ mcp-translation-plan: ## Print JSON missing translations for approved default-language content
233
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp translation-plan
234
+
235
+ mcp-bibliography-inventory: ## Print JSON bibliography inventory for PROJECT
236
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp bibliography-inventory
237
+
238
+ mcp-bibliometrics-check: ## Run the offline bibliometrics check for PROJECT
239
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp bibliometrics-check
240
+
241
+ mcp-build-health: ## Inspect existing _site build artefacts for PROJECT
242
+ @PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.cli --project "$(PROJECT)" mcp build-health
243
+
244
+ manual-compute-status: ## Inspect executable manual sources and generated artefacts
245
+ @COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" $(PYTHON) "$(COMPUTE_SCRIPT)" status --project "$(PROJECT_ROOT)" $(if $(strip $(COMPUTE_SOURCE)),--source "$(COMPUTE_SOURCE)",) $(if $(strip $(COMPUTE_MODE)),--mode "$(COMPUTE_MODE)",)
246
+
247
+ manual-compute-check: ## Fail when executable manual results are stale
248
+ @COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" $(PYTHON) "$(COMPUTE_SCRIPT)" check --project "$(PROJECT_ROOT)" $(if $(strip $(COMPUTE_SOURCE)),--source "$(COMPUTE_SOURCE)",) $(if $(strip $(COMPUTE_MODE)),--mode "$(COMPUTE_MODE)",)
249
+
250
+ manual-compute-render: ## Execute sources and atomically publish Markdown and figures
251
+ @set -e; \
252
+ runtime_dir="$(PROJECT_ROOT)/tmp/.unaltraweb/computations"; \
253
+ mkdir -p "$$runtime_dir"; runtime_script=$$(mktemp "$$runtime_dir/render.XXXXXX"); cp "$(COMPUTE_SCRIPT)" "$$runtime_script"; \
254
+ results=$$(mktemp); cidfiles=""; trap 'rm -f "$$results" "$$runtime_script" $$cidfiles' EXIT; \
255
+ project_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$(PROJECT_ROOT)" /project); \
256
+ runtime_mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$runtime_script" /opt/unaltraweb/computations/render.py readonly); \
257
+ status=$$(COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" $(PYTHON) "$(COMPUTE_SCRIPT)" status --project "$(PROJECT_ROOT)" $(if $(strip $(COMPUTE_SOURCE)),--source "$(COMPUTE_SOURCE)",) $(if $(strip $(COMPUTE_MODE)),--mode "$(COMPUTE_MODE)",)); \
258
+ engines=$$(printf '%s' "$$status" | $(PYTHON) -c 'import json,sys; data=json.load(sys.stdin); print(" ".join(f"{engine}={image}" for engine,image in sorted({(item["engine"], item["image"]["image"]) for item in data["sources"]})))'); \
259
+ for selection in $$engines; do \
260
+ engine=$${selection%%=*}; image=$${selection#*=}; \
261
+ python_image="$(COMPUTE_PYTHON_IMAGE)"; r_image="$(COMPUTE_R_IMAGE)"; \
262
+ if test "$$engine" = "r"; then r_image="$$image"; else python_image="$$image"; fi; \
263
+ if ! docker image inspect "$$image" >/dev/null 2>&1; then \
264
+ COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" COMPUTE_DOCKER_BUILD_NETWORK="$(COMPUTE_DOCKER_BUILD_NETWORK)" $(PYTHON) "$(COMPUTE_SCRIPT)" image --project "$(PROJECT_ROOT)" --engine "$$engine" >/dev/null; \
265
+ fi; \
266
+ identity=$$(docker image inspect "$$image" --format '{{.Id}}'); \
267
+ digest=$$(docker image inspect "$$image" --format '{{join .RepoDigests ","}}'); \
268
+ set --; if test -n "$(UNALTRAWEB_WORKER_TOKEN)"; then cidfile="$$runtime_dir/worker-$(UNALTRAWEB_WORKER_TOKEN)-$$engine.cid"; rm -f "$$cidfile"; cidfiles="$$cidfiles $$cidfile"; set -- --cidfile "$$cidfile"; fi; \
269
+ docker run --rm "$$@" $(WORKER_LABEL_ARGS) --user "$(LOCAL_UID):$(LOCAL_GID)" --network none --read-only --cap-drop ALL --security-opt no-new-privileges --pids-limit "$(COMPUTE_PIDS_LIMIT)" --cpus "$(COMPUTE_CPUS)" --memory "$(COMPUTE_MEMORY)" --tmpfs /tmp:rw,noexec,nosuid,size=1g \
270
+ -e HOME=/tmp -e COMPUTE_PYTHON_IMAGE="$$python_image" -e COMPUTE_R_IMAGE="$$r_image" \
271
+ -e UNALTRAWEB_COMPUTE_IMAGE_ID="$$identity" -e UNALTRAWEB_COMPUTE_IMAGE_DIGEST="$$digest" \
272
+ --mount "$$project_mount" \
273
+ --mount "$$runtime_mount" \
274
+ -w /project --entrypoint python3 "$$image" \
275
+ /opt/unaltraweb/computations/render.py render --project /project --engine "$$engine" $(if $(strip $(COMPUTE_SOURCE)),--source "$(COMPUTE_SOURCE)",) $(if $(filter 1 true TRUE yes YES y Y,$(COMPUTE_CONFIRM_OVERWRITE)),--confirm-overwrite,) $(if $(filter 1 true TRUE yes YES y Y,$(COMPUTE_STALE_ONLY)),--stale-only,) $(if $(strip $(COMPUTE_MODE)),--mode "$(COMPUTE_MODE)",) >> "$$results"; \
276
+ done; \
277
+ if test -z "$(strip $(COMPUTE_SOURCE))"; then $(PYTHON) "$(COMPUTE_SCRIPT)" prune --project "$(PROJECT_ROOT)" >/dev/null; fi; \
278
+ $(PYTHON) -c 'import json,sys; text=open(sys.argv[1], encoding="utf-8").read(); decoder=json.JSONDecoder(); items=[]; index=0; exec("while index < len(text):\n index += len(text[index:]) - len(text[index:].lstrip())\n if index >= len(text): break\n item,index = decoder.raw_decode(text,index)\n items.append(item)"); rendered=[entry for item in items for entry in item.get("rendered", [])]; print(json.dumps({"project":sys.argv[2],"rendered":rendered,"rendered_count":len(rendered),"ok":all(item.get("ok",False) for item in items)}, indent=2))' "$$results" "$(PROJECT_ROOT)"
279
+
280
+ manual-compute-render-figures: override COMPUTE_STALE_ONLY := 1
281
+ manual-compute-render-figures: override COMPUTE_MODE := figure
282
+ manual-compute-render-figures: manual-compute-render ## Render only stale figure-mode computation sources
283
+
284
+ manual-compute-image-python: ## Build or pull the selected Python computation image
285
+ @COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" COMPUTE_DOCKER_BUILD_NETWORK="$(COMPUTE_DOCKER_BUILD_NETWORK)" $(PYTHON) "$(COMPUTE_SCRIPT)" image --project "$(PROJECT_ROOT)" --engine python
286
+
287
+ manual-compute-image-r: ## Build or pull the selected R computation image
288
+ @COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" COMPUTE_DOCKER_BUILD_NETWORK="$(COMPUTE_DOCKER_BUILD_NETWORK)" $(PYTHON) "$(COMPUTE_SCRIPT)" image --project "$(PROJECT_ROOT)" --engine r
289
+
290
+ manual-compute-images: manual-compute-image-python manual-compute-image-r
291
+
292
+ compute-base-image-python: ## Build the reusable local Python computation image
293
+ docker build --network "$(COMPUTE_DOCKER_BUILD_NETWORK)" -f scripts/computations/python/Dockerfile -t "$(COMPUTE_PYTHON_LOCAL_IMAGE)" .
294
+
295
+ compute-base-image-r: ## Build the reusable local R computation image
296
+ docker build --network "$(COMPUTE_DOCKER_BUILD_NETWORK)" -f scripts/computations/r/Dockerfile -t "$(COMPUTE_R_LOCAL_IMAGE)" .
297
+
298
+ manual-compute-rstudio: manual-compute-image-r ## Open the selected R computation image in RStudio Server
299
+ @image=$$(COMPUTE_PYTHON_IMAGE="$(COMPUTE_PYTHON_IMAGE)" COMPUTE_R_IMAGE="$(COMPUTE_R_IMAGE)" $(PYTHON) "$(COMPUTE_SCRIPT)" resolve --project "$(PROJECT_ROOT)" --engine r | $(PYTHON) -c 'import json,sys; print(json.load(sys.stdin)["image"])'); \
300
+ mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$(PROJECT_ROOT)" /home/rstudio/project); \
301
+ docker run --rm -it -p "127.0.0.1:$(RSTUDIO_PORT):8787" -e DISABLE_AUTH=true -e USERID="$(LOCAL_UID)" -e GROUPID="$(LOCAL_GID)" --mount "$$mount" -w /home/rstudio/project "$$image" /init
302
+
303
+ web-capture-status: ## Inspect web capture recipes and generated artefacts
304
+ @WEB_CAPTURE_IMAGE="$(WEB_CAPTURE_IMAGE)" $(PYTHON) "$(WEB_CAPTURE_SCRIPT)" status --project "$(PROJECT_ROOT)" $(if $(strip $(WEB_CAPTURE_SOURCE)),--source "$(WEB_CAPTURE_SOURCE)",)
305
+
306
+ web-capture-check: ## Fail when web capture PNG, SVG, or edited overrides are stale
307
+ @WEB_CAPTURE_IMAGE="$(WEB_CAPTURE_IMAGE)" $(PYTHON) "$(WEB_CAPTURE_SCRIPT)" check --project "$(PROJECT_ROOT)" $(if $(strip $(WEB_CAPTURE_SOURCE)),--source "$(WEB_CAPTURE_SOURCE)",)
308
+
309
+ web-capture-render: ## Capture a trusted running preview and publish PNG plus annotated SVG
310
+ @WEB_CAPTURE_IMAGE="$(WEB_CAPTURE_IMAGE)" WEB_CAPTURE_DOCKER_BUILD_NETWORK="$(WEB_CAPTURE_DOCKER_BUILD_NETWORK)" WEB_CAPTURE_DOCKER_NETWORK="$(WEB_CAPTURE_DOCKER_NETWORK)" WEB_CAPTURE_SERVICE_HOST="$(WEB_CAPTURE_SERVICE_HOST)" $(PYTHON) "$(WEB_CAPTURE_SCRIPT)" render --project "$(PROJECT_ROOT)" --base-url "$(WEB_CAPTURE_BASE_URL)" $(if $(strip $(WEB_CAPTURE_SOURCE)),--source "$(WEB_CAPTURE_SOURCE)",) $(if $(filter 1 true TRUE yes YES y Y,$(WEB_CAPTURE_CONFIRM_OVERWRITE)),--confirm-overwrite,)
311
+
312
+ web-capture-image: ## Build the isolated Playwright web capture image
313
+ docker build --network "$(WEB_CAPTURE_DOCKER_BUILD_NETWORK)" -f scripts/web_captures/Dockerfile -t "$(WEB_CAPTURE_DEV_IMAGE)" .
314
+
315
+ define run_vegavisuals
316
+ @visuals_root="$${VEGAVISUALS_PATH:-$(PROJECT_ROOT)/../vegavisuals}"; visuals_root="$$(realpath -m -- "$$visuals_root")"; \
317
+ if test ! -f "$(PROJECT_ROOT)/.vegavisuals.yml"; then \
318
+ printf '%s\n' 'No .vegavisuals.yml; skipping visualization $(1).'; \
319
+ elif test -n "$(strip $(VEGAVISUALS_CLI))"; then \
320
+ "$(VEGAVISUALS_CLI)" --project "$(PROJECT_ROOT)" $(1); \
321
+ elif test -f "$$visuals_root/src/vegavisuals/cli.py"; then \
322
+ PYTHONPATH="$$visuals_root/src$${PYTHONPATH:+:$$PYTHONPATH}" $(PYTHON) -m vegavisuals.cli --project "$(PROJECT_ROOT)" $(1); \
323
+ elif command -v vegavisuals >/dev/null 2>&1; then \
324
+ vegavisuals --project "$(PROJECT_ROOT)" $(1); \
325
+ else \
326
+ printf '%s\n' 'vegavisuals CLI not found. Set VEGAVISUALS_CLI or VEGAVISUALS_PATH, or install vegavisuals.' >&2; \
327
+ exit 1; \
328
+ fi
329
+ endef
330
+
331
+ visualization-status: ## Report Vega visualization manifest and output freshness when configured
332
+ $(call run_vegavisuals,status)
333
+
334
+ visualization-check: ## Reject stale Vega visualization outputs when configured
335
+ $(call run_vegavisuals,check)
336
+
337
+ visualization-render: ## Render missing or stale Vega visualizations when configured
338
+ $(call run_vegavisuals,render-all)
339
+
340
+ manual-pdf-image: ## Ensure the selected versioned Pandoc/XeLaTeX image is present
341
+ @docker image inspect "$(MANUAL_PDF_IMAGE)" >/dev/null 2>&1 || docker pull "$(MANUAL_PDF_IMAGE)"
342
+
343
+ manual-pdf-image-dev: ## Build the explicitly named maintainer PDF development image
344
+ docker build -f scripts/manual/Dockerfile -t "$(MANUAL_PDF_DEV_IMAGE)" scripts/manual
345
+
346
+ define run_manual_pdf_worker
347
+ @set -e; set --; cidfile=""; \
348
+ if test -n "$(UNALTRAWEB_WORKER_TOKEN)"; then runtime_dir="$(PROJECT_ROOT)/tmp/.unaltraweb/manual-pdf"; mkdir -p "$$runtime_dir"; cidfile="$$runtime_dir/worker-$(UNALTRAWEB_WORKER_TOKEN).cid"; rm -f "$$cidfile"; set -- --cidfile "$$cidfile"; fi; \
349
+ mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$(PROJECT_ROOT)" /project); \
350
+ trap 'test -z "$$cidfile" || rm -f "$$cidfile"' EXIT; \
351
+ docker run --rm "$$@" $(WORKER_LABEL_ARGS) --user "$(LOCAL_UID):$(LOCAL_GID)" -e HOME=/tmp -e "UNALTRAWEB_MANUAL_RELEASE_SELECTOR=$${MANUAL_RELEASE_SELECTOR}" --mount "$$mount" -w /project "$(MANUAL_PDF_IMAGE)" $(1) --project /project $(if $(strip $(MANUAL_PDF_LANG)),--language "$(MANUAL_PDF_LANG)",) $(2)
352
+ endef
353
+
354
+ manual-pdf-preflight: ## Run required PDF gates without contaminating the worker JSON stream
355
+ @$(MAKE) --silent --no-print-directory manual-compute-check >/dev/null
356
+ @$(MAKE) --silent --no-print-directory web-capture-check >/dev/null
357
+ @docker image inspect "$(MANUAL_PDF_IMAGE)" >/dev/null 2>&1 || docker pull "$(MANUAL_PDF_IMAGE)" >/dev/null
358
+
359
+ manual-pdf-status: ## Inspect manual PDF configuration and artefacts without Docker, network, or writes
360
+ @UNALTRAWEB_MANUAL_RELEASE_SELECTOR="$${MANUAL_RELEASE_SELECTOR}" $(PYTHON) "$(CURDIR)/scripts/manual/build_pdf.py" status --project "$(PROJECT_ROOT)" $(if $(strip $(MANUAL_PDF_LANG)),--language "$(MANUAL_PDF_LANG)",)
361
+
362
+ manual-pdf-check: ## Reject stale or unpublished manual PDF artefacts without Docker or network
363
+ @UNALTRAWEB_MANUAL_RELEASE_SELECTOR="$${MANUAL_RELEASE_SELECTOR}" $(PYTHON) "$(CURDIR)/scripts/manual/build_pdf.py" check --project "$(PROJECT_ROOT)" $(if $(strip $(MANUAL_PDF_LANG)),--language "$(MANUAL_PDF_LANG)",)
364
+
365
+ manual-pdf-build: manual-pdf-preflight ## Build manual PDFs and cover previews under tmp
366
+ $(call run_manual_pdf_worker,build)
367
+
368
+ manual-pdf-publish: manual-pdf-preflight ## Copy built PDF artefacts to configured public paths
369
+ $(call run_manual_pdf_worker,publish,$(if $(filter 1 true TRUE yes YES y Y,$(MANUAL_PDF_PUBLISH_DRY_RUN)),--dry-run,))
370
+
371
+ manual-pdf-sync: manual-pdf-preflight ## Build and copy changed manual PDFs to their public paths
372
+ $(call run_manual_pdf_worker,sync)
373
+
374
+ define run_manual_release_worker
375
+ @{ $(MAKE) --silent --no-print-directory manual-pdf-status MANUAL_PDF_LANG= || true; } | \
376
+ UNALTRAWEB_MANUAL_RELEASE_SELECTOR="$${MANUAL_RELEASE_SELECTOR}" PYTHONPATH="$(CURDIR)/src" $(PYTHON) -m unaltraweb_mcp.manual_release $(1) --project "$(PROJECT_ROOT)" $(2)
377
+ endef
378
+
379
+ manual-release-status: ## Inspect release readiness and local candidate state without publishing or writing
380
+ $(call run_manual_release_worker,status)
381
+
382
+ manual-release-check: ## Fail unless the selected local candidate exactly matches verified current outputs
383
+ $(call run_manual_release_worker,check)
384
+
385
+ manual-release-prepare: ## Prepare only a local candidate; defaults to dry-run and never publishes
386
+ $(call run_manual_release_worker,prepare,$(if $(filter 0 false FALSE no NO n N,$(MANUAL_RELEASE_DRY_RUN)),--apply,) $(if $(filter 1 true TRUE yes YES y Y,$(MANUAL_RELEASE_CONFIRM_PREPARE)),--confirm-prepare,))
387
+
388
+ docs-build: visualization-check
389
+ @mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$PWD" /work); docker run --rm --user "$(LOCAL_UID):$(LOCAL_GID)" -e HOME=/tmp -e BUNDLE_GEMFILE=docs/Gemfile -e BUNDLE_APP_CONFIG=/work/tmp/docs_bundle_config -e BUNDLE_PATH=/work/tmp/docs_bundle_path --mount "$$mount" -w /work $(DOCKER_IMAGE) bash -lc 'git config --global --add safe.directory /work >/dev/null 2>&1 || true; mkdir -p tmp/docs_bundle_config tmp/docs_bundle_path; bundle check || bundle install; core_config=$$(bundle exec ruby -e "spec = Gem::Specification.find_by_name(\"unaltraweb\"); print File.join(spec.full_gem_path, \"_config.yml\")"); bundle exec jekyll build --source docs --destination tmp/docs-site --config "$$core_config,docs/_config.yml" --disable-disk-cache'
390
+
391
+ docs-serve: visualization-check
392
+ -docker rm -f "$(DOCS_CONTAINER)" >/dev/null 2>&1 || true
393
+ @mount=$$(/bin/sh "$(DOCKER_MOUNT_SCRIPT)" "$$PWD" /work); docker run --name "$(DOCS_CONTAINER)" --rm --user "$(LOCAL_UID):$(LOCAL_GID)" -e HOME=/tmp -e BUNDLE_GEMFILE=docs/Gemfile -e BUNDLE_APP_CONFIG=/work/tmp/docs_bundle_config -e BUNDLE_PATH=/work/tmp/docs_bundle_path -p "$(DOCS_PORT):$(DOCS_PORT)" --mount "$$mount" -w /work $(DOCKER_IMAGE) bash -lc 'git config --global --add safe.directory /work >/dev/null 2>&1 || true; mkdir -p tmp/docs_bundle_config tmp/docs_bundle_path; bundle check || bundle install; core_config=$$(bundle exec ruby -e "spec = Gem::Specification.find_by_name(\"unaltraweb\"); print File.join(spec.full_gem_path, \"_config.yml\")"); bundle exec jekyll serve --source docs --destination tmp/docs-site --config "$$core_config,docs/_config.yml" --host $(DOCS_HOST) --port $(DOCS_PORT) --disable-disk-cache'
394
+
395
+ docs-publish: docs-build
396
+ PUBLISH_REMOTE="$(PUBLISH_REMOTE)" PUBLISH_BRANCH="$(PUBLISH_BRANCH)" PUBLISH_SOURCE="$(PUBLISH_SOURCE)" PUBLISH_WORKTREE="$(PUBLISH_WORKTREE)" PUBLISH_DRY_RUN="$(PUBLISH_DRY_RUN)" scripts/deploy/publish_branch.sh
397
+
398
+ docs-down:
399
+ -docker rm -f "$(DOCS_CONTAINER)" >/dev/null 2>&1 || true
400
+
401
+ metrics-scimago-fetch:
402
+ @cd "$(PROJECT_ROOT)" && "$(CURDIR)/scripts/biblio/fetch_scimago_csv.sh" $(SCIMAGO_ARGS) 1>&2 && $(PYTHON) -c 'import json,sys; print(json.dumps({"ok": True, "project": sys.argv[1], "scimago": ".cache/scimago/scimagojr.csv"}, indent=2))' "$(PROJECT_ROOT)"
403
+
404
+ metrics-update:
405
+ @cd "$(PROJECT_ROOT)" && $(PYTHON) "$(CURDIR)/scripts/biblio/metrics_update.py" $(METRICS_ARGS) 1>&2 && $(PYTHON) -c 'import json,sys; print(json.dumps({"ok": True, "project": sys.argv[1], "updated": True}, indent=2))' "$(PROJECT_ROOT)"
406
+
407
+ metrics-update-all:
408
+ @$(MAKE) --silent --no-print-directory metrics-scimago-fetch SCIMAGO_INPUT="$(SCIMAGO_INPUT)" 1>&2
409
+ @$(MAKE) --silent --no-print-directory metrics-update METRICS_ARGS="$(METRICS_ARGS)"
410
+
411
+ metrics-check:
412
+ @cd "$(PROJECT_ROOT)" && $(PYTHON) "$(CURDIR)/scripts/biblio/metrics_update.py" --offline --dry-run $(METRICS_ARGS) 1>&2 && $(PYTHON) -c 'import json,sys; print(json.dumps({"ok": True, "project": sys.argv[1], "offline": True, "dry_run": True}, indent=2))' "$(PROJECT_ROOT)"