@askexenow/exe-os 0.9.373 → 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 (373) hide show
  1. package/deploy/compose/.env.customer.example +28 -10
  2. package/deploy/compose/.env.example +28 -8
  3. package/deploy/compose/docker-compose.yml +101 -12
  4. package/deploy/compose/generate-env.ts +122 -31
  5. package/deploy/compose/sso-edge/default.conf.template +46 -7
  6. package/deploy/compose/sso-edge/sso-redirect.conf +50 -14
  7. package/dist/.dist-verified.json +3 -3
  8. package/dist/{active-agent-BVREYGFJ.js → active-agent-ONPPEWQV.js} +3 -3
  9. package/dist/{active-agent-HLV7IEU3.js → active-agent-UJKMG7LJ.js} +3 -3
  10. package/dist/{agent-defs-generator-TFBUJ67B.js → agent-defs-generator-ZWI6DXOE.js} +2 -2
  11. package/dist/{agent-loop-CYDFBCNA.js → agent-loop-OYHJKNYH.js} +1 -1
  12. package/dist/{agentic-ontology-WZKVHOUV.js → agentic-ontology-WHFJ3QFS.js} +1 -1
  13. package/dist/{backfill-metadata-FN3YMSKC.js → backfill-metadata-3OUSQD5V.js} +5 -5
  14. package/dist/{backup-verify-76235AHA.js → backup-verify-ZKTUYLTA.js} +1 -1
  15. package/dist/{behavior-injection-76FH424R.js → behavior-injection-M6UYZCMW.js} +13 -12
  16. package/dist/{behaviors-33WKK3BG.js → behaviors-ZJ45TFBJ.js} +11 -10
  17. package/dist/bin/agentic-ontology-backfill.js +6 -6
  18. package/dist/bin/agentic-reflection-backfill.js +7 -7
  19. package/dist/bin/agentic-semantic-label.js +6 -6
  20. package/dist/bin/backfill-conversations.js +9 -8
  21. package/dist/bin/backfill-responses.js +9 -8
  22. package/dist/bin/backfill-vectors.js +11 -10
  23. package/dist/bin/bulk-sync-postgres.js +15 -14
  24. package/dist/bin/cc-doctor.js +5 -5
  25. package/dist/bin/cleanup-stale-review-tasks.js +19 -18
  26. package/dist/bin/cli.js +24 -21
  27. package/dist/bin/deferred-daemon-restart.js +86 -85
  28. package/dist/bin/exe-agent-config.js +2 -2
  29. package/dist/bin/exe-agent.js +15 -14
  30. package/dist/bin/exe-assign.js +11 -10
  31. package/dist/bin/exe-boot.js +37 -36
  32. package/dist/bin/exe-call.js +4 -4
  33. package/dist/bin/exe-cloud.js +16 -15
  34. package/dist/bin/exe-config-dump.js +2 -2
  35. package/dist/bin/exe-dispatch.js +20 -19
  36. package/dist/bin/exe-doctor.js +7 -5
  37. package/dist/bin/exe-export-behaviors.js +15 -14
  38. package/dist/bin/exe-forget.js +7 -7
  39. package/dist/bin/exe-gateway.js +7 -7
  40. package/dist/bin/exe-healthcheck.js +5 -5
  41. package/dist/bin/exe-heartbeat.js +25 -24
  42. package/dist/bin/exe-kill.js +23 -22
  43. package/dist/bin/exe-launch-agent.js +30 -29
  44. package/dist/bin/exe-mcp.js +3 -3
  45. package/dist/bin/exe-memory-reads.js +5 -5
  46. package/dist/bin/exe-new-employee.js +8 -8
  47. package/dist/bin/exe-os-mcp-proxy.js +3 -3
  48. package/dist/bin/exe-pending-messages.js +20 -19
  49. package/dist/bin/exe-pending-notifications.js +19 -18
  50. package/dist/bin/exe-pending-reviews.js +20 -19
  51. package/dist/bin/exe-rename.js +4 -4
  52. package/dist/bin/exe-review.js +22 -21
  53. package/dist/bin/exe-search.js +6 -6
  54. package/dist/bin/exe-session-cleanup.js +23 -22
  55. package/dist/bin/exe-settings.js +15 -14
  56. package/dist/bin/exe-start-codex.js +21 -20
  57. package/dist/bin/exe-start-opencode.js +19 -18
  58. package/dist/bin/exe-status.js +21 -20
  59. package/dist/bin/exe-support.js +3 -3
  60. package/dist/bin/exe-team.js +4 -4
  61. package/dist/bin/exe-watchdog.js +13 -2
  62. package/dist/bin/git-sweep.js +20 -19
  63. package/dist/bin/graph-backfill.js +7 -7
  64. package/dist/bin/graph-export.js +6 -6
  65. package/dist/bin/import-history.js +10 -10
  66. package/dist/bin/install.js +88 -87
  67. package/dist/bin/intercom-check.js +5 -5
  68. package/dist/bin/mcp-sessions.js +2 -2
  69. package/dist/bin/orchestration-metrics.js +4 -4
  70. package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
  71. package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
  72. package/dist/bin/reconcile-backlog.js +2 -2
  73. package/dist/bin/registry-proxy.js +1 -1
  74. package/dist/bin/scan-tasks.js +19 -18
  75. package/dist/bin/setup.js +1 -1
  76. package/dist/bin/shard-migrate.js +5 -5
  77. package/dist/bin/stack-update.js +7 -6
  78. package/dist/bin/verify-stack.js +2 -2
  79. package/dist/bin/vps-health-gate.js +1 -1
  80. package/dist/{boot-generation-QY4H2VST.js → boot-generation-JKVZ4ZAT.js} +3 -3
  81. package/dist/{boot-review-sections-ITQVY2ZQ.js → boot-review-sections-2M6BTG73.js} +18 -17
  82. package/dist/build-manifest.json +950 -920
  83. package/dist/{capability-cards-JDJTJX4D.js → capability-cards-5IMJT6J7.js} +2 -2
  84. package/dist/{capacity-monitor-GK5IB6FJ.js → capacity-monitor-SAXCQK7O.js} +20 -19
  85. package/dist/{catchup-brief-ROSFMS46.js → catchup-brief-U2TXBLHD.js} +23 -22
  86. package/dist/{chunk-FGHPLZDF.js → chunk-23MVDXLY.js} +4 -4
  87. package/dist/{chunk-O5HTTJ2X.js → chunk-2ZOEC4KC.js} +2 -2
  88. package/dist/{chunk-72Y3I24H.js → chunk-32YV32VA.js} +2 -2
  89. package/dist/{chunk-JS5XMVXY.js → chunk-3KDCORDO.js} +1 -1
  90. package/dist/{chunk-NLGEFBND.js → chunk-3UUX5OY4.js} +1 -1
  91. package/dist/{chunk-SNW6E3Y4.js → chunk-44TLJZJ5.js} +1 -1
  92. package/dist/{chunk-MQAHDPU5.js → chunk-4EN3IZ3Q.js} +1 -1
  93. package/dist/{chunk-4IZ2ELU7.js → chunk-4HKTO2SV.js} +1 -1
  94. package/dist/{chunk-NMOEWLJY.js → chunk-4SJ4LK4V.js} +5 -5
  95. package/dist/{chunk-UUPAOKEO.js → chunk-55BEFF4V.js} +1 -1
  96. package/dist/{chunk-WZFVNICF.js → chunk-636LKCKE.js} +1 -1
  97. package/dist/{chunk-2W5J4T2F.js → chunk-6EZQUNE6.js} +2 -2
  98. package/dist/{chunk-NY75HDWW.js → chunk-6RKKVPYF.js} +1 -1
  99. package/dist/{chunk-HWKSG33T.js → chunk-6SCGLHJ7.js} +2 -2
  100. package/dist/{chunk-EM7NP2AC.js → chunk-6VHOQ3IM.js} +6 -6
  101. package/dist/{chunk-6KS57E66.js → chunk-6YVUR3OU.js} +2 -2
  102. package/dist/{chunk-DRXO46LA.js → chunk-7GE2EQ23.js} +1 -1
  103. package/dist/{chunk-U6RXHPK4.js → chunk-7TSBV3SD.js} +1 -1
  104. package/dist/{chunk-X65OJFQM.js → chunk-AETLDRZB.js} +1 -1
  105. package/dist/{chunk-7TIAQUBH.js → chunk-AKLJ4JH3.js} +1 -1
  106. package/dist/{chunk-IMX3VIIT.js → chunk-AKLQSC6W.js} +21 -21
  107. package/dist/{chunk-NMICTLJK.js → chunk-ANLFH23R.js} +1 -1
  108. package/dist/{chunk-JG4IOKQE.js → chunk-AWWKRZMB.js} +2 -2
  109. package/dist/{chunk-ICHQULGD.js → chunk-BBSIEYF5.js} +2 -2
  110. package/dist/{chunk-I422WQ3A.js → chunk-BJ7AVSY6.js} +2 -2
  111. package/dist/{chunk-L6WHOLGP.js → chunk-CBCGDEJA.js} +4 -4
  112. package/dist/{chunk-J4C442ZT.js → chunk-DB55JZHU.js} +1 -1
  113. package/dist/{chunk-XPPQ4PBN.js → chunk-DIXXEE3S.js} +158 -146
  114. package/dist/{chunk-YRC4NV2C.js → chunk-DJ7YXOTU.js} +2 -2
  115. package/dist/{chunk-SCHARPXE.js → chunk-DJOIMFKV.js} +2 -2
  116. package/dist/{chunk-ZFFRW73K.js → chunk-DSJI76XL.js} +2 -2
  117. package/dist/{chunk-3LQVIRGL.js → chunk-DZKPOSFD.js} +1 -1
  118. package/dist/{chunk-DMPIS4BY.js → chunk-EKE37MO4.js} +2 -2
  119. package/dist/{chunk-2HB5U5QT.js → chunk-EXTZSNWL.js} +1 -1
  120. package/dist/{chunk-6WUXRDTF.js → chunk-FTZET5YX.js} +138 -1
  121. package/dist/chunk-GHR4ZPJ7.js +70 -0
  122. package/dist/{chunk-FLNUXH6H.js → chunk-GJI77VDO.js} +3 -3
  123. package/dist/{chunk-45KCQK24.js → chunk-GNUAL43X.js} +2 -2
  124. package/dist/{chunk-I73AHVH5.js → chunk-GOMQ7PVQ.js} +1 -1
  125. package/dist/{chunk-KEC47ERR.js → chunk-GS7LIT34.js} +121 -5
  126. package/dist/{chunk-PFLDEJJJ.js → chunk-HNWS7YHN.js} +1 -1
  127. package/dist/{chunk-4XUPFJNB.js → chunk-I4DNJFDR.js} +4 -4
  128. package/dist/{chunk-6F4QFV4Q.js → chunk-IN6CAM4F.js} +3 -3
  129. package/dist/{chunk-ODOLBT7W.js → chunk-IRVOXUSK.js} +3 -3
  130. package/dist/{chunk-6D5KMMK4.js → chunk-JHI5WMK5.js} +4 -4
  131. package/dist/{chunk-LSY2JAFY.js → chunk-JSMDRKPJ.js} +1 -1
  132. package/dist/{chunk-TTELLO3M.js → chunk-JTVIANUB.js} +1 -1
  133. package/dist/{chunk-MJKWLOCW.js → chunk-KTCXJWJG.js} +1 -1
  134. package/dist/{chunk-MLYG3TI6.js → chunk-KTU3EAWK.js} +5 -5
  135. package/dist/{chunk-3W7U6ZKY.js → chunk-L6RXG36J.js} +1 -1
  136. package/dist/{chunk-TN2AXREB.js → chunk-LDNYSMPZ.js} +1 -1
  137. package/dist/{chunk-XEPLZKEB.js → chunk-LGS2V2XD.js} +3 -3
  138. package/dist/{chunk-RHRK3VDF.js → chunk-LP4GB656.js} +2 -2
  139. package/dist/{chunk-3FLDC2ZI.js → chunk-MOGA4Q7F.js} +1 -1
  140. package/dist/{chunk-HTUEAERH.js → chunk-MXPNVSXI.js} +14 -10
  141. package/dist/{chunk-KBRHGXE7.js → chunk-N7VEP5B3.js} +4 -4
  142. package/dist/{chunk-UEZQNJET.js → chunk-NBXDXKLC.js} +1 -1
  143. package/dist/{chunk-J7RIPMDI.js → chunk-NKETJCB5.js} +1 -1
  144. package/dist/{chunk-7HNQK2JA.js → chunk-NMH5ZQPU.js} +1 -1
  145. package/dist/{chunk-6WMJHNGN.js → chunk-NT7W4RXD.js} +1 -1
  146. package/dist/{chunk-P5YTFPCV.js → chunk-NUK7EEN5.js} +6 -4
  147. package/dist/{chunk-4Y523526.js → chunk-OVEQE6YS.js} +10 -10
  148. package/dist/{chunk-PLSY7Y5F.js → chunk-PB5S7YOF.js} +1 -1
  149. package/dist/{chunk-U45XMFOM.js → chunk-PDVXWXTL.js} +3 -3
  150. package/dist/{chunk-JKLA7AUZ.js → chunk-PLZSZOZN.js} +2 -2
  151. package/dist/{chunk-OTJVG7JM.js → chunk-QHJR7IMX.js} +1 -1
  152. package/dist/{chunk-P3DQL6JT.js → chunk-R4CBHKZ2.js} +1 -1
  153. package/dist/{chunk-BZYEOIT3.js → chunk-R522MWAR.js} +1 -1
  154. package/dist/{chunk-X63RNRZF.js → chunk-S2WBS6BG.js} +1 -1
  155. package/dist/{chunk-LFKRM3RK.js → chunk-SEQIPGLU.js} +1 -1
  156. package/dist/{chunk-S37PAH7F.js → chunk-SL6KQYDU.js} +24 -4
  157. package/dist/chunk-SLLLOOEI.js +103 -0
  158. package/dist/{chunk-T7AZ5K5K.js → chunk-T3QUKNLI.js} +1 -1
  159. package/dist/{chunk-USMESBOR.js → chunk-TAMDAOCU.js} +4 -4
  160. package/dist/{chunk-AMPNM6SB.js → chunk-TFKCERAK.js} +69 -21
  161. package/dist/{chunk-JVKIRKLC.js → chunk-TQAZTRQ3.js} +3 -3
  162. package/dist/{chunk-NFFCNZVD.js → chunk-U6SUKSZR.js} +2 -2
  163. package/dist/{chunk-TRMR77JJ.js → chunk-U73AC5AN.js} +11 -11
  164. package/dist/{chunk-RHNIWSOP.js → chunk-UBK7HK3J.js} +2 -2
  165. package/dist/{chunk-7P6YUA53.js → chunk-UCFC2AEI.js} +1 -1
  166. package/dist/{chunk-5SDE2HWI.js → chunk-UKLN57Q5.js} +2 -2
  167. package/dist/{chunk-QSAAN3H6.js → chunk-ULIBLJ6W.js} +5 -5
  168. package/dist/{chunk-X36BZYJ3.js → chunk-UM3N6VND.js} +4 -4
  169. package/dist/{chunk-KXBMR4ZD.js → chunk-V3WLC5TJ.js} +1 -98
  170. package/dist/{chunk-SMGSSWCW.js → chunk-VKJGHAZT.js} +8 -8
  171. package/dist/{chunk-V6KKNYF2.js → chunk-VMTZ4RUW.js} +13 -11
  172. package/dist/{chunk-GJD7D6HM.js → chunk-VYQ7B7DI.js} +3 -3
  173. package/dist/{chunk-PHA3OES7.js → chunk-W75GTHR3.js} +1 -1
  174. package/dist/{chunk-VYNY7K44.js → chunk-WJG344NC.js} +2 -2
  175. package/dist/{chunk-PBVBMZGO.js → chunk-WMEYJT4R.js} +3 -3
  176. package/dist/{chunk-L6MLYKY5.js → chunk-XH7YL7JM.js} +1 -1
  177. package/dist/{chunk-E7DFTCUW.js → chunk-XL5MFGMR.js} +2 -2
  178. package/dist/{chunk-3J37XIWU.js → chunk-XNNECNDL.js} +56 -11
  179. package/dist/{chunk-AWKZRRPX.js → chunk-XXFKSJYA.js} +5 -5
  180. package/dist/{chunk-G6P45SFB.js → chunk-XXOPG4BW.js} +3 -3
  181. package/dist/{chunk-UMNMC3DZ.js → chunk-XZ65ST2I.js} +1 -1
  182. package/dist/{chunk-SWK6MNAI.js → chunk-YMP2QSOP.js} +1 -1
  183. package/dist/{chunk-ZN3FAXDX.js → chunk-YSLGFPWX.js} +3 -3
  184. package/dist/{chunk-D2AR5PXE.js → chunk-YTSXPJUQ.js} +1 -1
  185. package/dist/{chunk-ZFXOA2CF.js → chunk-ZCERWHY2.js} +9 -9
  186. package/dist/{chunk-IVU3WN7S.js → chunk-ZG62LIK3.js} +74 -4
  187. package/dist/{chunk-52EK7KIA.js → chunk-ZGYNKA3O.js} +29 -87
  188. package/dist/{chunk-L67OHDSD.js → chunk-ZL4AGWAH.js} +2 -2
  189. package/dist/{chunk-WC6WL52H.js → chunk-ZSODLMFV.js} +1 -1
  190. package/dist/{cleanup-graph-garbage-6IJ6GJY2.js → cleanup-graph-garbage-DPJGO52H.js} +8 -8
  191. package/dist/{cloud-sync-command-TZVPTKZV.js → cloud-sync-command-JPNTT4OQ.js} +2 -2
  192. package/dist/{cloud-sync-db-init-2QLU6GCD.js → cloud-sync-db-init-V2LWIUQU.js} +1 -1
  193. package/dist/{cloud-sync-shutdown-OPCDMH4L.js → cloud-sync-shutdown-BNALPWGX.js} +2 -2
  194. package/dist/{co-activation-YMDKMDZ6.js → co-activation-CMNSWS6B.js} +2 -2
  195. package/dist/{co-occurrence-VYWPQSLC.js → co-occurrence-WRI2NAN6.js} +6 -6
  196. package/dist/{code-context-index-QLJDRL7B.js → code-context-index-NOJSHLPN.js} +9 -4
  197. package/dist/code-context-watcher-VZNZU3BO.js +118 -0
  198. package/dist/{conversation-entity-extractor-KGW4UEY4.js → conversation-entity-extractor-74252CAO.js} +4 -4
  199. package/dist/{crdt-sync-QS2DHTKW.js → crdt-sync-B3JN6AIV.js} +1 -1
  200. package/dist/{crm-webhook-5PNRCVO2.js → crm-webhook-GYWQRFET.js} +2 -2
  201. package/dist/{cto-delegation-gate-LD4XTG6U.js → cto-delegation-gate-LQHVLEMW.js} +18 -17
  202. package/dist/{daemon-orchestration-XC2VTPVI.js → daemon-orchestration-5HIQALZH.js} +23 -22
  203. package/dist/{daemon-ready-3WSKI3R5.js → daemon-ready-P2BR2XP5.js} +1 -1
  204. package/dist/{doc-graph-extractor-6TVQTBLO.js → doc-graph-extractor-PQHDHQPQ.js} +6 -6
  205. package/dist/{documents-4WQ5MQR2.js → documents-C4SSPJMC.js} +11 -10
  206. package/dist/{dreaming-SO4VH44W.js → dreaming-XAO3FCBV.js} +22 -21
  207. package/dist/{employee-boot-brief-Z4WTZVUC.js → employee-boot-brief-W4OHUMRQ.js} +26 -25
  208. package/dist/{exe-drift-BWSUUAEA.js → exe-drift-AG2KMKD5.js} +3 -3
  209. package/dist/{exe-export-4WPMVRNO.js → exe-export-IC5BT335.js} +12 -11
  210. package/dist/{exe-import-7C3SS62E.js → exe-import-A35ZLDPG.js} +12 -11
  211. package/dist/{exe-key-NFHZNJU6.js → exe-key-TCMJNYLA.js} +86 -85
  212. package/dist/{exe-org-5HYTAUH6.js → exe-org-JXCR3JYZ.js} +8 -8
  213. package/dist/{exe-snapshot-REKNH2WI.js → exe-snapshot-SV6SRIG6.js} +25 -24
  214. package/dist/{fast-db-init-OW6Z4YDB.js → fast-db-init-L2RGKJWH.js} +1 -1
  215. package/dist/{founder-context-6FAAM5LY.js → founder-context-D4HFIESJ.js} +2 -2
  216. package/dist/gateway/index.js +8 -8
  217. package/dist/{git-staleness-ELGGOVRV.js → git-staleness-TN7CYGFG.js} +2 -2
  218. package/dist/{global-procedures-JBMGJRR6.js → global-procedures-YFDEIOG7.js} +3 -3
  219. package/dist/{graph-auto-extract-O6IIL5O3.js → graph-auto-extract-3YR3TYRW.js} +6 -6
  220. package/dist/{graph-rag-WHZ6EPMW.js → graph-rag-Z2KCJTPK.js} +4 -4
  221. package/dist/{hook-integrity-UU5OXONF.js → hook-integrity-KGAV6ZC2.js} +1 -1
  222. package/dist/{hook-prefetch-VWHIZBTX.js → hook-prefetch-K5DN3TOQ.js} +19 -18
  223. package/dist/hooks/bug-report-worker.js +23 -22
  224. package/dist/hooks/codex-stop-task-finalizer.js +25 -24
  225. package/dist/hooks/commit-complete.js +22 -21
  226. package/dist/hooks/error-recall.js +8 -8
  227. package/dist/hooks/exe-heartbeat-hook.js +4 -4
  228. package/dist/hooks/ingest-worker.js +11 -10
  229. package/dist/hooks/ingest.js +13 -13
  230. package/dist/hooks/instructions-loaded.js +6 -6
  231. package/dist/hooks/manifest.json +20 -20
  232. package/dist/hooks/notification.js +5 -5
  233. package/dist/hooks/post-compact.js +4 -4
  234. package/dist/hooks/post-tool-combined.js +13 -13
  235. package/dist/hooks/pre-compact.js +22 -21
  236. package/dist/hooks/pre-tool-use.js +32 -31
  237. package/dist/hooks/prompt-submit.js +36 -35
  238. package/dist/hooks/session-end.js +27 -26
  239. package/dist/hooks/session-start.js +18 -18
  240. package/dist/hooks/stop.js +28 -27
  241. package/dist/hooks/subagent-stop.js +23 -22
  242. package/dist/hooks/summary-worker.js +27 -26
  243. package/dist/index.js +30 -29
  244. package/dist/{installer-OYBQQ7BY.js → installer-54HTN5RE.js} +5 -5
  245. package/dist/{installer-RYW65FRY.js → installer-LK35OX6R.js} +5 -5
  246. package/dist/{installer-A3V2W3NV.js → installer-LLWKZI2S.js} +5 -5
  247. package/dist/{intercom-queue-XBS5WVJM.js → intercom-queue-5NOT2RKI.js} +18 -17
  248. package/dist/lib/cloud-sync.js +15 -14
  249. package/dist/lib/consolidation.js +8 -8
  250. package/dist/lib/database.js +2 -2
  251. package/dist/lib/db-backup.js +1 -1
  252. package/dist/lib/db-daemon-client.js +5 -4
  253. package/dist/lib/db-write-worker.js +3 -3
  254. package/dist/lib/db.js +2 -2
  255. package/dist/lib/device-registry.js +1 -1
  256. package/dist/lib/embedder.js +5 -4
  257. package/dist/lib/employee-templates.js +4 -4
  258. package/dist/lib/employees.js +2 -2
  259. package/dist/lib/exe-daemon-client.js +4 -3
  260. package/dist/lib/exe-daemon.js +202 -88
  261. package/dist/lib/hybrid-search.js +8 -6
  262. package/dist/lib/identity.js +2 -2
  263. package/dist/lib/license.js +2 -2
  264. package/dist/lib/messaging.js +19 -18
  265. package/dist/lib/post-tool-memory.js +4 -4
  266. package/dist/lib/registry-proxy.js +1 -1
  267. package/dist/lib/reminders.js +3 -3
  268. package/dist/lib/schedules.js +6 -6
  269. package/dist/lib/session-registry.js +4 -4
  270. package/dist/lib/skill-learning.js +12 -11
  271. package/dist/lib/stack-invariants.js +11 -1
  272. package/dist/lib/store.js +5 -5
  273. package/dist/lib/task-router.js +3 -3
  274. package/dist/lib/tasks.js +20 -19
  275. package/dist/lib/tmux-routing.js +18 -17
  276. package/dist/lib/token-spend.js +3 -3
  277. package/dist/{license-gate-EOLMF7J5.js → license-gate-JVMB6OFD.js} +3 -3
  278. package/dist/{license-sync-ELY6PKEU.js → license-sync-5VYS2F2W.js} +2 -2
  279. package/dist/mcp/register-tools.js +85 -84
  280. package/dist/mcp/server.js +89 -88
  281. package/dist/mcp/tools/complete-reminder.js +4 -4
  282. package/dist/mcp/tools/create-reminder.js +4 -4
  283. package/dist/mcp/tools/create-task.js +22 -21
  284. package/dist/mcp/tools/deactivate-behavior.js +13 -12
  285. package/dist/mcp/tools/list-reminders.js +4 -4
  286. package/dist/mcp/tools/list-tasks.js +22 -21
  287. package/dist/mcp/tools/send-message.js +21 -20
  288. package/dist/mcp/tools/update-task.js +21 -20
  289. package/dist/{mcp-child-registry-FVGV5XSB.js → mcp-child-registry-OTG4MWO7.js} +3 -2
  290. package/dist/{mcp-http-config-4PHK6RHB.js → mcp-http-config-DQWL7U2Z.js} +3 -3
  291. package/dist/{mcp-session-identity-5DBVDLQR.js → mcp-session-identity-277GASTQ.js} +18 -17
  292. package/dist/{memory-cards-WJM4NG3Q.js → memory-cards-3S2ZQPR7.js} +9 -5
  293. package/dist/{memory-graph-extractor-TSTO7PYI.js → memory-graph-extractor-A6DFEFIN.js} +7 -7
  294. package/dist/{memory-poisoning-defense-BWVA5OBI.js → memory-poisoning-defense-ZVP4H6DY.js} +2 -2
  295. package/dist/{memory-pressure-watchdog-GES7RFL3.js → memory-pressure-watchdog-6W5F6R7H.js} +19 -18
  296. package/dist/{memory-queue-client-62NS3U56.js → memory-queue-client-ADSDP6OX.js} +5 -4
  297. package/dist/{memory-reflection-6UAL4IHM.js → memory-reflection-BKB2YOE6.js} +30 -10
  298. package/dist/{notification-ledger-E2WOQ3WQ.js → notification-ledger-CLGM7ODF.js} +19 -18
  299. package/dist/{notifications-IHLUYF3E.js → notifications-MACUZPYP.js} +18 -17
  300. package/dist/{orchestration-events-TKZV4PAI.js → orchestration-events-N7LYMUGA.js} +3 -3
  301. package/dist/{orchestrator-MQXUNOS2.js → orchestrator-4X24EWHV.js} +20 -19
  302. package/dist/{org-brief-session-7KKLV5OW.js → org-brief-session-FZOFMO5U.js} +5 -5
  303. package/dist/{org-consent-policy-7AHSKB6L.js → org-consent-policy-O5E6HXBL.js} +1 -1
  304. package/dist/{org-partner-runtime-EVZKR2SJ.js → org-partner-runtime-FODONVTM.js} +5 -5
  305. package/dist/{org-row-visibility-GUMNPRK7.js → org-row-visibility-VX4AVV5Q.js} +1 -1
  306. package/dist/{pipeline-router-E5XQUJGU.js → pipeline-router-6GGT2ZW3.js} +3 -3
  307. package/dist/{plan-limits-AJ6K2P6R.js → plan-limits-FUN76LYY.js} +5 -5
  308. package/dist/{project-name-FQKW5SFG.js → project-name-LJVFMYTQ.js} +3 -3
  309. package/dist/{projection-worker-UKSYJ4PG.js → projection-worker-4OANGP5K.js} +2 -2
  310. package/dist/{prospective-memory-S22KIIBP.js → prospective-memory-KR3P4T6N.js} +2 -2
  311. package/dist/{push-notifications-T5SJMFL4.js → push-notifications-NCZLH6DI.js} +19 -18
  312. package/dist/ref-provenance-gate-M4AQO4OT.js +269 -0
  313. package/dist/{reproject-worktree-memories-G6QO5J3X.js → reproject-worktree-memories-PWYKPB2U.js} +18 -17
  314. package/dist/{reranker-NYOFY5FK.js → reranker-6V3C2AO4.js} +1 -1
  315. package/dist/resolve-image-labels-ZI6UBW5W.js +15 -0
  316. package/dist/{retrieval-health-LWDBIBWJ.js → retrieval-health-5D7O6VH6.js} +1 -1
  317. package/dist/{review-polling-BSZXGHER.js → review-polling-QW3LJ4KN.js} +19 -18
  318. package/dist/runtime/index.js +27 -26
  319. package/dist/{session-events-EO7BFQ73.js → session-events-T45SSTMF.js} +19 -18
  320. package/dist/{session-kill-telemetry-FXUGITZK.js → session-kill-telemetry-QSPVJGBF.js} +19 -18
  321. package/dist/{session-scope-B3VWUG4G.js → session-scope-KRWE54C4.js} +18 -17
  322. package/dist/{setup-wizard-3JEJSXXN.js → setup-wizard-GP3TBTPF.js} +1 -1
  323. package/dist/{skill-refinement-5DDEQHGM.js → skill-refinement-C7JTMLJG.js} +3 -3
  324. package/dist/stack-generate-manifest-MFMDWRUP.js +810 -0
  325. package/dist/{stack-promote-KPEARCCS.js → stack-promote-EKSCYY63.js} +5 -4
  326. package/dist/{stack-release-FMGC57AD.js → stack-release-2GZAAFO4.js} +5 -4
  327. package/dist/{stack-update-TZ4P6EXU.js → stack-update-J6JXSTAZ.js} +4 -3
  328. package/dist/{steward-gate-PC6MD5VP.js → steward-gate-BFCCMCSW.js} +3 -3
  329. package/dist/{subagent-brief-injection-NBSQ5IBS.js → subagent-brief-injection-ED36PLYY.js} +28 -27
  330. package/dist/{supervisor-handoff-CSJQMI53.js → supervisor-handoff-SGLEPOCY.js} +12 -3
  331. package/dist/{support-inbox-M3HDZFVF.js → support-inbox-YW47SYJF.js} +6 -6
  332. package/dist/{task-enforcement-LXNIF3US.js → task-enforcement-CECTQX4U.js} +19 -18
  333. package/dist/{task-request-inbox-3EFDJT4E.js → task-request-inbox-Q5T4N5K7.js} +1 -1
  334. package/dist/{task-scope-ERJTOAS4.js → task-scope-ERVEUEYU.js} +18 -17
  335. package/dist/{tasks-crud-GUP437HH.js → tasks-crud-ZRQNJXQ2.js} +18 -17
  336. package/dist/{tasks-notify-AXFFZTI2.js → tasks-notify-MIZH4C2O.js} +19 -18
  337. package/dist/{tasks-review-AYNV37GQ.js → tasks-review-Z7J2P6DG.js} +18 -17
  338. package/dist/{telemetry-upload-4IP7KKIR.js → telemetry-upload-LVQUQYFP.js} +7 -7
  339. package/dist/{token-budget-UJD5CHUG.js → token-budget-BU4NOVZF.js} +3 -3
  340. package/dist/{tool-capability-index-TCTWUUBO.js → tool-capability-index-7F42MOJT.js} +1 -1
  341. package/dist/{tool-telemetry-YRVOD2RP.js → tool-telemetry-O27EVMBR.js} +1 -1
  342. package/dist/tui/App.js +27 -26
  343. package/dist/{tui-data-ZUFCSQ3G.js → tui-data-TPWWBIUQ.js} +18 -17
  344. package/dist/{update-support-V5LF2KMQ.js → update-support-F2F5537B.js} +14 -13
  345. package/dist/{work-claims-2BECZ5GA.js → work-claims-B73X5NE7.js} +3 -3
  346. package/dist/{work-state-heartbeat-7TMN2GSO.js → work-state-heartbeat-P4YX6E2R.js} +1 -1
  347. package/dist/{worker-gate-WUX2AYYZ.js → worker-gate-BEEIIVWA.js} +1 -1
  348. package/dist/{workflow-engine-HDEYIAWI.js → workflow-engine-5X46PFCW.js} +2 -2
  349. package/dist/{worktree-ZMNKH46X.js → worktree-W47CIMJ6.js} +4 -4
  350. package/dist/{worktree-sweep-ZNX6R25W.js → worktree-sweep-BNBD4RFX.js} +5 -5
  351. package/package.json +3 -2
  352. package/release-notes.json +4 -4
  353. package/stack.release.json +6 -0
  354. /package/dist/{chunk-KXIYWHBU.js → chunk-2AJGV5UL.js} +0 -0
  355. /package/dist/{chunk-IUXVUUIA.js → chunk-6WIFPD2P.js} +0 -0
  356. /package/dist/{chunk-B72KXFDR.js → chunk-AISULNGL.js} +0 -0
  357. /package/dist/{chunk-DHWJMFR6.js → chunk-DN4YVV4Z.js} +0 -0
  358. /package/dist/{chunk-4VB6NJOL.js → chunk-GM7TLYOK.js} +0 -0
  359. /package/dist/{chunk-X7HB4KLA.js → chunk-GQOEWNVM.js} +0 -0
  360. /package/dist/{chunk-NP62DK7V.js → chunk-KQ6RJWRW.js} +0 -0
  361. /package/dist/{chunk-NZH5VSBC.js → chunk-M4IRPXSZ.js} +0 -0
  362. /package/dist/{chunk-D2Q3AYMB.js → chunk-NRG7KZIP.js} +0 -0
  363. /package/dist/{chunk-SBMBWO2Y.js → chunk-VZAFWPAY.js} +0 -0
  364. /package/dist/{chunk-OJTF4SV7.js → chunk-WSQASFLP.js} +0 -0
  365. /package/dist/{chunk-XXNSHYPO.js → chunk-XFTEX77S.js} +0 -0
  366. /package/dist/{chunk-RWTYLRNY.js → chunk-YO4BO2CL.js} +0 -0
  367. /package/dist/{core-memory-33XVE547.js → core-memory-7I7RE2SJ.js} +0 -0
  368. /package/dist/{entity-boost-JY3KNTO2.js → entity-boost-3UWGXG5O.js} +0 -0
  369. /package/dist/{memory-isolation-Q3DSVL72.js → memory-isolation-2TUZ7Z4K.js} +0 -0
  370. /package/dist/{message-queue-client-VMVKIPV7.js → message-queue-client-XQN7QABL.js} +0 -0
  371. /package/dist/{oauth-server-ZP5ZXRL7.js → oauth-server-AYM37SQ4.js} +0 -0
  372. /package/dist/{project-boot-5ZXAIOBB.js → project-boot-3Q65LCIP.js} +0 -0
  373. /package/dist/{wiki-acl-EICCXRAK.js → wiki-acl-IBQLLBTS.js} +0 -0
@@ -10,7 +10,12 @@ DOMAIN=CHANGEME_DOMAIN
10
10
  # bug 8dc31733: EXE_DB_IMAGE overrides the Postgres image tag in compose.
11
11
  # The manifest declares env: "EXE_DB_IMAGE" — keep this in sync with the
12
12
  # stack manifest pin. Defaults to pgvector/pgvector:0.8.0-pg16 in compose.
13
- # EXE_DB_IMAGE=pgvector/pgvector:0.8.0-pg16
13
+ EXE_DB_IMAGE=update.askexe.com/askexe/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9
14
+
15
+ # --- Observability ---
16
+ # OTLP collector image. Compose carries no fallback default: a missing pin
17
+ # ABORTS the deploy rather than substituting an old image.
18
+ OTEL_COLLECTOR_IMAGE=update.askexe.com/askexe/otel-collector-contrib:0.114.0@sha256:37fa87091cfaaec7234a27e4e395a40c31c2bfaea97a349a4afef6d9e9681197
14
19
  POSTGRES_USER=exe
15
20
  POSTGRES_PASSWORD=CHANGEME_POSTGRES_PASSWORD
16
21
  POSTGRES_DB=exedb
@@ -33,7 +38,12 @@ GOTRUE_EXTERNAL_URL=https://auth.CHANGEME_DOMAIN
33
38
  # tokens are rejected as iss-mismatch. Keep equal to GOTRUE_EXTERNAL_URL.
34
39
  GOTRUE_JWT_ISSUER=https://auth.CHANGEME_DOMAIN
35
40
  # SSO redirect allow-list (bug 66f8e10a) — app origins for unified SSO.
36
- GOTRUE_URI_ALLOW_LIST=https://crm.CHANGEME_DOMAIN,https://wiki.CHANGEME_DOMAIN,https://erp.CHANGEME_DOMAIN
41
+ # Must list EVERY origin the SPA can redirect back to, including the opt-in
42
+ # dashboard: dashboard-page sends ?redirect=https://dashboard.<domain> through
43
+ # auth, and GoTrue rejects any redirect_to that is not on this list. Kept in
44
+ # lockstep with generate-env.ts and .env.example — a customer who enables the
45
+ # dashboard profile must not have to discover this entry themselves.
46
+ GOTRUE_URI_ALLOW_LIST=https://crm.CHANGEME_DOMAIN,https://wiki.CHANGEME_DOMAIN,https://erp.CHANGEME_DOMAIN,https://dashboard.CHANGEME_DOMAIN,https://gateway.CHANGEME_DOMAIN
37
47
  # Bug 0327b017: parent-domain session cookie → shared across all subdomains.
38
48
  GOTRUE_COOKIE_DOMAIN=.CHANGEME_DOMAIN
39
49
  GOTRUE_COOKIE_KEY=exe-auth
@@ -48,10 +58,18 @@ SMTP_PORT=587
48
58
  SMTP_USER=
49
59
  SMTP_PASS=
50
60
 
61
+ # --- Dashboard (exe-dashboard — customer dashboard at dashboard.<domain>) ---
62
+ # OPT-IN: the exe-dashboard compose service sits behind `profiles: [dashboard]`.
63
+ # No default is written here on purpose — the pin comes from the signed stack
64
+ # manifest (services.dashboard.image), so .env stays derived rather than
65
+ # becoming a competing source of truth that outranks it once it goes stale.
66
+ #DASHBOARD_IMAGE_TAG=update.askexe.com/askexe/exe-dashboard:vX.Y.Z@sha256:...
67
+ #DASHBOARD_PORT=3301
68
+
51
69
  # --- Auth gateway (exe-auth — shared SSO sign-in UI at auth.<domain>) ---
52
70
  # Bug 58840873: pin the auth image so compose never falls back to its stale
53
71
  # hardcoded default tag. Keep in sync with the manifest AUTH_IMAGE_TAG.
54
- AUTH_IMAGE_TAG=update.askexe.com/askexe/exe-auth:v0.5.0
72
+ AUTH_IMAGE_TAG=update.askexe.com/askexe/exe-auth:v0.6.1@sha256:89670a15bc59255299be695525863e66f949694eec1dd8886038dc3659a4a941
55
73
  # Bug 379e5c13: server_name / CORS from the CONFIGURED apex domain, not by naive
56
74
  # last-2-label slicing (which breaks company.co.uk → co.uk).
57
75
  AUTH_SERVER_NAME=auth.CHANGEME_DOMAIN
@@ -106,7 +124,7 @@ EXE_ORG_ID=
106
124
  EXE_ORG_WORKSPACE_ID=
107
125
 
108
126
  # --- CRM ---
109
- CRM_IMAGE_TAG=update.askexe.com/askexe/exe-crm:v0.9.51
127
+ CRM_IMAGE_TAG=update.askexe.com/askexe/exe-crm:v0.9.53@sha256:a586dcc8bbd992538e3caa18c44e772d30f31155dfef0a2b7466ca3fc7c553d8
110
128
  CRM_SERVER_URL=https://crm.CHANGEME_DOMAIN
111
129
  CRM_APP_SECRET=CHANGEME_CRM_APP_SECRET
112
130
  # The CRM's first admin — seeded at boot by WorkspaceBootstrapService, which is
@@ -120,7 +138,7 @@ EXE_CRM_ADMIN_EMAIL=CHANGEME_ADMIN_EMAIL
120
138
  CRM_HOST_PORT=3000
121
139
 
122
140
  # --- Wiki ---
123
- WIKI_IMAGE_TAG=update.askexe.com/askexe/exe-wiki:v0.9.26
141
+ WIKI_IMAGE_TAG=update.askexe.com/askexe/exe-wiki:v0.9.28@sha256:61856a4c6b97ce62c62ecdc3a377139287be5860eb807d9fbb737115758d7856
124
142
  # Bug 2a8d3003 — DO NOT change this without migrating the data first.
125
143
  # The wiki's users / workspaces / workspace_documents live in `public`. Point it at a
126
144
  # different schema and Prisma will NOT error: it finds no tables, assumes a fresh
@@ -143,7 +161,7 @@ WIKI_HOST_PORT=3001
143
161
  EXE_SSO_COOKIE_NAME=exe_access_token
144
162
 
145
163
  # --- exe-os ---
146
- EXE_OS_IMAGE_TAG=update.askexe.com/askexe/exe-os:v0.9.311
164
+ EXE_OS_IMAGE_TAG=update.askexe.com/askexe/exe-os:v0.9.324@sha256:3ce6406e0f7f279ff2568bbbb7d55de51a46fdf35c49691f24fd959d6fd2d3fa
147
165
  EXED_MCP_TOKEN=CHANGEME_EXED_MCP_TOKEN
148
166
  EXED_DEVICE_ID=CHANGEME_DEVICE_ID
149
167
  EXE_MCP_HOST_BIND=127.0.0.1
@@ -153,7 +171,7 @@ EXE_MCP_HOST_PORT=48739
153
171
  EXE_CLOUD_SYNC_TO_POSTGRES=true
154
172
 
155
173
  # --- ERP (Frappe/ERPNext fork) ---
156
- ERP_IMAGE_TAG=update.askexe.com/askexe/exe-erp:v0.2.2
174
+ ERP_IMAGE_TAG=update.askexe.com/askexe/exe-erp:v2026.08.07-d185286-stamped@sha256:1c655f3f7819c797afd13c79561354f0276cf337403f32aee3e406a497e8827b
157
175
  # Administrator password for the ERPNext site (created on first boot).
158
176
  # bug 43854b31: this only applies at FIRST boot. To rotate it later you must also
159
177
  # run `bench --site $ERP_SITE_NAME set-admin-password <new>` inside exe-erp —
@@ -169,7 +187,7 @@ ERP_WS_PORT=9069
169
187
  ERP_SENTRY_DSN=
170
188
 
171
189
  # --- Gateway ---
172
- GATEWAY_IMAGE_TAG=update.askexe.com/askexe/exe-gateway:v0.9.24
190
+ GATEWAY_IMAGE_TAG=update.askexe.com/askexe/exe-gateway:v2026.08.07-c15f093-stamped@sha256:1bc11a2a0ad1f3929d59d2685696f22a72042b9fca9c75e15c02dc7d3c640105
173
191
  EXE_GATEWAY_AUTH_TOKEN=CHANGEME_EXE_GATEWAY_AUTH_TOKEN
174
192
  EXE_GATEWAY_WS_RELAY_AUTH_TOKEN=CHANGEME_EXE_GATEWAY_WS_RELAY_AUTH_TOKEN
175
193
  EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN=CHANGEME_EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN
@@ -190,7 +208,7 @@ CRM_GRAPHQL_URL=http://exe-crm:3000/graphql
190
208
  # bug 633995f1: v0.9.5 is a QUARANTINED build that crashloops on any existing
191
209
  # deployment; v0.9.4 is the last known-good generation and matches the signed
192
210
  # apps manifest. See deploy/known-bad-images.json.
193
- MONITOR_HUB_IMAGE_TAG=update.askexe.com/askexe/exe-monitor-hub:v0.9.4
211
+ MONITOR_HUB_IMAGE_TAG=update.askexe.com/askexe/exe-monitor-hub:v2026.08.09-10660eb4-stamped@sha256:c9a9218c2713b8dffea7e1cf8c0702a614657d311a7a4e821c6a543bab29bb97
194
212
  MONITOR_HUB_PORT=8090
195
213
  # Bootstrap superuser created on first start. Use your admin email + a strong password.
196
214
  # After first boot these values are no longer used (stored in pb_data volume).
@@ -224,7 +242,7 @@ GATEWAY_ALERT_URL=http://exe-gateway:3100/api/alerts/error-spike
224
242
  # Full scope details: deploy/monitor/HOST-ACCESS-CONSENT.md
225
243
  # COMPOSE_PROFILES=monitor-agent
226
244
  # bug 633995f1 / 9ce2a68b: the agent healthcheck is coupled to this generation.
227
- MONITOR_AGENT_IMAGE_TAG=update.askexe.com/askexe/exe-monitor-agent:v0.9.4
245
+ MONITOR_AGENT_IMAGE_TAG=update.askexe.com/askexe/exe-monitor-agent:v2026.08.09-10660eb4-stamped@sha256:29fbd445f79484df04f000603e4ff445e76f0380f86d687a0033e3a0ef7d1b7a
228
246
  # Reports to the local hub. Auto-populated by `exe-os stack-update` during bootstrap.
229
247
  MONITOR_HUB_URL=http://exe-monitor-hub:8090
230
248
  # bug dacf0042: TOKEN and KEY MUST start EMPTY (the safe "unpaired" state) — NOT a
@@ -76,11 +76,26 @@ SMTP_PORT=587
76
76
  SMTP_USER=
77
77
  SMTP_PASS=
78
78
 
79
+ # --- Dashboard (exe-dashboard — customer dashboard at dashboard.<domain>) ---
80
+ # OPT-IN: the exe-dashboard compose service sits behind `profiles: [dashboard]`
81
+ # and is off unless you run `docker compose --profile dashboard ...`.
82
+ # DELIBERATELY UNSET AND COMMENTED OUT. Unlike the older *_IMAGE_TAG lines
83
+ # above/below, this one carries no hardcoded literal: a pinned default here is
84
+ # a second source of truth that silently outranks the manifest the moment it
85
+ # goes stale. Take the value from the signed stack manifest
86
+ # (deploy/stack-manifests/v0.9.json -> services.dashboard.image), digest and all.
87
+ # Leave it unset and compose refuses the dashboard loudly ("has neither an image
88
+ # nor a build context specified") instead of booting something arbitrary.
89
+ #DASHBOARD_IMAGE_TAG=update.askexe.com/askexe/exe-dashboard:vX.Y.Z@sha256:...
90
+ # Host port for the dashboard container (bound to 127.0.0.1; the tunnel and the
91
+ # SSO edge reach it over the docker network, not this port).
92
+ #DASHBOARD_PORT=3301
93
+
79
94
  # --- Auth gateway (exe-auth — shared SSO sign-in UI at auth.<domain>) ---
80
95
  # Bug 58840873: pin the auth image so compose never falls back to its stale
81
96
  # hardcoded default tag. Keep in sync with the manifest AUTH_IMAGE_TAG. exe-auth
82
97
  # ships only from the private update.askexe.com registry (no GHCR mirror).
83
- AUTH_IMAGE_TAG=update.askexe.com/askexe/exe-auth:v0.5.0
98
+ AUTH_IMAGE_TAG=update.askexe.com/askexe/exe-auth:v0.6.1@sha256:89670a15bc59255299be695525863e66f949694eec1dd8886038dc3659a4a941
84
99
  # Bug 379e5c13: server_name / CORS derived from the CONFIGURED apex domain,
85
100
  # not by naive last-2-label slicing (which breaks company.co.uk → co.uk).
86
101
  AUTH_SERVER_NAME=auth.CHANGEME_DOMAIN
@@ -140,7 +155,7 @@ EXE_ORG_ID=
140
155
  EXE_ORG_WORKSPACE_ID=
141
156
 
142
157
  # --- CRM ---
143
- CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.51
158
+ CRM_IMAGE_TAG=ghcr.io/askexe/exe-crm:v0.9.53@sha256:a586dcc8bbd992538e3caa18c44e772d30f31155dfef0a2b7466ca3fc7c553d8
144
159
  CRM_SERVER_URL=https://crm.CHANGEME_DOMAIN
145
160
  CRM_APP_SECRET=CHANGEME_CRM_APP_SECRET
146
161
  EXE_CRM_ADMIN_TOKEN=CHANGEME_EXE_CRM_ADMIN_TOKEN
@@ -153,7 +168,7 @@ EXE_CRM_ADMIN_EMAIL=CHANGEME_ADMIN_EMAIL
153
168
  CRM_HOST_PORT=3000
154
169
 
155
170
  # --- Wiki ---
156
- WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.26
171
+ WIKI_IMAGE_TAG=ghcr.io/askexe/exe-wiki:v0.9.28@sha256:61856a4c6b97ce62c62ecdc3a377139287be5860eb807d9fbb737115758d7856
157
172
  # Bug 2a8d3003 — DO NOT change this without migrating the data first.
158
173
  # The wiki's users / workspaces / workspace_documents live in `public`. Point it at a
159
174
  # different schema and Prisma will NOT error: it finds no tables, assumes a fresh
@@ -176,7 +191,12 @@ WIKI_HOST_PORT=3001
176
191
  EXE_SSO_COOKIE_NAME=exe_access_token
177
192
 
178
193
  # --- exe-os ---
179
- EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.311
194
+ EXE_OS_IMAGE_TAG=ghcr.io/askexe/exe-os:v0.9.324@sha256:3ce6406e0f7f279ff2568bbbb7d55de51a46fdf35c49691f24fd959d6fd2d3fa
195
+
196
+ # Infra image pins — manifest-derived. Compose has no fallback default for
197
+ # these: a missing pin ABORTS the deploy instead of substituting an old image.
198
+ EXE_DB_IMAGE=update.askexe.com/askexe/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9
199
+ OTEL_COLLECTOR_IMAGE=update.askexe.com/askexe/otel-collector-contrib:0.114.0@sha256:37fa87091cfaaec7234a27e4e395a40c31c2bfaea97a349a4afef6d9e9681197
180
200
  EXED_MCP_TOKEN=CHANGEME_EXED_MCP_TOKEN
181
201
  EXED_DEVICE_ID=vps-default
182
202
  EXE_MCP_HOST_BIND=127.0.0.1
@@ -186,7 +206,7 @@ EXE_MCP_HOST_PORT=48739
186
206
  EXE_CLOUD_SYNC_TO_POSTGRES=true
187
207
 
188
208
  # --- Gateway ---
189
- GATEWAY_IMAGE_TAG=ghcr.io/askexe/exe-gateway:v0.9.24
209
+ GATEWAY_IMAGE_TAG=ghcr.io/askexe/exe-gateway:v2026.08.07-c15f093-stamped@sha256:1bc11a2a0ad1f3929d59d2685696f22a72042b9fca9c75e15c02dc7d3c640105
190
210
  EXE_GATEWAY_AUTH_TOKEN=CHANGEME_EXE_GATEWAY_AUTH_TOKEN
191
211
  EXE_GATEWAY_WS_RELAY_AUTH_TOKEN=CHANGEME_EXE_GATEWAY_WS_RELAY_AUTH_TOKEN
192
212
  EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN=CHANGEME_EXE_GATEWAY_WHATSAPP_VERIFY_TOKEN
@@ -226,7 +246,7 @@ ERROR_REPORTING_ENABLED=true
226
246
  MONITOR_ERROR_URL=http://exe-monitor-hub:8090/api/exe-monitor/errors
227
247
 
228
248
  # --- ERP (optional — Exe ERP, Frappe/ERPNext fork) ---
229
- ERP_IMAGE_TAG=ghcr.io/askexe/exe-erp:v0.2.2
249
+ ERP_IMAGE_TAG=ghcr.io/askexe/exe-erp:v2026.08.07-d185286-stamped@sha256:1c655f3f7819c797afd13c79561354f0276cf337403f32aee3e406a497e8827b
230
250
  ERP_ADMIN_PASSWORD=CHANGEME_ERP_ADMIN_PASSWORD
231
251
  EXE_ERP_ADMIN_TOKEN=CHANGEME_EXE_ERP_ADMIN_TOKEN
232
252
  # Frappe site name — must match the erp.<domain> the customer serves (bug e61ad373).
@@ -248,7 +268,7 @@ EXE_BUILD_HTTP_PORT=9222
248
268
  # data dir and entrypoint all changed) and crashloops on any existing
249
269
  # deployment. v0.9.4 is the last known-good generation and is what the signed
250
270
  # apps manifest pins. See deploy/known-bad-images.json.
251
- MONITOR_HUB_IMAGE_TAG=ghcr.io/askexe/exe-monitor-hub:v0.9.4
271
+ MONITOR_HUB_IMAGE_TAG=ghcr.io/askexe/exe-monitor-hub:v2026.08.09-10660eb4-stamped@sha256:c9a9218c2713b8dffea7e1cf8c0702a614657d311a7a4e821c6a543bab29bb97
252
272
  MONITOR_HUB_PORT=8090
253
273
  # Bootstrap superuser created on first start. Use your admin email + a strong password.
254
274
  # After first boot these values are no longer used (stored in pb_data volume).
@@ -268,7 +288,7 @@ MONITOR_HUB_ADMIN_PASSWORD=CHANGEME_MONITOR_HUB_ADMIN_PASSWORD
268
288
  # COMPOSE_PROFILES=monitor-agent
269
289
  # bug 633995f1 / 9ce2a68b: keep the agent on the v0.9.4 generation — the
270
290
  # compose healthcheck (`/app/beszel-agent health`) is coupled to it.
271
- MONITOR_AGENT_IMAGE_TAG=ghcr.io/askexe/exe-monitor-agent:v0.9.4
291
+ MONITOR_AGENT_IMAGE_TAG=ghcr.io/askexe/exe-monitor-agent:v2026.08.09-10660eb4-stamped@sha256:29fbd445f79484df04f000603e4ff445e76f0380f86d687a0033e3a0ef7d1b7a
272
292
  # Reports to the local hub. Auto-populated by `exe-os stack-update` during bootstrap.
273
293
  MONITOR_HUB_URL=http://exe-monitor-hub:8090
274
294
  # bug dacf0042: TOKEN and KEY MUST start EMPTY (the safe "unpaired" state) —
@@ -29,7 +29,7 @@ services:
29
29
  # bug ee16e7ef: pin a versioned tag, not the mutable :pg16 rolling tag.
30
30
  # pgvector/pgvector:pg16 can change upstream without notice; 0.8.0-pg16
31
31
  # is the tested stable release. Override via EXE_DB_IMAGE in .env.
32
- image: ${EXE_DB_IMAGE:-pgvector/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9}
32
+ image: ${EXE_DB_IMAGE:?EXE_DB_IMAGE must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
33
33
  container_name: exe-db
34
34
  restart: unless-stopped
35
35
  # SECURITY (bug 67d62490): no blanket `env_file: .env`. Each service
@@ -278,7 +278,7 @@ services:
278
278
  # is what the signed apps manifest (deploy/stack-manifests/v0.9.30-apps.json)
279
279
  # and exe-monitor's own stack.release.json pin. Do not reintroduce the bad
280
280
  # digest.
281
- image: ${MONITOR_HUB_IMAGE_TAG:-ghcr.io/askexe/exe-monitor-hub:v0.9.4@sha256:d593bec5a4b248388d0d85353fae1ba8f93cab628a03833aa79acd0632fd11cb}
281
+ image: ${MONITOR_HUB_IMAGE_TAG:?MONITOR_HUB_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
282
282
  container_name: exe-monitor-hub
283
283
  restart: unless-stopped
284
284
  # bug d3d49101 / 1fdb8be9: PocketBase's data dir for this hub is a RELATIVE
@@ -360,7 +360,7 @@ services:
360
360
  # ------------------------------------------------------------------
361
361
 
362
362
  exe-crm:
363
- image: ${CRM_IMAGE_TAG:-ghcr.io/askexe/exe-crm:v0.9.51@sha256:73864ce14aaac06b73d67100bbf88e669fd13c7da39edd9644107037211559b7}
363
+ image: ${CRM_IMAGE_TAG:?CRM_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
364
364
  container_name: exe-crm
365
365
  restart: unless-stopped
366
366
  # bug ad4471ad: NO compose `command` override. The image entrypoint
@@ -486,7 +486,7 @@ services:
486
486
  options: { max-size: "10m", max-file: "3" }
487
487
 
488
488
  exe-crm-worker:
489
- image: ${CRM_IMAGE_TAG:-ghcr.io/askexe/exe-crm:v0.9.51@sha256:73864ce14aaac06b73d67100bbf88e669fd13c7da39edd9644107037211559b7}
489
+ image: ${CRM_IMAGE_TAG:?CRM_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
490
490
  container_name: exe-crm-worker
491
491
  restart: unless-stopped
492
492
  command: ["yarn", "worker:prod"]
@@ -552,7 +552,7 @@ services:
552
552
  # erroring, so "wiki looks wiped" and "wiki is misconfigured" are indistinguishable
553
553
  # at a glance, and the wrong diagnosis (restore from backup) destroys real data.
554
554
  exe-wiki-schema-guard:
555
- image: ${EXE_DB_IMAGE:-pgvector/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9}
555
+ image: ${EXE_DB_IMAGE:?EXE_DB_IMAGE must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
556
556
  container_name: exe-wiki-schema-guard
557
557
  restart: "no"
558
558
  depends_on:
@@ -588,7 +588,7 @@ services:
588
588
  options: { max-size: "10m", max-file: "3" }
589
589
 
590
590
  exe-wiki:
591
- image: ${WIKI_IMAGE_TAG:-ghcr.io/askexe/exe-wiki:v0.9.26@sha256:c0d61d183b274a67977fdfb1b40d5e4736559a9d90507843183e5642da2a959d}
591
+ image: ${WIKI_IMAGE_TAG:?WIKI_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
592
592
  container_name: exe-wiki
593
593
  restart: unless-stopped
594
594
  # Wiki uses Prisma — runs migrate on boot via built-in entrypoint.
@@ -728,7 +728,15 @@ services:
728
728
  # to pin the split server image; falls back to the combined EXE_OS_IMAGE_TAG
729
729
  # for backward compatibility with existing manifests.
730
730
  exe-os:
731
- image: ${EXE_OS_SERVER_IMAGE_TAG:-${EXE_OS_IMAGE_TAG:-${EXED_IMAGE_TAG:-ghcr.io/askexe/exe-os:v0.9.311@sha256:011730042f55277724dbe83fde1a6416db2f3e8bf62d3254738d68d8de33e1f9}}}
731
+ # FAIL-CLOSED PIN. The signed stack manifest is the single source of truth for
732
+ # this image; stack-update writes EXE_OS_IMAGE_TAG from it. The legacy aliases are
733
+ # kept so an older .env keeps working, and the chain terminates EMPTY on purpose:
734
+ # docker compose evaluates nested defaults eagerly, so `:?` inside a chain would
735
+ # fire even when an alias IS set. With no pin at all compose aborts with
736
+ # "has neither an image nor a build context specified" — loud, not a silent
737
+ # substitution of a stale hard-coded version (which is how auth nearly shipped a
738
+ # four-minor-version downgrade).
739
+ image: ${EXE_OS_SERVER_IMAGE_TAG:-${EXE_OS_IMAGE_TAG:-${EXED_IMAGE_TAG:-}}}
732
740
  container_name: exe-os
733
741
  restart: unless-stopped
734
742
  # bug debf4a39 / 93ddfa27: the daemon connects to exe-db at boot
@@ -847,7 +855,7 @@ services:
847
855
  options: { max-size: "10m", max-file: "3" }
848
856
 
849
857
  exe-gateway:
850
- image: ${GATEWAY_IMAGE_TAG:-ghcr.io/askexe/exe-gateway:v0.9.24@sha256:9cda7c00d886b4ab16a3b88aa953aa45c991f2977084ea8532f55fcaf75e8f37}
858
+ image: ${GATEWAY_IMAGE_TAG:?GATEWAY_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
851
859
  container_name: exe-gateway
852
860
  restart: unless-stopped
853
861
  # Gateway needs 45s to flush outbound queues + disconnect Baileys adapters.
@@ -1011,7 +1019,7 @@ services:
1011
1019
  # v0.9.5 default contradicted that healthcheck, so the agent was
1012
1020
  # permanently unhealthy from the first recreate. Matches the signed apps
1013
1021
  # manifest and exe-monitor's stack.release.json.
1014
- image: ${MONITOR_AGENT_IMAGE_TAG:-ghcr.io/askexe/exe-monitor-agent:v0.9.4@sha256:9ca4e75577b2ff2abb754140ccfaf8df19161bcef601faf37d1fce743fe814fc}
1022
+ image: ${MONITOR_AGENT_IMAGE_TAG:?MONITOR_AGENT_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
1015
1023
  container_name: exe-monitor-agent
1016
1024
  # Host-access consent gate: only starts when the operator has
1017
1025
  # acknowledged the host-access scope (COMPOSE_PROFILES=monitor-agent).
@@ -1116,7 +1124,15 @@ services:
1116
1124
  # Without a token the binary exits 0 (no crash-loop). (bug 3416cead)
1117
1125
  # ------------------------------------------------------------------
1118
1126
  exe-update:
1119
- image: ${EXE_OS_IMAGE_TAG:-${EXED_IMAGE_TAG:-ghcr.io/askexe/exe-os:v0.9.311@sha256:011730042f55277724dbe83fde1a6416db2f3e8bf62d3254738d68d8de33e1f9}}
1127
+ # FAIL-CLOSED PIN. The signed stack manifest is the single source of truth for
1128
+ # this image; stack-update writes EXE_OS_IMAGE_TAG from it. The legacy aliases are
1129
+ # kept so an older .env keeps working, and the chain terminates EMPTY on purpose:
1130
+ # docker compose evaluates nested defaults eagerly, so `:?` inside a chain would
1131
+ # fire even when an alias IS set. With no pin at all compose aborts with
1132
+ # "has neither an image nor a build context specified" — loud, not a silent
1133
+ # substitution of a stale hard-coded version (which is how auth nearly shipped a
1134
+ # four-minor-version downgrade).
1135
+ image: ${EXE_OS_IMAGE_TAG:-${EXED_IMAGE_TAG:-}}
1120
1136
  container_name: exe-update
1121
1137
  profiles: ["registry-proxy", "askexe-control-plane"]
1122
1138
  restart: unless-stopped
@@ -1675,7 +1691,7 @@ services:
1675
1691
  exe-otel-collector:
1676
1692
  # bug 32d6e02f: digest-pinned default (was tag-only) — matches the
1677
1693
  # stack manifest pin for otel/opentelemetry-collector-contrib:0.114.0.
1678
- image: ${OTEL_COLLECTOR_IMAGE:-otel/opentelemetry-collector-contrib:0.114.0@sha256:37fa87091cfaaec7234a27e4e395a40c31c2bfaea97a349a4afef6d9e9681197}
1694
+ image: ${OTEL_COLLECTOR_IMAGE:?OTEL_COLLECTOR_IMAGE must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
1679
1695
  container_name: exe-otel-collector
1680
1696
  restart: unless-stopped
1681
1697
  command: ["--config=/etc/otelcol-contrib/config.yaml"]
@@ -1743,7 +1759,7 @@ services:
1743
1759
  # a fresh/migrated install boots an old image while the manifest reads "latest".
1744
1760
  # generate-env.ts now always writes AUTH_IMAGE_TAG, and this default mirrors the
1745
1761
  # pin as defense-in-depth — keep BOTH in lockstep on every auth release.
1746
- image: ${AUTH_IMAGE_TAG:-update.askexe.com/askexe/exe-auth:v0.5.0@sha256:ecc57f92b1f2c2d9df4fafe648622fe1fdd87c27012048d950e3f6b82086ccf9}
1762
+ image: ${AUTH_IMAGE_TAG:?AUTH_IMAGE_TAG must be set from the signed stack manifest (digest-pinned) — refusing to fall back to a stale hard-coded image}
1747
1763
  container_name: exe-auth
1748
1764
  restart: unless-stopped
1749
1765
  environment:
@@ -1813,6 +1829,79 @@ services:
1813
1829
  driver: json-file
1814
1830
  options: { max-size: "10m", max-file: "3" }
1815
1831
 
1832
+ # ------------------------------------------------------------------
1833
+ # Dashboard — customer dashboard at dashboard.yourdomain.com
1834
+ # Static nginx image built from dashboard-page/ in the exe-os repo.
1835
+ # ------------------------------------------------------------------
1836
+ #
1837
+ # WHY THIS IS HERE AT ALL (2026-08-20). exe-dashboard has been running in
1838
+ # production for months WITHOUT a service in this file. Its only compose
1839
+ # definition was dashboard-page/docker-compose.yml — a standalone side-car
1840
+ # that carried `build: .` and a hardcoded `image: …:v0.1.0`, joined the
1841
+ # external `exe-net` network, and answered the `upstream sso_dashboard`
1842
+ # in sso-edge/default.conf.template. Nothing in the stack manifest could pin
1843
+ # a service the stack compose did not define, which is exactly why the
1844
+ # dashboard drifted three builds behind main with nobody able to see it.
1845
+ # This entry makes it a first-class, manifest-governed stack service.
1846
+ #
1847
+ # OPT-IN VIA PROFILE. `profiles: ["dashboard"]` keeps this off for every
1848
+ # existing deployment that has not opted in. That is deliberate and it is why
1849
+ # the image pin uses the empty-default form and NOT the required-variable
1850
+ # (colon-question-mark) form: compose interpolates the WHOLE file before it
1851
+ # filters by profile (verified on Docker 28.5.1 — a required-variable
1852
+ # reference inside an INACTIVE profile still aborts `docker compose config`),
1853
+ # so that form here would break every customer who never asked for the
1854
+ # dashboard. The empty terminator gets the same fail-loud
1855
+ # behaviour exactly where it belongs: with the profile ACTIVE and the variable
1856
+ # unset, compose refuses with `service "exe-dashboard" has neither an image nor
1857
+ # a build context specified` instead of silently substituting a stale literal.
1858
+ exe-dashboard:
1859
+ image: ${DASHBOARD_IMAGE_TAG:-}
1860
+ profiles: ["dashboard"]
1861
+ container_name: exe-dashboard
1862
+ restart: unless-stopped
1863
+ environment:
1864
+ # Customer apex domain — templates server_name, CSP and the SPA's API/auth
1865
+ # URLs at container start via dashboard-page/docker-entrypoint.sh. Never
1866
+ # falls back to askexe.com.
1867
+ DOMAIN: ${DOMAIN:?DOMAIN is required — set to your customer apex domain (e.g. hygo.co)}
1868
+ # Optional explicit overrides; each defaults to the matching *.${DOMAIN}.
1869
+ DASH_DOMAIN: ${DASH_DOMAIN:-}
1870
+ DASH_API_URL: ${DASH_API_URL:-}
1871
+ DASH_AUTH_URL: ${DASH_AUTH_URL:-}
1872
+ DASH_DASHBOARD_URL: ${DASH_DASHBOARD_URL:-}
1873
+ ports:
1874
+ - "127.0.0.1:${DASHBOARD_PORT:-3301}:80"
1875
+ networks:
1876
+ # `backend` so exe-sso-edge can resolve `exe-dashboard` for its
1877
+ # `upstream sso_dashboard { server exe-dashboard:80; }`; `frontend` so the
1878
+ # cloudflared tunnel can reach it. Same pair as exe-auth/exe-crm/exe-wiki.
1879
+ #
1880
+ # NOTE: exe-sso-edge deliberately does NOT list this service in its
1881
+ # depends_on. The edge must keep starting on deployments that never enable
1882
+ # the dashboard profile, and a depends_on would make the edge unstartable
1883
+ # for them.
1884
+ - backend
1885
+ - frontend
1886
+ healthcheck:
1887
+ # dashboard-page/nginx.conf serves `location = /health` as a literal 200.
1888
+ # This is the same URL the stack manifest's healthUrl names, so the deploy
1889
+ # gate and the container agree on what "up" means. Before this existed,
1890
+ # /health fell through to the SPA `location /` and returned the index page
1891
+ # with a 200 — a probe that could not fail while nginx was running at all.
1892
+ test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1/health"]
1893
+ interval: 30s
1894
+ timeout: 5s
1895
+ start_period: 5s
1896
+ retries: 3
1897
+ deploy:
1898
+ resources:
1899
+ limits:
1900
+ memory: 128M
1901
+ logging:
1902
+ driver: json-file
1903
+ options: { max-size: "10m", max-file: "3" }
1904
+
1816
1905
  # ------------------------------------------------------------------
1817
1906
  # Volumes
1818
1907
  # ------------------------------------------------------------------
@@ -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;
@@ -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}`,
@@ -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",
@@ -559,6 +645,11 @@ export function generateExampleEnv(): string {
559
645
  "",
560
646
  "# --- exe-os ---",
561
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}`,
562
653
  "EXED_MCP_TOKEN=CHANGEME_EXED_MCP_TOKEN",
563
654
  "EXED_DEVICE_ID=vps-default",
564
655
  `EXE_MCP_HOST_BIND=${DEFAULT_EXE_MCP_HOST_BIND}`,