@askexenow/exe-os 0.9.372 → 0.9.374

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 (470) hide show
  1. package/deploy/compose/.env.customer.example +45 -10
  2. package/deploy/compose/.env.example +46 -9
  3. package/deploy/compose/docker-compose.yml +136 -18
  4. package/deploy/compose/generate-env.ts +142 -34
  5. package/deploy/compose/sso-edge/default.conf.template +78 -7
  6. package/deploy/compose/sso-edge/sso-redirect.conf +109 -13
  7. package/deploy/stack-manifests/v0.9.30-apps.json +1 -1
  8. package/deploy/stack-manifests/v0.9.json +4 -4
  9. package/dist/.dist-verified.json +3 -3
  10. package/dist/{active-agent-GRT5MKD5.js → active-agent-ONPPEWQV.js} +7 -6
  11. package/dist/{active-agent-L2ZSSXDK.js → active-agent-UJKMG7LJ.js} +7 -6
  12. package/dist/{agent-defs-generator-M4ZNYIVX.js → agent-defs-generator-ZWI6DXOE.js} +6 -5
  13. package/dist/{agent-loop-FOK2IRZQ.js → agent-loop-OYHJKNYH.js} +1 -1
  14. package/dist/{agentic-ontology-DMPRDEUX.js → agentic-ontology-WHFJ3QFS.js} +1 -1
  15. package/dist/{artifact-backup-767STHSW.js → artifact-backup-WXZNB7KE.js} +2 -1
  16. package/dist/{backfill-gate-VX2RZTQV.js → backfill-gate-KWJQ35YX.js} +3 -2
  17. package/dist/{backfill-metadata-ZMEHJQ5M.js → backfill-metadata-3OUSQD5V.js} +8 -7
  18. package/dist/{background-jobs-LTPWCMA3.js → background-jobs-6VMD55PK.js} +3 -2
  19. package/dist/{backup-verify-EX2K732J.js → backup-verify-ZKTUYLTA.js} +4 -3
  20. package/dist/{behavior-injection-22AGMS25.js → behavior-injection-M6UYZCMW.js} +17 -15
  21. package/dist/{behaviors-DVFXAWF5.js → behaviors-ZJ45TFBJ.js} +21 -13
  22. package/dist/bin/age-ontology-load.js +3 -2
  23. package/dist/bin/agentic-ontology-backfill.js +10 -9
  24. package/dist/bin/agentic-reflection-backfill.js +11 -10
  25. package/dist/bin/agentic-semantic-label.js +10 -9
  26. package/dist/bin/backfill-conversations.js +13 -11
  27. package/dist/bin/backfill-responses.js +13 -11
  28. package/dist/bin/backfill-vectors.js +17 -15
  29. package/dist/bin/bulk-sync-postgres.js +22 -20
  30. package/dist/bin/cc-doctor.js +10 -9
  31. package/dist/bin/cleanup-stale-review-tasks.js +29 -26
  32. package/dist/bin/cli.js +36 -26
  33. package/dist/bin/deferred-daemon-restart.js +114 -110
  34. package/dist/bin/exe-agent-config.js +6 -5
  35. package/dist/bin/exe-agent.js +127 -33
  36. package/dist/bin/exe-assign.js +15 -13
  37. package/dist/bin/exe-boot.js +57 -54
  38. package/dist/bin/exe-call.js +8 -7
  39. package/dist/bin/exe-cloud.js +24 -22
  40. package/dist/bin/exe-config-dump.js +6 -5
  41. package/dist/bin/exe-dispatch.js +30 -27
  42. package/dist/bin/exe-doctor.js +14 -10
  43. package/dist/bin/exe-export-behaviors.js +19 -17
  44. package/dist/bin/exe-forget.js +10 -9
  45. package/dist/bin/exe-gateway.js +199 -19
  46. package/dist/bin/exe-grant.js +5 -5
  47. package/dist/bin/exe-healthcheck.js +10 -9
  48. package/dist/bin/exe-heartbeat.js +35 -32
  49. package/dist/bin/exe-kill.js +34 -31
  50. package/dist/bin/exe-launch-agent.js +126 -54
  51. package/dist/bin/exe-mcp.js +6 -5
  52. package/dist/bin/exe-memory-reads.js +8 -7
  53. package/dist/bin/exe-new-employee.js +12 -11
  54. package/dist/bin/exe-os-mcp-proxy.js +6 -5
  55. package/dist/bin/exe-pending-messages.js +30 -27
  56. package/dist/bin/exe-pending-notifications.js +29 -26
  57. package/dist/bin/exe-pending-reviews.js +30 -27
  58. package/dist/bin/exe-rename.js +8 -7
  59. package/dist/bin/exe-repo-truth.js +1 -1
  60. package/dist/bin/exe-review.js +33 -30
  61. package/dist/bin/exe-search.js +9 -8
  62. package/dist/bin/exe-session-cleanup.js +35 -32
  63. package/dist/bin/exe-settings.js +24 -22
  64. package/dist/bin/exe-start-codex.js +137 -55
  65. package/dist/bin/exe-start-opencode.js +121 -23
  66. package/dist/bin/exe-status.js +31 -28
  67. package/dist/bin/exe-support.js +5 -4
  68. package/dist/bin/exe-team.js +7 -6
  69. package/dist/bin/exe-watchdog.js +31 -11
  70. package/dist/bin/generate-hook-manifest.js +44 -7
  71. package/dist/bin/git-sweep.js +31 -28
  72. package/dist/bin/graph-backfill.js +89 -35
  73. package/dist/bin/graph-export.js +9 -8
  74. package/dist/bin/import-history.js +14 -13
  75. package/dist/bin/install.js +137 -113
  76. package/dist/bin/intercom-check.js +5 -5
  77. package/dist/bin/mcp-sessions.js +2 -2
  78. package/dist/bin/orchestration-metrics.js +7 -6
  79. package/dist/bin/postgres-agentic-reflection-backfill.js +5 -4
  80. package/dist/bin/postgres-agentic-semantic-backfill.js +4 -3
  81. package/dist/bin/pre-publish.js +1 -1
  82. package/dist/bin/reconcile-backlog.js +2 -2
  83. package/dist/bin/registry-proxy.js +1 -1
  84. package/dist/bin/scan-tasks.js +29 -26
  85. package/dist/bin/setup.js +5 -4
  86. package/dist/bin/shard-migrate.js +9 -8
  87. package/dist/bin/stack-update.js +40 -9
  88. package/dist/bin/verify-stack.js +2 -2
  89. package/dist/bin/vps-health-gate.js +1 -1
  90. package/dist/{boot-generation-OHXH4YC5.js → boot-generation-JKVZ4ZAT.js} +6 -5
  91. package/dist/{boot-review-sections-N5IXIGSS.js → boot-review-sections-2M6BTG73.js} +28 -25
  92. package/dist/{branch-hygiene-KCGXRAWP.js → branch-hygiene-U5GFRSTP.js} +31 -7
  93. package/dist/{branding-GH43W3PU.js → branding-I6KIMB7F.js} +3 -2
  94. package/dist/budget-fallback-XJRPMP2D.js +11 -0
  95. package/dist/build-manifest.json +1318 -1233
  96. package/dist/{capability-cards-4PXVLIVS.js → capability-cards-5IMJT6J7.js} +5 -4
  97. package/dist/{capacity-monitor-FKMQXORX.js → capacity-monitor-SAXCQK7O.js} +30 -27
  98. package/dist/{catchup-brief-SN5EKO4N.js → catchup-brief-U2TXBLHD.js} +34 -31
  99. package/dist/{chunk-CNC57JCS.js → chunk-23MVDXLY.js} +4 -4
  100. package/dist/{chunk-V4XAKXXF.js → chunk-2AJGV5UL.js} +1 -1
  101. package/dist/{chunk-FBYAXTDM.js → chunk-2ZOEC4KC.js} +10 -2
  102. package/dist/{chunk-ELXFSIIM.js → chunk-32YV32VA.js} +2 -2
  103. package/dist/{chunk-44C7QNZS.js → chunk-3KDCORDO.js} +1 -1
  104. package/dist/{chunk-JTB5V6BV.js → chunk-3SXHEQ7X.js} +1 -1
  105. package/dist/{chunk-HDW4XPDV.js → chunk-3UUX5OY4.js} +1 -1
  106. package/dist/{chunk-7PSLK36P.js → chunk-44TLJZJ5.js} +1 -1
  107. package/dist/{chunk-JTWTBX2M.js → chunk-4EN3IZ3Q.js} +2 -1
  108. package/dist/{chunk-KPMC7PY7.js → chunk-4HKTO2SV.js} +1 -1
  109. package/dist/{chunk-CDUB5Q6J.js → chunk-4IK2K3B3.js} +1 -1
  110. package/dist/{chunk-GH6YJOOC.js → chunk-4SJ4LK4V.js} +6 -6
  111. package/dist/{chunk-PVEM537A.js → chunk-4YLBKEL5.js} +2 -2
  112. package/dist/chunk-4YNA3CM6.js +872 -0
  113. package/dist/{chunk-KYFFVTGO.js → chunk-55BEFF4V.js} +3 -3
  114. package/dist/{chunk-SEP5ITFQ.js → chunk-636LKCKE.js} +2 -2
  115. package/dist/{chunk-QTI4QAWA.js → chunk-6EZQUNE6.js} +338 -5
  116. package/dist/{chunk-WAEKYKTK.js → chunk-6RKKVPYF.js} +1 -1
  117. package/dist/{chunk-VX2F4ZUY.js → chunk-6SCGLHJ7.js} +3 -3
  118. package/dist/{chunk-MEGRQ53A.js → chunk-6VHOQ3IM.js} +51 -6
  119. package/dist/{chunk-HIIXCAEE.js → chunk-6YVUR3OU.js} +3 -3
  120. package/dist/{chunk-L6ZNURWN.js → chunk-7GE2EQ23.js} +1 -1
  121. package/dist/{chunk-2CWS374F.js → chunk-7RI2CNXJ.js} +1 -1
  122. package/dist/{chunk-OL3QP3AU.js → chunk-7TSBV3SD.js} +1 -1
  123. package/dist/{chunk-DSOQUQTV.js → chunk-A27Q27CT.js} +27 -0
  124. package/dist/{chunk-5AHRZI3R.js → chunk-AETLDRZB.js} +1 -1
  125. package/dist/{chunk-RNLF3CBB.js → chunk-AKLJ4JH3.js} +1 -1
  126. package/dist/{chunk-XHYHX6F7.js → chunk-AKLQSC6W.js} +329 -164
  127. package/dist/chunk-ANLFH23R.js +261 -0
  128. package/dist/{chunk-QLA3RTH4.js → chunk-AWWKRZMB.js} +5 -5
  129. package/dist/{chunk-ERVQTR7P.js → chunk-BBSIEYF5.js} +17 -3
  130. package/dist/{chunk-IPMUWYRQ.js → chunk-BJ7AVSY6.js} +2 -2
  131. package/dist/{chunk-HV6Y6F4X.js → chunk-C2L622QJ.js} +89 -3
  132. package/dist/{chunk-TX3Q2GIL.js → chunk-C5HUMAA7.js} +24 -1
  133. package/dist/{chunk-QTYJPWJN.js → chunk-CBCGDEJA.js} +7 -7
  134. package/dist/{chunk-XXSNLM6R.js → chunk-DB55JZHU.js} +1 -1
  135. package/dist/{chunk-LAZKEJMS.js → chunk-DIXXEE3S.js} +840 -607
  136. package/dist/{chunk-FB343XQX.js → chunk-DJ7YXOTU.js} +2 -2
  137. package/dist/{chunk-YFCNWQAM.js → chunk-DJOIMFKV.js} +2 -2
  138. package/dist/{chunk-UTDMTQNH.js → chunk-DSJI76XL.js} +92 -14
  139. package/dist/{chunk-EEXX4UMQ.js → chunk-DZKPOSFD.js} +1 -1
  140. package/dist/{chunk-WSOA3WMC.js → chunk-E426DOSY.js} +161 -4
  141. package/dist/{chunk-ZISQOOER.js → chunk-EKE37MO4.js} +3 -3
  142. package/dist/{chunk-RIECV7SR.js → chunk-EKYYMIVT.js} +1 -1
  143. package/dist/{chunk-HIVZ53YB.js → chunk-EXTZSNWL.js} +2 -2
  144. package/dist/{chunk-YYA5LXCT.js → chunk-FNEZ4BWT.js} +1 -1
  145. package/dist/chunk-FTZET5YX.js +313 -0
  146. package/dist/chunk-GHR4ZPJ7.js +70 -0
  147. package/dist/{chunk-MINXPXAB.js → chunk-GJI77VDO.js} +3 -3
  148. package/dist/{chunk-AAMGHW5W.js → chunk-GLQEJOXE.js} +1 -0
  149. package/dist/{chunk-ADNBOKYZ.js → chunk-GM7TLYOK.js} +60 -18
  150. package/dist/{chunk-RUWWES2K.js → chunk-GNUAL43X.js} +2 -2
  151. package/dist/{chunk-QZL6E4UB.js → chunk-GOMQ7PVQ.js} +2 -2
  152. package/dist/{chunk-GB3AHV5F.js → chunk-GQOEWNVM.js} +1 -1
  153. package/dist/{chunk-NQZUSEAR.js → chunk-GS7LIT34.js} +246 -17
  154. package/dist/{chunk-XTWHNLGD.js → chunk-GZOG2MAX.js} +1 -1
  155. package/dist/{chunk-E5HAY3DQ.js → chunk-HDLAB7W3.js} +1 -1
  156. package/dist/{chunk-E5QQZDQN.js → chunk-HNWS7YHN.js} +358 -136
  157. package/dist/{chunk-VV5EZZNT.js → chunk-HTBEVCO2.js} +1 -1
  158. package/dist/{chunk-OZBII5E3.js → chunk-I4DNJFDR.js} +4 -4
  159. package/dist/{chunk-SI5SZAJA.js → chunk-IBS2FAI4.js} +21 -4
  160. package/dist/{chunk-J5EYOBFF.js → chunk-IHXW4VUI.js} +1 -1
  161. package/dist/{chunk-RUVO3NJC.js → chunk-IN6CAM4F.js} +9 -3
  162. package/dist/{chunk-53PYNYTW.js → chunk-IRVOXUSK.js} +5 -5
  163. package/dist/{chunk-THM7J6UI.js → chunk-JHI5WMK5.js} +5 -5
  164. package/dist/{chunk-3KTQWMHI.js → chunk-JSMDRKPJ.js} +12 -4
  165. package/dist/chunk-JTVIANUB.js +131 -0
  166. package/dist/{chunk-2ADYTOHQ.js → chunk-K4ESASPL.js} +1 -1
  167. package/dist/{chunk-YWUQVHDL.js → chunk-KTCXJWJG.js} +1 -1
  168. package/dist/{chunk-RGUDGC6A.js → chunk-KTU3EAWK.js} +5 -5
  169. package/dist/{chunk-DKBPCOU4.js → chunk-L6RXG36J.js} +2 -2
  170. package/dist/{chunk-T4EK56WI.js → chunk-LDNYSMPZ.js} +1 -1
  171. package/dist/{chunk-RIK5GRWI.js → chunk-LGS2V2XD.js} +3 -3
  172. package/dist/{chunk-JKXZGRWR.js → chunk-LP4GB656.js} +2 -2
  173. package/dist/{chunk-H74466TM.js → chunk-M7O7TGGU.js} +1 -1
  174. package/dist/chunk-MJCSEIFI.js +54 -0
  175. package/dist/{chunk-IDZPQG2D.js → chunk-MOGA4Q7F.js} +2 -2
  176. package/dist/{chunk-OYQNNKNS.js → chunk-MXPNVSXI.js} +37 -14
  177. package/dist/{chunk-UVW7YFAF.js → chunk-N7VEP5B3.js} +4 -4
  178. package/dist/{chunk-HHE2HV3V.js → chunk-NBXDXKLC.js} +1 -1
  179. package/dist/{chunk-LDL3S7AC.js → chunk-NKETJCB5.js} +7 -3
  180. package/dist/{chunk-ECHLVLA7.js → chunk-NMH5ZQPU.js} +1 -1
  181. package/dist/{chunk-U3XLRMJD.js → chunk-NT7W4RXD.js} +1 -1
  182. package/dist/{chunk-UQUUNGTP.js → chunk-NUK7EEN5.js} +11 -9
  183. package/dist/{chunk-GBNB4EWD.js → chunk-ORM7ZFKC.js} +16 -0
  184. package/dist/{chunk-O4ZFRK6W.js → chunk-OVEQE6YS.js} +244 -49
  185. package/dist/{chunk-4ZJ5BPY6.js → chunk-PB5S7YOF.js} +2 -2
  186. package/dist/{chunk-JR23BL74.js → chunk-PDVXWXTL.js} +4 -4
  187. package/dist/{chunk-3CIMDFXG.js → chunk-PFQ3VEEM.js} +1 -1
  188. package/dist/{chunk-SBJV2PCU.js → chunk-PHBU4LGO.js} +1 -1
  189. package/dist/{chunk-W25RLOQ2.js → chunk-PLZSZOZN.js} +3 -3
  190. package/dist/{chunk-THIJIOE2.js → chunk-PY3FOMRN.js} +18 -6
  191. package/dist/{chunk-AAUWFXOX.js → chunk-Q3AXXKDF.js} +3 -3
  192. package/dist/{chunk-VKXS2YGN.js → chunk-QHJR7IMX.js} +2 -2
  193. package/dist/chunk-QLZ46RCK.js +45 -0
  194. package/dist/{chunk-UHPMK6QZ.js → chunk-R3CZWFFC.js} +10 -2
  195. package/dist/{chunk-6XEYELCA.js → chunk-R4CBHKZ2.js} +1 -1
  196. package/dist/{chunk-5APCDDJZ.js → chunk-R522MWAR.js} +9 -9
  197. package/dist/chunk-RH4AH3YB.js +80 -0
  198. package/dist/{chunk-AMKSDKMK.js → chunk-S2WBS6BG.js} +22 -35
  199. package/dist/{chunk-WUKQVNLP.js → chunk-SEQIPGLU.js} +1 -1
  200. package/dist/{chunk-7WQRFSZI.js → chunk-SL6KQYDU.js} +26 -6
  201. package/dist/chunk-SLLLOOEI.js +103 -0
  202. package/dist/{chunk-5N4SG5NB.js → chunk-T35RCQFE.js} +3 -3
  203. package/dist/{chunk-7V6M3QUS.js → chunk-T3QUKNLI.js} +1 -1
  204. package/dist/{chunk-CW2UCKHS.js → chunk-TADAO3HV.js} +2 -2
  205. package/dist/{chunk-5DCCKHDY.js → chunk-TAMDAOCU.js} +109 -13
  206. package/dist/{chunk-ZXB56YR2.js → chunk-TFKCERAK.js} +101 -23
  207. package/dist/{chunk-RBYHJDAT.js → chunk-TQAZTRQ3.js} +3 -3
  208. package/dist/{chunk-OKGIOWOB.js → chunk-U6SUKSZR.js} +2 -2
  209. package/dist/{chunk-23QKEUF6.js → chunk-U73AC5AN.js} +34 -12
  210. package/dist/{chunk-PM6WSWVU.js → chunk-UBK7HK3J.js} +3 -3
  211. package/dist/{chunk-H37FSTF2.js → chunk-UBMZ3YQU.js} +1 -1
  212. package/dist/{chunk-JJUGI2YL.js → chunk-UCFC2AEI.js} +1 -1
  213. package/dist/{chunk-6IWLAQ7O.js → chunk-UCUOGVDX.js} +4 -0
  214. package/dist/{chunk-E7UCDSUE.js → chunk-UKLN57Q5.js} +2 -2
  215. package/dist/{chunk-ZYCLSEZT.js → chunk-ULIBLJ6W.js} +33 -11
  216. package/dist/{chunk-RLR6VVKV.js → chunk-UM3N6VND.js} +4 -4
  217. package/dist/{chunk-ZNUJFX7L.js → chunk-UQGSBM3U.js} +1 -1
  218. package/dist/{chunk-ZZXMB5F2.js → chunk-UZDF6FLJ.js} +1 -1
  219. package/dist/{chunk-LNOS24GV.js → chunk-V3WLC5TJ.js} +2 -95
  220. package/dist/{chunk-UXLO7VHX.js → chunk-VI4ATC6I.js} +1 -1
  221. package/dist/{chunk-77JP3LK4.js → chunk-VKJGHAZT.js} +92 -21
  222. package/dist/{chunk-7R73IAHU.js → chunk-VMTZ4RUW.js} +67 -150
  223. package/dist/{chunk-TGPQMMQP.js → chunk-VYQ7B7DI.js} +30 -17
  224. package/dist/{chunk-E2WEFZOR.js → chunk-W75GTHR3.js} +1 -1
  225. package/dist/{chunk-UKLF7F3Z.js → chunk-WJG344NC.js} +9 -9
  226. package/dist/{chunk-MBNIJXKI.js → chunk-WMEYJT4R.js} +18 -4
  227. package/dist/{chunk-R6FLELV6.js → chunk-XFTEX77S.js} +3 -3
  228. package/dist/{chunk-MDGYXUOV.js → chunk-XH7YL7JM.js} +1 -1
  229. package/dist/{chunk-JOO35RHR.js → chunk-XL5MFGMR.js} +3 -3
  230. package/dist/{chunk-OW5RZIDW.js → chunk-XNNECNDL.js} +95 -33
  231. package/dist/{chunk-5AHDQCTB.js → chunk-XXFKSJYA.js} +6 -6
  232. package/dist/{chunk-TGEPLJ66.js → chunk-XXOPG4BW.js} +3 -3
  233. package/dist/{chunk-PGLPUP37.js → chunk-XZ65ST2I.js} +1 -1
  234. package/dist/{chunk-3TTKAT6V.js → chunk-YKC7QDZH.js} +9 -4
  235. package/dist/{chunk-KXYFBBZR.js → chunk-YMP2QSOP.js} +20 -3
  236. package/dist/{chunk-TK4MI6F6.js → chunk-YSLGFPWX.js} +6 -6
  237. package/dist/{chunk-X2P43TB2.js → chunk-YTSXPJUQ.js} +1 -1
  238. package/dist/{chunk-HECXZGGZ.js → chunk-ZCERWHY2.js} +33 -35
  239. package/dist/{chunk-IVU3WN7S.js → chunk-ZG62LIK3.js} +74 -4
  240. package/dist/{chunk-GU62SNDH.js → chunk-ZGYNKA3O.js} +744 -111
  241. package/dist/{chunk-QMSEL5YS.js → chunk-ZIG7VPJV.js} +28 -76
  242. package/dist/{chunk-WZJVGA5I.js → chunk-ZL4AGWAH.js} +258 -13
  243. package/dist/{chunk-QR624DER.js → chunk-ZSODLMFV.js} +2 -2
  244. package/dist/{cleanup-graph-garbage-IPYDS5OX.js → cleanup-graph-garbage-DPJGO52H.js} +11 -10
  245. package/dist/{cloud-sync-command-JLNVG7H4.js → cloud-sync-command-JPNTT4OQ.js} +2 -2
  246. package/dist/{cloud-sync-db-init-JXUF6GI3.js → cloud-sync-db-init-V2LWIUQU.js} +1 -1
  247. package/dist/{cloud-sync-shutdown-Z4SBP6PL.js → cloud-sync-shutdown-BNALPWGX.js} +5 -4
  248. package/dist/{co-activation-74RDFTKS.js → co-activation-CMNSWS6B.js} +5 -4
  249. package/dist/{co-occurrence-CN3TBYVR.js → co-occurrence-WRI2NAN6.js} +9 -8
  250. package/dist/{code-context-index-D4MJ4VFX.js → code-context-index-NOJSHLPN.js} +12 -6
  251. package/dist/code-context-watcher-VZNZU3BO.js +118 -0
  252. package/dist/{codex-consolidation-PPXNBXCV.js → codex-consolidation-SH4UKFBQ.js} +2 -1
  253. package/dist/{conversation-entity-extractor-QGTLH4BP.js → conversation-entity-extractor-74252CAO.js} +4 -4
  254. package/dist/{conversation-wiki-populator-EBUZXYEU.js → conversation-wiki-populator-OS4C6W54.js} +1 -1
  255. package/dist/conversations-retention-C4BLKFEL.js +54 -0
  256. package/dist/coordinator-notice-MHUY7AQB.js +55 -0
  257. package/dist/{crdt-sync-7T4WCOKD.js → crdt-sync-B3JN6AIV.js} +1 -1
  258. package/dist/{crm-webhook-FTW3XZTO.js → crm-webhook-GYWQRFET.js} +2 -2
  259. package/dist/{cto-delegation-gate-SZCE34LB.js → cto-delegation-gate-LQHVLEMW.js} +29 -26
  260. package/dist/{daemon-auth-SSPY5ODS.js → daemon-auth-QZHEO7IQ.js} +3 -2
  261. package/dist/{daemon-orchestration-IGPHVNFR.js → daemon-orchestration-5HIQALZH.js} +36 -34
  262. package/dist/{daemon-ready-OT2VQLS7.js → daemon-ready-P2BR2XP5.js} +1 -1
  263. package/dist/{db-integrity-events-5DTASXJF.js → db-integrity-events-2DTFO37N.js} +3 -2
  264. package/dist/{db-restore-events-2FI4ZMKA.js → db-restore-events-G6NOQOVE.js} +2 -1
  265. package/dist/{destructive-data-guard-6I5MDFVD.js → destructive-data-guard-BVFWPPIS.js} +1 -1
  266. package/dist/doc-graph-extractor-PQHDHQPQ.js +367 -0
  267. package/dist/{documents-URULIXGM.js → documents-C4SSPJMC.js} +15 -13
  268. package/dist/{dreaming-VIZO3QDO.js → dreaming-XAO3FCBV.js} +33 -30
  269. package/dist/{employee-boot-brief-XLOG4ULP.js → employee-boot-brief-W4OHUMRQ.js} +37 -34
  270. package/dist/{exe-drift-TLQM3IHD.js → exe-drift-AG2KMKD5.js} +6 -5
  271. package/dist/{exe-export-7YWYWJHY.js → exe-export-IC5BT335.js} +17 -15
  272. package/dist/{exe-import-DW6VAUKW.js → exe-import-A35ZLDPG.js} +17 -15
  273. package/dist/{exe-key-TLJP2B4Y.js → exe-key-TCMJNYLA.js} +116 -112
  274. package/dist/{exe-org-LU46N36E.js → exe-org-JXCR3JYZ.js} +24 -23
  275. package/dist/{exe-snapshot-QHUZRS62.js → exe-snapshot-SV6SRIG6.js} +36 -33
  276. package/dist/{fast-db-init-SCTOOIUT.js → fast-db-init-L2RGKJWH.js} +1 -1
  277. package/dist/{founder-context-ZFZC4UHO.js → founder-context-D4HFIESJ.js} +4 -3
  278. package/dist/{founder-monitor-envelope-5KTKNL5G.js → founder-monitor-envelope-TFKRGCFE.js} +5 -4
  279. package/dist/{fts-integrity-LKAZEZJE.js → fts-integrity-4YB34KWX.js} +3 -2
  280. package/dist/gateway/index.js +19 -17
  281. package/dist/{git-main-guard-TN27QBAI.js → git-main-guard-VTW4N3CM.js} +7 -1
  282. package/dist/{git-staleness-GSGP344N.js → git-staleness-TN7CYGFG.js} +5 -4
  283. package/dist/{global-procedures-YAR7G4C6.js → global-procedures-YFDEIOG7.js} +7 -6
  284. package/dist/{graph-auto-extract-GNQS64F5.js → graph-auto-extract-3YR3TYRW.js} +9 -8
  285. package/dist/{graph-rag-RMSFLUOB.js → graph-rag-Z2KCJTPK.js} +6 -4
  286. package/dist/{hook-integrity-CF567MVN.js → hook-integrity-KGAV6ZC2.js} +14 -4
  287. package/dist/{hook-prefetch-36BK4F7U.js → hook-prefetch-K5DN3TOQ.js} +29 -26
  288. package/dist/hooks/bug-report-worker.js +34 -30
  289. package/dist/hooks/codex-stop-task-finalizer.js +36 -32
  290. package/dist/hooks/commit-complete.js +33 -30
  291. package/dist/hooks/error-recall.js +12 -11
  292. package/dist/hooks/exe-heartbeat-hook.js +8 -7
  293. package/dist/hooks/ingest-worker.js +23 -11
  294. package/dist/hooks/ingest.js +18 -17
  295. package/dist/hooks/instructions-loaded.js +10 -9
  296. package/dist/hooks/manifest.json +20 -20
  297. package/dist/hooks/notification.js +9 -8
  298. package/dist/hooks/post-compact.js +8 -7
  299. package/dist/hooks/post-tool-combined.js +26 -15
  300. package/dist/hooks/pre-compact.js +33 -30
  301. package/dist/hooks/pre-tool-use.js +404 -46
  302. package/dist/hooks/prompt-submit.js +57 -47
  303. package/dist/hooks/session-end.js +40 -41
  304. package/dist/hooks/session-start.js +21 -20
  305. package/dist/hooks/stop.js +40 -37
  306. package/dist/hooks/subagent-stop.js +38 -35
  307. package/dist/hooks/summary-worker.js +39 -36
  308. package/dist/hyde-MP4QNMU5.js +80 -0
  309. package/dist/index.js +44 -39
  310. package/dist/{installer-LUN4HQIC.js → installer-54HTN5RE.js} +8 -7
  311. package/dist/{installer-OC5VXNC7.js → installer-LK35OX6R.js} +8 -7
  312. package/dist/{installer-MPRFUQJE.js → installer-LLWKZI2S.js} +8 -7
  313. package/dist/intercom-ack-VCW755TN.js +13 -0
  314. package/dist/{intercom-queue-6DZ7BANV.js → intercom-queue-5NOT2RKI.js} +28 -25
  315. package/dist/{key-backup-status-6L2ARCXW.js → key-backup-status-LQPINQ3W.js} +2 -1
  316. package/dist/lib/agent-config.js +3 -2
  317. package/dist/lib/cloud-sync.js +26 -20
  318. package/dist/lib/config.js +2 -1
  319. package/dist/lib/consolidation.js +17 -10
  320. package/dist/lib/database.js +7 -4
  321. package/dist/lib/db-backup.js +17 -2
  322. package/dist/lib/db-daemon-client.js +8 -6
  323. package/dist/lib/db-write-worker-client.js +3 -1
  324. package/dist/lib/db-write-worker.js +20 -3
  325. package/dist/lib/db.js +7 -4
  326. package/dist/lib/device-registry.js +3 -2
  327. package/dist/lib/embed-worker.js +2 -1
  328. package/dist/lib/embedder.js +8 -6
  329. package/dist/lib/employee-templates.js +8 -7
  330. package/dist/lib/employees.js +5 -4
  331. package/dist/lib/exe-daemon-client.js +7 -5
  332. package/dist/lib/exe-daemon.js +467 -221
  333. package/dist/lib/hybrid-search.js +11 -8
  334. package/dist/lib/identity.js +5 -4
  335. package/dist/lib/license.js +4 -3
  336. package/dist/lib/messaging.js +29 -26
  337. package/dist/lib/post-tool-memory.js +16 -2
  338. package/dist/lib/registry-proxy.js +3 -1
  339. package/dist/lib/reminders.js +6 -5
  340. package/dist/lib/schedules.js +9 -8
  341. package/dist/lib/session-registry.js +7 -6
  342. package/dist/lib/skill-learning.js +16 -14
  343. package/dist/lib/stack-invariants.js +17 -1
  344. package/dist/lib/status-brief.js +5 -4
  345. package/dist/lib/store.js +10 -7
  346. package/dist/lib/task-router.js +6 -5
  347. package/dist/lib/tasks.js +31 -27
  348. package/dist/lib/tmux-routing.js +40 -25
  349. package/dist/lib/tmux-status.js +3 -1
  350. package/dist/lib/tmux-transport.js +2 -1
  351. package/dist/lib/token-spend.js +6 -5
  352. package/dist/lib/transport.js +3 -2
  353. package/dist/{license-gate-ESER24PJ.js → license-gate-JVMB6OFD.js} +5 -4
  354. package/dist/{license-sync-JVG5KNIY.js → license-sync-5VYS2F2W.js} +4 -3
  355. package/dist/mcp/register-tools.js +113 -109
  356. package/dist/mcp/server.js +118 -114
  357. package/dist/mcp/tools/complete-reminder.js +7 -6
  358. package/dist/mcp/tools/create-reminder.js +7 -6
  359. package/dist/mcp/tools/create-task.js +34 -30
  360. package/dist/mcp/tools/deactivate-behavior.js +18 -16
  361. package/dist/mcp/tools/list-reminders.js +7 -6
  362. package/dist/mcp/tools/list-tasks.js +34 -30
  363. package/dist/mcp/tools/send-message.js +32 -29
  364. package/dist/mcp/tools/update-task.js +32 -28
  365. package/dist/mcp-child-registry-OTG4MWO7.js +25 -0
  366. package/dist/{mcp-http-config-6K6IKH5F.js → mcp-http-config-DQWL7U2Z.js} +6 -5
  367. package/dist/{mcp-session-identity-LRC6WJSD.js → mcp-session-identity-277GASTQ.js} +28 -25
  368. package/dist/{memory-cards-V3OZHIYP.js → memory-cards-3S2ZQPR7.js} +17 -8
  369. package/dist/{memory-graph-extractor-JC2Z64L4.js → memory-graph-extractor-A6DFEFIN.js} +10 -9
  370. package/dist/{memory-poisoning-defense-YM4QJHCX.js → memory-poisoning-defense-ZVP4H6DY.js} +5 -4
  371. package/dist/{memory-pressure-watchdog-6F6KEQHN.js → memory-pressure-watchdog-6W5F6R7H.js} +29 -26
  372. package/dist/{memory-queue-QJNWKWKG.js → memory-queue-YF7IDSFY.js} +3 -2
  373. package/dist/{memory-queue-client-COA4ABEV.js → memory-queue-client-ADSDP6OX.js} +9 -7
  374. package/dist/{memory-reflection-QXHJPYPC.js → memory-reflection-BKB2YOE6.js} +52 -6
  375. package/dist/{monitor-grants-BW2WL4IU.js → monitor-grants-EV747HMW.js} +4 -3
  376. package/dist/{notification-ledger-6QRLQW4Q.js → notification-ledger-CLGM7ODF.js} +30 -27
  377. package/dist/{notifications-7B6D7Y5C.js → notifications-MACUZPYP.js} +28 -25
  378. package/dist/{oauth-server-TZFNQAFS.js → oauth-server-AYM37SQ4.js} +25 -4
  379. package/dist/{orchestration-events-GY5VP5LU.js → orchestration-events-N7LYMUGA.js} +6 -5
  380. package/dist/{orchestration-phase-UDS24CVQ.js → orchestration-phase-T2WD45UA.js} +3 -2
  381. package/dist/{orchestrator-JVPVOYWA.js → orchestrator-4X24EWHV.js} +30 -27
  382. package/dist/{org-brief-session-GRV5R5E3.js → org-brief-session-FZOFMO5U.js} +13 -12
  383. package/dist/{org-consent-policy-3FHHSYXV.js → org-consent-policy-O5E6HXBL.js} +1 -1
  384. package/dist/{org-join-BY4PV6UO.js → org-join-POWUG25F.js} +8 -7
  385. package/dist/{org-key-admin-WSCPT2CZ.js → org-key-admin-E7EMDOZZ.js} +9 -8
  386. package/dist/{org-key-pin-5WUSPGVN.js → org-key-pin-WHWHVWUO.js} +4 -3
  387. package/dist/{org-membership-ESALTLLN.js → org-membership-WRT2IHJK.js} +5 -4
  388. package/dist/{org-partner-config-YKHPDPZR.js → org-partner-config-B7T4CL2T.js} +7 -6
  389. package/dist/{org-partner-runtime-UJDGECZ4.js → org-partner-runtime-FODONVTM.js} +13 -12
  390. package/dist/{org-row-visibility-V5DXIHTE.js → org-row-visibility-VX4AVV5Q.js} +1 -1
  391. package/dist/{pipeline-router-YY5FQKTY.js → pipeline-router-6GGT2ZW3.js} +6 -5
  392. package/dist/{plan-limits-OVX6SN6B.js → plan-limits-FUN76LYY.js} +8 -7
  393. package/dist/{platform-procedures-I57ITMDC.js → platform-procedures-7YSCLF4Z.js} +1 -1
  394. package/dist/{postinstall-failure-B2JHNFPM.js → postinstall-failure-O6TSSNJB.js} +3 -2
  395. package/dist/{project-boot-LXLU2J32.js → project-boot-3Q65LCIP.js} +2 -1
  396. package/dist/project-name-LJVFMYTQ.js +30 -0
  397. package/dist/{projection-worker-D2472IOD.js → projection-worker-4OANGP5K.js} +5 -4
  398. package/dist/{prospective-memory-JXO2A6PL.js → prospective-memory-KR3P4T6N.js} +5 -4
  399. package/dist/{push-notifications-HR3FZRDI.js → push-notifications-NCZLH6DI.js} +29 -26
  400. package/dist/ref-provenance-gate-M4AQO4OT.js +269 -0
  401. package/dist/{reproject-worktree-memories-OSS3PGRF.js → reproject-worktree-memories-PWYKPB2U.js} +106 -23
  402. package/dist/{reranker-IMZRPYJ2.js → reranker-6V3C2AO4.js} +3 -2
  403. package/dist/resolve-image-labels-ZI6UBW5W.js +15 -0
  404. package/dist/{retrieval-health-W7OD44FE.js → retrieval-health-5D7O6VH6.js} +4 -3
  405. package/dist/{review-polling-2INP7H6M.js → review-polling-QW3LJ4KN.js} +29 -26
  406. package/dist/runtime/index.js +38 -34
  407. package/dist/{session-events-G4XUPVWV.js → session-events-T45SSTMF.js} +31 -26
  408. package/dist/{session-kill-telemetry-W7MHWJTQ.js → session-kill-telemetry-QSPVJGBF.js} +29 -26
  409. package/dist/{session-mcp-config-F7KATWOF.js → session-mcp-config-SC5BLWZG.js} +3 -2
  410. package/dist/{session-scope-LG2J4EMQ.js → session-scope-KRWE54C4.js} +28 -25
  411. package/dist/{setup-wizard-YQJI3SVM.js → setup-wizard-GP3TBTPF.js} +5 -4
  412. package/dist/{shard-manager-UROHZE46.js → shard-manager-OE36A4MY.js} +3 -2
  413. package/dist/{skill-refinement-RA37U756.js → skill-refinement-C7JTMLJG.js} +6 -5
  414. package/dist/stack-generate-manifest-MFMDWRUP.js +810 -0
  415. package/dist/{stack-promote-IYBRXHTA.js → stack-promote-EKSCYY63.js} +8 -6
  416. package/dist/{stack-release-OXWLVVG6.js → stack-release-2GZAAFO4.js} +8 -6
  417. package/dist/{stack-update-2CZEROPK.js → stack-update-J6JXSTAZ.js} +51 -5
  418. package/dist/{steward-gate-LTNFB3FY.js → steward-gate-BFCCMCSW.js} +6 -5
  419. package/dist/{subagent-brief-injection-OHLWLECQ.js → subagent-brief-injection-ED36PLYY.js} +44 -36
  420. package/dist/{subagent-spawn-ledger-USYZXU3M.js → subagent-spawn-ledger-E6U3OY6Z.js} +3 -2
  421. package/dist/{supervisor-handoff-CSJQMI53.js → supervisor-handoff-SGLEPOCY.js} +12 -3
  422. package/dist/{support-inbox-4KCEPAZQ.js → support-inbox-YW47SYJF.js} +20 -5
  423. package/dist/{task-enforcement-LGXWXGVZ.js → task-enforcement-CECTQX4U.js} +29 -26
  424. package/dist/{task-request-inbox-WHCOSUCP.js → task-request-inbox-Q5T4N5K7.js} +1 -1
  425. package/dist/{task-scope-KXF7Y6KA.js → task-scope-ERVEUEYU.js} +28 -25
  426. package/dist/{tasks-crud-5EM55WRZ.js → tasks-crud-ZRQNJXQ2.js} +28 -25
  427. package/dist/{tasks-notify-VFMAURTN.js → tasks-notify-MIZH4C2O.js} +29 -26
  428. package/dist/{tasks-review-MHGMBHUZ.js → tasks-review-Z7J2P6DG.js} +28 -25
  429. package/dist/{telemetry-upload-6NRTN7QJ.js → telemetry-upload-LVQUQYFP.js} +10 -9
  430. package/dist/{token-budget-LZPOYTRP.js → token-budget-BU4NOVZF.js} +6 -5
  431. package/dist/{tool-capability-index-ED5OAPMW.js → tool-capability-index-7F42MOJT.js} +1 -1
  432. package/dist/{tool-gates-7PLIOLAL.js → tool-gates-JWVSAYTW.js} +1 -1
  433. package/dist/{tool-gates-2OZY3GZM.js → tool-gates-VXITVRFQ.js} +1 -1
  434. package/dist/{tool-telemetry-ZX7VSAXK.js → tool-telemetry-O27EVMBR.js} +1 -1
  435. package/dist/tui/App.js +43 -40
  436. package/dist/{tui-data-CC5POSUV.js → tui-data-TPWWBIUQ.js} +28 -25
  437. package/dist/{update-support-KH6NSQON.js → update-support-F2F5537B.js} +22 -20
  438. package/dist/{whatsapp-QW3X7OCN.js → whatsapp-YM4A2CSK.js} +3 -1
  439. package/dist/{work-claims-MNK7PEPW.js → work-claims-B73X5NE7.js} +6 -5
  440. package/dist/{work-state-heartbeat-YEWT5NMZ.js → work-state-heartbeat-P4YX6E2R.js} +1 -1
  441. package/dist/{worker-gate-BOQSIU2Z.js → worker-gate-BEEIIVWA.js} +3 -2
  442. package/dist/{workflow-engine-MUUD7ZEX.js → workflow-engine-5X46PFCW.js} +4 -2
  443. package/dist/{worktree-GOGT2LZP.js → worktree-W47CIMJ6.js} +9 -6
  444. package/dist/worktree-ownership-guard-OUWJROW2.js +88 -0
  445. package/dist/{worktree-sweep-46VWPVQT.js → worktree-sweep-BNBD4RFX.js} +8 -7
  446. package/package.json +14 -5
  447. package/release-notes.json +5 -5
  448. package/src/commands/exe/call.md +1 -1
  449. package/stack.release.json +6 -0
  450. package/dist/chunk-KZXMP6JG.js +0 -319
  451. package/dist/chunk-TCTED52S.js +0 -120
  452. package/dist/chunk-W2IRQJ6R.js +0 -67
  453. package/dist/doc-graph-extractor-VPTRIEKN.js +0 -149
  454. package/dist/project-name-ILJTETUE.js +0 -14
  455. /package/dist/{chunk-3Y5THOU6.js → chunk-6WIFPD2P.js} +0 -0
  456. /package/dist/{chunk-7XGXRD22.js → chunk-AISULNGL.js} +0 -0
  457. /package/dist/{chunk-3F2UB4IQ.js → chunk-DN4YVV4Z.js} +0 -0
  458. /package/dist/{chunk-WV3TOOL7.js → chunk-KQ6RJWRW.js} +0 -0
  459. /package/dist/{chunk-HR2R2QER.js → chunk-M4IRPXSZ.js} +0 -0
  460. /package/dist/{chunk-ORA5BWCV.js → chunk-NRG7KZIP.js} +0 -0
  461. /package/dist/{chunk-7UTJA6HF.js → chunk-VZAFWPAY.js} +0 -0
  462. /package/dist/{chunk-VJSDGDNS.js → chunk-WSQASFLP.js} +0 -0
  463. /package/dist/{chunk-FZQWVQJG.js → chunk-YO4BO2CL.js} +0 -0
  464. /package/dist/{core-memory-6WBNT2HL.js → core-memory-7I7RE2SJ.js} +0 -0
  465. /package/dist/{entity-boost-MT336PI3.js → entity-boost-3UWGXG5O.js} +0 -0
  466. /package/dist/{memory-isolation-EJ45IXBH.js → memory-isolation-2TUZ7Z4K.js} +0 -0
  467. /package/dist/{message-queue-client-MVBTYCSV.js → message-queue-client-XQN7QABL.js} +0 -0
  468. /package/dist/{webhook-pipe-UQSEHFPO.js → webhook-pipe-W2FVXY7M.js} +0 -0
  469. /package/dist/{wiki-acl-WXRJGZ5Q.js → wiki-acl-IBQLLBTS.js} +0 -0
  470. /package/dist/{wiki-client-AXNM5FWY.js → wiki-client-W65IOSWF.js} +0 -0
@@ -1,40 +1,89 @@
1
1
  import { randomBytes } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ // ---------------------------------------------------------------------------
4
+ // IMAGE PINS — DERIVED FROM THE SIGNED MANIFEST. NEVER HAND-TYPED.
5
+ //
6
+ // .env used to be an INDEPENDENT source of pins: a block of hand-edited
7
+ // `*_RELEASE_TAG` constants that had to be "kept in sync" with
8
+ // deploy/stack-manifests/v0.9.json. It was not kept in sync. On 2026-08-20 the
9
+ // manifest, /opt/exe-stack/.env and the compose fallback defaults disagreed on
10
+ // 5 of 7 apps in production.
11
+ //
12
+ // One direction only: each repo cuts a release -> the manifest is generated
13
+ // from those releases -> .env is DERIVED from the manifest -> the VPS pulls what
14
+ // .env says. The version AND digest of every pin below now come from the
15
+ // manifest and nowhere else, so drift is unrepresentable rather than merely
16
+ // discouraged.
17
+ //
18
+ // The registry HOST is deployment topology, not a pin: .env.example targets
19
+ // GHCR so local simulation runs without private update.askexe.com credentials,
20
+ // while the same tag@digest is served by the pull-through proxy. Re-hosting
21
+ // preserves the digest, so the artifact is identical either way.
22
+ // ---------------------------------------------------------------------------
2
23
  const REGISTRY = "ghcr.io/askexe";
3
24
  // exe-auth (the shared SSO sign-in/sign-up SPA) ships only from the private
4
25
  // update.askexe.com registry — it is not mirrored to GHCR — so it carries its
5
26
  // own registry constant rather than reusing REGISTRY (bug 58840873).
6
27
  const AUTH_REGISTRY = "update.askexe.com/askexe";
7
28
 
8
- // Keep these defaults in sync with deploy/stack-manifests/v0.9.json latest.
9
- // deploy/compose/.env.example intentionally uses GHCR fallbacks so local
10
- // simulation can run without private update.askexe.com registry credentials.
11
- const CRM_RELEASE_TAG = "v0.9.51";
12
- const WIKI_RELEASE_TAG = "v0.9.26";
13
- const EXED_RELEASE_TAG = "v0.9.311";
14
- const GATEWAY_RELEASE_TAG = "v0.9.24";
15
- // Bug 633995f1: v0.9.5 is a quarantined build — it regressed to stock Beszel
16
- // (runtime uid 1001 -> 65532, data dir -> /beszel_data, entrypoint -> /beszel),
17
- // so it crashloops on any deployment carrying an existing monitor_hub_data
18
- // volume, and its agent half contradicts the generation-coupled compose
19
- // healthcheck. Generated .env files must never hand a customer that tag — a
20
- // generated .env overrides the compose default outright, so leaving this stale
21
- // would have silently defeated the compose pin. v0.9.4 is the last known-good
22
- // build. See deploy/known-bad-images.json.
23
- const MONITOR_RELEASE_TAG = "v0.9.4";
24
- const ERP_RELEASE_TAG = "v0.2.2";
25
- const EXE_BUILD_RELEASE_TAG = "v0.1.0";
26
- // Bug 58840873: pin exe-auth to the manifest-pinned tag so a generated .env never
27
- // lets compose fall back to its (stale) hardcoded default image. MUST equal the
28
- // AUTH_IMAGE_TAG tag in deploy/stack-manifests/v0.9.json and the compose default.
29
- const AUTH_RELEASE_TAG = "v0.5.0";
29
+ const MANIFEST_PATH = new URL("../stack-manifests/v0.9.json", import.meta.url);
30
+
31
+ type ManifestFile = {
32
+ latest: string;
33
+ stacks: Record<string, { services?: Record<string, { image?: string }> }>;
34
+ };
35
+
36
+ function loadManifestServices(): Record<string, { image?: string }> {
37
+ const manifest = JSON.parse(readFileSync(MANIFEST_PATH, "utf8")) as ManifestFile;
38
+ const services = manifest.stacks?.[manifest.latest]?.services;
39
+ if (!services) {
40
+ throw new Error(
41
+ `generate-env: stack manifest ${MANIFEST_PATH.pathname} has no services for latest="${manifest.latest}". ` +
42
+ `Refusing to generate a .env with no pins — that is exactly the silent-substitution failure ` +
43
+ `the manifest-as-single-source-of-truth change exists to prevent.`,
44
+ );
45
+ }
46
+ return services;
47
+ }
48
+
49
+ const MANIFEST_SERVICES = loadManifestServices();
50
+
51
+ /**
52
+ * The manifest's pin for a service, re-hosted onto `registry`. FAILS LOUDLY
53
+ * when the manifest does not govern the service, or governs it without a
54
+ * digest: a missing pin must abort generation, never fall back to a literal.
55
+ */
56
+ function pin(serviceKey: string, registry: string, imageName: string): string {
57
+ const image = MANIFEST_SERVICES[serviceKey]?.image;
58
+ if (!image) {
59
+ throw new Error(
60
+ `generate-env: the stack manifest does not pin "${serviceKey}". Every service .env pins must be ` +
61
+ `manifest-governed — add it to the manifest (exe-os stack-generate-manifest) rather than ` +
62
+ `hard-coding a version here.`,
63
+ );
64
+ }
65
+ const at = image.indexOf("@");
66
+ if (at === -1) {
67
+ throw new Error(
68
+ `generate-env: the manifest pin for "${serviceKey}" (${image}) carries no @sha256 digest. ` +
69
+ `Tags move, digests do not — refusing to emit an unpinned .env value.`,
70
+ );
71
+ }
72
+ const digest = image.slice(at + 1);
73
+ const beforeDigest = image.slice(0, at);
74
+ const colon = beforeDigest.lastIndexOf(":");
75
+ const slash = beforeDigest.lastIndexOf("/");
76
+ const tag = colon > slash ? beforeDigest.slice(colon + 1) : "";
77
+ return tag ? `${registry}/${imageName}:${tag}@${digest}` : `${registry}/${imageName}@${digest}`;
78
+ }
30
79
 
31
80
  const POSTGRES_USER = "exe";
32
81
  const POSTGRES_DB = "exedb";
33
82
  const CLICKHOUSE_DB = "default";
34
83
  const CLICKHOUSE_USER = "exe";
35
- export const CRM_IMAGE_TAG = `${REGISTRY}/exe-crm:${CRM_RELEASE_TAG}`;
84
+ export const CRM_IMAGE_TAG = pin("crm", REGISTRY, "exe-crm");
36
85
  const CRM_HOST_PORT = "3000";
37
- export const WIKI_IMAGE_TAG = `${REGISTRY}/exe-wiki:${WIKI_RELEASE_TAG}`;
86
+ export const WIKI_IMAGE_TAG = pin("wiki", REGISTRY, "exe-wiki");
38
87
  // Bug 2a8d3003: the wiki's data lives in `public` and generated .env files must say
39
88
  // so. This constant used to be "wiki", which meant every freshly generated stack
40
89
  // pinned the wiki to an empty schema — Prisma bootstraps it silently rather than
@@ -42,13 +91,22 @@ export const WIKI_IMAGE_TAG = `${REGISTRY}/exe-wiki:${WIKI_RELEASE_TAG}`;
42
91
  const WIKI_DB_SCHEMA = "public";
43
92
  const WIKI_VECTOR_DB = "exeOsMcp";
44
93
  const WIKI_HOST_PORT = "3001";
45
- export const EXE_OS_IMAGE_TAG = `${REGISTRY}/exe-os:${EXED_RELEASE_TAG}`;
46
- export const GATEWAY_IMAGE_TAG = `${REGISTRY}/exe-gateway:${GATEWAY_RELEASE_TAG}`;
47
- export const MONITOR_AGENT_IMAGE_TAG = `${REGISTRY}/exe-monitor-agent:${MONITOR_RELEASE_TAG}`;
48
- export const MONITOR_HUB_IMAGE_TAG = `${REGISTRY}/exe-monitor-hub:${MONITOR_RELEASE_TAG}`;
49
- export const ERP_IMAGE_TAG = `${REGISTRY}/exe-erp:${ERP_RELEASE_TAG}`;
50
- export const EXE_BUILD_IMAGE_TAG = `${REGISTRY}/exe-build:${EXE_BUILD_RELEASE_TAG}`;
51
- export const AUTH_IMAGE_TAG = `${AUTH_REGISTRY}/exe-auth:${AUTH_RELEASE_TAG}`;
94
+ export const EXE_OS_IMAGE_TAG = pin("exe-os", REGISTRY, "exe-os");
95
+ export const GATEWAY_IMAGE_TAG = pin("gateway", REGISTRY, "exe-gateway");
96
+ export const MONITOR_AGENT_IMAGE_TAG = pin("monitorAgent", REGISTRY, "exe-monitor-agent");
97
+ export const MONITOR_HUB_IMAGE_TAG = pin("monitorHub", REGISTRY, "exe-monitor-hub");
98
+ export const ERP_IMAGE_TAG = pin("erp", REGISTRY, "exe-erp");
99
+ // exe-build is control-plane only (not part of the customer stack), so the
100
+ // manifest does not govern it and there is nothing to derive. It is emitted
101
+ // as an opt-in for askexe-control-plane hosts.
102
+ export const EXE_BUILD_IMAGE_TAG = `${REGISTRY}/exe-build:v0.1.0`;
103
+ export const AUTH_IMAGE_TAG = pin("auth", AUTH_REGISTRY, "exe-auth");
104
+ // Infra pins. Compose no longer carries fallback defaults for these either, so
105
+ // the generated .env must state them — derived from the manifest like the rest.
106
+ // Third-party artifacts are served from the same pull-through proxy the manifest
107
+ // names, so they are NOT re-hosted onto GHCR.
108
+ export const EXE_DB_IMAGE = pin("exe-db", "update.askexe.com/askexe", "pgvector");
109
+ export const OTEL_COLLECTOR_IMAGE = pin("exe-otel-collector", "update.askexe.com/askexe", "otel-collector-contrib");
52
110
  const GATEWAY_HTTP_HOST_PORT = "3100";
53
111
  const GATEWAY_WS_HOST_PORT = "3101";
54
112
  const RANDOM_SECRET_16 = 16;
@@ -172,8 +230,8 @@ export function generateEnv(options: GenerateEnvOptions): string {
172
230
  "# http://gotrue:9999 and can reject browser tokens as iss-mismatch.",
173
231
  `GOTRUE_JWT_ISSUER=https://auth.${normalizedDomain}`,
174
232
  "# SSO redirect allow-list (bug 66f8e10a): app origins the gateway may bounce",
175
- "# users back to via ?redirect=. Required for unified SSO across crm/wiki/erp.",
176
- `GOTRUE_URI_ALLOW_LIST=https://crm.${normalizedDomain},https://wiki.${normalizedDomain},https://erp.${normalizedDomain}`,
233
+ "# users back to via ?redirect=. Required for unified SSO across crm/wiki/erp/dashboard/gateway (bug 2d2de534).",
234
+ `GOTRUE_URI_ALLOW_LIST=https://crm.${normalizedDomain},https://wiki.${normalizedDomain},https://erp.${normalizedDomain},https://dashboard.${normalizedDomain},https://gateway.${normalizedDomain}`,
177
235
  "# Bug 0327b017: scope the session cookie to the PARENT apex domain so it is",
178
236
  "# shared across crm/wiki/erp/auth subdomains → true SSO (no re-login).",
179
237
  `GOTRUE_COOKIE_DOMAIN=.${normalizedDomain}`,
@@ -201,6 +259,14 @@ export function generateEnv(options: GenerateEnvOptions): string {
201
259
  "SMTP_USER=",
202
260
  "SMTP_PASS=",
203
261
  "",
262
+ "# --- Dashboard (exe-dashboard — customer dashboard at dashboard.<domain>) ---",
263
+ "# OPT-IN: the exe-dashboard compose service sits behind `profiles: [dashboard]`.",
264
+ "# No default is written here on purpose — the pin comes from the signed stack",
265
+ "# manifest (services.dashboard.image), so .env stays derived rather than",
266
+ "# becoming a competing source of truth that outranks it once it goes stale.",
267
+ "#DASHBOARD_IMAGE_TAG=update.askexe.com/askexe/exe-dashboard:vX.Y.Z@sha256:...",
268
+ "#DASHBOARD_PORT=3301",
269
+ "",
204
270
  "# --- Auth gateway (exe-auth — shared SSO sign-in UI at auth.<domain>) ---",
205
271
  "# Bug 58840873: pin the auth image in .env so compose never falls back to its",
206
272
  "# stale hardcoded default tag. Keep in sync with the manifest AUTH_IMAGE_TAG.",
@@ -262,6 +328,11 @@ export function generateEnv(options: GenerateEnvOptions): string {
262
328
  "",
263
329
  "# --- exe-os ---",
264
330
  `EXE_OS_IMAGE_TAG=${EXE_OS_IMAGE_TAG}`,
331
+ "",
332
+ "# Infra image pins — manifest-derived. Compose has no fallback default for",
333
+ "# these: a missing pin ABORTS the deploy instead of substituting an old image.",
334
+ `EXE_DB_IMAGE=${EXE_DB_IMAGE}`,
335
+ `OTEL_COLLECTOR_IMAGE=${OTEL_COLLECTOR_IMAGE}`,
265
336
  `EXED_MCP_TOKEN=${randomSecret(RANDOM_SECRET_48)}`,
266
337
  `EXED_DEVICE_ID=vps-${normalizedClientName}`,
267
338
  `EXE_MCP_HOST_BIND=${DEFAULT_EXE_MCP_HOST_BIND}`,
@@ -466,7 +537,7 @@ export function generateExampleEnv(): string {
466
537
  "# Bug 51086951: JWT issuer pinned to the public auth URL so signer + consumers agree.",
467
538
  "GOTRUE_JWT_ISSUER=https://auth.CHANGEME_DOMAIN",
468
539
  "# SSO redirect allow-list (bug 66f8e10a) — app origins for unified SSO.",
469
- "GOTRUE_URI_ALLOW_LIST=https://crm.CHANGEME_DOMAIN,https://wiki.CHANGEME_DOMAIN,https://erp.CHANGEME_DOMAIN",
540
+ "GOTRUE_URI_ALLOW_LIST=https://crm.CHANGEME_DOMAIN,https://wiki.CHANGEME_DOMAIN,https://erp.CHANGEME_DOMAIN,https://dashboard.CHANGEME_DOMAIN,https://gateway.CHANGEME_DOMAIN",
470
541
  "# Bug 0327b017: parent-domain cookie → session shared across all subdomains.",
471
542
  "GOTRUE_COOKIE_DOMAIN=.CHANGEME_DOMAIN",
472
543
  "GOTRUE_COOKIE_KEY=exe-auth",
@@ -483,6 +554,21 @@ export function generateExampleEnv(): string {
483
554
  "SMTP_USER=",
484
555
  "SMTP_PASS=",
485
556
  "",
557
+ "# --- Dashboard (exe-dashboard — customer dashboard at dashboard.<domain>) ---",
558
+ "# OPT-IN: the exe-dashboard compose service sits behind `profiles: [dashboard]`",
559
+ "# and is off unless you run `docker compose --profile dashboard ...`.",
560
+ "# DELIBERATELY UNSET AND COMMENTED OUT. Unlike the older *_IMAGE_TAG lines",
561
+ "# above/below, this one carries no hardcoded literal: a pinned default here is",
562
+ "# a second source of truth that silently outranks the manifest the moment it",
563
+ "# goes stale. Take the value from the signed stack manifest",
564
+ "# (deploy/stack-manifests/v0.9.json -> services.dashboard.image), digest and all.",
565
+ "# Leave it unset and compose refuses the dashboard loudly (\"has neither an image",
566
+ "# nor a build context specified\") instead of booting something arbitrary.",
567
+ "#DASHBOARD_IMAGE_TAG=update.askexe.com/askexe/exe-dashboard:vX.Y.Z@sha256:...",
568
+ "# Host port for the dashboard container (bound to 127.0.0.1; the tunnel and the",
569
+ "# SSO edge reach it over the docker network, not this port).",
570
+ "#DASHBOARD_PORT=3301",
571
+ "",
486
572
  "# --- Auth gateway (exe-auth — shared SSO sign-in UI at auth.<domain>) ---",
487
573
  "# Bug 58840873: pin the auth image so compose never falls back to its stale",
488
574
  "# hardcoded default tag. Keep in sync with the manifest AUTH_IMAGE_TAG. exe-auth",
@@ -502,6 +588,23 @@ export function generateExampleEnv(): string {
502
588
  "# the sign-up UI/route instead of showing a form that always fails.",
503
589
  "AUTH_DISABLE_SIGNUP=true",
504
590
  "",
591
+ "# --- Session cookie contract (exe-auth v0.6.0) \u2014 INFORMATIONAL, not settings ---",
592
+ "# Recorded here because operators reason about XSS blast radius from this file,",
593
+ "# and an earlier draft of these notes described the OPPOSITE of what ships.",
594
+ "# exe-auth performs the GoTrue token exchange server-side in njs and sets:",
595
+ "# exe_sess HttpOnly Secure SameSite=Lax \u2014 the real access token",
596
+ "# exe_sess_refresh HttpOnly Secure SameSite=Lax \u2014 the real refresh token",
597
+ "# exe_access_token JS-readable, value literally \"1\" \u2014 presence sentinel only",
598
+ "# All three are scoped to the apex (AUTH_COOKIE_DOMAIN) so they are shared",
599
+ "# across product subdomains.",
600
+ "#",
601
+ "# The credentials are HttpOnly ON PURPOSE (security bug 368bf916): page",
602
+ "# JavaScript CANNOT read them, so an XSS on any subdomain cannot exfiltrate a",
603
+ "# session token from document.cookie. The only JS-readable cookie is the",
604
+ "# sentinel, whose value is the constant \"1\" and is not a credential.",
605
+ "# Apps must NOT read a token from document.cookie \u2014 send credentialed",
606
+ "# same-site requests and let the HttpOnly cookie ride along.",
607
+ "",
505
608
  ...MANAGED_PERMS_ENV_BLOCK,
506
609
  "",
507
610
  "# --- CRM ---",
@@ -542,6 +645,11 @@ export function generateExampleEnv(): string {
542
645
  "",
543
646
  "# --- exe-os ---",
544
647
  `EXE_OS_IMAGE_TAG=${EXE_OS_IMAGE_TAG}`,
648
+ "",
649
+ "# Infra image pins — manifest-derived. Compose has no fallback default for",
650
+ "# these: a missing pin ABORTS the deploy instead of substituting an old image.",
651
+ `EXE_DB_IMAGE=${EXE_DB_IMAGE}`,
652
+ `OTEL_COLLECTOR_IMAGE=${OTEL_COLLECTOR_IMAGE}`,
545
653
  "EXED_MCP_TOKEN=CHANGEME_EXED_MCP_TOKEN",
546
654
  "EXED_DEVICE_ID=vps-default",
547
655
  `EXE_MCP_HOST_BIND=${DEFAULT_EXE_MCP_HOST_BIND}`,
@@ -37,15 +37,86 @@ map $request_uri $sso_uri_access_token {
37
37
  "~[?&]access_token=(?<tok>[^&]+)" $tok;
38
38
  }
39
39
 
40
- # Extract the shared GoTrue session cookie (exe-auth, domain .${DOMAIN}) from
41
- # the Cookie header. Cross-app logout: GoTrue POST /logout clears this cookie
42
- # on the parent domain, so its absence signals a globally-revoked session.
43
- # The gate checks this alongside the app-native cookie — if the app cookie is
44
- # present but the GoTrue cookie is gone, the session was revoked on another app
45
- # and the edge forces re-auth (return 401 → login redirect).
40
+ # Extract the shared apex SSO cookie from the Cookie header.
41
+ #
42
+ # THE COOKIE IS `exe_access_token` (bug 21ae2388). This map previously matched
43
+ # `exe-auth` — a name NOTHING has ever set. That made the cross-app-logout arm
44
+ # below fire on every single request, so any visitor holding a valid app-native
45
+ # session was bounced back to auth forever. It is the FOURTH instance of one
46
+ # recurring bug class: gating on a cookie name nothing mints. The first three
47
+ # all gated on the retired `exe_sso_token` — exe-wiki f1bb40d8, exe-crm
48
+ # 9f60e8e6, exe-erp 3938ac3d. See .github/workflows/sso-cookie-contract-monitor.yml.
49
+ #
50
+ # THE REAL CONTRACT (exe-auth v0.6.0, auth.njs.js setSessionCookies):
51
+ # exe_sess HttpOnly Secure SameSite=Lax — the real access_token
52
+ # exe_sess_refresh HttpOnly Secure SameSite=Lax — the real refresh_token
53
+ # exe_access_token JS-readable, value literally "1" — presence sentinel
54
+ # All three are scoped to the registrable apex (".${DOMAIN}") via
55
+ # AUTH_COOKIE_DOMAIN, so they are presented across every product subdomain.
56
+ # The two credentials are HttpOnly deliberately (security bug 368bf916) and are
57
+ # therefore unusable as an edge signal; the sentinel is the one that is visible
58
+ # here and is exactly what a presence gate needs.
59
+ #
60
+ # Cross-app logout: exe-auth's logout handler (clearSessionCookies) expires
61
+ # exe_access_token on the apex, so its absence alongside a live app-native
62
+ # cookie means the session was revoked on another app — the edge forces re-auth
63
+ # (return 401 → login redirect).
64
+ #
65
+ # PRESENCE SIGNAL ONLY. The value is the literal "1", not a token. Never treat
66
+ # it as a bearer credential and never forward it as one — the gate below tests
67
+ # only whether it is empty. Token validation is step 3's GoTrue /user call.
46
68
  map $http_cookie $sso_gotrue_cookie {
47
69
  default "";
48
- "~(?:^|;\s*)exe-auth=([^\s;]+)" $1;
70
+ "~(?:^|;\s*)exe_access_token=([^\s;]+)" $1;
71
+ }
72
+
73
+ # Static-asset exemption for the gate (see sso-redirect.conf step 0). Exempting
74
+ # assets is required for the SPA to boot at all: the app sets its session cookie
75
+ # only after its JS runs, so gating app.js hands a session-bearing document auth
76
+ # HTML in place of its script -> blank page.
77
+ #
78
+ # MAPS OVER $request_uri, NOT $uri (bug 06a3daae). Same trap the token map
79
+ # above documents: $sso_is_static is read inside the auth_request subrequest,
80
+ # where $uri is the gate's own path `/_sso_gate` — never the original request
81
+ # path — so an extension regex over $uri can never match and this exemption was
82
+ # completely inert from the day it shipped. $request_uri IS inherited, but it
83
+ # carries the query string, so the anchor admits `?`/`#` as well as end-of-
84
+ # string — without that, /assets/app.js?v=abc would fall back into the gate.
85
+ #
86
+ # SCOPED BY PATH PREFIX, NOT BY BARE EXTENSION (P0 review of PR #874). A bare
87
+ # extension test over $request_uri exempts ANY URL shaped like an asset, and the
88
+ # app locations are catch-all proxies, so `/uploads/customer.png` and
89
+ # `/api/export.js` would walk straight past the gate — the gate returns 204
90
+ # before it ever looks at a cookie. The allow arms below are anchored at `^/`
91
+ # on the build-output directories the SPAs actually boot from; everything else
92
+ # — including every proxied application path — falls to `default ""` and stays
93
+ # gated. This is now a path test AND an extension test, not a URL-shape test.
94
+ #
95
+ # nginx takes the FIRST matching regex in a map, so the deny arms are listed
96
+ # first and win unconditionally over the allow arms.
97
+ map $request_uri $sso_is_static {
98
+ default "";
99
+
100
+ # ── DENY (evaluated first, wins over everything below) ───────────────────
101
+ # Proxied application surface: API, user uploads and app-served files can
102
+ # never be exempt, whatever extension or query string they are dressed in.
103
+ "~*^/(?:api|uploads?|files|private|attachments|media|desk|app|method|admin)(?:[/?#]|$)" "";
104
+ # Traversal, raw or percent-encoded. $request_uri is the RAW request line:
105
+ # `/assets/../api/secret.js` is a prefix match here but normalizes to
106
+ # `/api/secret.js` before it reaches the app, so it must never be exempt.
107
+ "~\.\." "";
108
+ "~*%2e" "";
109
+ "~*%2f" "";
110
+ "~*%5c" "";
111
+
112
+ # ── ALLOW ────────────────────────────────────────────────────────────────
113
+ # Build-output directories only: Vite/Frappe `/assets/`, CRA/Twenty
114
+ # `/static/`, Next `/_next/static/`, Nuxt `/_nuxt/`, Vite-in-subdir
115
+ # `/build/assets/`. `[^?#]*` keeps the extension test on the PATH, so a
116
+ # query string can never supply the matching extension.
117
+ "~*^/(?:_next/static|_nuxt|assets|static|build/assets)/[^?#]*\.(?:js|mjs|css|map|png|jpe?g|gif|svg|ico|webp|woff2?|ttf)(?:[?#]|$)" "static";
118
+ # Root icons the browser requests on its own before any app code runs.
119
+ "~*^/(?:favicon\.(?:ico|svg|png)|apple-touch-icon(?:-precomposed)?\.png)(?:[?#]|$)" "static";
49
120
  }
50
121
 
51
122
  map $http_upgrade $sso_conn_upgrade {
@@ -7,13 +7,17 @@
7
7
  # advertised "single front door" does not exist.
8
8
  #
9
9
  # ── How it works ────────────────────────────────────────────────────────────
10
- # 1. Every request runs the edge auth gate (auth_request → /_sso_gate).
10
+ # 0. Static assets (JS/CSS/images/fonts, via the $sso_is_static map) are
11
+ # exempted from the gate and answered 204 — see step 0 inside /_sso_gate
12
+ # for why gating them deadlocks first page load.
13
+ # 1. Every other request runs the edge auth gate (auth_request → /_sso_gate).
11
14
  # 2. If the app session cookie is present the request passes (the app validates
12
15
  # its own session server-side — the cookie name differs per app; set it via
13
16
  # $sso_session_cookie below). Cross-app logout: the edge also checks for the
14
- # shared GoTrue cookie (exe-auth on .${DOMAIN}); if the app cookie is present
15
- # but the GoTrue cookie is gone, the session was revoked on another app and
16
- # the edge forces re-auth.
17
+ # shared apex SSO cookie `exe_access_token` (set on .${DOMAIN} by exe-auth's
18
+ # njs handlers — a NON-CREDENTIAL presence sentinel whose value is literally
19
+ # "1"); if the app cookie is present but that sentinel is gone, the session
20
+ # was revoked on another app and the edge forces re-auth.
17
21
  # 3. If the request carries ?access_token= (the SSO callback), the edge
18
22
  # VALIDATES the token against the shared GoTrue (`GET /user` with
19
23
  # `Authorization: Bearer <token>`) before letting it through. P0 bug
@@ -22,6 +26,8 @@
22
26
  # trusted — only a token GoTrue accepts passes.
23
27
  # 4. Anything else 401s inside the gate and is 302-redirected to:
24
28
  # https://auth.<domain>/?product=<App>&redirect=https://<app>.<domain><uri>
29
+ # A 403 from the GoTrue /user validation subrequest is mapped to the same
30
+ # login redirect, so it is never leaked raw to the browser.
25
31
  # 5. The gateway authenticates against the shared GoTrue and bounces the user
26
32
  # back to the app URL with ?access_token=<jwt>&refresh_token=<...>. The app
27
33
  # consumes the token and sets its session cookie — subsequent requests carry
@@ -31,7 +37,7 @@
31
37
  # These are templated values — replace before installing, or render with envsubst
32
38
  # (DOMAIN, APP_NAME, APP_SUBDOMAIN, APP_SESSION_COOKIE):
33
39
  #
34
- # # TWO http-context declarations MUST exist once per nginx config (the
40
+ # # FOUR http-context declarations MUST exist once per nginx config (the
35
41
  # # compose edge ships them in sso-edge/default.conf.template; host-nginx
36
42
  # # installs add them next to their `include`s — see sso-redirect.README.md):
37
43
  # #
@@ -45,6 +51,34 @@
45
51
  # default "";
46
52
  # "~[?&]access_token=(?<tok>[^&]+)" $tok;
47
53
  # }
54
+ # # 3. The shared apex SSO cookie — the cross-app-logout signal. The name is
55
+ # # `exe_access_token` (bug 21ae2388: this used to read a nonexistent
56
+ # # `exe-auth`, which 401'd every authenticated request). Presence only —
57
+ # # the value is the literal "1", never a bearer token:
58
+ # map $http_cookie $sso_gotrue_cookie {
59
+ # default "";
60
+ # "~(?:^|;\s*)exe_access_token=([^\s;]+)" $1;
61
+ # }
62
+ # # 4. The static-asset exemption (see step 0 inside /_sso_gate). Like #2
63
+ # # this MUST map over $request_uri: inside the auth_request subrequest
64
+ # # $uri is `/_sso_gate`, so a map over $uri never matches and the
65
+ # # exemption is silently inert (bug 06a3daae). $request_uri includes the
66
+ # # query string, hence the `[?#]` anchor instead of a bare `$`.
67
+ # # It must ALSO be anchored to the build-output PATH PREFIXES: a bare
68
+ # # extension test exempts any URL shaped like an asset, and since the app
69
+ # # location is a catch-all proxy that hands `/uploads/customer.png` and
70
+ # # `/api/export.js` straight past the gate. Deny arms come first because
71
+ # # nginx takes the FIRST matching regex in a map:
72
+ # map $request_uri $sso_is_static {
73
+ # default "";
74
+ # "~*^/(?:api|uploads?|files|private|attachments|media|desk|app|method|admin)(?:[/?#]|$)" "";
75
+ # "~\.\." "";
76
+ # "~*%2e" "";
77
+ # "~*%2f" "";
78
+ # "~*%5c" "";
79
+ # "~*^/(?:_next/static|_nuxt|assets|static|build/assets)/[^?#]*\.(?:js|mjs|css|map|png|jpe?g|gif|svg|ico|webp|woff2?|ttf)(?:[?#]|$)" "static";
80
+ # "~*^/(?:favicon\.(?:ico|svg|png)|apple-touch-icon(?:-precomposed)?\.png)(?:[?#]|$)" "static";
81
+ # }
48
82
  #
49
83
  # server {
50
84
  # server_name crm.${DOMAIN};
@@ -70,9 +104,47 @@
70
104
  # are app-native sessions the edge cannot verify against GoTrue); each app fully
71
105
  # validates its own session server-side. The edge gate's job is the login funnel
72
106
  # plus never letting an unvalidated bearer token skip it (bug 462d3273).
73
- # Cross-app logout adds a GoTrue-cookie check: if the app-native cookie is present
74
- # but the shared GoTrue cookie is absent, the edge 401s — the session was revoked
75
- # on another app and the app-native cookie is stale.
107
+ # Cross-app logout adds a sentinel-cookie check: if the app-native cookie is
108
+ # present but the shared apex `exe_access_token` sentinel is absent, the edge
109
+ # 401s — the session was revoked on another app and the app-native cookie is
110
+ # stale. This is ALWAYS ON; it is the mechanism that makes "log out once, out
111
+ # everywhere" real across crm/wiki/erp/dashboard.
112
+ #
113
+ # ── SCOPE OF THE STATIC-ASSET EXEMPTION ──────────────────────────────────────
114
+ # Step 0 exempts a request from the gate BEFORE any cookie check, matching on
115
+ # $request_uri (bug 06a3daae — $uri is `/_sso_gate` inside the subrequest).
116
+ #
117
+ # The exemption is scoped by PATH PREFIX **and** extension, never by extension
118
+ # alone. An extension-only test is a pure URL-shape test, and because each app
119
+ # location is a catch-all `proxy_pass`, it would hand `/uploads/customer.png`
120
+ # or `/api/export.js` a 204 from the gate and proxy them to the app with no SSO
121
+ # at all. Only these prefixes can ever be exempt:
122
+ #
123
+ # /_next/static/ /_nuxt/ /assets/ /static/ /build/assets/
124
+ # /favicon.{ico,svg,png} /apple-touch-icon[-precomposed].png
125
+ #
126
+ # and only when the PATH (not the query string) also ends in a known asset
127
+ # extension. Deny arms listed FIRST in the map — nginx takes the first matching
128
+ # regex — make it explicit that /api/, /uploads/, /files/, /private/, /media/,
129
+ # /attachments/, /desk, /app, /method and /admin can NEVER be exempt whatever
130
+ # their extension or query string, and reject traversal forms (`..`, %2e, %2f,
131
+ # %5c) so a raw `/assets/../api/secret.js` cannot prefix-match here and then
132
+ # normalize into the API before it reaches the app.
133
+ #
134
+ # What is still true of anything that IS exempt: it is a URL test, not a
135
+ # content test. If an app serves user content out of one of those build-output
136
+ # prefixes, that content is reachable unauthenticated at the edge. Two reasons
137
+ # that is acceptable:
138
+ # 1. Every app validates its own session server-side. The edge gate is the
139
+ # LOGIN FUNNEL, not the authorization boundary — an exempted request still
140
+ # reaches an app that will refuse to serve it to an unauthenticated user.
141
+ # 2. Without the exemption the stack does not work at all: the SPA only sets
142
+ # its session cookie after its JS runs, so gating app.js returns auth HTML
143
+ # in place of the script and the app never boots (blank page).
144
+ #
145
+ # The limit of that reasoning: never serve private content from one of the
146
+ # prefixes above, and do not rely on the edge gate for an app that does no
147
+ # authorization of its own.
76
148
  # ─────────────────────────────────────────────────────────────────────────────
77
149
 
78
150
  # Run the gate for every request on this vhost. The gate is a zero-cost local
@@ -82,6 +154,11 @@
82
154
  # official nginx / nginx:alpine builds).
83
155
  auth_request /_sso_gate;
84
156
  error_page 401 = @sso_login;
157
+ # A 403 from the gate's GoTrue /user validation must funnel to login too, not
158
+ # leak raw to the browser. Safe: proxy_intercept_errors is not enabled on the
159
+ # app proxy_pass blocks, so a genuine 403 from an upstream app is NOT converted
160
+ # — only the auth_request subrequest's own status reaches this mapping.
161
+ error_page 403 = @sso_login;
85
162
 
86
163
  location = /_sso_gate {
87
164
  internal;
@@ -93,12 +170,31 @@ location = /_sso_gate {
93
170
  # which auth_request rejects ("auth request unexpected status: 302").
94
171
  error_page 401 = @sso_gate_deny;
95
172
 
173
+ # 0. Static assets (JS/CSS/images/fonts via the $sso_is_static http-context
174
+ # map) pass BEFORE any cookie check. Assets are non-sensitive — all SPA
175
+ # data flows only via the authenticated APIs, which stay fully gated —
176
+ # and gating them deadlocks first page load: the SPA sets its session
177
+ # cookie only AFTER it boots, so answering app.js with the auth HTML
178
+ # leaves a session-bearing document that can never boot (blank page).
179
+ # See the SCOPE note in the header: the map is path-prefix scoped, so
180
+ # only build-output directories can reach this 204 — /api/* and
181
+ # /uploads/* stay gated no matter what extension they carry.
182
+ # The map MUST be over $request_uri, not $uri: in here $uri is
183
+ # `/_sso_gate`, so a $uri-based map never matches (bug 06a3daae).
184
+ if ($sso_is_static) {
185
+ return 204;
186
+ }
187
+
96
188
  # 1. App session cookie present → check for cross-app logout.
97
- # The GoTrue cookie (exe-auth, domain .${DOMAIN}) is shared across all
98
- # subdomains. GoTrue POST /logout clears it globally. If the app-native
99
- # cookie is present but the GoTrue cookie is gone, the session was
100
- # revoked on another app — force re-auth instead of trusting the stale
101
- # app cookie.
189
+ # The shared apex cookie is `exe_access_token` (domain .${DOMAIN}), set
190
+ # by exe-auth's njs login handler and expired by its logout handler. It
191
+ # is a NON-CREDENTIAL presence sentinel — its value is literally "1", so
192
+ # only its presence is meaningful and it is never used as a bearer token.
193
+ # If the app-native cookie is present but the sentinel is gone, the
194
+ # session was revoked on another app — force re-auth instead of trusting
195
+ # the stale app cookie.
196
+ # Bug 21ae2388: this arm matched a cookie named `exe-auth` that nothing
197
+ # has ever minted, so it fired unconditionally and 401'd every request.
102
198
  set $sso_auth_check "";
103
199
  if ($sso_session_cookie) {
104
200
  set $sso_auth_check "app";
@@ -52,7 +52,7 @@
52
52
  "env": "ERP_IMAGE_TAG",
53
53
  "composeService": "exe-erp",
54
54
  "healthUrl": "http://127.0.0.1:8069/api/method/ping",
55
- "healthHost": "erp.askexe.com",
55
+ "healthHost": "${ERP_SITE_NAME:-erp.localhost}",
56
56
  "required": false,
57
57
  "category": "app",
58
58
  "description": "Enterprise Resource Planning"
@@ -2752,13 +2752,13 @@
2752
2752
  "gitSha": "10660eb4abdeffbcba2aad13549aa58e208ac7a3"
2753
2753
  },
2754
2754
  "auth": {
2755
- "image": "update.askexe.com/askexe/exe-auth:v0.6.0@sha256:e615aec50a75706c23db1652d18bca5f1b68cc7e0fe3d92963b7ebbc7a834733",
2755
+ "image": "update.askexe.com/askexe/exe-auth:v0.6.1@sha256:89670a15bc59255299be695525863e66f949694eec1dd8886038dc3659a4a941",
2756
2756
  "env": "AUTH_IMAGE_TAG",
2757
2757
  "composeService": "exe-auth",
2758
2758
  "healthUrl": "http://127.0.0.1:3300/api/health",
2759
2759
  "category": "auth",
2760
- "description": "exe-auth v0.6.0 — GoTrue's admin API is no longer published on the public internet (nginx returns 404 for /api/admin|invite); query strings redacted from nginx access + error logs. First image verified by the armed G2 provenance gate.",
2761
- "gitSha": "0658b41bf9eae04b83cd4eecdf23eb1426b9e781"
2760
+ "description": "exe-auth v0.6.1 — the v0.6.0 hardening (GoTrue admin API no longer public; nginx 404s /api/admin|invite; query strings redacted from access + error logs) PLUS the four fixes that merged after v0.6.0 was tagged and had never been built into any image (bug 9e054a59): /api/recover CORS + method restriction (0f9fbebe); a recovery link can no longer mint a session and link hashes are sent as token_hash (056abf8d, c9b62c91); the Secure cookie flag fails closed and HSTS is set (bb99ceda); the session token is kept out of upstream request lines, shape-checked, and a service_role JWT is refused (bff591fe). Verified inside this exact digest, not from a green badge.",
2761
+ "gitSha": "633e7a4d9930aad8b0ce6783a1b3bc2f96b454a8"
2762
2762
  },
2763
2763
  "erp": {
2764
2764
  "image": "update.askexe.com/askexe/exe-erp:v2026.08.07-d185286-stamped@sha256:1c655f3f7819c797afd13c79561354f0276cf337403f32aee3e406a497e8827b",
@@ -2809,6 +2809,6 @@
2809
2809
  "signature": {
2810
2810
  "keyId": "exe-stack-1",
2811
2811
  "alg": "ed25519",
2812
- "signature": "6ujWYOE1oXzshL8TxwgcKvZTubhCUyuoMxGAhqu84DgN3mBEG/R3psOlEv+GmqBmbD43D3ysyxIxHxG9alMzCw=="
2812
+ "signature": "zJx3MxMUaco9bPRAPvmMs8qFXScuuAS9xWXSQBgtzKJB3ERe5aNvb+f6O39jWjxAvoPUQUObPjCuhwbu0aD8AQ=="
2813
2813
  }
2814
2814
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "verified_at": "2026-08-14T09:06:28.983Z",
4
- "manifest_sha256": "80c62cd3f4b5f8ade7df79e58361f9eb10ae7d03c9aa2462c65dd9894ff73d07",
5
- "package_version": "0.9.372"
3
+ "verified_at": "2026-08-20T18:51:08.214Z",
4
+ "manifest_sha256": "185d088d5d3a1b4d1f2d293248438af3df4498155f42a6f9cfc35521103d5b70",
5
+ "package_version": "0.9.374"
6
6
  }
@@ -7,22 +7,23 @@ import {
7
7
  resolveAgentAttribution,
8
8
  resolveAgentForPayload,
9
9
  writeActiveAgent
10
- } from "./chunk-KYFFVTGO.js";
11
- import "./chunk-2ADYTOHQ.js";
10
+ } from "./chunk-55BEFF4V.js";
11
+ import "./chunk-K4ESASPL.js";
12
12
  import "./chunk-CVYC6DUW.js";
13
13
  import "./chunk-GJV3WDWM.js";
14
- import "./chunk-5DCCKHDY.js";
15
- import "./chunk-TKDITWDN.js";
14
+ import "./chunk-TAMDAOCU.js";
16
15
  import "./chunk-BBMTVAE3.js";
16
+ import "./chunk-TKDITWDN.js";
17
17
  import "./chunk-5YEUPUV4.js";
18
- import "./chunk-UTDMTQNH.js";
18
+ import "./chunk-DSJI76XL.js";
19
19
  import "./chunk-YYB5PMTK.js";
20
20
  import "./chunk-NJFJWQNN.js";
21
21
  import "./chunk-V3W3SATA.js";
22
22
  import "./chunk-JY5GAZYC.js";
23
23
  import "./chunk-FXU7JOXK.js";
24
- import "./chunk-QMSEL5YS.js";
24
+ import "./chunk-ZIG7VPJV.js";
25
25
  import "./chunk-HSGBZSCA.js";
26
+ import "./chunk-RH4AH3YB.js";
26
27
  import "./chunk-JKKZGDLP.js";
27
28
  import "./chunk-MLKGABMK.js";
28
29
  export {
@@ -8,22 +8,23 @@ import {
8
8
  resolveAgentAttribution,
9
9
  resolveAgentForPayload,
10
10
  writeActiveAgent
11
- } from "./chunk-KYFFVTGO.js";
12
- import "./chunk-2ADYTOHQ.js";
11
+ } from "./chunk-55BEFF4V.js";
12
+ import "./chunk-K4ESASPL.js";
13
13
  import "./chunk-CVYC6DUW.js";
14
14
  import "./chunk-GJV3WDWM.js";
15
- import "./chunk-5DCCKHDY.js";
16
- import "./chunk-TKDITWDN.js";
15
+ import "./chunk-TAMDAOCU.js";
17
16
  import "./chunk-BBMTVAE3.js";
17
+ import "./chunk-TKDITWDN.js";
18
18
  import "./chunk-5YEUPUV4.js";
19
- import "./chunk-UTDMTQNH.js";
19
+ import "./chunk-DSJI76XL.js";
20
20
  import "./chunk-YYB5PMTK.js";
21
21
  import "./chunk-NJFJWQNN.js";
22
22
  import "./chunk-V3W3SATA.js";
23
23
  import "./chunk-JY5GAZYC.js";
24
24
  import "./chunk-FXU7JOXK.js";
25
- import "./chunk-QMSEL5YS.js";
25
+ import "./chunk-ZIG7VPJV.js";
26
26
  import "./chunk-HSGBZSCA.js";
27
+ import "./chunk-RH4AH3YB.js";
27
28
  import "./chunk-JKKZGDLP.js";
28
29
  import "./chunk-MLKGABMK.js";
29
30
  export {