@askexenow/exe-os 0.9.290 → 0.9.292

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 (461) hide show
  1. package/deploy/compose/.env.customer.example +14 -1
  2. package/deploy/compose/.env.example +40 -1
  3. package/deploy/compose/backup.sh +147 -42
  4. package/deploy/compose/docker-compose.yml +128 -51
  5. package/deploy/compose/generate-env.ts +31 -0
  6. package/deploy/compose/setup.sh +11 -2
  7. package/dist/active-agent-5DCUU6QR.js +28 -0
  8. package/dist/active-agent-JTTDI66I.js +27 -0
  9. package/dist/active-agent-NQAHMQSR.js +27 -0
  10. package/dist/active-agent-QHGHLMYS.js +28 -0
  11. package/dist/agentic-ontology-7RXZLSZY.js +25 -0
  12. package/dist/agentic-ontology-BSSNX24R.js +25 -0
  13. package/dist/backfill-metadata-5I3PAO66.js +600 -0
  14. package/dist/backfill-metadata-F3KEE7WZ.js +600 -0
  15. package/dist/background-jobs-PUXOTBD4.js +25 -0
  16. package/dist/behaviors-AJFFFXT2.js +40 -0
  17. package/dist/behaviors-RXUKZLER.js +40 -0
  18. package/dist/bin/age-ontology-load.js +2 -2
  19. package/dist/bin/agentic-ontology-backfill.js +8 -7
  20. package/dist/bin/agentic-reflection-backfill.js +9 -8
  21. package/dist/bin/agentic-semantic-label.js +8 -7
  22. package/dist/bin/backfill-conversations.js +8 -7
  23. package/dist/bin/backfill-responses.js +8 -7
  24. package/dist/bin/backfill-vectors.js +11 -10
  25. package/dist/bin/bulk-sync-postgres.js +9 -8
  26. package/dist/bin/cc-doctor.js +7 -6
  27. package/dist/bin/cleanup-stale-review-tasks.js +13 -12
  28. package/dist/bin/cli.js +20 -20
  29. package/dist/bin/exe-agent-config.js +5 -4
  30. package/dist/bin/exe-agent.js +10 -9
  31. package/dist/bin/exe-assign.js +10 -9
  32. package/dist/bin/exe-boot.js +20 -19
  33. package/dist/bin/exe-call.js +6 -5
  34. package/dist/bin/exe-cloud.js +8 -7
  35. package/dist/bin/exe-dispatch.js +13 -12
  36. package/dist/bin/exe-doctor.js +2 -1
  37. package/dist/bin/exe-export-behaviors.js +9 -8
  38. package/dist/bin/exe-forget.js +8 -7
  39. package/dist/bin/exe-gateway.js +9 -8
  40. package/dist/bin/exe-healthcheck.js +11 -6
  41. package/dist/bin/exe-heartbeat.js +13 -12
  42. package/dist/bin/exe-kill.js +16 -15
  43. package/dist/bin/exe-launch-agent.js +20 -19
  44. package/dist/bin/exe-new-employee.js +9 -8
  45. package/dist/bin/exe-pending-messages.js +14 -13
  46. package/dist/bin/exe-pending-notifications.js +13 -12
  47. package/dist/bin/exe-pending-reviews.js +13 -12
  48. package/dist/bin/exe-rename.js +6 -5
  49. package/dist/bin/exe-review.js +15 -14
  50. package/dist/bin/exe-search.js +7 -6
  51. package/dist/bin/exe-session-cleanup.js +18 -17
  52. package/dist/bin/exe-settings.js +8 -7
  53. package/dist/bin/exe-start-codex.js +13 -12
  54. package/dist/bin/exe-start-opencode.js +10 -9
  55. package/dist/bin/exe-status.js +14 -13
  56. package/dist/bin/exe-support.js +3 -3
  57. package/dist/bin/exe-team.js +5 -4
  58. package/dist/bin/exe-watchdog.js +34 -1
  59. package/dist/bin/git-sweep.js +14 -13
  60. package/dist/bin/graph-backfill.js +8 -7
  61. package/dist/bin/graph-export.js +7 -6
  62. package/dist/bin/import-history.js +10 -9
  63. package/dist/bin/install-launchd.js +19 -1
  64. package/dist/bin/install.js +9 -8
  65. package/dist/bin/intercom-check.js +4 -4
  66. package/dist/bin/mcp-sessions.js +2 -2
  67. package/dist/bin/orchestration-metrics.js +6 -5
  68. package/dist/bin/postgres-agentic-reflection-backfill.js +4 -4
  69. package/dist/bin/postgres-agentic-semantic-backfill.js +3 -3
  70. package/dist/bin/scan-tasks.js +13 -12
  71. package/dist/bin/setup.js +2 -2
  72. package/dist/bin/shard-migrate.js +7 -6
  73. package/dist/bin/stack-update.js +4 -4
  74. package/dist/bin/vps-health-gate.js +1 -1
  75. package/dist/branding-RBMRJA5D.js +97 -0
  76. package/dist/capability-cards-DCWQI3NN.js +89 -0
  77. package/dist/capability-cards-TQVKK6TE.js +89 -0
  78. package/dist/capacity-monitor-7YZOMMMP.js +51 -0
  79. package/dist/capacity-monitor-S6GFT45S.js +51 -0
  80. package/dist/catchup-brief-DK7OD5DJ.js +175 -0
  81. package/dist/catchup-brief-J27L7LKR.js +175 -0
  82. package/dist/catchup-brief-JLMK2IP5.js +175 -0
  83. package/dist/chunk-2664Y4WA.js +14503 -0
  84. package/dist/chunk-2FTHXF6X.js +150 -0
  85. package/dist/chunk-2H2SCCA7.js +221 -0
  86. package/dist/chunk-2ISUEARV.js +76 -0
  87. package/dist/chunk-2RU66KAN.js +456 -0
  88. package/dist/chunk-2SI5Z24A.js +284 -0
  89. package/dist/chunk-2V6AASHE.js +668 -0
  90. package/dist/chunk-2ZMQI2J4.js +85 -0
  91. package/dist/chunk-3ET3QGXG.js +70 -0
  92. package/dist/chunk-3V6KXHSV.js +203 -0
  93. package/dist/chunk-3VT5IG2G.js +14439 -0
  94. package/dist/chunk-3YHG7W74.js +362 -0
  95. package/dist/chunk-434Z2LFO.js +30 -0
  96. package/dist/chunk-44SWZWGS.js +231 -0
  97. package/dist/chunk-4DFENB7E.js +128 -0
  98. package/dist/chunk-4EA3J7SE.js +333 -0
  99. package/dist/chunk-4JY5DRY2.js +1350 -0
  100. package/dist/chunk-5BUPY2ZC.js +81 -0
  101. package/dist/chunk-5FIQBJ5I.js +735 -0
  102. package/dist/chunk-5MQ4RUUP.js +244 -0
  103. package/dist/chunk-6CTHQKUS.js +1186 -0
  104. package/dist/chunk-6GEEAOFU.js +538 -0
  105. package/dist/chunk-6JOF37K6.js +1352 -0
  106. package/dist/chunk-6OAAN25C.js +727 -0
  107. package/dist/chunk-6S6QFQ33.js +382 -0
  108. package/dist/chunk-6U2BFODG.js +227 -0
  109. package/dist/chunk-76QWODZW.js +1119 -0
  110. package/dist/chunk-7BNDOTRZ.js +1094 -0
  111. package/dist/chunk-7HBACWKV.js +128 -0
  112. package/dist/chunk-7IWWRNJI.js +333 -0
  113. package/dist/chunk-7MH7VI6T.js +280 -0
  114. package/dist/chunk-7QKQE7J4.js +70 -0
  115. package/dist/chunk-7U4JXDBV.js +284 -0
  116. package/dist/chunk-7UF4323L.js +50 -0
  117. package/dist/chunk-7UUJMSFH.js +348 -0
  118. package/dist/chunk-7YEOKPZ6.js +185 -0
  119. package/dist/chunk-7Z3P23BX.js +244 -0
  120. package/dist/chunk-BK42Z2SX.js +1186 -0
  121. package/dist/chunk-BREJRA7B.js +171 -0
  122. package/dist/chunk-C3FMNIJT.js +94 -0
  123. package/dist/chunk-CCNSV7J5.js +128 -0
  124. package/dist/chunk-CKFT7GM6.js +128 -0
  125. package/dist/chunk-CRCB5S7I.js +454 -0
  126. package/dist/chunk-CSMTQ24E.js +97 -0
  127. package/dist/chunk-CSXNLHUU.js +185 -0
  128. package/dist/chunk-D3ELJGEI.js +97 -0
  129. package/dist/chunk-D6CCJVTB.js +214 -0
  130. package/dist/chunk-DEVITBD5.js +1079 -0
  131. package/dist/chunk-DKIFBCKT.js +157 -0
  132. package/dist/chunk-DRUPHYRL.js +286 -0
  133. package/dist/chunk-E4XU7EVT.js +1350 -0
  134. package/dist/chunk-EEZNLI6L.js +240 -0
  135. package/dist/chunk-EIA6LRM4.js +38 -0
  136. package/dist/chunk-FBIXI7WC.js +382 -0
  137. package/dist/chunk-FSQTZ57R.js +4349 -0
  138. package/dist/chunk-FW75WOTA.js +97 -0
  139. package/dist/chunk-GDSV52EC.js +85 -0
  140. package/dist/chunk-GMZTZ4KQ.js +345 -0
  141. package/dist/chunk-GNKHK5VD.js +1068 -0
  142. package/dist/chunk-GP3ZHQJO.js +362 -0
  143. package/dist/chunk-GSVK66OV.js +58 -0
  144. package/dist/chunk-GY2BY5VF.js +58 -0
  145. package/dist/chunk-HNDG5ZDJ.js +336 -0
  146. package/dist/chunk-HTD4AJUF.js +85 -0
  147. package/dist/chunk-HTU7RDZA.js +127 -0
  148. package/dist/chunk-HX4PBMY3.js +227 -0
  149. package/dist/chunk-IC2PIVLM.js +181 -0
  150. package/dist/chunk-IK3Q7NLP.js +2113 -0
  151. package/dist/chunk-IL5FQSUQ.js +2142 -0
  152. package/dist/chunk-ITWU5LJL.js +85 -0
  153. package/dist/chunk-IUIVLCAO.js +369 -0
  154. package/dist/chunk-JHJUV633.js +150 -0
  155. package/dist/chunk-JXOXGBC2.js +262 -0
  156. package/dist/chunk-KG55JL2G.js +604 -0
  157. package/dist/chunk-KGT7VT77.js +167 -0
  158. package/dist/chunk-L2DMZT56.js +210 -0
  159. package/dist/chunk-L57H26UP.js +33 -0
  160. package/dist/chunk-L5E3RXLR.js +197 -0
  161. package/dist/chunk-L5O4MFMV.js +402 -0
  162. package/dist/chunk-LAB3RQRN.js +204 -0
  163. package/dist/chunk-LCOPVYU2.js +3293 -0
  164. package/dist/chunk-LDI633LO.js +2078 -0
  165. package/dist/chunk-LJONNOFH.js +336 -0
  166. package/dist/chunk-LKM56CDI.js +2078 -0
  167. package/dist/chunk-LPO7KLSP.js +14470 -0
  168. package/dist/chunk-M46T2E3A.js +262 -0
  169. package/dist/chunk-MBJYQBUX.js +456 -0
  170. package/dist/chunk-MEWGYH6Z.js +190 -0
  171. package/dist/chunk-MHGR5CRN.js +731 -0
  172. package/dist/chunk-MR64FIZU.js +735 -0
  173. package/dist/chunk-MTRUOIND.js +159 -0
  174. package/dist/chunk-MUDCJP6B.js +68 -0
  175. package/dist/chunk-MUQ46NLH.js +3293 -0
  176. package/dist/chunk-MYVGG2VW.js +204 -0
  177. package/dist/chunk-NEFF4ATD.js +197 -0
  178. package/dist/chunk-NOC7GUHJ.js +836 -0
  179. package/dist/chunk-NOP22U7I.js +33 -0
  180. package/dist/chunk-OGFEQ264.js +448 -0
  181. package/dist/chunk-OGV67HHE.js +230 -0
  182. package/dist/chunk-OQ3CC5N2.js +54 -0
  183. package/dist/chunk-OTANU4LT.js +297 -0
  184. package/dist/chunk-P5A77YDA.js +58 -0
  185. package/dist/chunk-PIOBPKYE.js +377 -0
  186. package/dist/chunk-POEI5ZRV.js +731 -0
  187. package/dist/chunk-PS4W2VGW.js +129 -0
  188. package/dist/chunk-PT3URNVT.js +836 -0
  189. package/dist/chunk-Q4IL3S44.js +55 -0
  190. package/dist/chunk-QEDM5BJW.js +240 -0
  191. package/dist/chunk-QGYRNG7T.js +129 -0
  192. package/dist/chunk-QHNGZ6X2.js +538 -0
  193. package/dist/chunk-QOZQ2MYZ.js +42 -0
  194. package/dist/chunk-QPYEVLED.js +402 -0
  195. package/dist/chunk-QRTJNSKU.js +133 -0
  196. package/dist/chunk-R36FAN53.js +488 -0
  197. package/dist/chunk-R426G4MO.js +290 -0
  198. package/dist/chunk-RG4OHDY7.js +348 -0
  199. package/dist/chunk-RHNSYJCT.js +30 -0
  200. package/dist/chunk-RKYLET7V.js +1352 -0
  201. package/dist/chunk-RLSEMHP7.js +369 -0
  202. package/dist/chunk-ROGL26Q2.js +630 -0
  203. package/dist/chunk-RTC3JHFF.js +345 -0
  204. package/dist/chunk-RV62SMCL.js +171 -0
  205. package/dist/chunk-SC4MQTMY.js +192 -0
  206. package/dist/chunk-SCT6IMMD.js +630 -0
  207. package/dist/chunk-SOTS4FXN.js +546 -0
  208. package/dist/chunk-STS5552V.js +448 -0
  209. package/dist/chunk-SY65TI5X.js +424 -0
  210. package/dist/chunk-T67ELIV6.js +38 -0
  211. package/dist/chunk-TBSYE2WW.js +97 -0
  212. package/dist/chunk-TGRGBM7C.js +1094 -0
  213. package/dist/chunk-TGTJYERN.js +621 -0
  214. package/dist/chunk-THWAU77X.js +290 -0
  215. package/dist/chunk-TM7NUOZ7.js +574 -0
  216. package/dist/chunk-TNZWNC4O.js +106 -0
  217. package/dist/chunk-TRSYK4HA.js +1352 -0
  218. package/dist/chunk-TZIGQLY7.js +123 -0
  219. package/dist/chunk-U7PCRZEB.js +286 -0
  220. package/dist/chunk-UCBIETEA.js +373 -0
  221. package/dist/chunk-UGH4Z3BT.js +50 -0
  222. package/dist/chunk-UKRCNA3D.js +127 -0
  223. package/dist/chunk-ULUNIZOZ.js +2113 -0
  224. package/dist/chunk-UWTIDBMQ.js +411 -0
  225. package/dist/chunk-VJTS6RGD.js +81 -0
  226. package/dist/chunk-VLE2Z4JK.js +411 -0
  227. package/dist/chunk-VOGYUVYX.js +4349 -0
  228. package/dist/chunk-VPQAXUG4.js +210 -0
  229. package/dist/chunk-W3TXZRGP.js +1186 -0
  230. package/dist/chunk-WQKB25AU.js +1119 -0
  231. package/dist/chunk-WTEVY2WF.js +122 -0
  232. package/dist/chunk-X5CTZH7W.js +76 -0
  233. package/dist/chunk-XCZP6I5M.js +167 -0
  234. package/dist/chunk-XP3DCIAH.js +181 -0
  235. package/dist/chunk-XRN5MQRN.js +373 -0
  236. package/dist/chunk-XZXY66KH.js +123 -0
  237. package/dist/chunk-Y2SP7JYR.js +668 -0
  238. package/dist/chunk-Y5ZF5OFM.js +280 -0
  239. package/dist/chunk-YN7XRPQ6.js +546 -0
  240. package/dist/chunk-YQOOELC3.js +221 -0
  241. package/dist/chunk-YTKVJJSU.js +379 -0
  242. package/dist/chunk-YZJZXBPL.js +192 -0
  243. package/dist/chunk-Z2XRD6SJ.js +377 -0
  244. package/dist/chunk-ZBD56XE2.js +122 -0
  245. package/dist/chunk-ZE2XPYEC.js +299 -0
  246. package/dist/chunk-ZE4E4PMM.js +157 -0
  247. package/dist/chunk-ZIY6HVAD.js +214 -0
  248. package/dist/chunk-ZK4VCLCK.js +176 -0
  249. package/dist/chunk-ZOBV6QWD.js +54 -0
  250. package/dist/chunk-ZTGID7RE.js +1068 -0
  251. package/dist/co-activation-BOHQZWKI.js +74 -0
  252. package/dist/co-activation-KSBQKWYV.js +74 -0
  253. package/dist/co-occurrence-OSJQ2XQO.js +95 -0
  254. package/dist/co-occurrence-YKTIFNYA.js +95 -0
  255. package/dist/code-context-index-43MNXX4H.js +30 -0
  256. package/dist/conversation-entity-extractor-6PJUN5DP.js +114 -0
  257. package/dist/conversation-wiki-populator-PDL2SUZJ.js +105 -0
  258. package/dist/core-memory-TU636T4D.js +110 -0
  259. package/dist/core-memory-U74QUX6H.js +110 -0
  260. package/dist/crdt-sync-JTTYSLBV.js +33 -0
  261. package/dist/crdt-sync-UG3532QN.js +33 -0
  262. package/dist/crm-webhook-D5JCLN2M.js +10 -0
  263. package/dist/crm-webhook-Y2BDCVPM.js +10 -0
  264. package/dist/cto-delegation-gate-7TJT5EOE.js +280 -0
  265. package/dist/cto-delegation-gate-DCIFDJDX.js +280 -0
  266. package/dist/daemon-auth-CBMX4H6L.js +13 -0
  267. package/dist/daemon-orchestration-D5MFCNVH.js +139 -0
  268. package/dist/daemon-orchestration-XSDZPGYX.js +139 -0
  269. package/dist/db-backup-77QYAXID.js +37 -0
  270. package/dist/db-backup-LJVPP5AS.js +37 -0
  271. package/dist/db-restore-events-GNZS42YO.js +76 -0
  272. package/dist/doc-graph-extractor-3PI2M2LX.js +133 -0
  273. package/dist/doc-graph-extractor-CJU6HR2C.js +133 -0
  274. package/dist/dreaming-5A4MKONF.js +34 -0
  275. package/dist/dreaming-RFRHTYFN.js +34 -0
  276. package/dist/entity-boost-WXSBSZW4.js +375 -0
  277. package/dist/exe-drift-HBLGPMBH.js +70 -0
  278. package/dist/exe-drift-K7HAX5N4.js +70 -0
  279. package/dist/exe-export-JSJOEDBE.js +76 -0
  280. package/dist/exe-export-YVZMMVZZ.js +76 -0
  281. package/dist/exe-import-BO2GU36V.js +79 -0
  282. package/dist/exe-import-S6O6JTAB.js +79 -0
  283. package/dist/exe-key-5C5FYDC7.js +673 -0
  284. package/dist/exe-key-QVPXEUTV.js +673 -0
  285. package/dist/exe-org-35QVSGCM.js +73 -0
  286. package/dist/exe-snapshot-6MFTRMI5.js +338 -0
  287. package/dist/exe-snapshot-OFWZY3CY.js +338 -0
  288. package/dist/fast-db-init-E64KKZS2.js +7 -0
  289. package/dist/fast-db-init-ZSRLXT5Y.js +7 -0
  290. package/dist/founder-context-QAAWZEZM.js +96 -0
  291. package/dist/gateway/index.js +13 -12
  292. package/dist/git-staleness-3PLBSHA3.js +112 -0
  293. package/dist/git-staleness-XPWBDY2Q.js +112 -0
  294. package/dist/git-task-sweep-C5DM7CJS.js +42 -0
  295. package/dist/git-task-sweep-G2MKIFGS.js +42 -0
  296. package/dist/global-procedures-CGXY2AVS.js +22 -0
  297. package/dist/global-procedures-WLVOTD2Y.js +22 -0
  298. package/dist/graph-auto-extract-SAE3GKG5.js +183 -0
  299. package/dist/graph-auto-extract-ZLKCPSPD.js +183 -0
  300. package/dist/graph-query-AP5R6ZHO.js +28 -0
  301. package/dist/graph-rag-ZCJ4X7YL.js +35 -0
  302. package/dist/hook-integrity-A3NDG7EB.js +89 -0
  303. package/dist/hooks/bug-report-worker.js +15 -14
  304. package/dist/hooks/codex-stop-task-finalizer.js +15 -14
  305. package/dist/hooks/commit-complete.js +16 -15
  306. package/dist/hooks/error-recall.js +9 -8
  307. package/dist/hooks/exe-heartbeat-hook.js +6 -5
  308. package/dist/hooks/ingest-worker.js +5 -5
  309. package/dist/hooks/ingest.js +13 -12
  310. package/dist/hooks/instructions-loaded.js +7 -6
  311. package/dist/hooks/manifest.json +20 -20
  312. package/dist/hooks/notification.js +7 -6
  313. package/dist/hooks/post-compact.js +15 -14
  314. package/dist/hooks/post-tool-combined.js +7 -7
  315. package/dist/hooks/pre-compact.js +20 -19
  316. package/dist/hooks/pre-tool-use.js +28 -20
  317. package/dist/hooks/prompt-submit.js +28 -27
  318. package/dist/hooks/session-end.js +25 -24
  319. package/dist/hooks/session-start.js +27 -16
  320. package/dist/hooks/stop.js +22 -21
  321. package/dist/hooks/subagent-stop.js +20 -14
  322. package/dist/hooks/summary-worker.js +22 -21
  323. package/dist/index.js +23 -22
  324. package/dist/installer-ALESUE7P.js +298 -0
  325. package/dist/installer-APCDG6FF.js +40 -0
  326. package/dist/installer-BYIQKENA.js +40 -0
  327. package/dist/installer-JNHPJNO2.js +344 -0
  328. package/dist/installer-KWTPZCUH.js +40 -0
  329. package/dist/installer-MUKDPCXL.js +344 -0
  330. package/dist/installer-NR636CAL.js +298 -0
  331. package/dist/installer-O2S3ZLAH.js +344 -0
  332. package/dist/installer-T5XSDLBK.js +298 -0
  333. package/dist/key-backup-status-2EPRIAXU.js +39 -0
  334. package/dist/lib/agent-config.js +2 -2
  335. package/dist/lib/cloud-sync.js +7 -6
  336. package/dist/lib/config.js +1 -1
  337. package/dist/lib/consolidation.js +8 -7
  338. package/dist/lib/database.js +4 -3
  339. package/dist/lib/db-daemon-client.js +3 -3
  340. package/dist/lib/db.js +4 -3
  341. package/dist/lib/device-registry.js +1 -1
  342. package/dist/lib/embed-worker.js +6 -4
  343. package/dist/lib/embedder.js +4 -4
  344. package/dist/lib/employee-templates.js +6 -5
  345. package/dist/lib/employees.js +4 -3
  346. package/dist/lib/exe-daemon-client.js +3 -3
  347. package/dist/lib/exe-daemon.js +164 -63
  348. package/dist/lib/hybrid-search.js +7 -6
  349. package/dist/lib/identity.js +4 -3
  350. package/dist/lib/license.js +2 -2
  351. package/dist/lib/messaging.js +13 -12
  352. package/dist/lib/reminders.js +5 -4
  353. package/dist/lib/schedules.js +7 -6
  354. package/dist/lib/session-registry.js +10 -5
  355. package/dist/lib/skill-learning.js +8 -7
  356. package/dist/lib/store.js +6 -5
  357. package/dist/lib/task-router.js +5 -4
  358. package/dist/lib/tasks.js +14 -13
  359. package/dist/lib/tmux-routing.js +12 -11
  360. package/dist/lib/token-spend.js +5 -4
  361. package/dist/license-gate-O2LLJ6LS.js +16 -0
  362. package/dist/mcp/register-tools.js +69 -69
  363. package/dist/mcp/server.js +121 -90
  364. package/dist/mcp/tools/complete-reminder.js +6 -5
  365. package/dist/mcp/tools/create-reminder.js +6 -5
  366. package/dist/mcp/tools/create-task.js +16 -15
  367. package/dist/mcp/tools/deactivate-behavior.js +9 -8
  368. package/dist/mcp/tools/list-reminders.js +6 -5
  369. package/dist/mcp/tools/list-tasks.js +16 -15
  370. package/dist/mcp/tools/send-message.js +15 -14
  371. package/dist/mcp/tools/update-task.js +15 -14
  372. package/dist/mcp-http-config-XI53TYZL.js +29 -0
  373. package/dist/mcp-http-config-YQ3KWB73.js +29 -0
  374. package/dist/memory-cards-2F6RFUT5.js +180 -0
  375. package/dist/memory-cards-LLUWHHT3.js +180 -0
  376. package/dist/memory-graph-extractor-IT6HYWWM.js +22 -0
  377. package/dist/memory-graph-extractor-LZUQWU7P.js +22 -0
  378. package/dist/memory-poisoning-defense-45AMNLDK.js +224 -0
  379. package/dist/memory-poisoning-defense-FFO3YUFP.js +224 -0
  380. package/dist/memory-queue-HSHWXVZC.js +19 -0
  381. package/dist/memory-queue-client-AJ2WHEEE.js +16 -0
  382. package/dist/memory-reflection-JGA6ULGJ.js +244 -0
  383. package/dist/memory-reflection-ZT4ST2SS.js +244 -0
  384. package/dist/message-queue-client-SANA7URQ.js +92 -0
  385. package/dist/notifications-S5QQ3SBU.js +47 -0
  386. package/dist/notifications-YBJCZJDR.js +47 -0
  387. package/dist/oauth-server-VEMBOSS3.js +437 -0
  388. package/dist/orchestration-events-CYDARUFL.js +27 -0
  389. package/dist/orchestration-events-F67I3TG6.js +27 -0
  390. package/dist/orchestration-phase-EMDEZHIU.js +23 -0
  391. package/dist/orchestrator-B4CUAA7M.js +35 -0
  392. package/dist/orchestrator-GBONJR6S.js +35 -0
  393. package/dist/pipeline-router-FKCP3RCU.js +15 -0
  394. package/dist/pipeline-router-LIQTRMQW.js +15 -0
  395. package/dist/plan-limits-BQ2CEB66.js +28 -0
  396. package/dist/plan-limits-H63HOJ4H.js +28 -0
  397. package/dist/project-boot-4CLI3CLL.js +299 -0
  398. package/dist/project-boot-VSMQJDDI.js +299 -0
  399. package/dist/projection-worker-55EFFXOK.js +1084 -0
  400. package/dist/projection-worker-IQ55BIX7.js +1084 -0
  401. package/dist/prospective-memory-E7WBD5V4.js +232 -0
  402. package/dist/prospective-memory-GE7TW6EW.js +232 -0
  403. package/dist/push-notifications-CV5UD5CC.js +15 -0
  404. package/dist/reranker-PZWHSEGQ.js +19 -0
  405. package/dist/reranker-WSJEPXIY.js +19 -0
  406. package/dist/reranker-ZBN2GKIO.js +19 -0
  407. package/dist/retrieval-health-HBFTJ5M3.js +11 -0
  408. package/dist/retrieval-health-M2OE7USG.js +11 -0
  409. package/dist/review-polling-BBOASCWL.js +126 -0
  410. package/dist/review-polling-WTJZTCTD.js +126 -0
  411. package/dist/runtime/index.js +19 -18
  412. package/dist/session-events-POJ3YCUQ.js +38 -0
  413. package/dist/session-events-QVNSNSQN.js +38 -0
  414. package/dist/session-kill-telemetry-65TJ5XV7.js +31 -0
  415. package/dist/session-kill-telemetry-OC34JTYX.js +31 -0
  416. package/dist/session-scope-3WDVXSJH.js +88 -0
  417. package/dist/session-scope-KRQL3PIP.js +88 -0
  418. package/dist/setup-wizard-FE2MBSZS.js +12 -0
  419. package/dist/setup-wizard-UUAEUY3X.js +12 -0
  420. package/dist/shard-manager-P5ZJH4AX.js +30 -0
  421. package/dist/skill-refinement-5MCWYJW4.js +159 -0
  422. package/dist/skill-refinement-TRSMFCKK.js +159 -0
  423. package/dist/stack-update-OGFSAV6F.js +80 -0
  424. package/dist/steward-gate-L43S6CSV.js +15 -0
  425. package/dist/steward-gate-LCR46RJV.js +15 -0
  426. package/dist/support-outbox-QPQQK7F7.js +547 -0
  427. package/dist/task-enforcement-DRWNGNLH.js +506 -0
  428. package/dist/task-enforcement-STQBU5AM.js +506 -0
  429. package/dist/task-scope-A2IJJQQS.js +37 -0
  430. package/dist/task-scope-X3JOBCZV.js +37 -0
  431. package/dist/tasks-crud-66VBOQTI.js +79 -0
  432. package/dist/tasks-crud-ZD24ZQOL.js +79 -0
  433. package/dist/tasks-notify-EPWV6YRP.js +40 -0
  434. package/dist/tasks-notify-GHPMBTB3.js +40 -0
  435. package/dist/tasks-review-P6ZVW3ZV.js +49 -0
  436. package/dist/tasks-review-VXJVJ7ZT.js +49 -0
  437. package/dist/telemetry-upload-KCE2IT6P.js +741 -0
  438. package/dist/telemetry-upload-ZNAMKKNS.js +741 -0
  439. package/dist/token-budget-GHUZSDOD.js +86 -0
  440. package/dist/token-budget-O7B4NGY3.js +86 -0
  441. package/dist/tool-capability-index-3OZFBAC3.js +10 -0
  442. package/dist/tool-telemetry-EWAC3F75.js +17 -0
  443. package/dist/tool-telemetry-IO6L62QY.js +17 -0
  444. package/dist/tui/App.js +25 -24
  445. package/dist/tui-data-2KSB36YG.js +260 -0
  446. package/dist/tui-data-YVJ72ZVD.js +260 -0
  447. package/dist/webhook-pipe-PAPBITL4.js +114 -0
  448. package/dist/wiki-acl-HTRRAQGV.js +111 -0
  449. package/dist/wiki-acl-MNG2ROWJ.js +111 -0
  450. package/dist/wiki-client-Q4O6EMTP.js +157 -0
  451. package/dist/worker-gate-EVQTUUIF.js +21 -0
  452. package/dist/worker-gate-XKPDQQY4.js +21 -0
  453. package/dist/workflow-engine-JYGEDGTL.js +28 -0
  454. package/dist/workflow-engine-UBTXKWRV.js +28 -0
  455. package/dist/worktree-VPSXFHXP.js +28 -0
  456. package/dist/worktree-ZH5AT35X.js +28 -0
  457. package/dist/worktree-sweep-BIUP4BGY.js +21 -0
  458. package/dist/worktree-sweep-KEHR4NFP.js +21 -0
  459. package/package.json +2 -2
  460. package/release-notes.json +101 -101
  461. package/stack.release.json +8 -0
@@ -2,6 +2,10 @@
2
2
  # Copy to .env before deployment and replace every CHANGEME_* value.
3
3
  # Values under # SET_MANUALLY must be provided by the operator.
4
4
 
5
+ # --- Domain ---
6
+ # Customer apex domain. Drives auth gateway templating and GoTrue From address.
7
+ DOMAIN=CHANGEME_DOMAIN
8
+
5
9
  # --- Data Layer ---
6
10
  POSTGRES_USER=exe
7
11
  POSTGRES_PASSWORD=CHANGEME_POSTGRES_PASSWORD
@@ -18,8 +22,17 @@ GOTRUE_JWT_SECRET=CHANGEME_GOTRUE_JWT_SECRET
18
22
  GOTRUE_API_PORT=9999
19
23
  GOTRUE_SITE_URL=https://crm.CHANGEME_DOMAIN
20
24
  GOTRUE_EXTERNAL_URL=https://auth.CHANGEME_DOMAIN
25
+ # SSO redirect allow-list (bug 66f8e10a) — app origins for unified SSO.
26
+ GOTRUE_URI_ALLOW_LIST=https://crm.CHANGEME_DOMAIN,https://wiki.CHANGEME_DOMAIN,https://erp.CHANGEME_DOMAIN
21
27
  GOTRUE_DISABLE_SIGNUP=true
22
28
  GOTRUE_MAILER_AUTOCONFIRM=false
29
+ # Auth-email From address — customer domain, not askexe.com (bug 133c9d5b).
30
+ SMTP_FROM=noreply@CHANGEME_DOMAIN
31
+ # To enable verified email confirmation, set SMTP_* (MAILER_AUTOCONFIRM stays false).
32
+ SMTP_HOST=
33
+ SMTP_PORT=587
34
+ SMTP_USER=
35
+ SMTP_PASS=
23
36
 
24
37
  # --- CRM ---
25
38
  CRM_IMAGE_TAG=update.askexe.com/askexe/exe-crm:v0.9.47
@@ -48,7 +61,7 @@ EXE_MCP_HOST_PORT=48739
48
61
  EXE_CLOUD_SYNC_TO_POSTGRES=true
49
62
 
50
63
  # --- ERP (Frappe/ERPNext fork) ---
51
- ERP_IMAGE_TAG=update.askexe.com/askexe/exe-erp:v0.2.0-final7
64
+ ERP_IMAGE_TAG=update.askexe.com/askexe/exe-erp:v0.2.0-final8
52
65
  # Administrator password for the ERPNext site (created on first boot).
53
66
  ERP_ADMIN_PASSWORD=CHANGEME_ERP_ADMIN_PASSWORD
54
67
  ERP_SITE_NAME=erp.askexe.com
@@ -2,6 +2,10 @@
2
2
  # Copy to .env before deployment and replace every CHANGEME_* value.
3
3
  # Values under # SET_MANUALLY must be provided by the operator.
4
4
 
5
+ # --- Domain ---
6
+ # Customer apex domain. Drives auth gateway templating and GoTrue From address.
7
+ DOMAIN=CHANGEME_DOMAIN
8
+
5
9
  # --- Data Layer ---
6
10
  POSTGRES_USER=exe
7
11
  POSTGRES_PASSWORD=CHANGEME_POSTGRES_PASSWORD
@@ -13,13 +17,48 @@ CLICKHOUSE_PASSWORD=CHANGEME_CLICKHOUSE_PASSWORD
13
17
 
14
18
  REDIS_PASSWORD=CHANGEME_REDIS_PASSWORD
15
19
 
20
+ # --- Backups (bug 56a71515 off-box, fc71e7ca failure handling) ---
21
+ # Off-box upload: the daily cron runs `backup.sh --upload-r2`. Without this the
22
+ # encrypted archive only ever lands on the same disk as live data (disk death =
23
+ # total loss). R2 creds are reused from the R2_MEDIA_* vars when set.
24
+ # EXE_BACKUP_KEY=CHANGEME_EXE_BACKUP_KEY # 256-bit key — encrypts archives at rest
25
+ BACKUP_RETENTION_DAYS=7
26
+ # Override the DB container name if your topology differs (default: exe-db).
27
+ # BACKUP_DB_CONTAINER=exe-db
28
+ # Failure alerting (no silent success). Set either/both:
29
+ # BACKUP_ALERT_WEBHOOK — POST {host,stage,message} on any backup failure
30
+ # BACKUP_HEALTHCHECK_URL — ping on success, <url>/fail on failure (healthchecks.io)
31
+ # BACKUP_ALERT_WEBHOOK=
32
+ # BACKUP_HEALTHCHECK_URL=
33
+
34
+ # WAL archiving / Point-In-Time Recovery (bug 5176aa4e) — OPT-IN.
35
+ # Defaults below keep the stack booting exactly as before (archive_mode=off,
36
+ # RPO = nightly pg_dump). Set PG_ARCHIVE_MODE=on to enable continuous WAL
37
+ # archiving into the pg_wal_archive volume; back that volume off-box for PITR.
38
+ # PG_ARCHIVE_MODE=off
39
+ # PG_WAL_LEVEL=replica
40
+ # PG_ARCHIVE_TIMEOUT=300
41
+ # PG_MAX_WAL_SENDERS=3
42
+ # Custom archive target (e.g. push WAL straight to off-box storage). Leave unset
43
+ # to use the default copy into /var/lib/postgresql/wal_archive.
44
+ # PG_ARCHIVE_COMMAND=
45
+
16
46
  # --- GoTrue (shared auth) ---
17
47
  GOTRUE_JWT_SECRET=CHANGEME_GOTRUE_JWT_SECRET
18
48
  GOTRUE_API_PORT=9999
19
49
  GOTRUE_SITE_URL=https://crm.CHANGEME_DOMAIN
20
50
  GOTRUE_EXTERNAL_URL=https://auth.CHANGEME_DOMAIN
51
+ # SSO redirect allow-list (bug 66f8e10a) — app origins for unified SSO.
52
+ GOTRUE_URI_ALLOW_LIST=https://crm.CHANGEME_DOMAIN,https://wiki.CHANGEME_DOMAIN,https://erp.CHANGEME_DOMAIN
21
53
  GOTRUE_DISABLE_SIGNUP=true
22
54
  GOTRUE_MAILER_AUTOCONFIRM=false
55
+ # From address for auth emails — customer domain, not askexe.com (bug 133c9d5b).
56
+ SMTP_FROM=noreply@CHANGEME_DOMAIN
57
+ # To enable verified email confirmation, set SMTP_* below (MAILER_AUTOCONFIRM stays false).
58
+ SMTP_HOST=
59
+ SMTP_PORT=587
60
+ SMTP_USER=
61
+ SMTP_PASS=
23
62
 
24
63
  # --- CRM ---
25
64
  CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.47
@@ -73,7 +112,7 @@ ERROR_REPORTING_ENABLED=true
73
112
  MONITOR_ERROR_URL=http://exe-monitor-hub:8090/api/exe-monitor/errors
74
113
 
75
114
  # --- ERP (optional — Exe ERP, Frappe/ERPNext fork) ---
76
- ERP_IMAGE_TAG=ghcr.io/askexe/exe-erp:v0.2.0-final7
115
+ ERP_IMAGE_TAG=ghcr.io/askexe/exe-erp:v0.2.0-final8
77
116
  ERP_ADMIN_PASSWORD=CHANGEME_ERP_ADMIN_PASSWORD
78
117
  EXE_ERP_ADMIN_TOKEN=CHANGEME_EXE_ERP_ADMIN_TOKEN
79
118
  ERP_SITE_NAME=erp.askexe.com
@@ -5,8 +5,19 @@
5
5
  # ./backup.sh # Backup to /opt/exe-backups/
6
6
  # ./backup.sh --output /tmp/backup # Backup to custom dir
7
7
  # ./backup.sh --download # Create backup + print download command
8
- # ./backup.sh --upload-r2 # Backup + upload to Cloudflare R2
9
- # ./backup.sh --upload-s3 s3://bucket # Backup + upload to S3
8
+ # ./backup.sh --upload-r2 # Backup + upload to Cloudflare R2 (off-box)
9
+ # ./backup.sh --upload-s3 s3://bucket # Backup + upload to S3 (off-box)
10
+ #
11
+ # FAILURE HANDLING (bug fc71e7ca):
12
+ # The script aborts (non-zero exit) the moment a CRITICAL step fails — the
13
+ # postgres dump is gated on pg_dumpall's exit code, so it NEVER prints
14
+ # "backup ok" over a failed/empty dump. Failures are logged AND surface an
15
+ # alert via an optional webhook (BACKUP_ALERT_WEBHOOK) and/or a healthcheck
16
+ # ping (BACKUP_HEALTHCHECK_URL — e.g. healthchecks.io). No silent success.
17
+ #
18
+ # OFF-BOX (bug 56a71515): pass --upload-r2 (or --upload-s3) — or set the cron
19
+ # to do so — so the encrypted archive leaves the VPS disk. A backup that only
20
+ # ever lands on the same disk as live data does not survive disk/host loss.
10
21
  #
11
22
  set -euo pipefail
12
23
 
@@ -17,6 +28,51 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
17
28
  DOWNLOAD_MODE=false
18
29
  UPLOAD_R2=false
19
30
  UPLOAD_S3=""
31
+ # Real DB container name. Past bug fc71e7ca referenced a non-existent
32
+ # 'crm-postgres'; the canonical stack DB container is 'exe-db'. Override via env.
33
+ DB_CONTAINER="${BACKUP_DB_CONTAINER:-exe-db}"
34
+ PG_USER="${POSTGRES_USER:-exe}"
35
+
36
+ # ------------------------------------------------------------------
37
+ # Alerting — surface failures loudly. Optional, configured via env:
38
+ # BACKUP_ALERT_WEBHOOK — POST a JSON {host,stage,message} on failure
39
+ # BACKUP_HEALTHCHECK_URL — ping <url> on success, <url>/fail on failure
40
+ # (compatible with healthchecks.io / Uptime Kuma)
41
+ # ------------------------------------------------------------------
42
+ HOST_NAME="$(hostname 2>/dev/null || echo unknown)"
43
+ ALERT_WEBHOOK="${BACKUP_ALERT_WEBHOOK:-}"
44
+ HEALTHCHECK_URL="${BACKUP_HEALTHCHECK_URL:-}"
45
+ if [[ -z "$ALERT_WEBHOOK" && -f "$SCRIPT_DIR/.env" ]]; then
46
+ ALERT_WEBHOOK=$(grep -E '^BACKUP_ALERT_WEBHOOK=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d= -f2- || true)
47
+ fi
48
+ if [[ -z "$HEALTHCHECK_URL" && -f "$SCRIPT_DIR/.env" ]]; then
49
+ HEALTHCHECK_URL=$(grep -E '^BACKUP_HEALTHCHECK_URL=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d= -f2- || true)
50
+ fi
51
+
52
+ alert() {
53
+ # alert <stage> <message>
54
+ local stage="$1"; shift
55
+ local msg="$*"
56
+ echo "[backup][ERROR] stage=$stage: $msg" >&2
57
+ if [[ -n "$ALERT_WEBHOOK" ]] && command -v curl >/dev/null 2>&1; then
58
+ curl -fsS -m 10 -X POST "$ALERT_WEBHOOK" \
59
+ -H 'Content-Type: application/json' \
60
+ -d "{\"host\":\"$HOST_NAME\",\"stage\":\"$stage\",\"message\":\"$msg\"}" \
61
+ >/dev/null 2>&1 || echo "[backup] (alert webhook POST failed)" >&2
62
+ fi
63
+ if [[ -n "$HEALTHCHECK_URL" ]] && command -v curl >/dev/null 2>&1; then
64
+ curl -fsS -m 10 "${HEALTHCHECK_URL%/}/fail" >/dev/null 2>&1 || true
65
+ fi
66
+ }
67
+
68
+ # fail <stage> <message> — emit alert and exit non-zero. No silent success.
69
+ fail() {
70
+ alert "$1" "$2"
71
+ exit 1
72
+ }
73
+
74
+ # Any unexpected error (set -e) routes through here so we still alert.
75
+ trap 'fail "unexpected" "backup aborted at line $LINENO (see log above)"' ERR
20
76
 
21
77
  while [[ $# -gt 0 ]]; do
22
78
  case $1 in
@@ -34,12 +90,26 @@ mkdir -p "$ARCHIVE"
34
90
 
35
91
  echo "[backup] Starting exe-os full stack backup ($DATE)"
36
92
 
37
- # 1. Postgres dump (all databases)
38
- echo "[backup] Dumping postgres..."
39
- docker exec exe-db pg_dumpall -U exe > "$ARCHIVE/postgres.sql" 2>/dev/null || echo "[backup] Postgres dump failed"
40
- gzip "$ARCHIVE/postgres.sql" 2>/dev/null || true
93
+ # 1. Postgres dump (all databases) — CRITICAL. Gate success on the exit code.
94
+ # Previously a failure here was swallowed by `|| echo` and the script still
95
+ # printed "backup ok" over an empty dump (bug fc71e7ca). Now we abort.
96
+ echo "[backup] Dumping postgres from container '$DB_CONTAINER'..."
97
+ if ! docker exec "$DB_CONTAINER" pg_dumpall -U "$PG_USER" > "$ARCHIVE/postgres.sql" 2> "$ARCHIVE/postgres.err"; then
98
+ cat "$ARCHIVE/postgres.err" >&2 || true
99
+ fail "pg_dumpall" "postgres dump failed (container=$DB_CONTAINER user=$PG_USER) — backup aborted, NOT marked ok"
100
+ fi
101
+ # Guard against a 0-byte / truncated dump that still exits 0.
102
+ if [[ ! -s "$ARCHIVE/postgres.sql" ]]; then
103
+ fail "pg_dumpall" "postgres dump produced an empty file — refusing to report success"
104
+ fi
105
+ rm -f "$ARCHIVE/postgres.err"
106
+ if ! gzip "$ARCHIVE/postgres.sql"; then
107
+ fail "gzip" "failed to compress postgres.sql"
108
+ fi
109
+ echo "[backup] Postgres dump OK ($(du -h "$ARCHIVE/postgres.sql.gz" | cut -f1))"
41
110
 
42
111
  # 2. Customer config files (.env, gateway.json, branding.json, clickhouse-config.xml, cloudflared)
112
+ # Non-fatal: copy what exists. These are also recoverable from the operator's saved .env.
43
113
  echo "[backup] Backing up config files..."
44
114
  cp "$SCRIPT_DIR/.env" "$ARCHIVE/env.bak" 2>/dev/null || true
45
115
  cp "$SCRIPT_DIR/gateway.json" "$ARCHIVE/gateway.json" 2>/dev/null || true
@@ -49,20 +119,22 @@ cp -r "$SCRIPT_DIR/cloudflared" "$ARCHIVE/cloudflared" 2>/dev/null || true
49
119
 
50
120
  # 3. Gateway auth state (Baileys creds — critical for WhatsApp connection)
51
121
  echo "[backup] Backing up gateway WhatsApp auth state..."
52
- docker cp exe-gateway:/data/. "$ARCHIVE/gateway-data/" 2>/dev/null || echo "[backup] Gateway data skipped"
122
+ docker cp exe-gateway:/data/. "$ARCHIVE/gateway-data/" 2>/dev/null || echo "[backup] Gateway data skipped (container not running)"
53
123
 
54
124
  # 4. Wiki storage (uploaded documents)
55
125
  echo "[backup] Backing up wiki storage..."
56
- docker cp exe-wiki:/app/server/storage/. "$ARCHIVE/wiki-storage/" 2>/dev/null || echo "[backup] Wiki storage skipped"
126
+ docker cp exe-wiki:/app/server/storage/. "$ARCHIVE/wiki-storage/" 2>/dev/null || echo "[backup] Wiki storage skipped (container not running)"
57
127
 
58
128
  # 5. exe-os daemon state (optional — SQLCipher DB is local-first, not critical for VPS)
59
129
  echo "[backup] Backing up exe-os state..."
60
- docker cp exe-os:/home/exed/.exe-os/. "$ARCHIVE/exe-os-data/" 2>/dev/null || echo "[backup] exe-os data skipped"
130
+ docker cp exe-os:/home/exed/.exe-os/. "$ARCHIVE/exe-os-data/" 2>/dev/null || echo "[backup] exe-os data skipped (container not running)"
61
131
 
62
- # 6. Create single archive (compressed)
132
+ # 6. Create single archive (compressed) — CRITICAL.
63
133
  echo "[backup] Creating archive..."
64
134
  TARFILE="$BACKUP_DIR/exe-backup-$DATE.tar.gz"
65
- tar -czf "$TARFILE" -C "$BACKUP_DIR" "exe-backup-$DATE" 2>/dev/null
135
+ if ! tar -czf "$TARFILE" -C "$BACKUP_DIR" "exe-backup-$DATE"; then
136
+ fail "tar" "failed to create archive $TARFILE"
137
+ fi
66
138
  rm -rf "$ARCHIVE"
67
139
  echo "[backup] Archive: $TARFILE ($(du -h "$TARFILE" | cut -f1))"
68
140
 
@@ -71,28 +143,30 @@ echo "[backup] Archive: $TARFILE ($(du -h "$TARFILE" | cut -f1))"
71
143
  # Without this key, R2 backups are unreadable — even AskExe cannot access them.
72
144
  BACKUP_KEY="${EXE_BACKUP_KEY:-}"
73
145
  if [[ -z "$BACKUP_KEY" && -f "$SCRIPT_DIR/.env" ]]; then
74
- BACKUP_KEY=$(grep -E '^EXE_BACKUP_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d= -f2)
146
+ BACKUP_KEY=$(grep -E '^EXE_BACKUP_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d= -f2- || true)
75
147
  fi
76
148
  if [[ -n "$BACKUP_KEY" ]]; then
77
149
  ENCRYPTED_FILE="${TARFILE}.enc"
78
150
  echo "[backup] Encrypting with AES-256-CBC (customer-owned key)..."
79
- openssl enc -aes-256-cbc -pbkdf2 -iter 100000 \
80
- -in "$TARFILE" -out "$ENCRYPTED_FILE" \
81
- -pass "pass:${BACKUP_KEY}" 2>/dev/null
82
- if [[ -f "$ENCRYPTED_FILE" ]]; then
83
- rm -f "$TARFILE"
84
- TARFILE="$ENCRYPTED_FILE"
85
- echo "[backup] Encrypted: $TARFILE ($(du -h "$TARFILE" | cut -f1))"
86
- else
87
- echo "[backup] Encryption failed — uploading compressed (unencrypted)"
151
+ if ! openssl enc -aes-256-cbc -pbkdf2 -iter 100000 \
152
+ -in "$TARFILE" -out "$ENCRYPTED_FILE" \
153
+ -pass "pass:${BACKUP_KEY}"; then
154
+ fail "encrypt" "openssl encryption failed — refusing to upload plaintext customer data"
88
155
  fi
156
+ rm -f "$TARFILE"
157
+ TARFILE="$ENCRYPTED_FILE"
158
+ echo "[backup] Encrypted: $TARFILE ($(du -h "$TARFILE" | cut -f1))"
89
159
  else
90
- echo "[backup] WARNING: EXE_BACKUP_KEY not set — backup NOT encrypted. Set it in .env for E2E encryption."
160
+ echo "[backup] WARNING: EXE_BACKUP_KEY not set — backup NOT encrypted. Set it in .env for E2E encryption." >&2
91
161
  fi
92
162
 
93
- # 7. Retention — delete old backups
163
+ # 7. Retention — delete old backups (match BOTH .tar.gz and encrypted .tar.gz.enc).
94
164
  echo "[backup] Cleaning backups older than $RETENTION_DAYS days..."
95
- find "$BACKUP_DIR" -name "exe-backup-*.tar.gz" -mtime "+$RETENTION_DAYS" -delete 2>/dev/null
165
+ find "$BACKUP_DIR" -name "exe-backup-*.tar.gz" -mtime "+$RETENTION_DAYS" -delete 2>/dev/null || true
166
+ find "$BACKUP_DIR" -name "exe-backup-*.tar.gz.enc" -mtime "+$RETENTION_DAYS" -delete 2>/dev/null || true
167
+
168
+ # Track off-box result so we can refuse to claim success on an upload-only run.
169
+ OFFBOX_OK=true
96
170
 
97
171
  # 8. Download instructions
98
172
  if $DOWNLOAD_MODE; then
@@ -100,58 +174,89 @@ if $DOWNLOAD_MODE; then
100
174
  echo "=== Download to your local machine ==="
101
175
  echo "Run on your local machine:"
102
176
  echo ""
103
- HOSTNAME=$(hostname)
104
177
  IP=$(curl -s ifconfig.me 2>/dev/null || echo "<VPS_IP>")
105
- echo " scp root@$IP:$TARFILE ./exe-backup-$DATE.tar.gz"
178
+ echo " scp root@$IP:$TARFILE ./$(basename "$TARFILE")"
106
179
  echo ""
107
180
  echo "Or via Tailscale:"
108
181
  TS_IP=$(tailscale ip -4 2>/dev/null || echo "<TAILSCALE_IP>")
109
- echo " scp root@$TS_IP:$TARFILE ./exe-backup-$DATE.tar.gz"
182
+ echo " scp root@$TS_IP:$TARFILE ./$(basename "$TARFILE")"
110
183
  echo ""
111
184
  echo "To restore on a new VPS:"
112
- echo " tar -xzf exe-backup-$DATE.tar.gz"
185
+ echo " tar -xzf exe-backup-$DATE.tar.gz # (decrypt the .enc first if encrypted)"
113
186
  echo " cp env.bak /opt/exe-stack/.env"
114
187
  echo " cp gateway.json /opt/exe-stack/"
115
188
  echo " cp branding.json /opt/exe-stack/"
116
189
  echo " cp clickhouse-config.xml /opt/exe-stack/"
117
190
  echo " cp -r cloudflared/ /opt/exe-stack/"
118
- echo " cat postgres.sql.gz | gunzip | docker exec -i exe-db psql -U exe"
191
+ echo " cat postgres.sql.gz | gunzip | docker exec -i $DB_CONTAINER psql -U $PG_USER"
119
192
  echo " docker compose up -d"
120
193
  fi
121
194
 
122
- # 9. Upload to R2 (Cloudflare) — uses same R2 credentials as media/cloud sync
195
+ # 9. Upload to R2 (Cloudflare) — uses same R2 credentials as media/cloud sync.
196
+ # OFF-BOX target (bug 56a71515): this is what survives disk/host death.
123
197
  if $UPLOAD_R2; then
124
- # Source .env for R2 credentials if not already in environment
125
198
  if [[ -z "${R2_ENDPOINT:-}" && -f "$SCRIPT_DIR/.env" ]]; then
126
199
  # Map R2_MEDIA_* vars to the aws-cli vars backup needs
127
- eval "$(grep -E '^R2_MEDIA_' "$SCRIPT_DIR/.env" 2>/dev/null)"
200
+ eval "$(grep -E '^R2_MEDIA_' "$SCRIPT_DIR/.env" 2>/dev/null || true)"
128
201
  export R2_ENDPOINT="${R2_ENDPOINT:-${R2_MEDIA_ENDPOINT:-}}"
129
202
  export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY_ID:-${R2_MEDIA_ACCESS_KEY:-}}"
130
203
  export AWS_SECRET_ACCESS_KEY="${AWS_SECRET_ACCESS_KEY:-${R2_MEDIA_SECRET_KEY:-}}"
131
204
  fi
132
205
 
133
206
  R2_BACKUP_BUCKET="${R2_BACKUP_BUCKET:-${R2_MEDIA_BUCKET:-exe-backups}}"
134
- R2_BACKUP_PREFIX="${R2_BACKUP_PREFIX:-backups/$(hostname)}"
207
+ R2_BACKUP_PREFIX="${R2_BACKUP_PREFIX:-backups/$HOST_NAME}"
135
208
 
136
209
  if [[ -z "${R2_ENDPOINT:-}" ]]; then
137
- echo "[backup] R2 upload skipped — R2_MEDIA_ENDPOINT not set in .env"
210
+ OFFBOX_OK=false
211
+ alert "r2-config" "R2 upload requested but R2_MEDIA_ENDPOINT not set in .env — backup stayed on-box only"
138
212
  elif command -v rclone >/dev/null 2>&1; then
139
- rclone copy "$TARFILE" "r2:${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/" 2>&1 && echo "[backup] R2 upload complete → ${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/" || echo "[backup] R2 upload failed"
213
+ if rclone copy "$TARFILE" "r2:${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/"; then
214
+ echo "[backup] R2 upload complete → ${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/"
215
+ else
216
+ OFFBOX_OK=false
217
+ alert "r2-upload" "rclone upload to ${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/ failed — off-box copy missing"
218
+ fi
140
219
  elif command -v aws >/dev/null 2>&1; then
141
- aws s3 cp "$TARFILE" "s3://${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/$(basename "$TARFILE")" \
142
- --endpoint-url "${R2_ENDPOINT}" 2>&1 && echo "[backup] R2 upload complete" || echo "[backup] R2 upload failed"
220
+ if aws s3 cp "$TARFILE" "s3://${R2_BACKUP_BUCKET}/${R2_BACKUP_PREFIX}/$(basename "$TARFILE")" \
221
+ --endpoint-url "${R2_ENDPOINT}"; then
222
+ echo "[backup] R2 upload complete"
223
+ else
224
+ OFFBOX_OK=false
225
+ alert "r2-upload" "aws s3 cp to ${R2_BACKUP_BUCKET} failed — off-box copy missing"
226
+ fi
143
227
  else
144
- echo "[backup] Install rclone or aws-cli for R2 upload. apt install awscli"
228
+ OFFBOX_OK=false
229
+ alert "r2-tooling" "neither rclone nor aws-cli installed — cannot push backup off-box. apt install rclone"
145
230
  fi
146
231
  fi
147
232
 
148
- # 10. Upload to S3
233
+ # 10. Upload to S3 (off-box)
149
234
  if [[ -n "$UPLOAD_S3" ]]; then
150
235
  echo "[backup] Uploading to S3..."
151
- aws s3 cp "$TARFILE" "$UPLOAD_S3/$(basename "$TARFILE")" 2>&1 && echo "[backup] S3 upload complete" || echo "[backup] S3 upload failed"
236
+ if ! command -v aws >/dev/null 2>&1; then
237
+ OFFBOX_OK=false
238
+ alert "s3-tooling" "aws-cli not installed — cannot upload to $UPLOAD_S3"
239
+ elif aws s3 cp "$TARFILE" "$UPLOAD_S3/$(basename "$TARFILE")"; then
240
+ echo "[backup] S3 upload complete"
241
+ else
242
+ OFFBOX_OK=false
243
+ alert "s3-upload" "aws s3 cp to $UPLOAD_S3 failed — off-box copy missing"
244
+ fi
245
+ fi
246
+
247
+ # 11. Final result. Only ping the healthcheck success URL if everything that was
248
+ # requested actually succeeded — including the off-box upload when asked for.
249
+ if { $UPLOAD_R2 || [[ -n "$UPLOAD_S3" ]]; } && [[ "$OFFBOX_OK" != true ]]; then
250
+ fail "offbox" "local archive created but off-box upload did not complete — DR copy is missing"
251
+ fi
252
+
253
+ if [[ -n "$HEALTHCHECK_URL" ]] && command -v curl >/dev/null 2>&1; then
254
+ curl -fsS -m 10 "$HEALTHCHECK_URL" >/dev/null 2>&1 || echo "[backup] (success healthcheck ping failed)" >&2
152
255
  fi
153
256
 
154
- echo "[backup] Done."
257
+ # Clear the ERR trap before the clean exit.
258
+ trap - ERR
259
+ echo "[backup] Done — backup OK."
155
260
  echo ""
156
261
  echo "Backups:"
157
- ls -lh "$BACKUP_DIR"/exe-backup-*.tar.gz 2>/dev/null | tail -5
262
+ ls -lh "$BACKUP_DIR"/exe-backup-*.tar.gz* 2>/dev/null | tail -5