@askexenow/exe-os 0.9.382 → 0.9.384

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 (493) hide show
  1. package/delivery/catalog.json +1254 -0
  2. package/deploy/compose/.env.customer.example +5 -5
  3. package/deploy/compose/.env.example +3 -3
  4. package/deploy/compose/docker-compose.yml +1 -1
  5. package/deploy/compose/generate-env.ts +65 -9
  6. package/deploy/compose/setup.sh +205 -7
  7. package/deploy/compose/sso-edge/default.conf.template +45 -0
  8. package/deploy/compose/sso-edge/sso-redirect.conf +11 -2
  9. package/deploy/stack-manifests/v0.9.30-apps.json +1 -1
  10. package/deploy/stack-manifests/v0.9.json +254 -2
  11. package/dist/.dist-verified.json +3 -3
  12. package/dist/{active-agent-GFUUCFLD.js → active-agent-F5V4E4UL.js} +7 -7
  13. package/dist/{active-agent-LE6FE6SO.js → active-agent-YTBB4ZQM.js} +7 -7
  14. package/dist/{agent-defs-generator-EIUA3SH5.js → agent-defs-generator-7TFISIJQ.js} +6 -6
  15. package/dist/{agent-loop-7ZRH56EX.js → agent-loop-EZ7LDAGD.js} +1 -1
  16. package/dist/{agentic-ontology-67JGSP7G.js → agentic-ontology-XVTUVV7W.js} +1 -1
  17. package/dist/{artifact-backup-NYXAYASJ.js → artifact-backup-TF6YWQT2.js} +5 -5
  18. package/dist/{backfill-gate-KWJQ35YX.js → backfill-gate-FWYLCGNJ.js} +3 -3
  19. package/dist/{backfill-metadata-RQYG2WUJ.js → backfill-metadata-J6MXIDCW.js} +10 -10
  20. package/dist/{background-jobs-6VMD55PK.js → background-jobs-V3DZRFKU.js} +3 -3
  21. package/dist/{backup-verify-HC4YDSGN.js → backup-verify-6DVBQMDP.js} +67 -18
  22. package/dist/{behavior-injection-6HSXP43Q.js → behavior-injection-XDA7ZCYN.js} +21 -20
  23. package/dist/{behavior-promotion-SJDQ2Y3U.js → behavior-promotion-4VLQ7LXK.js} +20 -19
  24. package/dist/{behaviors-6ITLA2CK.js → behaviors-SCCZP7RZ.js} +19 -18
  25. package/dist/bin/age-ontology-load.js +3 -3
  26. package/dist/bin/agentic-ontology-backfill.js +12 -12
  27. package/dist/bin/agentic-reflection-backfill.js +13 -13
  28. package/dist/bin/agentic-semantic-label.js +12 -12
  29. package/dist/bin/backfill-conversations.js +17 -16
  30. package/dist/bin/backfill-responses.js +17 -16
  31. package/dist/bin/backfill-vectors.js +23 -22
  32. package/dist/bin/bulk-sync-postgres.js +28 -27
  33. package/dist/bin/cc-doctor.js +17 -16
  34. package/dist/bin/cleanup-stale-review-tasks.js +29 -28
  35. package/dist/bin/cli.js +35 -26
  36. package/dist/bin/deferred-daemon-restart.js +124 -123
  37. package/dist/bin/exe-actions.js +1 -1
  38. package/dist/bin/exe-agent-config.js +6 -6
  39. package/dist/bin/exe-agent.js +22 -22
  40. package/dist/bin/exe-assign.js +19 -18
  41. package/dist/bin/exe-boot.js +57 -56
  42. package/dist/bin/exe-call.js +7 -7
  43. package/dist/bin/exe-cicd.js +38 -8
  44. package/dist/bin/exe-cloud.js +30 -29
  45. package/dist/bin/exe-config-dump.js +6 -6
  46. package/dist/bin/exe-dispatch.js +30 -29
  47. package/dist/bin/exe-doctor.js +11 -11
  48. package/dist/bin/exe-export-behaviors.js +23 -22
  49. package/dist/bin/exe-forget.js +13 -13
  50. package/dist/bin/exe-gateway.js +47 -14
  51. package/dist/bin/exe-grant.js +6 -6
  52. package/dist/bin/exe-healthcheck.js +17 -16
  53. package/dist/bin/exe-heartbeat.js +41 -35
  54. package/dist/bin/exe-kill.js +35 -34
  55. package/dist/bin/exe-launch-agent.js +43 -42
  56. package/dist/bin/exe-mcp.js +9 -9
  57. package/dist/bin/exe-memory-reads.js +10 -10
  58. package/dist/bin/exe-new-employee.js +11 -11
  59. package/dist/bin/exe-os-mcp-proxy.js +9 -9
  60. package/dist/bin/exe-pending-messages.js +30 -29
  61. package/dist/bin/exe-pending-notifications.js +29 -28
  62. package/dist/bin/exe-pending-reviews.js +30 -29
  63. package/dist/bin/exe-preflight.js +1 -1
  64. package/dist/bin/exe-rename.js +9 -9
  65. package/dist/bin/exe-review.js +34 -33
  66. package/dist/bin/exe-search.js +12 -12
  67. package/dist/bin/exe-session-cleanup.js +35 -34
  68. package/dist/bin/exe-settings.js +29 -28
  69. package/dist/bin/exe-start-codex.js +30 -29
  70. package/dist/bin/exe-start-opencode.js +27 -26
  71. package/dist/bin/exe-status.js +31 -30
  72. package/dist/bin/exe-support.js +5 -5
  73. package/dist/bin/exe-team.js +7 -7
  74. package/dist/bin/exe-verify-running-images.js +1 -1
  75. package/dist/bin/exe-watchdog.js +8 -8
  76. package/dist/bin/generate-hook-manifest.js +7 -1
  77. package/dist/bin/git-sweep.js +30 -29
  78. package/dist/bin/graph-backfill.js +12 -12
  79. package/dist/bin/graph-export.js +11 -11
  80. package/dist/bin/hooks-cli.js +1 -1
  81. package/dist/bin/import-history.js +15 -15
  82. package/dist/bin/install.js +130 -129
  83. package/dist/bin/intercom-check.js +11 -7
  84. package/dist/bin/mcp-sessions.js +2 -2
  85. package/dist/bin/orchestration-metrics.js +7 -7
  86. package/dist/bin/postgres-agentic-reflection-backfill.js +5 -5
  87. package/dist/bin/postgres-agentic-semantic-backfill.js +4 -4
  88. package/dist/bin/reconcile-backlog.js +2 -2
  89. package/dist/bin/registry-proxy.js +1 -1
  90. package/dist/bin/repair-document-chunks.js +161 -0
  91. package/dist/bin/scan-tasks.js +30 -29
  92. package/dist/bin/setup.js +5 -5
  93. package/dist/bin/shard-migrate.js +11 -11
  94. package/dist/bin/stack-update.js +625 -33
  95. package/dist/bin/update.js +96 -22
  96. package/dist/bin/verify-stack.js +2 -2
  97. package/dist/bin/vps-health-gate.js +1 -1
  98. package/dist/{boot-generation-L55QANCX.js → boot-generation-Q7LGQ3AO.js} +6 -6
  99. package/dist/{boot-review-sections-AON5ZCR2.js → boot-review-sections-G5774FR5.js} +28 -27
  100. package/dist/{branch-hygiene-QLD77IMJ.js → branch-hygiene-44WLSOZR.js} +2 -2
  101. package/dist/{branding-I6KIMB7F.js → branding-KMWCY5HZ.js} +3 -3
  102. package/dist/build-manifest.json +1259 -1219
  103. package/dist/{capability-cards-WTOXY7O6.js → capability-cards-I3RHCF4F.js} +5 -5
  104. package/dist/{capacity-monitor-ZLG7FSWM.js → capacity-monitor-7I7GDONU.js} +30 -29
  105. package/dist/{catchup-brief-QHY7D7N2.js → catchup-brief-3T5PARIR.js} +39 -36
  106. package/dist/check-image-pullability-2AIVB4BX.js +338 -0
  107. package/dist/{chunk-CTCCYKOV.js → chunk-2FKU4ZEO.js} +55 -29
  108. package/dist/{chunk-M7O7TGGU.js → chunk-2NW4LRDU.js} +1 -1
  109. package/dist/{chunk-XTFM4KMW.js → chunk-2PZTMSMG.js} +6 -6
  110. package/dist/{chunk-UWX6MMCX.js → chunk-3B6FLNLV.js} +1 -1
  111. package/dist/{chunk-GPJIBLP4.js → chunk-3DAEZILW.js} +1 -1
  112. package/dist/{chunk-NY6SBR4O.js → chunk-3FGBBJYM.js} +15 -3
  113. package/dist/{chunk-C4OZVVSG.js → chunk-3OX34OC3.js} +50 -18
  114. package/dist/{chunk-TXTXC3QG.js → chunk-3RGTLZNO.js} +12 -12
  115. package/dist/{chunk-PYRO25A5.js → chunk-3SUPEE6H.js} +10 -11
  116. package/dist/{chunk-PPMGQFLJ.js → chunk-3XY57PKT.js} +2 -2
  117. package/dist/{chunk-CRHI5QTZ.js → chunk-46VSBDUW.js} +2 -2
  118. package/dist/{chunk-VZT66WWP.js → chunk-4AAMFWJT.js} +2 -2
  119. package/dist/{chunk-4GZTBLJG.js → chunk-4AR5XKCH.js} +1 -1
  120. package/dist/{chunk-IHXW4VUI.js → chunk-5IADGFGR.js} +1 -1
  121. package/dist/{chunk-GLQEJOXE.js → chunk-5MVKTNZP.js} +57 -0
  122. package/dist/{chunk-AVMLC2MR.js → chunk-5U2IJBFV.js} +290 -41
  123. package/dist/{chunk-JUKDL5MF.js → chunk-6BJCDWSM.js} +1 -1
  124. package/dist/{chunk-6WWNK7UX.js → chunk-6FIC57PH.js} +1 -1
  125. package/dist/{chunk-ASUICGPX.js → chunk-6YDY6ZTD.js} +4 -4
  126. package/dist/{chunk-FU5O2REK.js → chunk-72V3S44T.js} +108 -29
  127. package/dist/{chunk-LTIIZHNA.js → chunk-7J2ZQ4XN.js} +1 -1
  128. package/dist/{chunk-7RI2CNXJ.js → chunk-7OTR2OET.js} +1 -1
  129. package/dist/{chunk-ZVBVPX4W.js → chunk-7UHZBVP3.js} +82 -51
  130. package/dist/{chunk-PTY2N23C.js → chunk-AGC2V7JS.js} +26 -13
  131. package/dist/{chunk-44VR3PFW.js → chunk-AHESD3KW.js} +1 -1
  132. package/dist/{chunk-NPGV4MZ3.js → chunk-ALRHGEAJ.js} +1 -1
  133. package/dist/{chunk-WJC6AAJN.js → chunk-ANVHWV2X.js} +2 -2
  134. package/dist/{chunk-AGZSGAEN.js → chunk-APL7HUE3.js} +105 -32
  135. package/dist/{chunk-7UH2JWBF.js → chunk-AZSTIAVL.js} +176 -11
  136. package/dist/chunk-AZXMR25O.js +545 -0
  137. package/dist/{chunk-WPWEBZ37.js → chunk-B7AMNZTC.js} +2 -2
  138. package/dist/{chunk-4CF5KUWH.js → chunk-BPVFZ6Q4.js} +3 -3
  139. package/dist/{chunk-XTQ7R2PA.js → chunk-BV2IET6B.js} +73 -17
  140. package/dist/{chunk-4F5CNI65.js → chunk-C5ISP5FO.js} +2 -2
  141. package/dist/{chunk-NPWNXJ3U.js → chunk-CH7BUBP3.js} +7 -7
  142. package/dist/{chunk-X5Q66EOG.js → chunk-CHIUS5QB.js} +16 -16
  143. package/dist/{chunk-ZG62LIK3.js → chunk-CIPDQRFO.js} +1 -1
  144. package/dist/{chunk-4PYIRIU6.js → chunk-CM7N5MBY.js} +5 -5
  145. package/dist/{chunk-L5YDAFUH.js → chunk-CYCIX7AW.js} +5 -5
  146. package/dist/{chunk-76YRJKKF.js → chunk-D3LXVAIQ.js} +28 -16
  147. package/dist/{chunk-2GNAHBRD.js → chunk-DMUOTCDN.js} +1 -1
  148. package/dist/{chunk-QMUFSRQX.js → chunk-DN3ZR3UE.js} +1 -1
  149. package/dist/{chunk-V3WLC5TJ.js → chunk-DRTJCG6B.js} +1 -1
  150. package/dist/{chunk-275WHBEN.js → chunk-DYVLEMKS.js} +1 -1
  151. package/dist/{chunk-O34F5EP5.js → chunk-DZN7SDY2.js} +1 -1
  152. package/dist/{chunk-ZDIXMHY7.js → chunk-E3ZM32LF.js} +8 -8
  153. package/dist/{chunk-N2HXR5MB.js → chunk-E7C2WNR5.js} +4 -4
  154. package/dist/{chunk-VVGXWVZU.js → chunk-EGOEB42T.js} +3 -3
  155. package/dist/{chunk-QV5CQLQH.js → chunk-EIOGV75A.js} +2 -2
  156. package/dist/{chunk-ZY4IGUOS.js → chunk-ELCRJGCH.js} +3 -3
  157. package/dist/{chunk-5QCIWWFA.js → chunk-ELEGH4DX.js} +130 -14
  158. package/dist/{chunk-S7CTCPSW.js → chunk-EOTZSAQL.js} +1 -1
  159. package/dist/{chunk-PPLQ4ECD.js → chunk-EUGEFBGV.js} +3 -3
  160. package/dist/{chunk-UFNCL6MS.js → chunk-EYMFVITZ.js} +1 -1
  161. package/dist/{chunk-F6H7GP2O.js → chunk-F4BBMIPG.js} +3 -3
  162. package/dist/{chunk-FNEZ4BWT.js → chunk-FEU6QEEL.js} +1 -1
  163. package/dist/{chunk-JKOC2L6P.js → chunk-FHIFTSPL.js} +1 -1
  164. package/dist/{chunk-4RTKETV3.js → chunk-FMIYFHLE.js} +3 -3
  165. package/dist/{chunk-TK544DEW.js → chunk-FVLNNNH6.js} +3 -3
  166. package/dist/{chunk-AY2U4NZ5.js → chunk-GL47M7NY.js} +85 -17
  167. package/dist/{chunk-DN24VTS5.js → chunk-GSLFH4AI.js} +25 -13
  168. package/dist/{chunk-CHO5SNWR.js → chunk-HA63SH5W.js} +1 -1
  169. package/dist/{chunk-4IK2K3B3.js → chunk-HME6ITKV.js} +1 -1
  170. package/dist/{chunk-H2T6TFJZ.js → chunk-HU3VD4MQ.js} +2 -2
  171. package/dist/{chunk-ZW32RI66.js → chunk-I5XIW2BP.js} +49 -11
  172. package/dist/{chunk-3CL2I3RG.js → chunk-IGJMS7C5.js} +2 -2
  173. package/dist/{chunk-BRPO6GOH.js → chunk-JA3Y5TV6.js} +2 -2
  174. package/dist/{chunk-SFFXAPYK.js → chunk-JDDM6C57.js} +1 -1
  175. package/dist/{chunk-W4EGAQXW.js → chunk-JFJP6ATJ.js} +2 -2
  176. package/dist/{chunk-ENCUOZXX.js → chunk-JFTUAV4J.js} +1 -1
  177. package/dist/{chunk-3UOQH2DJ.js → chunk-JJTPPAZY.js} +2568 -345
  178. package/dist/{chunk-A6QBAUJH.js → chunk-KILR4FBR.js} +4 -4
  179. package/dist/{chunk-CGFGNHSP.js → chunk-KTKIFXIP.js} +1 -1
  180. package/dist/{chunk-NCJBPXGM.js → chunk-KXYKSLW4.js} +108 -24
  181. package/dist/{chunk-3MUARHPO.js → chunk-L3VUW5M4.js} +1 -1
  182. package/dist/{chunk-GZOG2MAX.js → chunk-L5EPGGDP.js} +1 -1
  183. package/dist/{chunk-T7VSKWES.js → chunk-L63V25HS.js} +6 -5
  184. package/dist/{chunk-R4VNGRKU.js → chunk-LFBLQE2P.js} +1 -1
  185. package/dist/{chunk-W5MCOZTW.js → chunk-LFUBEHFW.js} +12 -2
  186. package/dist/{chunk-AIBIEP4R.js → chunk-LKTN22L6.js} +61 -25
  187. package/dist/{chunk-3KFQCFQB.js → chunk-LR5O2XWZ.js} +5 -5
  188. package/dist/{chunk-VUOAPKPI.js → chunk-LSNBTGW4.js} +1 -1
  189. package/dist/{chunk-P5U3GAWU.js → chunk-MB47DRF5.js} +2 -2
  190. package/dist/{chunk-HZESME3B.js → chunk-MC4IM2CC.js} +16 -13
  191. package/dist/{chunk-ZKJ5S23O.js → chunk-MFAOAIUE.js} +12 -9
  192. package/dist/{chunk-62J64CHO.js → chunk-MKM6D7JM.js} +26 -7
  193. package/dist/{chunk-ZIG7VPJV.js → chunk-MMS2HBRT.js} +15 -3
  194. package/dist/{chunk-FHSV4BSW.js → chunk-MOANZQXF.js} +12 -4
  195. package/dist/{chunk-RTZZBWQC.js → chunk-MPZ2AVNS.js} +16 -5
  196. package/dist/{chunk-AZ6KLVDX.js → chunk-MROSARM5.js} +2 -2
  197. package/dist/{chunk-RV2FFCDS.js → chunk-MUAWCFW6.js} +6 -2
  198. package/dist/{chunk-K4ESASPL.js → chunk-MUCNYSJP.js} +1 -1
  199. package/dist/{chunk-5QGKMP6T.js → chunk-NF5FOSLD.js} +1 -1
  200. package/dist/{chunk-CKOJP7JI.js → chunk-NKEFYE4R.js} +2 -2
  201. package/dist/{chunk-3SXHEQ7X.js → chunk-NPXIS2RY.js} +1 -1
  202. package/dist/{chunk-A5USSF66.js → chunk-NVFNADTX.js} +12 -8
  203. package/dist/{chunk-VVUO3RJS.js → chunk-NYLJQ2M2.js} +4 -4
  204. package/dist/{chunk-HIVOLPLD.js → chunk-OAFENIHN.js} +1 -1
  205. package/dist/{chunk-PMZHZQ6K.js → chunk-OBBO6EJR.js} +1 -1
  206. package/dist/{chunk-SS6EMDLL.js → chunk-P2UY34XE.js} +6 -6
  207. package/dist/{chunk-Y4T5IUEP.js → chunk-P3QQ52QK.js} +2 -2
  208. package/dist/{chunk-GGEKMY6G.js → chunk-P3UX5EH4.js} +4 -4
  209. package/dist/{chunk-F7IRZU5G.js → chunk-P4PIZOL2.js} +3 -3
  210. package/dist/{chunk-GEPFKUUR.js → chunk-P4XLIPB7.js} +1 -1
  211. package/dist/{chunk-GPUOUUHA.js → chunk-PCV52RYM.js} +1 -1
  212. package/dist/{chunk-XR3773KZ.js → chunk-PL4CFSQ7.js} +1 -1
  213. package/dist/{chunk-LLZNPOGB.js → chunk-PLII76NJ.js} +58 -0
  214. package/dist/{chunk-FT5PPV2C.js → chunk-PRDDPQLC.js} +5 -5
  215. package/dist/{chunk-BZ546I4Q.js → chunk-PUBA5B4M.js} +24 -0
  216. package/dist/{chunk-2TGJ5XCV.js → chunk-PWC3C5ME.js} +4 -4
  217. package/dist/{chunk-A4YCLD3L.js → chunk-QFAFKEB5.js} +40 -4
  218. package/dist/{chunk-CL4J4757.js → chunk-QH5ZQ5SJ.js} +26 -0
  219. package/dist/{chunk-UJWZYK46.js → chunk-QNZ4562V.js} +1 -1
  220. package/dist/{chunk-IPHLUZ37.js → chunk-QPTSA4PP.js} +2 -2
  221. package/dist/{chunk-O3YJTHWI.js → chunk-R5E7WNAC.js} +3 -3
  222. package/dist/{chunk-V3M4LJRA.js → chunk-RB3J2WYQ.js} +1 -1
  223. package/dist/{chunk-IUCWOI4Y.js → chunk-RDWIKDMY.js} +237 -11
  224. package/dist/{chunk-ENN6DY4T.js → chunk-RVO5O5SR.js} +46 -21
  225. package/dist/{chunk-LY4AXCYJ.js → chunk-RZN2LEAK.js} +6 -6
  226. package/dist/{chunk-2YIB75UQ.js → chunk-S26CV7BE.js} +57 -13
  227. package/dist/{chunk-XC36HYP6.js → chunk-SDYWZRPN.js} +1 -1
  228. package/dist/{chunk-PHBU4LGO.js → chunk-SNHYZYGZ.js} +1 -1
  229. package/dist/{chunk-4KTTBKWQ.js → chunk-T5FEAQES.js} +1 -1
  230. package/dist/{chunk-XU57KFD6.js → chunk-T5SM4RXY.js} +5 -1
  231. package/dist/{chunk-KUV5VBAO.js → chunk-TKAU7IJ2.js} +1 -1
  232. package/dist/{chunk-KBR5LIWD.js → chunk-TKS5GMYA.js} +1 -1
  233. package/dist/{chunk-5DFE2NAF.js → chunk-TNS63ATU.js} +96 -22
  234. package/dist/{chunk-RFPMXR6B.js → chunk-U4GMOT4M.js} +1 -1
  235. package/dist/{chunk-CO5ZVE3D.js → chunk-UOPCVFVR.js} +17 -17
  236. package/dist/{chunk-22LNFCDF.js → chunk-UX2EO653.js} +1 -1
  237. package/dist/{chunk-LGC6TBA3.js → chunk-UXN4BICC.js} +2 -2
  238. package/dist/{chunk-7J5X4AK7.js → chunk-VF2KRROX.js} +1 -1
  239. package/dist/{chunk-7THUQU44.js → chunk-VF3BZOZK.js} +5 -2
  240. package/dist/{chunk-M2B35MUK.js → chunk-VHHX4UCP.js} +1 -1
  241. package/dist/{chunk-AZBJXATK.js → chunk-VJEJ7JNB.js} +1 -1
  242. package/dist/{chunk-4TRVALTR.js → chunk-VLBHZ6TF.js} +2 -2
  243. package/dist/{chunk-7BMSBACY.js → chunk-VOVFUKEB.js} +5 -5
  244. package/dist/{chunk-MDPGZS6C.js → chunk-VROK4X2L.js} +1 -1
  245. package/dist/{chunk-J6ABJDZ4.js → chunk-W3KPQE7H.js} +4 -4
  246. package/dist/{chunk-3Q7NEDHB.js → chunk-W6BZ4UGA.js} +48 -9
  247. package/dist/{chunk-IZ3IFLL2.js → chunk-XEBKIWI7.js} +14 -14
  248. package/dist/{chunk-UZDF6FLJ.js → chunk-XHU3KOKJ.js} +1 -1
  249. package/dist/{chunk-PA37MXV5.js → chunk-XSUALA32.js} +2 -2
  250. package/dist/{chunk-GR5WJPKF.js → chunk-XUZK23V7.js} +11 -6
  251. package/dist/{chunk-IDB3EZLW.js → chunk-YLB365YX.js} +148 -5
  252. package/dist/{chunk-JDQ7JU3A.js → chunk-YLFCH3VA.js} +24 -16
  253. package/dist/{chunk-ZJJL2Z23.js → chunk-YRQ26MNP.js} +4 -4
  254. package/dist/chunk-YRUZK2QA.js +35 -0
  255. package/dist/{chunk-7HLJ4BSF.js → chunk-ZAEUEDTN.js} +2 -2
  256. package/dist/{chunk-NY74W3S4.js → chunk-ZBPZDADW.js} +313 -43
  257. package/dist/{chunk-ZLPS3GR7.js → chunk-ZJQ56DZZ.js} +42 -1
  258. package/dist/{chunk-VMZZTFXT.js → chunk-ZOTTYCP5.js} +4 -4
  259. package/dist/{chunk-MP4ST7RO.js → chunk-ZPP63JSQ.js} +51 -11
  260. package/dist/{chunk-N4J5WHO2.js → chunk-ZT4LFTUJ.js} +1 -1
  261. package/dist/{cleanup-graph-garbage-GE2DYOTB.js → cleanup-graph-garbage-VQAJ2RBT.js} +11 -11
  262. package/dist/{cloud-sync-command-T6KF3ARK.js → cloud-sync-command-J7NEFUY7.js} +2 -2
  263. package/dist/{cloud-sync-db-init-RSHCCY74.js → cloud-sync-db-init-KWEMNMGA.js} +1 -1
  264. package/dist/{cloud-sync-shutdown-6IVCSLM5.js → cloud-sync-shutdown-P63AUTUI.js} +5 -5
  265. package/dist/{co-activation-AF7RCJPX.js → co-activation-7IHRPBZN.js} +5 -5
  266. package/dist/{co-occurrence-DMOOGBVV.js → co-occurrence-R5AG4OAU.js} +9 -9
  267. package/dist/{code-context-index-LIDOFKOR.js → code-context-index-WFLLZBVB.js} +10 -9
  268. package/dist/{code-context-watcher-4F7K2N3U.js → code-context-watcher-3QAPHO7N.js} +10 -9
  269. package/dist/{codex-consolidation-SH4UKFBQ.js → codex-consolidation-ONZ2AQFX.js} +2 -2
  270. package/dist/{consent-passphrase-WV7MZPMO.js → consent-passphrase-5ZBDJ5G7.js} +2 -2
  271. package/dist/{content-extractor-DJM5EUDA.js → content-extractor-ZLXC6GNR.js} +2 -2
  272. package/dist/{conversation-entity-extractor-4UG7BKWL.js → conversation-entity-extractor-7FRKLLBD.js} +4 -4
  273. package/dist/{conversation-wiki-populator-OS4C6W54.js → conversation-wiki-populator-YAOVCUGO.js} +1 -1
  274. package/dist/{crdt-sync-VL4KXZB7.js → crdt-sync-IFRZOEIS.js} +4 -4
  275. package/dist/{crm-webhook-IDBJ7X5Y.js → crm-webhook-L2S63ASV.js} +2 -2
  276. package/dist/{cto-delegation-gate-4FLSHSLO.js → cto-delegation-gate-3WU7OHX7.js} +29 -28
  277. package/dist/{daemon-auth-PNKHERLV.js → daemon-auth-OWLFYEFR.js} +3 -3
  278. package/dist/{daemon-orchestration-HFCB6OK4.js → daemon-orchestration-3VQYKLOR.js} +33 -32
  279. package/dist/{daemon-ready-BN6EZLTQ.js → daemon-ready-VZ6ZHA2C.js} +1 -1
  280. package/dist/{db-integrity-events-GYGANKZV.js → db-integrity-events-7NKWS5MT.js} +3 -3
  281. package/dist/{db-restore-events-G6NOQOVE.js → db-restore-events-XYL6CGPC.js} +2 -2
  282. package/dist/{destructive-data-guard-HHWUBIGS.js → destructive-data-guard-JDUJ2ULM.js} +58 -2
  283. package/dist/{dispatch-ack-X4DXUSKP.js → dispatch-ack-UYEAKON5.js} +2 -1
  284. package/dist/{doc-graph-extractor-E36PQUCS.js → doc-graph-extractor-YIR5E7OF.js} +9 -9
  285. package/dist/{documents-SCKKHDR7.js → documents-QEHPTYIY.js} +19 -18
  286. package/dist/{dreaming-Q26JBH56.js → dreaming-LNFE7DTN.js} +34 -33
  287. package/dist/{employee-boot-brief-XU6EI2EO.js → employee-boot-brief-ZTXDYNWM.js} +39 -38
  288. package/dist/{entity-boost-VNQLLR3Q.js → entity-boost-R5N6JWXD.js} +1 -1
  289. package/dist/{exe-drift-YZ6OIUAY.js → exe-drift-WYSJVZFO.js} +6 -6
  290. package/dist/{exe-export-HHRQMLSS.js → exe-export-GOLNAEAV.js} +20 -19
  291. package/dist/{exe-import-5XR4NQAB.js → exe-import-U4BSI6OH.js} +20 -19
  292. package/dist/{exe-key-5XOFVP3I.js → exe-key-V42G3NGO.js} +152 -130
  293. package/dist/{exe-org-TPAX4AAK.js → exe-org-U4GLQ6OP.js} +27 -27
  294. package/dist/{exe-snapshot-GIRP3XCJ.js → exe-snapshot-U7ONBYNY.js} +38 -37
  295. package/dist/{fast-db-init-MGY6VCLG.js → fast-db-init-W3NGKAEU.js} +1 -1
  296. package/dist/{founder-context-WD72OL2P.js → founder-context-ZSIBRVDM.js} +4 -4
  297. package/dist/{founder-monitor-envelope-XGYMHT4W.js → founder-monitor-envelope-L3IWZLFY.js} +7 -7
  298. package/dist/{fts-integrity-PLAL6NMG.js → fts-integrity-PHCKKOBC.js} +3 -3
  299. package/dist/gateway/index.js +23 -22
  300. package/dist/{gateway-client-VO3BRLV5.js → gateway-client-DJFCVIPT.js} +1 -1
  301. package/dist/{git-staleness-KGZABPP3.js → git-staleness-OF24QXFZ.js} +5 -5
  302. package/dist/{global-procedures-KOU6A5E5.js → global-procedures-WSIOWO43.js} +6 -6
  303. package/dist/{graph-auto-extract-OZNRDAHE.js → graph-auto-extract-IEVVN3L3.js} +9 -9
  304. package/dist/{graph-query-36K6VXFF.js → graph-query-JDZWAVCU.js} +1 -1
  305. package/dist/{graph-rag-TZLH3CTQ.js → graph-rag-BKAD2XQA.js} +4 -4
  306. package/dist/{hook-integrity-BWFFISJV.js → hook-integrity-TPWDGX2M.js} +3 -1
  307. package/dist/{hook-prefetch-MFUJRAIM.js → hook-prefetch-FD6VGJJA.js} +29 -28
  308. package/dist/hooks/bug-report-worker.js +34 -33
  309. package/dist/hooks/codex-stop-task-finalizer.js +36 -35
  310. package/dist/hooks/commit-complete.js +40 -36
  311. package/dist/hooks/error-recall.js +15 -15
  312. package/dist/hooks/exe-heartbeat-hook.js +8 -8
  313. package/dist/hooks/ingest-worker.js +21 -20
  314. package/dist/hooks/ingest.js +23 -23
  315. package/dist/hooks/instructions-loaded.js +10 -10
  316. package/dist/hooks/manifest.json +20 -20
  317. package/dist/hooks/notification.js +9 -9
  318. package/dist/hooks/post-compact.js +8 -8
  319. package/dist/hooks/post-tool-combined.js +15 -15
  320. package/dist/hooks/pre-compact.js +33 -32
  321. package/dist/hooks/pre-tool-use.js +2 -2
  322. package/dist/hooks/prompt-submit.js +52 -51
  323. package/dist/hooks/session-end.js +38 -37
  324. package/dist/hooks/session-start.js +25 -22
  325. package/dist/hooks/stop.js +40 -39
  326. package/dist/hooks/subagent-stop.js +36 -35
  327. package/dist/hooks/summary-worker.js +41 -40
  328. package/dist/index.js +43 -42
  329. package/dist/{inrun-inbox-DRKVDPLY.js → inrun-inbox-RGNFFGMU.js} +5 -0
  330. package/dist/{installer-RM4ASY7U.js → installer-NMOBSEZ2.js} +11 -11
  331. package/dist/{installer-IESPHXVH.js → installer-OTI5SA43.js} +11 -11
  332. package/dist/{installer-SQZRVD36.js → installer-SRJGE4GU.js} +11 -11
  333. package/dist/{intercom-queue-DGLAC224.js → intercom-queue-4FFXCBHO.js} +28 -27
  334. package/dist/{key-backup-status-LQPINQ3W.js → key-backup-status-6U7D5GOD.js} +2 -2
  335. package/dist/lib/agent-config.js +3 -3
  336. package/dist/lib/cloud-sync.js +28 -27
  337. package/dist/lib/config.js +4 -2
  338. package/dist/lib/consolidation.js +14 -12
  339. package/dist/lib/crypto.js +5 -3
  340. package/dist/lib/database.js +5 -5
  341. package/dist/lib/db-backup.js +11 -3
  342. package/dist/lib/db-daemon-client.js +11 -10
  343. package/dist/lib/db-write-worker.js +4 -4
  344. package/dist/lib/db.js +5 -5
  345. package/dist/lib/delivery-catalog.js +431 -0
  346. package/dist/lib/delivery-schemas.js +62 -0
  347. package/dist/lib/delivery-truth.js +1 -1
  348. package/dist/lib/device-registry.js +3 -3
  349. package/dist/lib/embed-worker.js +2 -2
  350. package/dist/lib/embedder.js +10 -9
  351. package/dist/lib/employee-templates.js +7 -7
  352. package/dist/lib/employees.js +5 -5
  353. package/dist/lib/exe-daemon-client.js +9 -8
  354. package/dist/lib/exe-daemon.js +186 -117
  355. package/dist/lib/hybrid-search.js +12 -12
  356. package/dist/lib/identity.js +5 -5
  357. package/dist/lib/keychain.js +13 -1
  358. package/dist/lib/license.js +8 -4
  359. package/dist/lib/messaging.js +39 -30
  360. package/dist/lib/post-tool-memory.js +9 -9
  361. package/dist/lib/registry-proxy.js +9 -1
  362. package/dist/lib/reminders.js +6 -6
  363. package/dist/lib/schedules.js +11 -11
  364. package/dist/lib/session-registry.js +7 -7
  365. package/dist/lib/skill-learning.js +20 -19
  366. package/dist/lib/status-brief.js +5 -4
  367. package/dist/lib/store.js +10 -10
  368. package/dist/lib/task-router.js +6 -6
  369. package/dist/lib/tasks.js +30 -29
  370. package/dist/lib/tmux-routing.js +28 -27
  371. package/dist/lib/tmux-status.js +3 -1
  372. package/dist/lib/token-spend.js +6 -6
  373. package/dist/lib/ws-client.js +1 -1
  374. package/dist/{license-gate-E6GTRYBA.js → license-gate-R4JWTWM4.js} +5 -5
  375. package/dist/{license-recheck-RBAO6Z2H.js → license-recheck-3MBJ4IJX.js} +1 -1
  376. package/dist/{license-sync-ZCZ2LIHK.js → license-sync-BVSG3WMW.js} +4 -4
  377. package/dist/local-secret-inventory-JWNBHZZ4.js +20 -0
  378. package/dist/mailbox-inbox-MTAT4MXX.js +13 -0
  379. package/dist/{mailbox-outbox-DNDDP2HW.js → mailbox-outbox-OY4IU6S4.js} +2 -1
  380. package/dist/mcp/register-tools.js +121 -120
  381. package/dist/mcp/server.js +123 -122
  382. package/dist/mcp/tools/complete-reminder.js +7 -7
  383. package/dist/mcp/tools/create-reminder.js +7 -7
  384. package/dist/mcp/tools/create-task.js +35 -32
  385. package/dist/mcp/tools/deactivate-behavior.js +22 -21
  386. package/dist/mcp/tools/list-reminders.js +7 -7
  387. package/dist/mcp/tools/list-tasks.js +33 -32
  388. package/dist/mcp/tools/send-message.js +32 -31
  389. package/dist/mcp/tools/update-task.js +31 -30
  390. package/dist/{mcp-child-registry-DVHYAHPW.js → mcp-child-registry-TIZERM7O.js} +5 -5
  391. package/dist/{mcp-health-B5EKRCZG.js → mcp-health-4ZHU67LM.js} +9 -3
  392. package/dist/{mcp-http-config-ME67QDOF.js → mcp-http-config-VUMSFWFH.js} +12 -12
  393. package/dist/{mcp-session-identity-DNG4ULAE.js → mcp-session-identity-DZHWEJRV.js} +28 -27
  394. package/dist/{memory-cards-WCISXY62.js → memory-cards-JVXTMSAT.js} +10 -10
  395. package/dist/{memory-graph-extractor-GXIK4QUF.js → memory-graph-extractor-PPBJMYFJ.js} +10 -10
  396. package/dist/{memory-poisoning-defense-25LZ5FJI.js → memory-poisoning-defense-K5Q74XQ4.js} +5 -5
  397. package/dist/{memory-pressure-watchdog-XGXI7WGE.js → memory-pressure-watchdog-YMJH5CSA.js} +29 -28
  398. package/dist/{memory-queue-YF7IDSFY.js → memory-queue-2MA67TAA.js} +3 -3
  399. package/dist/{memory-queue-client-QC2OTMJB.js → memory-queue-client-4G7HVRSX.js} +11 -10
  400. package/dist/{memory-reflection-GFGT44NT.js → memory-reflection-7BZWIHRE.js} +10 -10
  401. package/dist/{monitor-grants-Z2SEFE6E.js → monitor-grants-Q7X3MYQP.js} +6 -6
  402. package/dist/{monitor-identity-AEMHCVHV.js → monitor-identity-ZQB4IXEE.js} +2 -2
  403. package/dist/{notification-ledger-ETQBGRP7.js → notification-ledger-XRAXL5OI.js} +32 -29
  404. package/dist/{notifications-LPRCFJYY.js → notifications-JE3PX55X.js} +28 -27
  405. package/dist/{orchestration-events-T2GXV2NG.js → orchestration-events-JCQ5F5IJ.js} +6 -6
  406. package/dist/{orchestration-phase-T2WD45UA.js → orchestration-phase-QKTGQ2YT.js} +3 -3
  407. package/dist/{orchestrator-HY2IB3NA.js → orchestrator-X65INDTR.js} +30 -29
  408. package/dist/{org-brief-session-UWFCFEEB.js → org-brief-session-3PQ22UIX.js} +19 -18
  409. package/dist/{org-consent-policy-XXMST37J.js → org-consent-policy-VGELJ7K7.js} +7 -6
  410. package/dist/{org-join-72QKM7JR.js → org-join-6TO5ZYUZ.js} +12 -12
  411. package/dist/{org-key-admin-YCIAYP7V.js → org-key-admin-XHYVRRAZ.js} +12 -12
  412. package/dist/{org-key-pin-F7BQPI5P.js → org-key-pin-TTTYGTQL.js} +6 -6
  413. package/dist/{org-membership-JQSU4Z5P.js → org-membership-Y7T2BS57.js} +7 -7
  414. package/dist/{org-partner-config-PVJ45SLC.js → org-partner-config-OP4NEUNF.js} +10 -10
  415. package/dist/{org-partner-runtime-U4CTLWLC.js → org-partner-runtime-YNVUNT2R.js} +20 -19
  416. package/dist/{org-row-visibility-WUX4N3FX.js → org-row-visibility-JBBXNYXD.js} +1 -1
  417. package/dist/{pipeline-router-2RMBCBRM.js → pipeline-router-EIBB7QNG.js} +6 -6
  418. package/dist/{plan-limits-Z47XYEJR.js → plan-limits-MEWXYLEN.js} +8 -8
  419. package/dist/{postinstall-failure-O6TSSNJB.js → postinstall-failure-VETYYWEZ.js} +3 -3
  420. package/dist/{pre-tool-use-impl-JPE6XMRJ.js → pre-tool-use-impl-C6KJY22W.js} +60 -49
  421. package/dist/{project-boot-UFQDAFU5.js → project-boot-VEYFCCSL.js} +2 -2
  422. package/dist/{project-name-V4IREGHO.js → project-name-UYORSNGE.js} +6 -6
  423. package/dist/{projection-worker-HAD6H3VJ.js → projection-worker-WYFDWS57.js} +5 -5
  424. package/dist/{prospective-memory-KIF4JLFF.js → prospective-memory-E6XBQFJA.js} +5 -5
  425. package/dist/{push-notifications-GDKRTYXH.js → push-notifications-M7YU63FY.js} +29 -28
  426. package/dist/{reproject-worktree-memories-SG4BZJ3Z.js → reproject-worktree-memories-B5XMGJSD.js} +28 -27
  427. package/dist/{reranker-G2AZ67JP.js → reranker-SRA4BR7N.js} +3 -3
  428. package/dist/{retrieval-health-GBJRXTBZ.js → retrieval-health-P2JPZUPV.js} +4 -4
  429. package/dist/{review-polling-VUZPAAGT.js → review-polling-KQPN7IQE.js} +29 -28
  430. package/dist/runtime/index.js +37 -36
  431. package/dist/{session-events-BI6NIFIR.js → session-events-6LDDKKY3.js} +29 -28
  432. package/dist/{session-kill-telemetry-HPBDOPHT.js → session-kill-telemetry-5DSRGWCL.js} +29 -28
  433. package/dist/{session-mcp-config-WFZAH6R5.js → session-mcp-config-F7RCERUG.js} +3 -3
  434. package/dist/{session-scope-UB3HA5E7.js → session-scope-XG5R3P3D.js} +28 -27
  435. package/dist/{setup-wizard-6XULOT3L.js → setup-wizard-7QFLZIKT.js} +5 -5
  436. package/dist/{shard-manager-DYEJ6ETD.js → shard-manager-HHHHV2KZ.js} +3 -3
  437. package/dist/{skill-refinement-MKBQIWZ6.js → skill-refinement-I5RMAHSC.js} +6 -6
  438. package/dist/{stack-generate-manifest-7ODQ6W2O.js → stack-generate-manifest-AKMZ3AUX.js} +246 -13
  439. package/dist/stack-init-5VKL5PL5.js +136 -0
  440. package/dist/{stack-promote-3UKJBJSP.js → stack-promote-34CE2HHF.js} +7 -6
  441. package/dist/{stack-release-5CVXMJM5.js → stack-release-5PGWV5D4.js} +123 -12
  442. package/dist/{stack-update-Z53KG2P5.js → stack-update-ZQQ5YYPJ.js} +20 -5
  443. package/dist/{steward-gate-OKUYYIX6.js → steward-gate-AQJ6KT2C.js} +6 -6
  444. package/dist/{subagent-brief-injection-T2CVQLAS.js → subagent-brief-injection-3GU7YAWY.js} +50 -42
  445. package/dist/{subagent-spawn-ledger-E6U3OY6Z.js → subagent-spawn-ledger-52I66CLW.js} +3 -3
  446. package/dist/{supervisor-handoff-SGLEPOCY.js → supervisor-handoff-BWJW6CKZ.js} +4 -4
  447. package/dist/{support-inbox-WJIDCKJC.js → support-inbox-NY5TB3FN.js} +12 -12
  448. package/dist/{support-outbox-G2NG2U5K.js → support-outbox-KNI3FR3G.js} +3 -2
  449. package/dist/{task-enforcement-JL5ADPS6.js → task-enforcement-CAA6D2MH.js} +29 -28
  450. package/dist/{task-request-inbox-54BRRFHZ.js → task-request-inbox-QBZVU66E.js} +9 -6
  451. package/dist/{task-scope-OBPZBID5.js → task-scope-NHXB4ZRN.js} +32 -27
  452. package/dist/{tasks-crud-YBCPT7TY.js → tasks-crud-JHSWL5NM.js} +28 -27
  453. package/dist/{tasks-notify-CEEQSDJF.js → tasks-notify-7PBE4U7T.js} +29 -28
  454. package/dist/{tasks-review-JIEI656P.js → tasks-review-PPPVEE62.js} +28 -27
  455. package/dist/{telemetry-upload-ZZSEZR2U.js → telemetry-upload-YU2VRNHX.js} +10 -10
  456. package/dist/{token-budget-AUFMEMQ2.js → token-budget-QCMWKG3K.js} +6 -6
  457. package/dist/{tool-capability-index-6HLZU437.js → tool-capability-index-7AWQAJRP.js} +1 -1
  458. package/dist/{tool-gates-VXITVRFQ.js → tool-gates-5Q3RSQEG.js} +1 -1
  459. package/dist/{tool-gates-JWVSAYTW.js → tool-gates-QD26D2NE.js} +1 -1
  460. package/dist/{tool-telemetry-RHSEK2TO.js → tool-telemetry-LTOIC64I.js} +1 -1
  461. package/dist/tui/App.js +43 -42
  462. package/dist/{tui-data-PBZNN5YB.js → tui-data-NDBXD6U7.js} +32 -31
  463. package/dist/{update-support-V3ZCJR6L.js → update-support-BMJM4NG7.js} +27 -26
  464. package/dist/{whatsapp-NAM2CRVQ.js → whatsapp-QQLDAHUX.js} +2 -2
  465. package/dist/{wiki-acl-NUBAPLCD.js → wiki-acl-W6WDCVCP.js} +1 -1
  466. package/dist/{work-claims-Q2NU6JON.js → work-claims-6DM32MGO.js} +6 -6
  467. package/dist/{work-state-heartbeat-HAQRV3RK.js → work-state-heartbeat-HG7D4AWJ.js} +1 -1
  468. package/dist/{worker-gate-NUUSQMBT.js → worker-gate-FTMW7GBB.js} +3 -3
  469. package/dist/{workflow-engine-GEWPU5YR.js → workflow-engine-ZWC6CCXE.js} +2 -2
  470. package/dist/{worktree-C7LFMRKW.js → worktree-EMQCPGFE.js} +7 -7
  471. package/dist/{worktree-ownership-guard-4LKMW6PW.js → worktree-ownership-guard-O6JQF2CL.js} +2 -2
  472. package/dist/{worktree-sweep-SYF62ANH.js → worktree-sweep-XVUJZBXV.js} +8 -8
  473. package/package.json +23 -7
  474. package/release-notes.json +39 -12
  475. package/stack.release.json +4 -4
  476. package/dist/mailbox-inbox-XE72D3AX.js +0 -10
  477. /package/dist/{chunk-QIEYJ4KZ.js → chunk-2KY7WZZF.js} +0 -0
  478. /package/dist/{chunk-T3667X2B.js → chunk-2Q2CD6CD.js} +0 -0
  479. /package/dist/{chunk-JZJZYKMW.js → chunk-AJK2PVQW.js} +0 -0
  480. /package/dist/{chunk-ZEGEFBZV.js → chunk-AWWDKF22.js} +0 -0
  481. /package/dist/{chunk-QNTKRGJ6.js → chunk-GIRD7O5X.js} +0 -0
  482. /package/dist/{chunk-FWA4MYTA.js → chunk-JRIH6I7D.js} +0 -0
  483. /package/dist/{chunk-C7H2D7LX.js → chunk-M4XY4JRK.js} +0 -0
  484. /package/dist/{chunk-Q3DN5J6F.js → chunk-P2VVMGMI.js} +0 -0
  485. /package/dist/{chunk-BRAIWGMF.js → chunk-Q46NYJ77.js} +0 -0
  486. /package/dist/{chunk-3LQ2N4H7.js → chunk-U2D6PJ5T.js} +0 -0
  487. /package/dist/{chunk-3O6OGZL3.js → chunk-XDVOGDBC.js} +0 -0
  488. /package/dist/{core-memory-UNCAPGD4.js → core-memory-O6D5UC3T.js} +0 -0
  489. /package/dist/{hook-tamper-log-Z4PWC7N4.js → hook-tamper-log-ARGWCXKJ.js} +0 -0
  490. /package/dist/{memory-isolation-ALPJWLR5.js → memory-isolation-EBFFC6HF.js} +0 -0
  491. /package/dist/{oauth-server-AC2KB7NB.js → oauth-server-ZKBUHDFI.js} +0 -0
  492. /package/dist/{webhook-pipe-W2FVXY7M.js → webhook-pipe-PXH5MBRM.js} +0 -0
  493. /package/dist/{wiki-client-W65IOSWF.js → wiki-client-DD2NVWK2.js} +0 -0
@@ -69,7 +69,7 @@ SMTP_PASS=
69
69
  # --- Auth gateway (exe-auth — shared SSO sign-in UI at auth.<domain>) ---
70
70
  # Bug 58840873: pin the auth image so compose never falls back to its stale
71
71
  # hardcoded default tag. Keep in sync with the manifest AUTH_IMAGE_TAG.
72
- AUTH_IMAGE_TAG=update.askexe.com/askexe/exe-auth:v0.6.1@sha256:89670a15bc59255299be695525863e66f949694eec1dd8886038dc3659a4a941
72
+ AUTH_IMAGE_TAG=update.askexe.com/askexe/exe-auth:v0.6.5@sha256:dc8c1476ef1247079a6e115450bd35681712fa06367461589998ecf943f88089
73
73
  # Bug 379e5c13: server_name / CORS from the CONFIGURED apex domain, not by naive
74
74
  # last-2-label slicing (which breaks company.co.uk → co.uk).
75
75
  AUTH_SERVER_NAME=auth.CHANGEME_DOMAIN
@@ -124,7 +124,7 @@ EXE_ORG_ID=
124
124
  EXE_ORG_WORKSPACE_ID=
125
125
 
126
126
  # --- CRM ---
127
- CRM_IMAGE_TAG=update.askexe.com/askexe/exe-crm:v0.9.53@sha256:a586dcc8bbd992538e3caa18c44e772d30f31155dfef0a2b7466ca3fc7c553d8
127
+ CRM_IMAGE_TAG=update.askexe.com/askexe/exe-crm:v0.9.59@sha256:40619dce57540f86dc7c8b71f1da57f44600a288f75a28850a9a9b425d0b92a6
128
128
  CRM_SERVER_URL=https://crm.CHANGEME_DOMAIN
129
129
  CRM_APP_SECRET=CHANGEME_CRM_APP_SECRET
130
130
  # The CRM's first admin — seeded at boot by WorkspaceBootstrapService, which is
@@ -138,7 +138,7 @@ EXE_CRM_ADMIN_EMAIL=CHANGEME_ADMIN_EMAIL
138
138
  CRM_HOST_PORT=3000
139
139
 
140
140
  # --- Wiki ---
141
- WIKI_IMAGE_TAG=update.askexe.com/askexe/exe-wiki:v0.9.28@sha256:61856a4c6b97ce62c62ecdc3a377139287be5860eb807d9fbb737115758d7856
141
+ WIKI_IMAGE_TAG=update.askexe.com/askexe/exe-wiki:v0.9.33@sha256:1f9e04a557c6034e0eac85ecdf76d465eab88394614184387ecf06cd2281e7d8
142
142
  # Bug 2a8d3003 — DO NOT change this without migrating the data first.
143
143
  # The wiki's users / workspaces / workspace_documents live in `public`. Point it at a
144
144
  # different schema and Prisma will NOT error: it finds no tables, assumes a fresh
@@ -176,7 +176,7 @@ WIKI_HOST_PORT=3001
176
176
  EXE_SSO_COOKIE_NAME=exe_access_token
177
177
 
178
178
  # --- exe-os ---
179
- EXE_OS_IMAGE_TAG=update.askexe.com/askexe/exe-os:v0.9.324@sha256:3ce6406e0f7f279ff2568bbbb7d55de51a46fdf35c49691f24fd959d6fd2d3fa
179
+ EXE_OS_IMAGE_TAG=update.askexe.com/askexe/exe-os:v0.9.382@sha256:266a59a482865eab9f79497999acb33c1fe1868ec54ea5cd1ce971c492f11bd6
180
180
  EXED_MCP_TOKEN=CHANGEME_EXED_MCP_TOKEN
181
181
  EXED_DEVICE_ID=CHANGEME_DEVICE_ID
182
182
  EXE_MCP_HOST_BIND=127.0.0.1
@@ -186,7 +186,7 @@ EXE_MCP_HOST_PORT=48739
186
186
  EXE_CLOUD_SYNC_TO_POSTGRES=true
187
187
 
188
188
  # --- ERP (Frappe/ERPNext fork) ---
189
- ERP_IMAGE_TAG=update.askexe.com/askexe/exe-erp:v2026.08.07-d185286-stamped@sha256:1c655f3f7819c797afd13c79561354f0276cf337403f32aee3e406a497e8827b
189
+ ERP_IMAGE_TAG=update.askexe.com/askexe/exe-erp:v0.3.11@sha256:5888b3e9d4ff309f37052dbdcac1fda66e235dbecb186a9ccf69380576e7b363
190
190
  # Administrator password for the ERPNext site (created on first boot).
191
191
  # bug 43854b31: this only applies at FIRST boot. To rotate it later you must also
192
192
  # run `bench --site $ERP_SITE_NAME set-admin-password <new>` inside exe-erp —
@@ -158,7 +158,7 @@ EXE_ORG_ID=
158
158
  EXE_ORG_WORKSPACE_ID=
159
159
 
160
160
  # --- CRM ---
161
- CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.53@sha256:a586dcc8bbd992538e3caa18c44e772d30f31155dfef0a2b7466ca3fc7c553d8
161
+ CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.59@sha256:40619dce57540f86dc7c8b71f1da57f44600a288f75a28850a9a9b425d0b92a6
162
162
  CRM_SERVER_URL=https://crm.CHANGEME_DOMAIN
163
163
  CRM_APP_SECRET=CHANGEME_CRM_APP_SECRET
164
164
  EXE_CRM_ADMIN_TOKEN=CHANGEME_EXE_CRM_ADMIN_TOKEN
@@ -209,7 +209,7 @@ WIKI_HOST_PORT=3001
209
209
  EXE_SSO_COOKIE_NAME=exe_access_token
210
210
 
211
211
  # --- exe-os ---
212
- EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.324@sha256:3ce6406e0f7f279ff2568bbbb7d55de51a46fdf35c49691f24fd959d6fd2d3fa
212
+ EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.382@sha256:266a59a482865eab9f79497999acb33c1fe1868ec54ea5cd1ce971c492f11bd6
213
213
 
214
214
  # Infra image pins — manifest-derived. Compose has no fallback default for
215
215
  # these: a missing pin ABORTS the deploy instead of substituting an old image.
@@ -264,7 +264,7 @@ ERROR_REPORTING_ENABLED=true
264
264
  MONITOR_ERROR_URL=http://exe-monitor-hub:8090/api/exe-monitor/errors
265
265
 
266
266
  # --- ERP (optional — Exe ERP, Frappe/ERPNext fork) ---
267
- ERP_IMAGE_TAG=ghcr.io/askexe/exe-erp:v2026.08.07-d185286-stamped@sha256:1c655f3f7819c797afd13c79561354f0276cf337403f32aee3e406a497e8827b
267
+ ERP_IMAGE_TAG=ghcr.io/askexe/exe-erp:v0.3.11@sha256:5888b3e9d4ff309f37052dbdcac1fda66e235dbecb186a9ccf69380576e7b363
268
268
  ERP_ADMIN_PASSWORD=CHANGEME_ERP_ADMIN_PASSWORD
269
269
  EXE_ERP_ADMIN_TOKEN=CHANGEME_EXE_ERP_ADMIN_TOKEN
270
270
  # Frappe site name — must match the erp.<domain> the customer serves (bug e61ad373).
@@ -764,7 +764,7 @@ services:
764
764
  # overridden back to exeOsMcp — see bug c604df37 above before doing that;
765
765
  # the spawn args below currently point at the wrong CLI entrypoint.
766
766
  EXE_OS_MCP_COMMAND: ${WIKI_EXE_OS_MCP_COMMAND:-npx}
767
- EXE_OS_MCP_ARGS: ${WIKI_EXE_OS_MCP_ARGS:--y @askexenow/exe-os@${WIKI_EXE_OS_NPM_VERSION:-0.9.324} mcp}
767
+ EXE_OS_MCP_ARGS: ${WIKI_EXE_OS_MCP_ARGS:--y @askexenow/exe-os@${WIKI_EXE_OS_NPM_VERSION:-0.9.382} mcp}
768
768
  BRANDING_CONFIG_PATH: /app/branding.json
769
769
  ports:
770
770
  - "127.0.0.1:${WIKI_HOST_PORT:-3001}:3001"
@@ -1,5 +1,6 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { readFileSync } from "node:fs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
3
4
  // ---------------------------------------------------------------------------
4
5
  // IMAGE PINS — DERIVED FROM THE SIGNED MANIFEST. NEVER HAND-TYPED.
5
6
  //
@@ -26,7 +27,52 @@ const REGISTRY = "ghcr.io/askexe";
26
27
  // own registry constant rather than reusing REGISTRY (bug 58840873).
27
28
  const AUTH_REGISTRY = "update.askexe.com/askexe";
28
29
 
29
- const MANIFEST_PATH = new URL("../stack-manifests/v0.9.json", import.meta.url);
30
+ // Bug cff0de47: the manifest used to be resolved as ONE path relative to this
31
+ // module's own file (`../stack-manifests/v0.9.json`). The documented VPS install
32
+ // copies `deploy/compose/*` into /opt/exe-stack WITHOUT its sibling
33
+ // `deploy/stack-manifests/`, so the relocated generator looked for
34
+ // /opt/stack-manifests/v0.9.json — a directory nobody ever creates — and died at
35
+ // MODULE INITIALIZATION before generating a single line of configuration.
36
+ //
37
+ // Resolution is now an ordered search over EXPLICIT, configurable locations, so
38
+ // relocating this file cannot break it:
39
+ // 1. $EXE_STACK_MANIFEST — explicit override (setup.sh exports it)
40
+ // 2. <this dir>/stack-manifests/… — manifest copied ALONGSIDE the compose files
41
+ // 3. <this dir>/../stack-manifests/…— in-repo / in-package layout
42
+ // A failure names every location searched instead of one phantom path.
43
+ const MANIFEST_FILENAME = "v0.9.json";
44
+ const MANIFEST_PATH_ENV_VAR = "EXE_STACK_MANIFEST";
45
+
46
+ export function manifestSearchPaths(
47
+ env: NodeJS.ProcessEnv = process.env,
48
+ moduleUrl: string = import.meta.url,
49
+ ): string[] {
50
+ const paths: string[] = [];
51
+ const override = (env[MANIFEST_PATH_ENV_VAR] ?? "").trim();
52
+ if (override) paths.push(override);
53
+ paths.push(fileURLToPath(new URL(`./stack-manifests/${MANIFEST_FILENAME}`, moduleUrl)));
54
+ paths.push(fileURLToPath(new URL(`../stack-manifests/${MANIFEST_FILENAME}`, moduleUrl)));
55
+ return paths;
56
+ }
57
+
58
+ export function resolveManifestPath(
59
+ env: NodeJS.ProcessEnv = process.env,
60
+ moduleUrl: string = import.meta.url,
61
+ exists: (p: string) => boolean = existsSync,
62
+ ): string {
63
+ const candidates = manifestSearchPaths(env, moduleUrl);
64
+ for (const candidate of candidates) {
65
+ if (exists(candidate)) return candidate;
66
+ }
67
+ throw new Error(
68
+ `generate-env: the signed stack manifest (${MANIFEST_FILENAME}) was not found. Searched:\n` +
69
+ candidates.map((c) => ` - ${c}`).join("\n") +
70
+ `\nThe manifest is the single source of truth for every image pin, so generation cannot ` +
71
+ `continue without it. Copy deploy/stack-manifests/ next to these compose files, or set ` +
72
+ `${MANIFEST_PATH_ENV_VAR}=/path/to/${MANIFEST_FILENAME}. ` +
73
+ `This is NOT a node/tsx problem.`,
74
+ );
75
+ }
30
76
 
31
77
  type ManifestFile = {
32
78
  latest: string;
@@ -34,11 +80,12 @@ type ManifestFile = {
34
80
  };
35
81
 
36
82
  function loadManifestServices(): Record<string, { image?: string }> {
37
- const manifest = JSON.parse(readFileSync(MANIFEST_PATH, "utf8")) as ManifestFile;
83
+ const manifestPath = resolveManifestPath();
84
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8")) as ManifestFile;
38
85
  const services = manifest.stacks?.[manifest.latest]?.services;
39
86
  if (!services) {
40
87
  throw new Error(
41
- `generate-env: stack manifest ${MANIFEST_PATH.pathname} has no services for latest="${manifest.latest}". ` +
88
+ `generate-env: stack manifest ${manifestPath} has no services for latest="${manifest.latest}". ` +
42
89
  `Refusing to generate a .env with no pins — that is exactly the silent-substitution failure ` +
43
90
  `the manifest-as-single-source-of-truth change exists to prevent.`,
44
91
  );
@@ -192,9 +239,18 @@ export interface GenerateEnvOptions {
192
239
  * a fresh deploy and the checked-in .env.example are unchanged.
193
240
  */
194
241
  disableSignup?: boolean;
242
+ /**
243
+ * The CRM's first administrator (bug cff0de47). When supplied it is written
244
+ * straight into EXE_CRM_ADMIN_EMAIL instead of the CHANGEME_ADMIN_EMAIL placeholder, so the documented first-run path produces
245
+ * a .env that the deploy gate accepts. It is still never GUESSED — no
246
+ * admin@<domain> default — because it must be a real mailbox that also exists
247
+ * in GoTrue.
248
+ */
249
+ adminEmail?: string;
195
250
  }
196
251
 
197
252
  export function generateEnv(options: GenerateEnvOptions): string {
253
+ const adminEmail = (options.adminEmail ?? "").trim();
198
254
  const normalizedDomain = normalizeDomain(options.domain);
199
255
  const normalizedClientName = normalizeClientName(options.clientName);
200
256
  const gatewayWsAuthToken = randomSecret(RANDOM_SECRET_48);
@@ -318,8 +374,8 @@ export function generateEnv(options: GenerateEnvOptions): string {
318
374
  // refused (e51ca54c §10.6b). It cannot be generated — it must be a real
319
375
  // mailbox that also exists in GoTrue — so it ships as SET_MANUALLY rather
320
376
  // than as a random secret or a guessed admin@<domain>.
321
- MANUAL_VALUE_COMMENT,
322
- "EXE_CRM_ADMIN_EMAIL=CHANGEME_ADMIN_EMAIL",
377
+ ...(adminEmail ? [] : [MANUAL_VALUE_COMMENT]),
378
+ `EXE_CRM_ADMIN_EMAIL=${adminEmail || "CHANGEME_ADMIN_EMAIL"}`,
323
379
  `CRM_HOST_PORT=${CRM_HOST_PORT}`,
324
380
  "",
325
381
  "# --- Wiki ---",
@@ -935,7 +991,7 @@ export function joinEnvLines(lines: string[]): string {
935
991
  function printUsage(): void {
936
992
  process.stderr.write(
937
993
  "Usage:\n" +
938
- " npx tsx deploy/compose/generate-env.ts <client-name> <domain> [license-key]\n" +
994
+ " npx tsx deploy/compose/generate-env.ts <client-name> <domain> [license-key] [admin-email]\n" +
939
995
  " npx tsx deploy/compose/generate-env.ts --example\n",
940
996
  );
941
997
  }
@@ -957,13 +1013,13 @@ function main(): void {
957
1013
  return;
958
1014
  }
959
1015
 
960
- const [clientName, domain, licenseKey] = args;
1016
+ const [clientName, domain, licenseKey, adminEmail] = args;
961
1017
  if (!clientName || !domain) {
962
1018
  printUsage();
963
1019
  process.exit(1);
964
1020
  }
965
1021
 
966
- process.stdout.write(generateEnv({ clientName, domain, licenseKey }));
1022
+ process.stdout.write(generateEnv({ clientName, domain, licenseKey, adminEmail }));
967
1023
  }
968
1024
 
969
1025
  if (isCliInvocation()) {
@@ -14,17 +14,106 @@ info() { echo -e "${GREEN}[setup]${NC} $1"; }
14
14
  warn() { echo -e "${YELLOW}[setup]${NC} $1"; }
15
15
  err() { echo -e "${RED}[setup]${NC} $1" >&2; }
16
16
 
17
+ # Read one KEY from .env, empty if absent. Used to decide whether a RE-RUN
18
+ # already has the configuration this run did not pass on the command line.
19
+ get_env_var() {
20
+ [[ -f .env ]] || { echo ""; return 0; }
21
+ local raw
22
+ raw=$(grep -E "^$1=" .env 2>/dev/null | head -n1 | cut -d= -f2- || true)
23
+ # set_env_var writes dotenv DOUBLE-QUOTED values, so undo that quoting here —
24
+ # otherwise a re-run compares `"true"` against `true` and takes the wrong
25
+ # branch. Values written by generate-env.ts are unquoted and pass through.
26
+ if [[ ${#raw} -ge 2 && "$raw" == '"'*'"' ]]; then
27
+ local bs='\' dq='"' dollar='$'
28
+ raw="${raw:1:${#raw}-2}"
29
+ raw="${raw//$dollar$dollar/$dollar}"
30
+ raw="${raw//"$bs$dq"/$dq}"
31
+ raw="${raw//"$bs$bs"/$bs}"
32
+ fi
33
+ printf '%s\n' "$raw"
34
+ }
35
+
36
+ # Set (or append) one KEY=VALUE in .env WITHOUT echoing the value. sed cannot be
37
+ # used safely here: secrets contain /, & and = which are sed metacharacters.
38
+ #
39
+ # COMPOSE INTERPOLATES .env VALUES, so a `$` written raw is not a `$`. An SMTP
40
+ # password of `abc$TOKEN` is read by Compose as the variable TOKEN and becomes
41
+ # `abc` — the credential is silently changed, email verification and password
42
+ # reset stop working, and nothing in the stack reports a wrong password as
43
+ # anything but a failed login. Measured:
44
+ #
45
+ # .env: SMTP_PASS=abc$TOKEN -> docker compose config -> P: abc
46
+ # .env: SMTP_PASS=abc$$TOKEN -> docker compose config -> P: abc$$TOKEN
47
+ #
48
+ # (`docker compose config` re-escapes a literal `$` as `$$` on output, which is
49
+ # how the second line reads back as the intended `abc$TOKEN`.)
50
+ #
51
+ # ESCAPING `$` IS NOT ENOUGH: an UNQUOTED value also loses everything from the
52
+ # first `#`, and its surrounding whitespace. Measured the same way:
53
+ #
54
+ # .env: SMTP_PASS=abc #def -> docker compose config -> P: abc
55
+ # .env: SMTP_PASS="abc #def" -> docker compose config -> P: abc #def
56
+ #
57
+ # So values are written dotenv DOUBLE-QUOTED, with `\`, `"` and `$` escaped.
58
+ # These are literal secrets and hostnames, never expressions — nothing here is
59
+ # meant to interpolate. get_env_var() undoes exactly this quoting.
60
+ set_env_var() {
61
+ local key="$1" value="$2"
62
+ # The replacement side of ${var//x/y} IS expanded, so a literal `$$` written
63
+ # there becomes the shell's PID — `abc$TOKEN` came out as `abc87319TOKEN`.
64
+ # Going through a variable whose value is a single `$` keeps both characters
65
+ # literal, because an expansion's RESULT is not expanded again.
66
+ local dollar='$' bs='\' dq='"'
67
+ # The PATTERN side is quoted: an unquoted `$bs` is a lone backslash, which the
68
+ # pattern matcher reads as an escape character and matches nothing, so `a\b`
69
+ # went out unescaped and Compose read `\b` as a BACKSPACE byte.
70
+ value="${value//"$bs"/$bs$bs}" # backslash first: it escapes the rest
71
+ value="${value//$dq/$bs$dq}"
72
+ value="${value//$dollar/$dollar$dollar}"
73
+ value="$dq$value$dq"
74
+ SEV_KEY="$key" SEV_VALUE="$value" awk '
75
+ $0 ~ "^" ENVIRON["SEV_KEY"] "=" { print ENVIRON["SEV_KEY"] "=" ENVIRON["SEV_VALUE"]; found=1; next }
76
+ { print }
77
+ END { if (!found) print ENVIRON["SEV_KEY"] "=" ENVIRON["SEV_VALUE"] }
78
+ ' .env > .env.setenv.tmp && mv .env.setenv.tmp .env
79
+ chmod 600 .env 2>/dev/null || true
80
+ }
81
+
17
82
  # Parse args
18
- CLIENT="" DOMAIN="" LICENSE=""
83
+ CLIENT="" DOMAIN="" LICENSE="" ADMIN_EMAIL="" TUNNEL_TOKEN=""
84
+ SMTP_HOST="" SMTP_PORT="" SMTP_USER="" SMTP_PASS="" NO_EMAIL="no"
19
85
  while [[ $# -gt 0 ]]; do
20
86
  case $1 in
21
87
  --client) CLIENT="$2"; shift 2;;
22
88
  --domain) DOMAIN="$2"; shift 2;;
23
89
  --license) LICENSE="$2"; shift 2;;
90
+ --admin-email) ADMIN_EMAIL="$2"; shift 2;;
91
+ --tunnel-token) TUNNEL_TOKEN="$2"; shift 2;;
92
+ --smtp-host) SMTP_HOST="$2"; shift 2;;
93
+ --smtp-port) SMTP_PORT="$2"; shift 2;;
94
+ --smtp-user) SMTP_USER="$2"; shift 2;;
95
+ --smtp-pass) SMTP_PASS="$2"; shift 2;;
96
+ --no-email) NO_EMAIL="yes"; shift 1;;
24
97
  *) err "Unknown arg: $1"; exit 1;;
25
98
  esac
26
99
  done
27
- [[ -z "$CLIENT" || -z "$DOMAIN" ]] && { err "Usage: ./setup.sh --client <name> --domain <domain>"; exit 1; }
100
+ [[ -z "$CLIENT" || -z "$DOMAIN" ]] && { err "Usage: ./setup.sh --client <name> --domain <domain> --admin-email <you@your-domain> [--tunnel-token <token>] [--smtp-host <host> --smtp-user <user> --smtp-pass <pass> | --no-email] [--license <key>]"; exit 1; }
101
+ # bug cff0de47: the CRM seeds its FIRST workspace owner from EXE_CRM_ADMIN_EMAIL.
102
+ # Without it the CRM boots healthy with no workspace and no user, and the first
103
+ # sign-in is refused with no way in. Ask for it here rather than deploying a
104
+ # stack nobody can log into (preflight refuses it either way).
105
+ if [[ -z "$ADMIN_EMAIL" ]]; then
106
+ if [[ -t 0 ]]; then
107
+ read -r -p " Admin email (owns the CRM/wiki; must be a real mailbox): " ADMIN_EMAIL
108
+ fi
109
+ fi
110
+ if [[ -z "$ADMIN_EMAIL" ]]; then
111
+ err "--admin-email is required. It becomes EXE_CRM_ADMIN_EMAIL: the mailbox that"
112
+ err "owns this stack. The CRM seeds its first workspace for exactly this address;"
113
+ err "without it the CRM comes up healthy but empty and NOBODY can sign in."
114
+ err " ./setup.sh --client $CLIENT --domain $DOMAIN --admin-email you@$DOMAIN${LICENSE:+ --license $LICENSE}"
115
+ exit 1
116
+ fi
28
117
 
29
118
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
30
119
  cd "$SCRIPT_DIR"
@@ -59,13 +148,44 @@ else
59
148
  # so any failure of the generator silently deployed ancient images that bypass
60
149
  # the manifest's digest-pinning entirely. There is NO safe inline fallback for
61
150
  # image tags — fail loudly instead and let the operator install node/npx.
151
+ # Bug cff0de47: generate-env.ts reads the SIGNED STACK MANIFEST at module
152
+ # initialization. The documented install copies deploy/compose/* into
153
+ # /opt/exe-stack without its sibling deploy/stack-manifests/, so the generator
154
+ # died on a manifest path that exists only inside the npm package — and the
155
+ # error below blamed node/tsx, sending the operator to debug the wrong thing.
156
+ # Locate the manifest explicitly and hand the generator its path.
157
+ if [[ -z "${EXE_STACK_MANIFEST:-}" ]]; then
158
+ for candidate in \
159
+ "$SCRIPT_DIR/stack-manifests/v0.9.json" \
160
+ "$SCRIPT_DIR/../stack-manifests/v0.9.json" \
161
+ "$(npm root -g 2>/dev/null)/@askexenow/exe-os/deploy/stack-manifests/v0.9.json"; do
162
+ if [[ -f "$candidate" ]]; then EXE_STACK_MANIFEST="$candidate"; break; fi
163
+ done
164
+ fi
165
+ if [[ -z "${EXE_STACK_MANIFEST:-}" || ! -f "${EXE_STACK_MANIFEST}" ]]; then
166
+ err "Stack manifest v0.9.json not found. Searched:"
167
+ err " - \$EXE_STACK_MANIFEST (${EXE_STACK_MANIFEST:-unset})"
168
+ err " - $SCRIPT_DIR/stack-manifests/v0.9.json"
169
+ err " - $SCRIPT_DIR/../stack-manifests/v0.9.json"
170
+ err " - \$(npm root -g)/@askexenow/exe-os/deploy/stack-manifests/v0.9.json"
171
+ err ""
172
+ err "The manifest is the single source of truth for every image pin, so .env"
173
+ err "cannot be generated without it. This is NOT a node/tsx problem."
174
+ err "Fix: run 'exe-os stack-init --dir $SCRIPT_DIR' (it copies the compose files"
175
+ err "AND the manifest), or set EXE_STACK_MANIFEST=/path/to/v0.9.json."
176
+ exit 1
177
+ fi
178
+ info "Using stack manifest: $EXE_STACK_MANIFEST"
179
+ export EXE_STACK_MANIFEST
62
180
  if command -v node >/dev/null 2>&1 && command -v npx >/dev/null 2>&1; then
63
181
  # Run via npx tsx (the project is pure ESM — require() is forbidden).
64
- if ! npx --yes tsx "$SCRIPT_DIR/generate-env.ts" "$CLIENT" "$DOMAIN" "${LICENSE:-}" > .env 2>/tmp/exe-generate-env.err; then
182
+ if ! npx --yes tsx "$SCRIPT_DIR/generate-env.ts" "$CLIENT" "$DOMAIN" "${LICENSE:-}" "$ADMIN_EMAIL" > .env 2>/tmp/exe-generate-env.err; then
65
183
  rm -f .env
66
184
  err "generate-env.ts failed — refusing to write a .env with stale fallback image tags."
67
185
  err "Generator error:"; cat /tmp/exe-generate-env.err >&2 || true
68
- err "Fix node/tsx and re-run setup.sh (the inline fallback was removed: bug 716c0f6e)."
186
+ err "If the error above is about a missing manifest, see EXE_STACK_MANIFEST"
187
+ err "(currently: $EXE_STACK_MANIFEST). Otherwise fix node/tsx and re-run"
188
+ err "setup.sh (the inline fallback was removed: bug 716c0f6e)."
69
189
  exit 1
70
190
  fi
71
191
  else
@@ -80,6 +200,79 @@ else
80
200
  info ".env generated with auto-generated secrets (chmod 600)"
81
201
  fi
82
202
 
203
+ # Step 2a: Cloudflare tunnel token.
204
+ #
205
+ # bug cff0de47: the gated deploy at the end of this script REFUSES to run
206
+ # without a tunnel token (the cloudflared service has no compose profile gate,
207
+ # so a stack without a token has no public ingress). The customer guide used to
208
+ # hand the token over in a LATER step than the one that runs this script, so the
209
+ # documented order could never complete on a fresh machine. Take it here.
210
+ if [[ -n "$TUNNEL_TOKEN" ]]; then
211
+ set_env_var CLOUDFLARE_TUNNEL_TOKEN "$TUNNEL_TOKEN"
212
+ info "Cloudflare tunnel token written to .env"
213
+ else
214
+ warn "No --tunnel-token given. The deploy step below REQUIRES CLOUDFLARE_TUNNEL_TOKEN"
215
+ warn "in .env (Zero Trust > Networks > Tunnels > your tunnel > install token)."
216
+ warn "Set it and re-run this script, or re-run with --tunnel-token <token>."
217
+ fi
218
+
219
+ # Step 2a-ii: Email delivery.
220
+ #
221
+ # bug cff0de47: a freshly generated .env ships SMTP_HOST empty and
222
+ # GOTRUE_MAILER_AUTOCONFIRM=false, and the deploy preflight REFUSES that
223
+ # combination — password-reset and email-verification would silently never
224
+ # send. Every fresh install hit it, and the customer guide never mentioned
225
+ # email at all. Ask for it here rather than deploying a stack whose recovery
226
+ # flow is dead, or record the operator's explicit decision to run without email.
227
+ if [[ "$NO_EMAIL" == "yes" ]]; then
228
+ set_env_var GOTRUE_MAILER_AUTOCONFIRM "true"
229
+ warn "Email flows DISABLED (--no-email): GOTRUE_MAILER_AUTOCONFIRM=true."
230
+ warn "Sign-ups are auto-confirmed and there is NO password-reset email."
231
+ warn "Signup stays disabled (invite-only), so this does not open registration."
232
+ elif [[ -n "$SMTP_HOST" ]]; then
233
+ set_env_var SMTP_HOST "$SMTP_HOST"
234
+ if [[ -n "$SMTP_PORT" ]]; then set_env_var SMTP_PORT "$SMTP_PORT"; fi
235
+ if [[ -n "$SMTP_USER" ]]; then set_env_var SMTP_USER "$SMTP_USER"; fi
236
+ if [[ -n "$SMTP_PASS" ]]; then set_env_var SMTP_PASS "$SMTP_PASS"; fi
237
+ # GOTRUE_MAILER_AUTOCONFIRM IS DERIVED FROM THE MAILER DECISION, not left at
238
+ # whatever a previous run wrote. Switching a `--no-email` install to SMTP used
239
+ # to leave AUTOCONFIRM=true behind: setup announced that verification would
240
+ # send while GoTrue kept auto-confirming every account without ever proving
241
+ # the mailbox belonged to the person signing up — and preflight's smtp_recovery
242
+ # check short-circuits on AUTOCONFIRM=true, so nothing downstream said
243
+ # otherwise. Each branch here writes the flag its own decision implies.
244
+ # (codex on PR #1152)
245
+ set_env_var GOTRUE_MAILER_AUTOCONFIRM "false"
246
+ info "SMTP configured ($SMTP_HOST) — email verification and password reset will send."
247
+ elif [[ -n "$(get_env_var SMTP_HOST)" ]]; then
248
+ # A RE-RUN IS NOT A FRESH INSTALL. This script is documented as re-runnable —
249
+ # the customer guide's own tunnel-token retry re-invokes it — and demanding
250
+ # the email flags again on every invocation made that retry fail on a stack
251
+ # that was already configured correctly. Judge the EFFECTIVE configuration in
252
+ # .env, not the flags of this particular run. (codex on PR #1152)
253
+ info "SMTP already configured in .env ($(get_env_var SMTP_HOST)) — keeping it."
254
+ if [[ "$(get_env_var GOTRUE_MAILER_AUTOCONFIRM)" == "true" ]]; then
255
+ # No decision was made THIS run, so this is reported, not silently flipped:
256
+ # SMTP + AUTOCONFIRM=true can be deliberate on an invite-only stack.
257
+ warn "...but GOTRUE_MAILER_AUTOCONFIRM=true, so accounts are auto-confirmed"
258
+ warn "WITHOUT verifying the mailbox. Re-run with --smtp-host to enforce"
259
+ warn "verification, or set GOTRUE_MAILER_AUTOCONFIRM=false in .env."
260
+ fi
261
+ elif [[ "$(get_env_var GOTRUE_MAILER_AUTOCONFIRM)" == "true" ]]; then
262
+ warn "Email flows already DISABLED in .env (GOTRUE_MAILER_AUTOCONFIRM=true) — keeping that choice."
263
+ warn "Sign-ups are auto-confirmed and there is NO password-reset email."
264
+ else
265
+ err "No email delivery configured. A stack with SMTP_HOST empty and"
266
+ err "GOTRUE_MAILER_AUTOCONFIRM=false cannot send password-reset or"
267
+ err "email-verification messages, and the deploy gate refuses it."
268
+ err ""
269
+ err "Either supply SMTP credentials:"
270
+ err " --smtp-host smtp.example.com --smtp-port 587 --smtp-user <user> --smtp-pass <pass>"
271
+ err "or run without email flows (sign-ups auto-confirmed, no password reset):"
272
+ err " --no-email"
273
+ exit 1
274
+ fi
275
+
83
276
  # Step 2b: Host-access consent for the monitor agent.
84
277
  #
85
278
  # exe-monitor-agent reports fleet health to the monitoring hub, but to do so it
@@ -235,7 +428,7 @@ fi
235
428
 
236
429
  if [[ -n "$EXE_CLI" ]]; then
237
430
  info "Step 4+5: Deploying via '$EXE_CLI stack-update' (preflight + proxy auth + health-gated rollout + rollback)..."
238
- if ! "$EXE_CLI" stack-update --yes; then
431
+ if ! "$EXE_CLI" stack-update --yes --domain "$DOMAIN" --admin-email "$ADMIN_EMAIL"; then
239
432
  err "stack-update failed — the gated deploy refused or rolled back. Review the"
240
433
  err "output above. Do NOT bypass with raw 'docker compose up' — fix the cause"
241
434
  err "(preflight RED, image pull, or health failure) and re-run setup.sh."
@@ -249,7 +442,7 @@ else
249
442
  err ""
250
443
  err "Install the CLI and re-run setup.sh:"
251
444
  err " npm install -g exe-os"
252
- err " ./setup.sh --client $CLIENT --domain $DOMAIN${LICENSE:+ --license $LICENSE}"
445
+ err " ./setup.sh --client $CLIENT --domain $DOMAIN --admin-email $ADMIN_EMAIL${LICENSE:+ --license $LICENSE}"
253
446
  exit 1
254
447
  fi
255
448
 
@@ -259,7 +452,12 @@ docker ps --format 'table {{.Names}}\t{{.Status}}'
259
452
  echo ""
260
453
  info "Stack deployed! Next steps:"
261
454
  echo " 1. Configure Cloudflare tunnel (if not done)"
262
- echo " 2. Open https://crm.${DOMAIN} to create admin account"
455
+ # bug cff0de47: this used to say "to create admin account". GoTrue signup is OFF
456
+ # by default (invite-only), so there is no account to create in the CRM UI — the
457
+ # admin is SEEDED from EXE_CRM_ADMIN_EMAIL and must also be created in GoTrue.
458
+ echo " 2. Create the GoTrue user for ${ADMIN_EMAIL} (signup is DISABLED by default —"
459
+ echo " see CUSTOMER-GUIDE.md 'Create Your Admin Account'), then sign in at"
460
+ echo " https://crm.${DOMAIN}"
263
461
  echo " 3. Open https://wiki.${DOMAIN} to set up wiki"
264
462
  echo " 4. Configure WhatsApp: edit gateway.json, restart gateway, pair at https://gateway.${DOMAIN}/pair/<name>"
265
463
  echo " 5. Verify: curl https://crm.${DOMAIN}/healthz && curl https://wiki.${DOMAIN}/api/ping"
@@ -153,6 +153,24 @@ server {
153
153
  location = /health { auth_request off; proxy_pass http://$crm_upstream/healthz; }
154
154
  location = /healthz { auth_request off; proxy_pass http://$crm_upstream/healthz; }
155
155
 
156
+ # G5 served-freshness (bug 529f45cf). See the doctrine note in
157
+ # sso-redirect.conf: an ungated path is granted EXPLICITLY, by exact match,
158
+ # never by a wildcard. Without this the watchdog's GET /__version was caught
159
+ # by the gate and 302'd to the auth login page, so the probe read auth's
160
+ # HTML and could not distinguish "wrong version" from "gated" from "down" —
161
+ # the served-freshness axis was unreadable for every SSO-gated surface.
162
+ #
163
+ # WHY UNAUTHENTICATED, DELIBERATELY: the response is a git sha/ref/repo and
164
+ # a build time, all of which the signed stack manifest already publishes
165
+ # unauthenticated at update.askexe.com/v1/stack-manifest.json. It leaks
166
+ # nothing the fleet does not already state publicly. The alternative —
167
+ # teaching the watchdog to hold an SSO session per surface — would put a
168
+ # live credential in a nightly job, widen its blast radius across five
169
+ # hosts, and make credential expiry look identical to real drift. A monitor
170
+ # whose failure mode is indistinguishable from the thing it monitors is the
171
+ # blind-monitor class this whole sweep is closing.
172
+ location = /__version { auth_request off; proxy_pass http://$crm_upstream/__version; }
173
+
156
174
  # Logout endpoint must be exempt from SSO gate (bug 96f8b2b2). Without this,
157
175
  # /auth/logout triggers 401 -> redirect to auth with logout URL as redirect param
158
176
  # -> infinite loop. Let the app handle logout (clear its own cookies), then it
@@ -207,6 +225,9 @@ server {
207
225
  location = /health { auth_request off; proxy_pass http://$wiki_upstream/api/ping; }
208
226
  location = /healthz { auth_request off; proxy_pass http://$wiki_upstream/api/ping; }
209
227
 
228
+ # G5 served-freshness — see the CRM vhost's note (bug 529f45cf).
229
+ location = /__version { auth_request off; proxy_pass http://$wiki_upstream/__version; }
230
+
210
231
  # Logout endpoint must be exempt from SSO gate (bug 96f8b2b2).
211
232
  location = /auth/logout { auth_request off; proxy_pass http://$wiki_upstream/auth/logout; }
212
233
 
@@ -246,6 +267,27 @@ server {
246
267
  set $gotrue_upstream gotrue:9999; # used by sso-redirect.conf's /_sso_gate
247
268
  include /etc/nginx/snippets/sso-redirect.conf;
248
269
 
270
+ # G5 served-freshness — see the CRM vhost's note (bug 529f45cf).
271
+ #
272
+ # HONEST ABOUT WHAT THIS DOES AND DOES NOT FIX: exe-erp does not implement
273
+ # /__version yet (that is a change in AskExe/exe-erp, not here). Today this
274
+ # location turns a MISLEADING answer into an honest one — the probe stops
275
+ # reading auth.askexe.com's login HTML and starts reading ERP's own 404, so
276
+ # served-freshness reports ERP as unverifiable-because-unimplemented rather
277
+ # than silently comparing a login page against a git sha. It becomes a real
278
+ # verification the moment exe-erp ships the route; nothing here changes then.
279
+ #
280
+ # Host is preserved and the standard forwarded headers are set, matching the
281
+ # main location block below — a bare proxy_pass would send
282
+ # Host: exe-erp-nginx, which frappe's origin check rejects.
283
+ location = /__version {
284
+ auth_request off;
285
+ proxy_pass http://$erp_upstream/__version;
286
+ proxy_set_header Host $host;
287
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
288
+ proxy_set_header X-Forwarded-Proto https;
289
+ }
290
+
249
291
  # ERP is the one upstream that runs a realtime socket.io service with
250
292
  # origin authentication: frappe's realtime middleware compares the Host
251
293
  # header against the Origin header and rejects mismatches ("Invalid
@@ -294,6 +336,9 @@ server {
294
336
  location = /health { auth_request off; proxy_pass http://$dashboard_upstream/health; }
295
337
  location = /healthz { auth_request off; proxy_pass http://$dashboard_upstream/health; }
296
338
 
339
+ # G5 served-freshness — see the CRM vhost's note (bug 529f45cf).
340
+ location = /__version { auth_request off; proxy_pass http://$dashboard_upstream/__version; }
341
+
297
342
  # Logout endpoint must be exempt from SSO gate (bug 96f8b2b2).
298
343
  location = /auth/logout { auth_request off; proxy_pass http://$dashboard_upstream/auth/logout; }
299
344
 
@@ -146,8 +146,17 @@
146
146
  # make it fire). That is not a typo fix — it would newly open a real bypass for
147
147
  # every path whose URI ends in an asset extension, including user-uploaded CRM
148
148
  # attachments and wiki images. If a future app genuinely needs an ungated path,
149
- # give it an explicit `location = /path { auth_request off; }` (as the /health
150
- # and /auth/logout routes already do), never an extension-shaped wildcard.
149
+ # give it an explicit `location = /path { auth_request off; }` (as the /health,
150
+ # /auth/logout and /__version routes already do), never an extension-shaped
151
+ # wildcard.
152
+ #
153
+ # /__version is the third such grant (bug 529f45cf). It is exact-match, it is
154
+ # read-only, and its body is a git sha/ref/repo already published without
155
+ # authentication in the signed stack manifest — so it widens no disclosure. It
156
+ # exists because the G5 served-freshness watchdog could not read ANY gated
157
+ # surface: every probe was 302'd to the login page, and the watchdog compared a
158
+ # git sha against auth's HTML. That is the shape this gate must never take —
159
+ # a control that cannot see reporting its blindness as ordinary traffic.
151
160
  # ─────────────────────────────────────────────────────────────────────────────
152
161
 
153
162
  # Run the gate for every request on this vhost. The gate is a zero-cost local
@@ -76,6 +76,6 @@
76
76
  "signature": {
77
77
  "keyId": "exe-stack-1",
78
78
  "alg": "ed25519",
79
- "signature": "ib9CL9sD/5c2q6M1UQDA1BUf9WT6iI18gUyCmY3+TitjVhIeAf5bTTyfs/FiWAAn8penUVWp21p65KJgSW1PCA=="
79
+ "signature": "hZxmmxAMTi7l2yI0XDe3vnm35xl7z6A+BVcLFZopjULs9Q+v9CsqvoaLoDv6APiBfsagwr1wPmN0A7Uw0GrJBw=="
80
80
  }
81
81
  }