@underpostnet/cyberia 3.3.0 → 3.3.76

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 (568) hide show
  1. package/.dockerignore +1 -0
  2. package/.env.example +17 -5
  3. package/.github/workflows/coverall.cyberia.ci.yml +39 -14
  4. package/.github/workflows/cyberia-client.cd.yml +5 -0
  5. package/.github/workflows/cyberia-server.cd.yml +5 -0
  6. package/.github/workflows/docker-image.cyberia-client.ci.yml +8 -5
  7. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +8 -3
  8. package/.github/workflows/docker-image.cyberia-server.ci.yml +8 -5
  9. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +8 -5
  10. package/.github/workflows/docker-image.engine-cyberia.ci.yml +15 -1
  11. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +15 -1
  12. package/.github/workflows/engine-cyberia.cd.yml +3 -0
  13. package/.github/workflows/engine-cyberia.ci.yml +4 -5
  14. package/.github/workflows/ghpkg.ci.yml +35 -20
  15. package/.github/workflows/hardhat.ci.yml +12 -11
  16. package/.github/workflows/npmpkg.ci.yml +17 -15
  17. package/.github/workflows/publish.cyberia.ci.yml +44 -0
  18. package/.github/workflows/pwa-microservices-template-test.ci.yml +2 -2
  19. package/.github/workflows/release.cd.yml +1 -0
  20. package/.prettierignore +1 -0
  21. package/AGENTS.md +96 -0
  22. package/CHANGELOG.md +653 -2513
  23. package/CLI-HELP.md +323 -157
  24. package/Dockerfile +25 -9
  25. package/Dockerfile.dev +25 -9
  26. package/Dockerfile.test +5 -5
  27. package/README.md +48 -28
  28. package/bin/build.js +86 -41
  29. package/bin/build.template.js +8 -3
  30. package/bin/cyberia.js +1494 -1403
  31. package/bin/deploy.js +18 -104
  32. package/bin/index.js +1494 -1403
  33. package/compose.env +17 -5
  34. package/conf.js +98 -7
  35. package/deploy/cyberia-client/deploy.sh +46 -0
  36. package/deploy/cyberia-client/package.sh +17 -0
  37. package/deploy/cyberia-client/state.sh +15 -0
  38. package/deploy/cyberia-server/deploy.sh +46 -0
  39. package/deploy/cyberia-server/package.sh +17 -0
  40. package/deploy/cyberia-server/state.sh +15 -0
  41. package/deploy/dd-cyberia/deploy.sh +9 -29
  42. package/deploy/dd-cyberia/init.sh +38 -45
  43. package/deploy/dd-cyberia/package.sh +16 -0
  44. package/deploy/dd-cyberia/state.sh +14 -0
  45. package/deploy/dd-cyberia/sync-deploy.sh +133 -147
  46. package/deploy/lib/config.sh +29 -0
  47. package/deploy/lib/github-actions-logging.sh +610 -0
  48. package/deploy/lib/host.sh +194 -0
  49. package/deploy/lib/state.sh +65 -0
  50. package/deploy/pwa-microservices-template/deploy.sh +17 -42
  51. package/deploy/release/deploy.sh +9 -41
  52. package/deployment.yaml +7 -2
  53. package/docker-compose.yml +23 -17
  54. package/examples/static-page/README.md +19 -19
  55. package/examples/static-page/ssr-components/CustomPage.js +2 -2
  56. package/hardhat/hardhat.config.js +1 -6
  57. package/hardhat/package-lock.json +101 -40
  58. package/hardhat/package.json +2 -2
  59. package/manifests/alertmanager/deployment.yaml +81 -0
  60. package/manifests/blackbox-exporter/deployment.yaml +75 -0
  61. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +32 -7
  62. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +32 -7
  63. package/manifests/deployment/dd-cyberia-development/deployment.yaml +7 -2
  64. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  65. package/manifests/deployment/mongo-express/deployment.yaml +46 -27
  66. package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
  67. package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
  68. package/manifests/deployment/mongo-express/service.yaml +16 -0
  69. package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
  70. package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
  71. package/manifests/grafana/deployment.yaml +26 -7
  72. package/manifests/grafana/kustomization.yaml +1 -0
  73. package/manifests/grafana/service.yaml +6 -1
  74. package/manifests/mariadb/pv.yaml +1 -0
  75. package/manifests/mongodb/statefulset.yaml +9 -2
  76. package/manifests/mysql/pv-pvc.yaml +14 -1
  77. package/manifests/postgresql/pv.yaml +12 -1
  78. package/manifests/postgresql/pvc.yaml +1 -0
  79. package/manifests/prometheus/deployment.yaml +18 -22
  80. package/package.json +87 -12
  81. package/scripts/event-monitor.sh +56 -0
  82. package/scripts/k3s-node-setup.sh +27 -14
  83. package/scripts/kubeadm-node-setup.sh +31 -11
  84. package/scripts/maas-setup.sh +8 -8
  85. package/scripts/selinux-normalize.sh +907 -0
  86. package/scripts/shutdown-machine.sh +843 -0
  87. package/scripts/test-monitor.sh +5 -5
  88. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +15 -10
  89. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
  90. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +7 -2
  91. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +90 -186
  92. package/src/api/core/core.controller.js +1 -1
  93. package/src/api/core/core.router.js +2 -2
  94. package/src/api/core/core.service.js +2 -2
  95. package/src/api/crypto/crypto.controller.js +1 -1
  96. package/src/api/crypto/crypto.service.js +1 -1
  97. package/src/api/cyberia-action/cyberia-action.controller.js +1 -1
  98. package/src/api/cyberia-action/cyberia-action.router.js +3 -3
  99. package/src/api/cyberia-action/cyberia-action.service.js +5 -6
  100. package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
  101. package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
  102. package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
  103. package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
  104. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +2 -4
  105. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
  106. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +13 -35
  107. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +17 -34
  108. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +1 -1
  109. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
  110. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +2 -2
  111. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +2 -2
  112. package/src/api/cyberia-entity/cyberia-entity.controller.js +1 -1
  113. package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
  114. package/src/api/cyberia-entity/cyberia-entity.router.js +1 -1
  115. package/src/api/cyberia-entity/cyberia-entity.service.js +3 -3
  116. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
  117. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
  118. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -2
  119. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +468 -5
  120. package/src/api/cyberia-instance/cyberia-fallback-capture.js +502 -0
  121. package/src/api/cyberia-instance/cyberia-fallback-world.js +29 -40
  122. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
  123. package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
  124. package/src/api/cyberia-instance/cyberia-instance-map.service.js +35 -142
  125. package/src/api/cyberia-instance/cyberia-instance.controller.js +2 -5
  126. package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
  127. package/src/api/cyberia-instance/cyberia-instance.router.js +5 -18
  128. package/src/api/cyberia-instance/cyberia-instance.service.js +5 -45
  129. package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
  130. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +1 -1
  131. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
  132. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +1 -1
  133. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +76 -3
  134. package/src/api/cyberia-map/cyberia-map.controller.js +1 -1
  135. package/src/api/cyberia-map/cyberia-map.router.js +1 -1
  136. package/src/api/cyberia-map/cyberia-map.service.js +8 -4
  137. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
  138. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
  139. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
  140. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
  141. package/src/api/cyberia-quest/cyberia-quest.controller.js +1 -1
  142. package/src/api/cyberia-quest/cyberia-quest.router.js +4 -4
  143. package/src/api/cyberia-quest/cyberia-quest.service.js +5 -5
  144. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +1 -1
  145. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
  146. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +1 -1
  147. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +2 -2
  148. package/src/api/cyberia-saga/cyberia-saga.controller.js +1 -1
  149. package/src/api/cyberia-saga/cyberia-saga.router.js +1 -1
  150. package/src/api/cyberia-saga/cyberia-saga.service.js +2 -2
  151. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -214
  152. package/src/api/cyberia-skill/cyberia-skill.controller.js +1 -1
  153. package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
  154. package/src/api/cyberia-skill/cyberia-skill.router.js +1 -1
  155. package/src/api/cyberia-skill/cyberia-skill.service.js +2 -2
  156. package/src/api/default/default.controller.js +1 -1
  157. package/src/api/default/default.router.js +1 -1
  158. package/src/api/default/default.service.js +2 -2
  159. package/src/api/document/document.controller.js +1 -1
  160. package/src/api/document/document.router.js +1 -1
  161. package/src/api/document/document.service.js +2 -2
  162. package/src/api/file/file.controller.js +1 -1
  163. package/src/api/file/file.ref.js +153 -0
  164. package/src/api/file/file.ref.json +11 -2
  165. package/src/api/file/file.router.js +1 -1
  166. package/src/api/file/file.service.js +2 -2
  167. package/src/api/instance/instance.controller.js +1 -1
  168. package/src/api/instance/instance.router.js +1 -1
  169. package/src/api/instance/instance.service.js +2 -2
  170. package/src/api/ipfs/ipfs.controller.js +1 -1
  171. package/src/api/ipfs/ipfs.router.js +2 -2
  172. package/src/api/ipfs/ipfs.service.js +2 -2
  173. package/src/api/object-layer/object-layer.controller.js +1 -1
  174. package/src/api/object-layer/object-layer.model.js +47 -12
  175. package/src/api/object-layer/object-layer.router.js +12 -5
  176. package/src/api/object-layer/object-layer.service.js +116 -123
  177. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +1 -1
  178. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +1 -1
  179. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +2 -2
  180. package/src/api/test/test.controller.js +1 -1
  181. package/src/api/test/test.service.js +1 -1
  182. package/src/api/user/guest.service.js +3 -3
  183. package/src/api/user/user.controller.js +1 -1
  184. package/src/api/user/user.router.js +2 -2
  185. package/src/api/user/user.service.js +4 -4
  186. package/src/api.js +5 -9
  187. package/src/cli/app.js +402 -0
  188. package/src/cli/baremetal.js +30 -35
  189. package/src/cli/client.js +306 -0
  190. package/src/cli/cloud-init.js +3 -3
  191. package/src/cli/cluster.js +191 -82
  192. package/src/cli/db.js +120 -68
  193. package/src/cli/deploy.js +157 -75
  194. package/src/cli/docker-compose.js +5 -5
  195. package/src/cli/domains.js +184 -0
  196. package/src/cli/dotenv-store.js +143 -0
  197. package/src/cli/event.js +2281 -0
  198. package/src/cli/fs-selection.js +115 -0
  199. package/src/cli/fs.js +159 -343
  200. package/src/cli/host.js +672 -0
  201. package/src/cli/image.js +4 -6
  202. package/src/cli/index.js +343 -151
  203. package/src/cli/ipfs.js +34 -30
  204. package/src/cli/kickstart.js +1 -1
  205. package/src/cli/kubectl.js +218 -41
  206. package/src/cli/lxd.js +3 -3
  207. package/src/cli/monitor.js +1359 -26
  208. package/src/cli/package.js +90 -0
  209. package/src/cli/release.js +16 -12
  210. package/src/cli/repository.js +586 -363
  211. package/src/cli/run.js +398 -843
  212. package/src/cli/secrets.js +2158 -964
  213. package/src/cli/ssh.js +478 -279
  214. package/src/cli/state.js +394 -0
  215. package/src/cli/static.js +2 -2
  216. package/src/cli/system.js +1 -1
  217. package/src/cli/test.js +203 -125
  218. package/src/cli/vultr.js +61 -21
  219. package/src/cli/wireguard.js +1112 -306
  220. package/src/client/components/core/CalendarCore.js +53 -96
  221. package/src/client/components/core/Docs.js +327 -303
  222. package/src/client/components/core/FileExplorer.js +0 -21
  223. package/src/client/components/core/Modal.js +56 -1
  224. package/src/client/components/core/PanelForm.js +4 -4
  225. package/src/client/components/core/Repository.js +56 -0
  226. package/src/client/components/core/Translate.js +7 -0
  227. package/src/client/components/core/{FullScreen.js → ViewModeController.js} +42 -39
  228. package/src/client/components/core/Wallet.js +0 -11
  229. package/src/client/components/core/Worker.js +7 -1
  230. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +2 -2
  231. package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
  232. package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
  233. package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
  234. package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
  235. package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
  236. package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
  237. package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
  238. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
  239. package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
  240. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +2 -35
  241. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
  242. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
  243. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +2 -2
  244. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
  245. package/src/client/components/default/AppShellDefault.js +1 -1
  246. package/src/client/components/default/SettingsDefault.js +2 -2
  247. package/src/client/components/itemledger/SettingsItemledger.js +2 -2
  248. package/src/client/components/underpost/AppShellUnderpost.js +3 -2
  249. package/src/client/components/underpost/SettingsUnderpost.js +2 -2
  250. package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
  251. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +313 -30
  252. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
  253. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
  254. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
  255. package/src/client/public/cyberia-docs/CYBERIA.md +48 -28
  256. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
  257. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +23 -6
  258. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  259. package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
  260. package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
  261. package/src/client/public/default/android-chrome-144x144.png +0 -0
  262. package/src/client/public/default/android-chrome-192x192.png +0 -0
  263. package/src/client/public/default/android-chrome-256x256.png +0 -0
  264. package/src/client/public/default/android-chrome-36x36.png +0 -0
  265. package/src/client/public/default/android-chrome-384x384.png +0 -0
  266. package/src/client/public/default/android-chrome-48x48.png +0 -0
  267. package/src/client/public/default/android-chrome-512x512.png +0 -0
  268. package/src/client/public/default/android-chrome-72x72.png +0 -0
  269. package/src/client/public/default/android-chrome-96x96.png +0 -0
  270. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  271. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  272. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  273. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  274. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  275. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  276. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  277. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  278. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  279. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  280. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  281. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  282. package/src/client/public/default/apple-touch-icon.png +0 -0
  283. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  284. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  285. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  286. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  287. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  288. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  289. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  290. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  291. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  292. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  293. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  294. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  295. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  296. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  297. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  298. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  299. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  300. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  301. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  302. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  303. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  304. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  305. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  306. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  307. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  308. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  309. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  310. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  311. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  312. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  313. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  314. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  315. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  316. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  317. package/src/client/public/default/assets/background/white.jpg +0 -0
  318. package/src/client/public/default/browserconfig.xml +1 -1
  319. package/src/client/public/default/favicon-16x16.png +0 -0
  320. package/src/client/public/default/favicon-32x32.png +0 -0
  321. package/src/client/public/default/favicon-48x48.png +0 -0
  322. package/src/client/public/default/favicon.ico +0 -0
  323. package/src/client/public/default/manifest.webmanifest +5 -5
  324. package/src/client/public/default/mstile-144x144.png +0 -0
  325. package/src/client/public/default/mstile-150x150.png +0 -0
  326. package/src/client/public/default/mstile-310x150.png +0 -0
  327. package/src/client/public/default/mstile-310x310.png +0 -0
  328. package/src/client/public/default/mstile-70x70.png +0 -0
  329. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  330. package/src/client/public/default/yandex-browser-manifest.json +1 -1
  331. package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
  332. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
  333. package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
  334. package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
  335. package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
  336. package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
  337. package/src/client/services/object-layer/object-layer.management.js +6 -10
  338. package/src/client/services/object-layer/object-layer.service.js +3 -1
  339. package/src/client/ssr/RootDocument.js +1 -1
  340. package/src/client/ssr/body/404.js +1 -1
  341. package/src/client/ssr/body/500.js +1 -1
  342. package/src/client/ssr/body/CacheControl.js +1 -1
  343. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +1 -1
  344. package/src/client/ssr/body/DefaultSplashScreen.js +1 -1
  345. package/src/client/ssr/body/SwaggerDarkMode.js +1 -1
  346. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +1 -1
  347. package/src/client/ssr/head/CryptokoynScripts.js +1 -1
  348. package/src/client/ssr/head/Css.js +1 -1
  349. package/src/client/ssr/head/CyberiaPortalScripts.js +1 -1
  350. package/src/client/ssr/head/DefaultScripts.js +1 -1
  351. package/src/client/ssr/head/ItemledgerScripts.js +1 -1
  352. package/src/client/ssr/head/Microdata.js +1 -1
  353. package/src/client/ssr/head/Production.js +1 -1
  354. package/src/client/ssr/head/Pwa.js +1 -1
  355. package/src/client/ssr/head/PwaItemledger.js +1 -1
  356. package/src/client/ssr/head/Seo.js +1 -1
  357. package/src/client/ssr/head/UnderpostScripts.js +1 -1
  358. package/src/client/ssr/mailer/DefaultRecoverEmail.js +1 -1
  359. package/src/client/ssr/mailer/DefaultVerifyEmail.js +1 -1
  360. package/src/client/ssr/views/Cyberia404.js +7 -5
  361. package/src/client/ssr/views/CyberiaServerMetrics.js +1 -1
  362. package/src/client/ssr/views/Maintenance.js +1 -1
  363. package/src/client/ssr/views/NoNetworkConnection.js +1 -1
  364. package/src/client/ssr/views/Test.js +1 -1
  365. package/src/client/sw/core.sw.js +20 -14
  366. package/src/client-builder/client-build-docs.js +92 -77
  367. package/src/client-builder/client-build-live.js +2 -2
  368. package/src/client-builder/client-build.js +105 -74
  369. package/src/client-builder/client-bundle.js +347 -0
  370. package/src/client-builder/client-dev-server.js +3 -3
  371. package/src/client-builder/client-icons.js +2 -2
  372. package/src/client-builder/ssr.js +3 -3
  373. package/src/client.build.js +3 -6
  374. package/src/client.dev.js +3 -6
  375. package/src/db/DataBaseProvider.js +186 -3
  376. package/src/db/mariadb/MariaDB.js +3 -2
  377. package/src/db/mongo/MongoBootstrap.js +273 -101
  378. package/src/db/mongo/MongoExpress.js +187 -0
  379. package/src/db/mongo/MongooseDB.js +7 -8
  380. package/src/{server/valkey.js → db/valkey/Valkey.js} +5 -4
  381. package/src/grpc/cyberia/grpc-server.js +6 -8
  382. package/src/index.js +79 -23
  383. package/src/mailer/EmailRender.js +2 -2
  384. package/src/mailer/MailerInterceptor.js +87 -0
  385. package/src/mailer/MailerProvider.js +50 -6
  386. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +144 -147
  387. package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
  388. package/src/projects/cyberia/besu-genesis-generator.js +8 -17
  389. package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
  390. package/src/projects/cyberia/catalog-cyberia.js +54 -10
  391. package/src/projects/cyberia/gemini-client.js +4 -4
  392. package/src/projects/cyberia/generate-saga.js +5 -12
  393. package/src/projects/cyberia/hot-reload-trigger.js +18 -29
  394. package/src/projects/cyberia/instance-backup.js +210 -0
  395. package/src/projects/cyberia/instance-data.js +178 -258
  396. package/src/projects/cyberia/ipfs-client.js +4 -4
  397. package/src/projects/cyberia/map-preview-generator.js +33 -69
  398. package/src/projects/cyberia/object-layer.js +153 -320
  399. package/src/projects/cyberia/seed-audio.js +139 -0
  400. package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
  401. package/src/projects/cyberia/semantic-layer-generator.js +3 -19
  402. package/src/projects/cyberia/stat-balance.js +81 -0
  403. package/src/projects/cyberia/stat-commands.js +23 -0
  404. package/src/projects/cyberia/stat-contract-generator.js +101 -0
  405. package/src/projects/underpost/catalog-underpost.js +9 -1
  406. package/src/proxy.js +4 -7
  407. package/src/runtime/cyberia-client/Dockerfile +17 -8
  408. package/src/runtime/cyberia-client/Dockerfile.dev +13 -4
  409. package/src/runtime/cyberia-server/Dockerfile +18 -6
  410. package/src/runtime/cyberia-server/Dockerfile.dev +16 -3
  411. package/src/runtime/engine-cyberia/Dockerfile +25 -9
  412. package/src/runtime/engine-cyberia/Dockerfile.dev +25 -9
  413. package/src/runtime/engine-cyberia/Dockerfile.test +5 -5
  414. package/src/runtime/engine-cyberia/compose.env +17 -5
  415. package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
  416. package/src/runtime/express/Express.js +32 -27
  417. package/src/runtime/lampp/Lampp.js +22 -70
  418. package/src/runtime/nginx/Nginx.js +1 -1
  419. package/src/runtime/wp/Wp.js +16 -48
  420. package/src/server/{catalog.js → build/catalog.js} +15 -5
  421. package/src/server/build/coverage.js +188 -0
  422. package/src/server/build/execution.js +402 -0
  423. package/src/server/build/package.js +508 -0
  424. package/src/server/build/testing.js +578 -0
  425. package/src/server/{dns.js → network/dns.js} +144 -11
  426. package/src/server/{forward-proxy.js → network/forward-proxy.js} +10 -18
  427. package/src/server/{middlewares.js → network/middlewares.js} +11 -5
  428. package/src/server/network/node-capability.js +98 -0
  429. package/src/server/{peer.js → network/peer.js} +3 -3
  430. package/src/server/{proxy.js → network/proxy.js} +7 -13
  431. package/src/server/network/router.js +356 -0
  432. package/src/server/{tls.js → network/tls.js} +2 -2
  433. package/src/server/{underpost-compression.js → network/underpost-compression.js} +1 -1
  434. package/src/server/{underpost-gateway.js → network/underpost-gateway.js} +7 -7
  435. package/src/server/{underpost-ingress.js → network/underpost-ingress.js} +2 -2
  436. package/src/server/{cri.js → ops/cri.js} +2 -2
  437. package/src/server/{cron.js → ops/cron.js} +349 -74
  438. package/src/server/ops/event-notification.js +284 -0
  439. package/src/server/{logger.js → ops/logger.js} +143 -23
  440. package/src/server/ops/monitoring.js +1724 -0
  441. package/src/server/{systemd.js → ops/systemd.js} +55 -1
  442. package/src/server/{conf.js → runtime/conf.js} +516 -423
  443. package/src/server/runtime/config-scope.js +215 -0
  444. package/src/server/runtime/environment.js +149 -0
  445. package/src/server/{process.js → runtime/process.js} +153 -12
  446. package/src/server/{runtime-status.js → runtime/runtime-status.js} +155 -16
  447. package/src/server/{runtime.js → runtime/runtime.js} +12 -8
  448. package/src/server/{start.js → runtime/start.js} +128 -39
  449. package/src/server/{auth.js → security/auth.js} +7 -8
  450. package/src/server/security/container-storage.js +382 -0
  451. package/src/server/{crypto.js → security/crypto.js} +1 -1
  452. package/src/server/{selinux.js → security/selinux.js} +1 -1
  453. package/src/server/{backup.js → storage/backup.js} +17 -8
  454. package/src/server/{data-query.js → storage/data-query.js} +17 -1
  455. package/src/server/storage/downloader.js +121 -0
  456. package/src/server/storage/repository.js +68 -0
  457. package/src/server/storage/zip.js +153 -0
  458. package/src/server.js +4 -7
  459. package/src/ws/IoInterface.js +1 -1
  460. package/src/ws/IoServer.js +1 -1
  461. package/src/ws/core/core.ws.connection.js +1 -1
  462. package/src/ws/core/core.ws.emit.js +1 -1
  463. package/src/ws/core/core.ws.server.js +1 -1
  464. package/src/ws/default/default.ws.connection.js +1 -1
  465. package/src/ws/default/default.ws.emit.js +1 -1
  466. package/src/ws/default/default.ws.server.js +1 -1
  467. package/test/e2e/event-e2e-public-ingress-down.js +45 -0
  468. package/test/e2e/event-e2e-wireguard-server-down.js +38 -0
  469. package/test/e2e/event-e2e-wireguard-spoke-down.js +40 -0
  470. package/test/{api.test.js → integration/app/api.test.js} +33 -14
  471. package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
  472. package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
  473. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +64 -0
  474. package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
  475. package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
  476. package/test/{cyberia-instance-conf-defaults.test.js → integration/app/cyberia/cyberia-instance-conf-defaults.test.js} +17 -23
  477. package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
  478. package/test/integration/app/cyberia/cyberia-load.test.js +466 -0
  479. package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
  480. package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
  481. package/test/integration/app/cyberia/fallback-world-capture.test.js +338 -0
  482. package/test/integration/app/cyberia/object-layer-item-id.test.js +327 -0
  483. package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
  484. package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
  485. package/test/integration/app/cyberia/seed-audio.test.js +275 -0
  486. package/test/{shape-generator.test.js → integration/app/cyberia/shape-generator.test.js} +1 -1
  487. package/test/integration/infra/1-security/config-scope.test.js +305 -0
  488. package/test/integration/infra/1-security/container-storage.test.js +356 -0
  489. package/test/integration/infra/1-security/in-pod-cli-surface.test.js +86 -0
  490. package/test/integration/infra/1-security/secret-onboarding.test.js +930 -0
  491. package/test/{selinux.test.js → integration/infra/1-security/selinux.test.js} +2 -4
  492. package/test/{sops-secret-store.test.js → integration/infra/1-security/sops-secret-store.test.js} +415 -61
  493. package/test/integration/infra/1-security/systemd-service.test.js +70 -0
  494. package/test/integration/infra/1-security/underpost-config-secret.test.js +367 -0
  495. package/test/integration/infra/2-network/dns-firewall.test.js +566 -0
  496. package/test/integration/infra/2-network/node-capability.test.js +182 -0
  497. package/test/integration/infra/2-network/wireguard-cli.test.js +1187 -0
  498. package/test/{wireguard-edge.test.js → integration/infra/2-network/wireguard-edge.test.js} +649 -55
  499. package/test/{cluster-instances.test.js → integration/infra/3-cluster/cluster-instances.test.js} +11 -15
  500. package/test/{deploy-node-placement.test.js → integration/infra/3-cluster/deploy-node-placement.test.js} +3 -3
  501. package/test/integration/infra/3-cluster/docker-compose-stack.test.js +313 -0
  502. package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
  503. package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
  504. package/test/integration/infra/4-ingress/deploy-routes.test.js +379 -0
  505. package/test/integration/infra/4-ingress/gateway-static-assets.test.js +453 -0
  506. package/test/{instance-traffic-plan.test.js → integration/infra/4-ingress/instance-traffic-plan.test.js} +10 -6
  507. package/test/{underpost-gateway.test.js → integration/infra/4-ingress/underpost-gateway.test.js} +6 -6
  508. package/test/{underpost-ingress.test.js → integration/infra/4-ingress/underpost-ingress.test.js} +4 -4
  509. package/test/integration/infra/5-observability/cron-jobs.test.js +652 -0
  510. package/test/{deploy-monitor.test.js → integration/infra/5-observability/deploy-monitor.test.js} +29 -31
  511. package/test/integration/infra/5-observability/event-notification.test.js +197 -0
  512. package/test/integration/infra/5-observability/event-remediation.test.js +502 -0
  513. package/test/integration/infra/5-observability/event-targets.test.js +1174 -0
  514. package/test/integration/infra/5-observability/monitoring-stack.test.js +902 -0
  515. package/test/support/shell-harness.js +73 -0
  516. package/test/unit/build-template.test.js +97 -0
  517. package/test/unit/build-workflow-offline.test.js +132 -0
  518. package/test/unit/catalog.test.js +71 -0
  519. package/test/unit/client-build-docs.test.js +361 -0
  520. package/test/unit/client-bundle.test.js +313 -0
  521. package/test/unit/conf-loading.test.js +303 -0
  522. package/test/unit/conf-resolution.test.js +996 -0
  523. package/test/unit/coverage-artifact.test.js +221 -0
  524. package/test/{crypto.test.js → unit/crypto.test.js} +1 -1
  525. package/test/unit/cyberia/instance-backup.test.js +183 -0
  526. package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
  527. package/test/unit/cyberia/publish-workflow.test.js +22 -0
  528. package/test/unit/cyberia/stat-balance.test.js +69 -0
  529. package/test/unit/deploy-env-resolution.test.js +38 -0
  530. package/test/unit/deploy-log-table.test.js +518 -0
  531. package/test/unit/downloader-integrity.test.js +98 -0
  532. package/test/unit/execution-profiles.test.js +219 -0
  533. package/test/unit/file-reference-registry.test.js +141 -0
  534. package/test/unit/fleet-sync-source.test.js +149 -0
  535. package/test/unit/fs-storage-paths.test.js +596 -0
  536. package/test/unit/logger-redaction.test.js +141 -0
  537. package/test/unit/package.test.js +457 -0
  538. package/test/unit/prepare-host.test.js +382 -0
  539. package/test/unit/process-environment.test.js +18 -0
  540. package/test/unit/propagation-message.test.js +78 -0
  541. package/test/unit/redeploy-plan.test.js +24 -0
  542. package/test/unit/release-bump.test.js +474 -0
  543. package/test/unit/ssh-output-redaction.test.js +28 -0
  544. package/test/unit/start-options.test.js +46 -0
  545. package/test/unit/test-tiers.test.js +220 -0
  546. package/test/unit/zip-archive.test.js +142 -0
  547. package/vitest.config.js +66 -0
  548. package/.nycrc +0 -9
  549. package/deploy/lib/logging.sh +0 -96
  550. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +0 -48
  551. package/manifests/mongodb/pv-pvc.yaml +0 -59
  552. package/scripts/coverall-test-cyberia.sh +0 -24
  553. package/scripts/coverall-test.sh +0 -24
  554. package/scripts/link-local-underpost-cli.sh +0 -6
  555. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
  556. package/src/api/user/user.build.js +0 -16
  557. package/src/cli/env.js +0 -177
  558. package/src/client/components/core/Blockchain.js +0 -41
  559. package/src/client/components/core/Blog.js +0 -9
  560. package/src/client/components/core/KeyboardAvoidance.js +0 -145
  561. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
  562. package/src/client/public/default/assets/background/dark.jpg +0 -0
  563. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  564. package/src/client/public/default/assets/background/white0.jpg +0 -0
  565. package/src/client/public/doc/favicon.ico +0 -0
  566. package/src/client/public/doc/sitemap +0 -148
  567. package/src/server/downloader.js +0 -73
  568. package/src/server/environment.js +0 -98
package/src/cli/index.js CHANGED
@@ -2,9 +2,11 @@ import dotenv from 'dotenv';
2
2
  import fs from 'fs-extra';
3
3
 
4
4
  import { Command } from 'commander';
5
- import { loadConf } from '../server/conf.js';
6
- import { getNpmRootPath, getUnderpostRootPath } from '../server/environment.js';
5
+ import { deployEnvFactory, getNpmRootPath, getUnderpostRootPath } from '../server/runtime/environment.js';
7
6
  import { commitData } from '../client/components/core/CommonJs.js';
7
+ import { registerDomainCommand } from './domains.js';
8
+ import { TEST_TIERS, testSuiteNames } from '../server/build/testing.js';
9
+ import { EXECUTION_PROFILES, profileFromOptionsFactory, setExecutionProfile } from '../server/build/execution.js';
8
10
 
9
11
  import Underpost from '../index.js';
10
12
 
@@ -17,19 +19,38 @@ const program = new Command();
17
19
 
18
20
  program.name('underpost').description(`underpost ci/cd cli ${Underpost.version}`).version(Underpost.version);
19
21
 
22
+ // One gate for every command. The profile decides which classes of side effect this run
23
+ // may cause; `src/server/runtime/process.js` enforces it under all 1400+ call sites, so a
24
+ // command never has to be taught that its environment is unreachable.
25
+ program.option(
26
+ '--profile <profile>',
27
+ `Execution profile. One of: ${Object.keys(EXECUTION_PROFILES).join(', ')}.\n` +
28
+ Object.values(EXECUTION_PROFILES)
29
+ .map((profile) => ` ${profile.name.padEnd(16)} ${profile.description}`)
30
+ .join('\n'),
31
+ );
32
+
33
+ // Resolved before any action runs, from the root flag, the subcommand's own options, or a
34
+ // legacy bypass flag standing in for a profile. Writing it to the environment is what
35
+ // carries it into nested `underpost` invocations.
36
+ program.hook('preAction', (command, actionCommand) => {
37
+ const profile = profileFromOptionsFactory({ ...command.opts(), ...actionCommand.opts() });
38
+ if (profile) setExecutionProfile(profile);
39
+ });
40
+
20
41
  program
21
42
  .command('new')
22
43
  .argument('[app-name]', 'The name of the new project.')
23
44
  .option('--deploy-id <deploy-id>', 'Create deploy ID conf env files')
24
45
  .option('--sub-conf <sub-conf>', 'Create sub conf env files')
25
- .option('--cluster', 'Create deploy ID cluster files and sync to current cluster')
46
+ .option('--cluster', 'Initialize the base cluster deploy folder engine-private/deploy from ./conf.js')
26
47
  .option('--build-repos', 'Create deploy ID repositories')
27
48
  .option('--build', 'Build the deployment to pwa-microservices-template (requires --deploy-id)')
28
49
  .option('--clean-template', 'Clean the build directory (pwa-microservices-template)')
29
50
  .option('--sync-conf', 'Sync configuration to private repositories (requires --deploy-id)')
30
51
  .option(
31
52
  '--sync-start',
32
- "Sync start scripts in deploy ID package.json with root package.json (use 'dd' as --deploy-id to sync all dd.router)",
53
+ "Sync start scripts in deploy ID package.json with root package.json (use 'dd' as --deploy-id to sync all dd.routes)",
33
54
  )
34
55
  .option('--purge', 'Remove deploy ID conf and all related repositories (requires --deploy-id)')
35
56
  .option('--dev', 'Sets the development cli context')
@@ -53,8 +74,13 @@ program
53
74
  .option('--lite-build', 'Skip full build (default is full build)')
54
75
  .option('--icons-build', 'Build icons')
55
76
  .option('--ssr', 'Rebuild only SSR views defined in conf.ssr.json, leaving client assets untouched')
77
+ .option(
78
+ '--env <env>',
79
+ 'Target environment for the build (e.g. "production", "development"). Falls back to --dev, then NODE_ENV.',
80
+ )
81
+ .option('--dev', 'Sets the development cli context (shorthand for --env development).')
56
82
  .description('Builds client assets, single replicas, and/or syncs environment ports.')
57
- .action(Underpost.repo.client);
83
+ .action(Underpost.client.callback);
58
84
 
59
85
  program
60
86
  .command('start')
@@ -66,7 +92,11 @@ program
66
92
  .option('--run', 'Starts application servers and monitors their health.')
67
93
  .option('--build', 'Triggers the client-side application build process.')
68
94
  .option('--underpost-quickly-install', 'Uses Underpost Quickly Install for dependency installation.')
69
- .option('--skip-pull-base', 'Skips cloning repositories, uses current workspace code directly.')
95
+ .option('--skip-pull-repo-base', 'Skips cloning the engine source repository, uses current workspace code directly.')
96
+ .option(
97
+ '--skip-pull-private-repo',
98
+ 'Skips cloning the private configuration repository, uses the engine-private already in the workspace.',
99
+ )
70
100
  .option('--skip-full-build', 'Skips the full client bundle build during deployment.')
71
101
  .option(
72
102
  '--pull-bundle',
@@ -117,7 +147,7 @@ program
117
147
  .option('--hashes <hashes>', 'Comma-separated list of specific file hashes of commits.')
118
148
  .option('--extension <extension>', 'specific file extensions of commits.')
119
149
  .option('--changelog', 'Print the plain changelog of the last N commits (see --from-n-commit, default 1).')
120
- .option('--changelog-build', 'Builds a CHANGELOG.md file based on the commit history')
150
+ .option('--changelog-build', 'Builds a CHANGELOG.md from the latest five versions')
121
151
  .option('--changelog-min-version <version>', 'Sets the minimum version limit for --changelog-build (default: 2.85.0)')
122
152
  .option(
123
153
  '--changelog-no-hash',
@@ -128,6 +158,12 @@ program
128
158
  'Print the sanitized, commit-ready changelog message of the last N commits (see --from-n-commit, default 1). Empty when there are no tagged entries.',
129
159
  )
130
160
  .option('--from-n-commit <n>', 'Number of latest commits to include in --changelog/--changelog-msg (default: 1).')
161
+ .option(
162
+ '--propagate-msg',
163
+ 'Prints the changelog payload carried by the propagation chain, read from the PROPAGATED_MESSAGE ' +
164
+ 'environment variable and stripped of the commit subject wrapper. Falls back to --changelog-msg ' +
165
+ 'over the last N commits (see --from-n-commit) when nothing was propagated.',
166
+ )
131
167
  .option('--unpush', 'With --log, automatically sets range to unpushed commits ahead of remote.')
132
168
  .option('-b', 'Shows the current Git branch name.')
133
169
  .option('-p [branch]', 'Shows the reflog for the specified branch.')
@@ -158,24 +194,6 @@ program
158
194
  .description('Pushes committed changes from a local repository to a remote GitHub repository.')
159
195
  .action(Underpost.repo.push);
160
196
 
161
- program
162
- .command('env')
163
- .argument(
164
- '[deploy-id]',
165
- `The deployment configuration ID. Use 'clean' to restore default environment settings. Use 'root' to load underpost root env. Use 'current' to get plain current deploy Id.`,
166
- )
167
- .argument('[env]', 'Optional: The environment to set (e.g., "production", "development"). Defaults to "production".')
168
- .argument('[subConf]', 'Optional: The sub configuration to set.')
169
- .description('Sets environment variables and configurations related to a specific deployment ID.')
170
- .action((deployId, env, subConf) => {
171
- if (deployId === 'root') {
172
- const underpostRootDeployId = Underpost.env.get('DEPLOY_ID');
173
- if (underpostRootDeployId) deployId = underpostRootDeployId;
174
- }
175
- if (env) process.env.NODE_ENV = env;
176
- loadConf(deployId, subConf);
177
- });
178
-
179
197
  program
180
198
  .command('static')
181
199
  .option('--page <ssr-component-path>', 'Build custom static pages.')
@@ -223,19 +241,6 @@ program
223
241
  .description(`Manages static build of page, bundles, and documentation with comprehensive customization options.`)
224
242
  .action(Underpost.static.callback);
225
243
 
226
- program
227
- .command('config')
228
- .argument('operator', `The configuration operation to perform. Options: ${Object.keys(Underpost.env).join(', ')}.`)
229
- .argument('[key]', 'Optional: The specific configuration key to manage.')
230
- .argument('[value]', 'Optional: The value to set for the configuration key.')
231
- .option('--plain', 'Prints the configuration value in plain text.')
232
- .option('--filter <keyword>', 'Filters the list by matching key or value (only for list operation).')
233
- .option('--deploy-id <deploy-id>', 'Sets the deployment configuration ID for the operation context.')
234
- .option('--build', 'Sets the build context for the operation.')
235
- .option('--copy', 'Copies the configuration value to the clipboard (only for get operation).')
236
- .description(`Manages Underpost configurations using various operators.`)
237
- .action((...args) => Underpost.env[args[0]](args[1], args[2], args[3]));
238
-
239
244
  program
240
245
  .command('root')
241
246
  .description('Displays the root path of the npm installation.')
@@ -260,6 +265,11 @@ program
260
265
  .option('--unblock-all-egress', 'Unblocks all outbound traffic and restores default ACCEPT policy.')
261
266
  .option('--block-all-ingress', 'Blocks all new inbound traffic to this host (keeps established/related connections).')
262
267
  .option('--unblock-all-ingress', 'Unblocks all inbound traffic and restores default ACCEPT policy.')
268
+ .option(
269
+ '--block-ingress-port <ports>',
270
+ 'Blocks new inbound traffic on comma-separated TCP ports, leaving the management path reachable.',
271
+ )
272
+ .option('--unblock-ingress-port <ports>', 'Withdraws the port rules --block-ingress-port installed.')
263
273
  .option('--mac', 'Prints the MAC address of the main network interface.')
264
274
  .description('Displays the current public machine IP addresses.')
265
275
  .action(Underpost.dns.ipDispatcher);
@@ -279,6 +289,12 @@ program
279
289
  .option('--service-host <host>', 'Set custom host/IP for exposed MongoDB and Valkey clients.')
280
290
  .option('--postgresql', 'Initializes the cluster with a PostgreSQL statefulset.')
281
291
  .option('--mongodb4', 'Initializes the cluster with a MongoDB 4.4 service.')
292
+ .option(
293
+ '--mongo-express',
294
+ 'Deploys the mongo-express web client for inspecting the MongoDB statefulset databases and collections. ' +
295
+ 'Reuses the mongodb-secret credentials, and drops them when the deployed mongod runs without --auth. ' +
296
+ 'Combine with --node-port to expose it on the node network.',
297
+ )
282
298
  .option('--valkey', 'Initializes the cluster with a Valkey service.')
283
299
  .option('--ipfs', 'Initializes the cluster with an ipfs-cluster statefulset.')
284
300
  .option('--contour', 'Initializes the cluster with Project Contour base HTTPProxy and Envoy.')
@@ -297,8 +313,9 @@ program
297
313
  'Exposes enabled ready services (e.g. MongoDB 4.4, Valkey) to the host/public network via their NodePort Service manifest.',
298
314
  )
299
315
  .option(
300
- '--node-selector <k8s-node-name>',
301
- 'Pins the just-deployed StatefulSet (MongoDB 4.4 / Valkey) to the given Kubernetes node once it is ready (via a kubernetes.io/hostname nodeSelector).',
316
+ '--node-name <k8s-node-name>',
317
+ 'Pins the just-deployed workload (MongoDB 4.4 / Valkey StatefulSets, the observability Deployments) ' +
318
+ 'to the given Kubernetes node once it is ready, via a kubernetes.io/hostname nodeSelector.',
302
319
  )
303
320
  .option('--cert-manager', "Initializes the cluster with a Let's Encrypt production ClusterIssuer.")
304
321
  .option('--dedicated-gpu', 'Initializes the cluster with dedicated GPU base resources and environment settings.')
@@ -315,10 +332,15 @@ program
315
332
  '--control-plane-endpoint <endpoint>',
316
333
  'Sets custom control plane endpoint for kubeadm cluster initialization (defaults to "localhost:6443").',
317
334
  )
318
- .option('--grafana', 'Initializes the cluster with a Grafana deployment.')
335
+ .option(
336
+ '--grafana',
337
+ 'Initializes the cluster with the observability stack (Prometheus, Alertmanager, Blackbox Exporter, Grafana). ' +
338
+ 'Equivalent to --prom; both converge the one stack.',
339
+ )
319
340
  .option(
320
341
  '--prom [hosts]',
321
- 'Initializes the cluster with a Prometheus Operator deployment and monitor scrap for specified hosts.',
342
+ 'Initializes the cluster with the observability stack. Scrape targets are derived from each deploy conf.server.json; ' +
343
+ 'the optional comma-separated hosts are scraped at /metrics in addition to them.',
322
344
  )
323
345
  .option('--dev', 'Initializes a development-specific cluster configuration.')
324
346
  .option('--list-pods', 'Displays detailed information about all pods.')
@@ -427,69 +449,41 @@ program
427
449
  .description('Manages application deployments, defaulting to deploying development pods.')
428
450
  .action(Underpost.deploy.callback);
429
451
 
430
- program
431
- .command('secret')
432
- .argument(
433
- '[platform]',
434
- `The secret management platform. Options: ${Object.keys(Underpost.secret).join(', ')}. Defaults to "sops".`,
435
- 'sops',
436
- )
437
- .option('--init', 'Initializes the secrets platform environment.')
438
- .option('--create-from-file <path-env-file>', 'Creates secrets from a specified environment file.')
439
- .option('--create-from-env', 'Creates secrets from container environment variables (envFrom: secretRef).')
440
- .option('--global-clean', 'Removes all filesystem traces of secrets (engine-private, .env, conf cache).')
441
- .option('--list', 'Lists all available secrets for the platform.')
442
- .option(
443
- '--encrypt <plaintext-path>',
444
- 'Encrypts a plaintext Secret manifest into the Git-tracked SOPS store and shreds the source (sops platform).',
445
- )
446
- .option(
447
- '--apply',
448
- 'Decrypts stored SOPS manifests and streams them into kubectl apply, without writing plaintext to disk (sops platform).',
449
- )
450
- .option('--namespace <namespace>', 'Kubernetes namespace for secret operations (defaults to "default").')
451
- .option(
452
- '--install-tools',
453
- 'Installs the sops and age host binaries only, without running a full cluster host initialization.',
454
- )
455
- .option(
456
- '--rotate',
457
- 'Re-keys every stored SOPS manifest onto --recipient. Secret values are unchanged, so no workload restart is needed.',
458
- )
459
- .option('--recipient <age-public-key>', 'Incoming Age public recipient for --rotate.')
460
- .option(
461
- '--prune-recipients',
462
- 'With --rotate, makes --recipient the only recipient, revoking every previous key (use after a key compromise). ' +
463
- 'Requires --force, and revokes CI/CD keys too unless they are named in --keep-recipients.',
464
- )
465
- .option(
466
- '--keep-recipients <age-public-keys>',
467
- 'Comma-separated recipients to retain while --prune-recipients revokes the rest (e.g. the CI/CD key).',
468
- )
469
- .option(
470
- '--purge <secret-name>',
471
- 'Emergency removal: deletes the live Kubernetes Secret and takes its encrypted manifest out of the store.',
472
- )
473
- .option(
474
- '--force',
475
- 'Confirms the irreversible variant: deletes the manifest instead of archiving it (--purge), ' +
476
- 'revokes recipients (--rotate --prune-recipients), or replaces an existing manifest (--encrypt).',
477
- )
478
- .option('--dry-run', 'Reports what --apply, --rotate, or --purge would do without changing anything.')
479
- .description(`Manages secrets for various platforms.`)
480
- .action((platform, options) => {
481
- // Host tooling install is platform-independent, so it resolves before any platform lookup.
482
- if (options.installTools) return Underpost.secret.sops.installTooling();
483
- if (options.globalClean) return Underpost.secret.globalSecretClean();
484
- if (options.rotate) return Underpost.secret[platform].rotate(options.recipient, options);
485
- if (options.purge) return Underpost.secret[platform].purge(options.purge, options);
486
- if (options.encrypt) return Underpost.secret[platform].encrypt(options.encrypt, options.namespace, options);
487
- if (options.apply) return Underpost.secret[platform].apply(options.namespace, options);
488
- if (options.createFromFile) return Underpost.secret[platform].createFromEnvFile(options.createFromFile);
489
- if (options.createFromEnv) return Underpost.secret[platform].createFromContainerEnv();
490
- if (options.list) return Underpost.secret[platform].list();
491
- if (options.init) return Underpost.secret[platform].init();
492
- });
452
+ // The four domains are registered from one factory, so their action list and their option list
453
+ // exist exactly once. Adding a verb or a flag here adds it to all four; there is no place to add
454
+ // one to a single domain.
455
+ for (const domain of [
456
+ {
457
+ name: 'secret',
458
+ description: 'Workload secret store: SOPS/Age encrypted credentials projected as Kubernetes Secrets.',
459
+ api: () => Underpost.secret,
460
+ },
461
+ {
462
+ // The only store-owning domain: `host get|set|delete|list` reads and writes the host
463
+ // configuration store this domain already owns end to end, so there is no second command
464
+ // addressing the same file. Container status is not here — it is `underpost state`.
465
+ name: 'host',
466
+ description: 'Host configuration: the node-level operational environment shared by the cluster.',
467
+ api: () => Underpost.host,
468
+ store: true,
469
+ },
470
+ {
471
+ name: 'app',
472
+ description: "Application environment: one deployment's runtime configuration.",
473
+ api: () => Underpost.app,
474
+ },
475
+ {
476
+ // The runtime monitoring / telemetry layer. Unlike the other three it has no durable
477
+ // source — an observation is only true of a running container — so its `load` collects from
478
+ // the live workload and its `publish` exports off-cluster. Its store is the container state
479
+ // store, never the host domain's: different owner, different lifetime.
480
+ name: 'state',
481
+ description: 'Runtime state: live container execution state, health and metrics, exported off-cluster.',
482
+ api: () => Underpost.state,
483
+ store: true,
484
+ },
485
+ ])
486
+ registerDomainCommand(program, domain);
493
487
 
494
488
  program
495
489
  .command('image')
@@ -548,7 +542,6 @@ program
548
542
  )
549
543
  .option('--all-pods', 'Target all matching pods instead of just the first one.')
550
544
  .option('--primary-pod', 'Automatically detect and use MongoDB primary pod (MongoDB only).')
551
- .option('--primary-pod-ensure <pod-name>', 'Ensure setup of MongoDB replica set primary pod before operations.')
552
545
  .option('--stats', 'Display database statistics (collection/table names with document/row counts).')
553
546
  .option('--collections <collections>', 'Comma-separated list of database collections to operate on.')
554
547
  .option('--out-path <out-path>', 'Specifies a custom output path for backups.')
@@ -614,7 +607,11 @@ program
614
607
  )
615
608
  .option('--namespace <namespace>', 'Kubernetes namespace for the CronJob resources (default: "default").')
616
609
  .option('--image <image>', 'Custom container image for the CronJob pods.')
617
- .option('--node-name <node-name>', 'Pins the CronJob pods to this node via a kubernetes.io/hostname nodeSelector.')
610
+ .option(
611
+ '--node-name <node-name>',
612
+ 'Pins the CronJob pods to this node via a kubernetes.io/hostname nodeSelector. ' +
613
+ 'With --apply, defaults to this machine when the cluster knows it as a node, because the pods mount its checkout.',
614
+ )
618
615
  .option('--git', 'Pass --git flag to cron job execution.')
619
616
  .option('--cmd <cmd>', 'Optional pre-script commands to run before cron execution.')
620
617
  .option('--dev', 'Use local ./ base path instead of global underpost installation.')
@@ -631,33 +628,31 @@ program
631
628
 
632
629
  program
633
630
  .command('fs')
634
- .argument('[path]', 'The absolute or relative directory path for file operations.')
635
- .option('--rm', 'Removes the specified file.')
636
- .option('--git', 'Displays current Git changes related to file storage.')
637
- .option('--recursive', 'Uploads files recursively from the specified path.')
638
- .option('--deploy-id <deploy-id>', 'Specifies the deployment configuration ID for file operations.')
639
- .option('--pull', 'Downloads the specified file.')
631
+ .argument('[path]', 'Selects one file or all files below a directory. Required unless --tracked is set.')
632
+ .option('--rm', 'Deletes selected remote assets and their manifest entries.')
633
+ .option('--git', 'Restricts filesystem selection to Git-tracked files. Does not change Git state.')
634
+ .option('--recursive', 'Compatibility option. Directories always select files recursively.')
635
+ .option('--tracked', 'Selects only manifest entries. An optional path limits their scope.')
636
+ .requiredOption('--deploy-id <deploy-id>', 'Selects the deployment configuration.')
637
+ .option('--pull', 'Downloads selected manifest assets. Use --tracked to restore missing local files.')
640
638
  .option('--omit-unzip', 'With --pull, keeps the downloaded .zip file and skips extraction.')
641
- .option('--force', 'Forces the action, overriding any warnings or conflicts.')
642
- .option('--storage-file-path <storage-file-path>', 'Specifies a custom file storage path.')
643
- .description('Manages file storage, defaulting to file upload operations.')
639
+ .option('--force', 'Overwrites remote uploads or local downloads. Does not change selection.')
640
+ .option('--storage-id <sub-id>', 'Selects storage.<sub-id>.json. The default is storage.json.')
641
+ .option('--key <path>', 'Selects one exact manifest key within the path scope and filters.')
642
+ .option('--from-key <path>', 'Starts an inclusive range in manifest key order.')
643
+ .option('--to-key <path>', 'Ends an inclusive range. The default start is the first manifest key.')
644
+ .option('--key-regex <pattern>', 'Filters manifest keys by a JavaScript regular expression.')
645
+ .description('Uploads, pulls, or deletes Cloudinary assets and synchronizes the selected storage manifest.')
644
646
  .action(Underpost.fs.callback);
645
647
 
646
- program
647
- .command('test')
648
- .argument('[deploy-list]', 'A comma-separated list of deployment IDs (e.g., "default-a,default-b").')
649
- .description('Manages and runs tests, defaulting to the current Underpost default test suite.')
650
- .option('--itc', 'Executes tests within the container execution context.')
651
- .option('--sh', 'Copies the container entrypoint shell command to the clipboard.')
652
- .option('--logs', 'Displays container logs for test debugging.')
653
- .option('--pod-name <pod-name>', 'Optional: Specifies the pod name for test execution.')
654
- .option('--pod-status <pod-status>', 'Optional: Filters tests by pod status.')
655
- .option('--kind-type <kind-type>', 'Optional: Specifies the Kind cluster type for tests.')
656
- .action(Underpost.test.callback);
657
-
658
648
  program
659
649
  .command('monitor')
660
- .argument('<deploy-id>', 'The deployment configuration ID to monitor.')
650
+ .argument(
651
+ '[deploy-id]',
652
+ 'The deployment configuration ID to monitor. With the observability flags it selects which deploys are scraped; ' +
653
+ '"dd" covers every deploy in dd.routes.',
654
+ 'dd',
655
+ )
661
656
  .argument(
662
657
  '[env]',
663
658
  'Optional: The environment to monitor (e.g., "development", "production"). Defaults to "development".',
@@ -677,12 +672,104 @@ program
677
672
  .option('--versions <deployment-versions>', 'Specifies the deployment versions to monitor. eg. "blue,green", "green"')
678
673
  .option('--ready-deployment', 'Run in ready deployment monitor mode.')
679
674
  .option('--promote', 'Promotes the deployment after monitoring.')
680
- .description('Manages health server monitoring for specified deployments.')
675
+ .option(
676
+ '--observability',
677
+ 'Deploys or converges the cluster observability stack (Prometheus, Alertmanager, Blackbox Exporter, Grafana), ' +
678
+ 'ensuring the Gateway API metrics source and local-path storage provisioner are ready.',
679
+ )
680
+ .option(
681
+ '--sync-prom',
682
+ 'Regenerates the scrape configuration, alert rules and Alertmanager route from the live deploy configuration ' +
683
+ 'and event registry, applies Grafana admin credentials, then reloads or rolls only the affected component.',
684
+ )
685
+ .option('--events <event-ids>', 'Comma-separated event ids to provision; empty provisions every registered event.')
686
+ .option(
687
+ '--webhook-url <url>',
688
+ 'URL Alertmanager delivers events to (defaults to the node address of `event --serve`).',
689
+ )
690
+ .option('--extra-targets <targets>', 'Comma-separated additional "host:port" scrape targets.')
691
+ .option(
692
+ '--metrics-server',
693
+ 'Installs the Kubernetes metrics-server (kubectl top / HPA resource API). Skipped on K3s, which bundles its own, unless --force.',
694
+ )
695
+ .option(
696
+ '--cockpit',
697
+ 'Installs and enables the Cockpit KVM dashboard on this host (cockpit, cockpit-machines, libvirt) and opens its firewall service.',
698
+ )
699
+ .option('--cockpit-stop', 'Stops and disables the Cockpit KVM dashboard and closes its firewall service.')
700
+ .option(
701
+ '--grafana-host <host>',
702
+ 'Publishes Grafana at https://<host>/grafana through the edge Gateway that already serves that hostname.',
703
+ )
704
+ .option('--node-port', "Publishes Grafana on the node's LAN address (port 32300).")
705
+ .option('--expose-grafana', 'Republishes Grafana with --grafana-host / --node-port without redeploying the stack.')
706
+ .option(
707
+ '--webhook-token',
708
+ 'Prints the shared event webhook token, to persist as UNDERPOST_EVENT_TOKEN in the cron deploy env.',
709
+ )
710
+ .option(
711
+ '--node-name <k8s-node-name>',
712
+ 'Pins every monitoring workload to this node; moving Grafana deletes and recreates its node-local data.',
713
+ )
714
+ .option('--kubeadm', 'Treats the cluster as kubeadm when resolving node and host addresses.')
715
+ .option('--kind', 'Treats the cluster as Kind (Docker nodes) when resolving node and host addresses.')
716
+ .option('--k3s', 'Treats the cluster as K3s when resolving node and host addresses.')
717
+ .option('--force', 'Confirms an install that would replace a bundled component (e.g. --metrics-server on K3s).')
718
+ .option('--dev', 'Sets the development cli context (scrapes over HTTP, defaults the cluster type to Kind).')
719
+ .description('Manages health server monitoring, the cluster observability stack, and host dashboards.')
681
720
  .action(Underpost.monitor.callback);
682
721
 
722
+ program
723
+ .command('event')
724
+ .argument('[event-id]', `The operational event to dispatch. Options: ${Object.keys(Underpost.event.EVENTS)}.`)
725
+ .option(
726
+ '--deploy',
727
+ 'Merges the event into the set already deployed in the cluster and republishes the monitoring configuration.',
728
+ )
729
+ .option('--undeploy', 'Removes the event from the deployed set and republishes without it.')
730
+ .option(
731
+ '--suspend-events <state-file>',
732
+ 'Saves the exact deployed event set and temporarily republishes observability without event probes or alerts.',
733
+ )
734
+ .option(
735
+ '--resume-events <state-file>',
736
+ 'Restores and resynchronizes the exact event set saved by --suspend-events, then removes the state file.',
737
+ )
738
+ .option('--serve', 'Runs the Alertmanager webhook receiver in the foreground (use --service to supervise it).')
739
+ .option(
740
+ '--service',
741
+ 'Installs the receiver on a WireGuard control node as the underpost-event systemd unit. ' +
742
+ 'It remains available while the tunnel is down.',
743
+ )
744
+ .option('--service-stop', 'Stops, disables and removes the underpost-event systemd unit.')
745
+ .option('--service-status', 'Reports whether the underpost-event unit is active and enabled.')
746
+ .option('--list', 'Lists the registered events with their resolved probe targets.')
747
+ .option('--port <port>', 'Listening port for --serve and the generated unit (default: 39099).')
748
+ .option('--cooldown-ms <ms>', 'Minimum interval between two dispatches of one event in --serve (default: 10000).')
749
+ .option(
750
+ '--spoke <spoke-id>',
751
+ 'Spoke to remediate when dispatching wireguard-spoke-down by hand; a webhook takes it from the alert labels.',
752
+ )
753
+ .option(
754
+ '--nodes <node-names>',
755
+ 'Comma-separated node documents to act on — hubs for wireguard-server-down, peers for wireguard-spoke-down. ' +
756
+ 'Empty covers every registered hub, or every peer of this node hub.',
757
+ )
758
+ .option('--namespace <namespace>', 'Kubernetes namespace holding the observability stack. Defaults to "default".')
759
+ .option('--webhook-url <url>', 'URL Alertmanager delivers to, written into the generated route with --deploy.')
760
+ .option('--dev', 'Sets the development cli context.')
761
+ .option('--dry-run', 'Reports the remediation the event would run without executing it.')
762
+ .option('--no-notify', 'Skips the operational alert declared in engine-private/deploy/conf.event.json.')
763
+ .option(
764
+ '--e2e-test',
765
+ 'Rehearses the event against the live edge: breaks the real subject, waits for the probe to fail, ' +
766
+ 'runs the remediation, and verifies the notification was actually sent.',
767
+ )
768
+ .description('Dispatches operational events and provisions the monitoring rules that trigger them.')
769
+ .action(Underpost.event.callback);
770
+
683
771
  program
684
772
  .command('ssh')
685
- .option('--deploy-id <deploy-id>', 'Sets deploy id context for ssh operations.')
686
773
  .option('--generate', 'Generates new ssh credential and stores it in current private keys file storage.')
687
774
  .option('--user <user>', 'Sets custom ssh user')
688
775
  .option('--password <password>', 'Sets custom ssh password')
@@ -701,9 +788,10 @@ program
701
788
  .option('--key-test', 'Tests the SSH key using ssh-keygen.')
702
789
  .option('--stop', 'Stops the SSH service.')
703
790
  .option('--status', 'Checks the status of the SSH service.')
704
- .option('--connect-uri', 'Displays the connection URI.')
705
- .option('--copy', 'Copies the connection URI to clipboard.')
706
- .description('Manages SSH credentials and sessions for remote access to cluster nodes or services.')
791
+ .description(
792
+ 'Manages cluster scoped SSH credentials and sessions for remote access to cluster nodes or services. ' +
793
+ 'Users are registered in engine-private/deploy/conf.users.json and keys are stored in engine-private/deploy/users/<user>.',
794
+ )
707
795
  .action(Underpost.ssh.callback);
708
796
 
709
797
  // `underpost wireguard` and `underpost haproxy` are two entrypoints onto one
@@ -716,28 +804,36 @@ const edgeCommandFactory = (name, description) =>
716
804
  .option(
717
805
  '--deploy-id <deploy-id>',
718
806
  'Deploy IDs whose conf.server.json/conf.instances.json define the routes. ' +
719
- 'Accepts one id or a comma-separated list; defaults to "dd", every deploy in dd.router, ' +
807
+ 'Accepts one id or a comma-separated list; defaults to "dd", every deploy in dd.routes, ' +
720
808
  'because the edge holds one pair of map files for the whole cluster.',
721
809
  )
722
810
  .option('--interface <name>', 'WireGuard interface name (default: "wg0").')
723
811
  .option('--wireguard-install', 'Installs the wireguard-tools, haproxy and iptables host packages.')
724
812
  .option('--wireguard-setup', 'Generates keys, builds the interface config, and applies local network rules.')
725
- .option('--server', 'Configures this node as the hub endpoint accepting inbound tunnel traffic.')
726
- .option('--client', 'Configures this node as a spoke endpoint maintaining an outbound tunnel.')
813
+ .option('--node-config', 'Writes a node identity under deploy/nodes, named after the machine it describes.')
814
+ .option(
815
+ '--node-name <node-name>',
816
+ 'Node record to write; defaults to this hostname, which is what runtime commands resolve their identity by.',
817
+ )
818
+ .option('--node-role <role>', 'Machine role: control, worker, or hub.')
819
+ .option('--hub-host <ipv4>', 'Static public IPv4 key of the hub topology this node belongs to.')
727
820
  .option('--port <port>', 'WireGuard UDP listening port (default: 51820).')
728
821
  .option(
729
822
  '--cidr <cidr>',
730
- 'Hub interface address with prefix when used with --server (e.g. "10.0.0.1/24"); ' +
731
- 'the overlay subnet a spoke routes back through the hub when used with --client (default: "10.0.0.0/24").',
823
+ 'Hub interface address on a hub; overlay subnet routed through the hub on control and worker nodes.',
732
824
  )
733
- .option('--peer-ip <ip>', 'Tunnel address of the target spoke. Required with --client and --peer-add.')
734
- .option('--endpoint <host:port>', 'Hub host and port a spoke dials. Required with --client.')
735
- .option('--public-key <key>', 'Hub public key with --client; spoke public key with --peer-add.')
825
+ .option('--peer-ip <ip>', 'Tunnel address used by --peer-add or to update the selected node during setup.')
826
+ .option('--peer-id <peer-id>', 'Topology peer represented by a control or worker node identity.')
827
+ .option('--public-key <key>', 'Public key used by off-host topology authoring or --peer-add.')
736
828
  .option('--peer-add <peer-id>', 'Registers a spoke and applies it to the running hub without a restart.')
737
- .option('--peer-remove <peer-id>', 'Removes a spoke from the registry and from the running hub.')
829
+ .option('--peer-remove <peer-id>', 'Removes a peer from the selected topology and running hub.')
738
830
  .option('--allowed-ips <cidrs>', 'Comma-separated CIDRs routed to the spoke (e.g. "10.0.0.2/32,192.168.10.0/24").')
739
831
  .option('--hosts <hosts>', 'Comma-separated hostnames bound to the spoke, overriding instance resolution.')
740
832
  .option('--instances <instances>', 'Comma-separated conf.instances.json ids bound to the spoke.')
833
+ .option(
834
+ '--management-host <host>',
835
+ 'Stable LAN or management address used to repair this peer when its tunnel address is unavailable.',
836
+ )
741
837
  .option('--default', 'Marks the spoke as the fallback for hostnames that match no other binding.')
742
838
  .option('--haproxy-setup', 'Installs HAProxy, publishes the current routes, and enables the daemon.')
743
839
  .option('--haproxy-sync', 'Recompiles the SNI/Host maps from deploy config and hot-reloads HAProxy.')
@@ -750,7 +846,7 @@ const edgeCommandFactory = (name, description) =>
750
846
  '--build-conf',
751
847
  'Writes only engine-private/deploy/conf.wireguard.json and touches no host state. ' +
752
848
  'Combine with --wireguard-setup / --peer-add / --peer-remove to author the topology off-box; ' +
753
- 'alone it normalizes and validates the existing registry.',
849
+ 'alone it normalizes and validates the existing topology.',
754
850
  )
755
851
  .option(
756
852
  '--forward-proxy-server',
@@ -761,18 +857,58 @@ const edgeCommandFactory = (name, description) =>
761
857
  )
762
858
  .option(
763
859
  '--forward-proxy-server-host <host>',
764
- 'Address the forward proxy binds, overriding the hub tunnel address from the registry.',
860
+ 'Address the forward proxy binds, overriding the selected hub tunnel address.',
765
861
  )
766
862
  .option('--forward-proxy-server-port <port>', 'Port the forward proxy binds (default: 1080).')
767
863
  .option(
768
864
  '--ssh-forward-port <port>',
769
865
  'Publishes the default spoke SSH port on this public TCP port of the hub, so CI with no fixed ' +
770
- 'address can reach the cluster node (e.g. 2222). "0" closes it. Stored in the registry.',
866
+ 'address can reach the cluster node (e.g. 2222). "0" closes it. Stored in hub topology.',
867
+ )
868
+ .option(
869
+ '--sync',
870
+ 'Brings every registered node engine checkout up to date over its SSH identity: clean, pull, fix and install.',
871
+ )
872
+ .option(
873
+ '--nodes <node-names>',
874
+ 'Comma-separated node documents --sync, --cmd, --node-exporter and --connect-uri act on. ' +
875
+ 'Empty covers every hub and every peer of this node hub.',
876
+ )
877
+ .option(
878
+ '--connect-uri',
879
+ 'Prints the SSH command that reaches each node named by --nodes, joining the node document under ' +
880
+ 'engine-private/deploy/nodes to the management address it is registered under in ' +
881
+ 'engine-private/deploy/conf.users.json. Empty --nodes lists the whole fleet.',
882
+ )
883
+ .option('--copy', 'Copies the --connect-uri output to the clipboard instead of printing it.')
884
+ .option(
885
+ '--cmd <command-list>',
886
+ 'Comma-separated custom commands to run on the selected nodes over their SSH identity. ' +
887
+ 'Given with --sync, only these run in place of the sync steps.',
888
+ )
889
+ .option(
890
+ '--node-exporter',
891
+ 'Provisions the host metrics collector as a systemd service on the selected hub nodes, bound to their ' +
892
+ 'tunnel address, so machines outside the cluster report hardware metrics like every cluster node.',
893
+ )
894
+ .option(
895
+ '--repo-engine <repo>',
896
+ 'Engine repository --sync pulls from, as owner/repo or a clone URL. Defaults to the configured account engine.',
897
+ )
898
+ .option(
899
+ '--repo-engine-private <repo>',
900
+ 'Private engine repository --sync pulls from, as owner/repo or a clone URL. ' +
901
+ 'Defaults to the configured private repo derived from --repo-engine.',
771
902
  )
772
903
  .option('--wireguard-start', 'Enables and starts wg-quick@<interface> and the QUIC forward.')
904
+ .option('--wireguard-restart', 'Restarts wg-quick@<interface> and restores the hub QUIC forward.')
773
905
  .option('--wireguard-stop', 'Tears down the interface and removes its transient packet rules.')
774
- .option('--wireguard-reset', 'Removes generated configs and packet rules, keeping the key pair and registry.')
775
- .option('--wireguard-reinstall', 'Full purge, package reinstall and re-key; every spoke must re-register.')
906
+ .option('--check', 'Waits for an active interface and a fresh handshake with its required peer.')
907
+ .option('--check-timeout <seconds>', 'Maximum wait for --check (default: 30).')
908
+ .option('--expected-role <role>', 'Refuses restart/check unless this host has the expected node role.')
909
+ .option('--expected-id <peer-id>', 'Refuses restart/check unless this node represents the expected peer id.')
910
+ .option('--wireguard-reset', 'Removes generated host state, keeping keys, topology and node identity.')
911
+ .option('--wireguard-reinstall', 'Full purge, package reinstall and re-key; updates the selected topology key.')
776
912
  .option('--dry-run', 'Prints the files and commands the run would apply, without touching the host.')
777
913
  .description(description)
778
914
  .action(Underpost.wireguard.callback);
@@ -842,6 +978,12 @@ program
842
978
  .option('--volume-mount-path <volume-mount-path>', 'Optional: Specifies the volume mount path for test execution.')
843
979
  .option('--volume-type <volume-type>', 'Optional: Specifies the volume type for test execution.')
844
980
  .option('--image-name <image-name>', 'Optional: Specifies the image name for test execution.')
981
+ .option('--image <image>', 'Container image the deployment pulls and runs (sync).')
982
+ .option('--runtime-image <name>', 'src/runtime/<name> image family the cluster runner brings up (default "express").')
983
+ .option(
984
+ '--versions <deployment-versions>',
985
+ 'Comma-separated blue/green deployment versions (sync); unset resolves the next colour.',
986
+ )
845
987
  .option('--container-name <container-name>', 'Optional: Specifies the container name for test execution.')
846
988
  .option('--namespace <namespace>', 'Optional: Specifies the namespace for test execution.')
847
989
  .option('--tty', 'Enables TTY for the container in deploy-job.')
@@ -895,6 +1037,7 @@ program
895
1037
  .option('--deploy-id <deploy-id>', 'Sets deploy id context for the runner execution.')
896
1038
  .option('--user <user>', 'Sets user context for the runner execution.')
897
1039
  .option('--hosts <hosts>', 'Comma-separated list of hosts for the runner execution.')
1040
+ .option('--split <mb>', 'Zip part size in MB for push-bundle, or "none" to upload a single zip. Defaults to 8.')
898
1041
  .option('--instance-id <instance-id>', 'Sets instance id context for the runner execution.')
899
1042
  .option('--pid <process-id>', 'Sets process id context for the runner execution.')
900
1043
  .option(
@@ -919,6 +1062,11 @@ program
919
1062
  'Omits the QUIC/HTTP3 listener config and the Alt-Svc advertisement from Gateway API manifests.',
920
1063
  )
921
1064
  .option('--quic-port <port>', 'UDP port advertised for QUIC/HTTP3 in generated Gateway API manifests (default 443).')
1065
+ .option(
1066
+ '--repo-engine-private <repo>',
1067
+ 'Private configuration repository the pull runner checks out, as owner/repo or a clone URL. ' +
1068
+ 'Defaults to the private repo derived from the engine source.',
1069
+ )
922
1070
  .option('--disable-private-conf-update', 'Disables updates to private configuration during execution.')
923
1071
  .option('--logs', 'Streams logs during the runner execution.')
924
1072
  .option('--monitor-status <status>', 'Sets the status to monitor for pod/resource (default: "Running").')
@@ -967,6 +1115,33 @@ program
967
1115
  .description('Runs specified scripts using various runners.')
968
1116
  .action(Underpost.run.callback);
969
1117
 
1118
+ program
1119
+ .command('test')
1120
+ .argument(
1121
+ '[suite]',
1122
+ `A comma-separated list of suites or tiers to run. Suites: ${testSuiteNames().join(', ')}. ` +
1123
+ `Tiers: ${TEST_TIERS.map(({ name }) => name).join(', ')}. Defaults to every tier, in tier order.`,
1124
+ '',
1125
+ )
1126
+ .option('--itc', 'Runs in this execution context instead of dispatching into deployment pods.')
1127
+ .option('--deploy-list <deploy-list>', 'A comma-separated list of deployment IDs to run the suite inside.')
1128
+ .option('--grep <pattern>', 'Runs only tests whose name matches the pattern.')
1129
+ .option('--watch', 'Keeps the runner open and re-runs affected suites on change.')
1130
+ .option('--no-coverage', 'Skips coverage instrumentation and reporters.')
1131
+ .option('--allure', 'Writes Allure results for the cluster dashboard alongside the run.')
1132
+ .option('--dashboard', 'Applies the Allure dashboard to the cluster and exits.')
1133
+ .option('--job', 'Runs the selected suite on the cluster as a Kubernetes Job (requires --image).')
1134
+ .option('--image <image>', 'Image carrying the engine and its dependencies, for --job.')
1135
+ .option('--node-name <node-name>', 'Pins the --job pod to this node.')
1136
+ .option('--host <host>', 'Hostname to route the --dashboard sub-path on.')
1137
+ .option('--namespace <namespace>', 'Kubernetes namespace for --dashboard, --job and --deploy-list.')
1138
+ .option('--dry-run', 'Renders the --dashboard or --job manifests without applying them.')
1139
+ .option('--pod-name <pod-name>', 'Waits for this cluster object to reach --pod-status instead of running tests.')
1140
+ .option('--pod-status <pod-status>', 'Status --pod-name waits for (default: "Running").')
1141
+ .option('--kind-type <kind-type>', 'Kind --pod-name queries (default: "pods").')
1142
+ .description('Runs the test tiers locally, inside deployment pods, or as a cluster Job with Allure reporting.')
1143
+ .action(Underpost.test.callback);
1144
+
970
1145
  program
971
1146
  .command('docker-compose')
972
1147
  .argument('[target]', 'Optional service name for --logs, --shell, --restart, or --build.')
@@ -1138,15 +1313,15 @@ program
1138
1313
  .option('--control <ip>', 'Control-plane IP the worker node joins (used with --worker for kubeadm infra setup).')
1139
1314
  .option(
1140
1315
  '--ssh-key-dir <dir>',
1141
- 'Directory holding the SSH key pair used for commissioning/orchestration (expects <dir>/id_rsa and <dir>/id_rsa.pub). Overrides the workflow "sshKeyDir"; defaults to engine-private/deploy. Supports a leading ~.',
1316
+ 'Directory holding the SSH key pair used for commissioning/orchestration (expects <dir>/id_rsa and <dir>/id_rsa.pub). Overrides the workflow "sshKeyDir"; defaults to engine-private/deploy/users/<user> for a non-root --user, otherwise engine-private/deploy. Supports a leading ~.',
1142
1317
  )
1143
1318
  .option(
1144
1319
  '--deploy-id <deploy-id>',
1145
- 'Deployment ID whose user key pair is used for SSH (key from engine-private/conf/<deploy-id>/users/<user>/id_rsa). Same user↔deployId↔key convention as the ssh command.',
1320
+ 'Deployment ID used to resolve the private engine repo cloned onto the node (engine-<suffix>-private.',
1146
1321
  )
1147
1322
  .option(
1148
1323
  '--user <user>',
1149
- 'SSH user paired with --deploy-id for key resolution and the login user on an existing control-plane (defaults to root). Mirrors the ssh command --user.',
1324
+ 'SSH user whose cluster scoped key pair is used (engine-private/deploy/users/<user>/id_rsa) and the login user on an existing control-plane (defaults to root, whose key is engine-private/deploy/id_rsa). Mirrors the ssh command --user.',
1150
1325
  )
1151
1326
  .option(
1152
1327
  '--engine-repo <url>',
@@ -1211,6 +1386,23 @@ program
1211
1386
  )
1212
1387
  .action(Underpost.baremetal.callback);
1213
1388
 
1389
+ program
1390
+ .command('package')
1391
+ .argument(
1392
+ '[deploy-id]',
1393
+ 'Deploy id, or a comma-separated list, to act on. Defaults to every deploy id in the private configuration tree.',
1394
+ )
1395
+ .option('--sync', 'Regenerates each deploy manifest from the engine manifest and the deploy catalog (default).')
1396
+ .option('--install', 'Installs the dependencies the deploy catalog pins into this checkout.')
1397
+ .option('--rename <name>', "Renames this checkout's package, in its manifest and its lockfile.")
1398
+ .option('--set-repo <owner/repo>', "Points this checkout's package at a repository.")
1399
+ .option('--dry-run', 'For --sync: resolves the manifests without writing them.')
1400
+ .description(
1401
+ "Generates the package manifests a deploy id owns, from the engine manifest and the deploy's " +
1402
+ 'product catalog, and installs the dependencies that catalog pins.',
1403
+ )
1404
+ .action(Underpost.package.callback);
1405
+
1214
1406
  program
1215
1407
  .command('release')
1216
1408
  .argument('[version]', 'The new version string to set (e.g., "3.1.4"). Defaults to current version.')