@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
@@ -0,0 +1,810 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ writeSignedStackManifest
4
+ } from "./chunk-3UUX5OY4.js";
5
+ import "./chunk-ZGYNKA3O.js";
6
+ import "./chunk-GHR4ZPJ7.js";
7
+ import "./chunk-C5HUMAA7.js";
8
+ import "./chunk-L25OAFOU.js";
9
+ import "./chunk-L6RXG36J.js";
10
+ import "./chunk-A7XLR3K7.js";
11
+ import "./chunk-GQOEWNVM.js";
12
+ import "./chunk-ZIG7VPJV.js";
13
+ import "./chunk-HSGBZSCA.js";
14
+ import "./chunk-RH4AH3YB.js";
15
+ import {
16
+ isMainModule
17
+ } from "./chunk-6Y4B3QF6.js";
18
+ import "./chunk-JKKZGDLP.js";
19
+ import "./chunk-MLKGABMK.js";
20
+
21
+ // src/bin/stack-generate-manifest.ts
22
+ import { execFile as execFileCb } from "child_process";
23
+ import { existsSync, readFileSync } from "fs";
24
+ import path from "path";
25
+ import { promisify } from "util";
26
+
27
+ // src/lib/stack-manifest-generate.ts
28
+ var STACK_SERVICE_SPECS = Object.freeze([
29
+ // ---- AskExe releases -----------------------------------------------------
30
+ {
31
+ key: "exe-os",
32
+ composeServices: ["exe-os", "exe-os-worker", "exe-update"],
33
+ origin: "askexe-release",
34
+ deployment: "stack",
35
+ ghRepo: "AskExe/exe-os",
36
+ imageName: "update.askexe.com/askexe/exe-os",
37
+ sourceImageName: "ghcr.io/askexe/exe-os",
38
+ // The version tag and the commit tag live in DIFFERENT ghcr repositories:
39
+ // release-stack-image.yml pushes `${stack.release.json image}` (exe-os:vX.Y.Z)
40
+ // and `ghcr.io/askexe/exed:sha-${github.sha}` from the same build.
41
+ commitImageName: "ghcr.io/askexe/exed",
42
+ env: "EXE_OS_IMAGE_TAG",
43
+ healthUrl: "http://127.0.0.1:8765/health",
44
+ required: true,
45
+ category: "core",
46
+ description: "exe-os daemon + MCP server"
47
+ },
48
+ {
49
+ key: "crm",
50
+ composeServices: ["exe-crm", "exe-crm-worker"],
51
+ origin: "askexe-release",
52
+ deployment: "stack",
53
+ ghRepo: "AskExe/exe-crm",
54
+ imageName: "update.askexe.com/askexe/exe-crm",
55
+ sourceImageName: "ghcr.io/askexe/exe-crm",
56
+ env: "CRM_IMAGE_TAG",
57
+ healthUrl: "http://127.0.0.1:3000/healthz",
58
+ category: "app",
59
+ description: "Customer relationship management",
60
+ note: "BLOCKED PENDING PROVENANCE (2026-08-20), not exempt: production runs an untagged image (digest bc0405717ed1) with EMPTY org.opencontainers.image.version and .revision labels, built 2026-08-07, matching no git tag, while main is 50 commits past v0.9.54. Resolving it to v0.9.54 would be a change of unknown scope. Trace the running image, cut a real release, then this entry flows through the identical code path as every other service with no special-casing."
61
+ },
62
+ {
63
+ key: "wiki",
64
+ composeServices: ["exe-wiki"],
65
+ origin: "askexe-release",
66
+ deployment: "stack",
67
+ ghRepo: "AskExe/exe-wiki",
68
+ imageName: "update.askexe.com/askexe/exe-wiki",
69
+ sourceImageName: "ghcr.io/askexe/exe-wiki",
70
+ env: "WIKI_IMAGE_TAG",
71
+ healthUrl: "http://127.0.0.1:3001/api/ping",
72
+ category: "app"
73
+ },
74
+ {
75
+ key: "gateway",
76
+ composeServices: ["exe-gateway"],
77
+ origin: "askexe-release",
78
+ deployment: "stack",
79
+ ghRepo: "AskExe/exe-gateway",
80
+ imageName: "update.askexe.com/askexe/exe-gateway",
81
+ sourceImageName: "ghcr.io/askexe/exe-gateway",
82
+ env: "GATEWAY_IMAGE_TAG",
83
+ healthUrl: "http://127.0.0.1:3100/health",
84
+ category: "app",
85
+ description: "WhatsApp/messaging gateway"
86
+ },
87
+ {
88
+ key: "auth",
89
+ composeServices: ["exe-auth"],
90
+ origin: "askexe-release",
91
+ deployment: "stack",
92
+ ghRepo: "AskExe/exe-auth",
93
+ // NO sourceImageName: exe-auth is published ONLY to the private
94
+ // update.askexe.com registry and is not mirrored to GHCR (bug 58840873 —
95
+ // the same reason deploy/compose/generate-env.ts carries a dedicated
96
+ // AUTH_REGISTRY constant). Probing ghcr.io for its `sha-*`/version tags
97
+ // resolves nothing, so provenance is read from — and the pin emitted for —
98
+ // the one registry the artifact actually exists in.
99
+ imageName: "update.askexe.com/askexe/exe-auth",
100
+ env: "AUTH_IMAGE_TAG",
101
+ healthUrl: "http://127.0.0.1:3300/api/health",
102
+ category: "auth",
103
+ description: "Shared SSO sign-in/sign-up"
104
+ },
105
+ {
106
+ key: "erp",
107
+ composeServices: ["exe-erp", "exe-erp-nginx", "exe-erp-websocket", "exe-erp-queue", "exe-erp-scheduler"],
108
+ origin: "askexe-release",
109
+ deployment: "stack",
110
+ ghRepo: "AskExe/exe-erp",
111
+ imageName: "update.askexe.com/askexe/exe-erp",
112
+ sourceImageName: "ghcr.io/askexe/exe-erp",
113
+ env: "ERP_IMAGE_TAG",
114
+ healthUrl: "http://127.0.0.1:8069/api/method/ping",
115
+ healthHost: "erp.askexe.com",
116
+ required: false,
117
+ category: "app",
118
+ description: "Enterprise resource planning"
119
+ },
120
+ {
121
+ key: "monitorHub",
122
+ composeServices: ["exe-monitor-hub"],
123
+ origin: "askexe-release",
124
+ deployment: "stack",
125
+ ghRepo: "AskExe/exe-monitor",
126
+ imageName: "update.askexe.com/askexe/exe-monitor-hub",
127
+ sourceImageName: "ghcr.io/askexe/exe-monitor-hub",
128
+ env: "MONITOR_HUB_IMAGE_TAG",
129
+ category: "monitoring"
130
+ },
131
+ {
132
+ key: "monitorAgent",
133
+ composeServices: ["exe-monitor-agent"],
134
+ origin: "askexe-release",
135
+ deployment: "stack",
136
+ ghRepo: "AskExe/exe-monitor",
137
+ imageName: "update.askexe.com/askexe/exe-monitor-agent",
138
+ sourceImageName: "ghcr.io/askexe/exe-monitor-agent",
139
+ env: "MONITOR_AGENT_IMAGE_TAG",
140
+ category: "monitoring"
141
+ },
142
+ {
143
+ key: "dashboard",
144
+ composeServices: ["exe-dashboard"],
145
+ origin: "askexe-release",
146
+ deployment: "stack",
147
+ // SOURCE IS KNOWN: exe-dashboard is built from THIS repo (AskExe/exe-os),
148
+ // build context dashboard-page/, by .github/workflows/dashboard-image.yml.
149
+ // Production's sha256:950699473914… came from exe-os commit 1d5b69cffa8d
150
+ // (#703, 2026-08-13), confirmed in build run 31714341386.
151
+ ghRepo: "AskExe/exe-os",
152
+ // …but it is OUTSIDE THE RELEASE LANE: that workflow pushes only
153
+ // `:sha-<sha>` and `:main`, sets no org.opencontainers.image.version, and
154
+ // neither stack.release.json nor the stack manifest mentions it. Production
155
+ // is three builds stale and nothing auto-deploys it.
156
+ releaseLane: "none",
157
+ imageName: "ghcr.io/askexe/exe-dashboard",
158
+ env: "DASHBOARD_IMAGE_TAG",
159
+ category: "app",
160
+ description: "Customer dashboard (credits, usage, keys, billing)",
161
+ note: "BLOCKED \u2014 NOT WIRED INTO THE RELEASE LANE (2026-08-20). Give dashboard-image.yml a versioned release tag + org.opencontainers.image.version/.revision stamps, and add it to stack.release.json, then it flows through the identical path as every other service."
162
+ },
163
+ {
164
+ key: "exe-build",
165
+ composeServices: [],
166
+ origin: "askexe-release",
167
+ // Control-plane only: exe-build was removed from the customer stack and
168
+ // runs on askexe-control-plane. Stated here so its absence from the
169
+ // customer manifest is a decision on the record, not an omission.
170
+ deployment: "control-plane",
171
+ ghRepo: "AskExe/exe-build",
172
+ imageName: "update.askexe.com/askexe/exe-build",
173
+ env: "EXE_BUILD_IMAGE_TAG",
174
+ category: "control-plane"
175
+ },
176
+ // ---- Upstream (third-party) artifacts ------------------------------------
177
+ {
178
+ key: "exe-db",
179
+ composeServices: ["exe-db", "exe-wiki-schema-guard"],
180
+ origin: "upstream-pinned",
181
+ deployment: "stack",
182
+ ghRepo: null,
183
+ imageName: "update.askexe.com/askexe/pgvector",
184
+ env: "EXE_DB_IMAGE",
185
+ pinnedImage: "update.askexe.com/askexe/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9",
186
+ required: true,
187
+ category: "core",
188
+ description: "Postgres (pgvector)"
189
+ },
190
+ {
191
+ key: "gotrue",
192
+ composeServices: ["gotrue"],
193
+ origin: "upstream-pinned",
194
+ deployment: "stack",
195
+ ghRepo: null,
196
+ imageName: "update.askexe.com/askexe/gotrue",
197
+ pinnedImage: "update.askexe.com/askexe/gotrue:v2.172.1@sha256:b0dd7aa28dd1f9a8bd31f136c8b912661f701d9b863171e5843cb08f18f49de4",
198
+ healthUrl: "http://127.0.0.1:9999/health",
199
+ category: "infra"
200
+ },
201
+ {
202
+ key: "redis",
203
+ composeServices: ["redis"],
204
+ origin: "upstream-pinned",
205
+ deployment: "stack",
206
+ ghRepo: null,
207
+ imageName: "update.askexe.com/askexe/redis",
208
+ pinnedImage: "update.askexe.com/askexe/redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99",
209
+ category: "infra"
210
+ },
211
+ {
212
+ key: "clickhouse",
213
+ composeServices: ["clickhouse"],
214
+ origin: "upstream-pinned",
215
+ deployment: "stack",
216
+ ghRepo: null,
217
+ imageName: "update.askexe.com/askexe/clickhouse-server",
218
+ pinnedImage: "update.askexe.com/askexe/clickhouse-server:24.8.4.13-alpine@sha256:88a45f9e328549b2579256c46ee38e5c0e25ae58303d9eb6d9c7ed8d6d2bbf3c",
219
+ category: "infra"
220
+ },
221
+ {
222
+ key: "cloudflared",
223
+ composeServices: ["cloudflared"],
224
+ origin: "upstream-pinned",
225
+ deployment: "stack",
226
+ ghRepo: null,
227
+ imageName: "update.askexe.com/askexe/cloudflared",
228
+ pinnedImage: "update.askexe.com/askexe/cloudflared:2026-07@sha256:ba461b8aa9c042156dbd39c38657fe7431bafa063220eab8d5330a523863da9f",
229
+ category: "infra"
230
+ },
231
+ {
232
+ key: "exe-sso-edge",
233
+ composeServices: ["exe-sso-edge"],
234
+ origin: "upstream-pinned",
235
+ deployment: "stack",
236
+ ghRepo: null,
237
+ imageName: "update.askexe.com/askexe/nginx",
238
+ pinnedImage: "update.askexe.com/askexe/nginx:alpine@sha256:20316569d8f81a160065d7d2a5eeffc7ca97d79022462ee255fd23fa103a6b5c",
239
+ category: "infra"
240
+ },
241
+ {
242
+ key: "exe-otel-collector",
243
+ composeServices: ["exe-otel-collector"],
244
+ origin: "upstream-pinned",
245
+ deployment: "stack",
246
+ ghRepo: null,
247
+ imageName: "update.askexe.com/askexe/otel-collector-contrib",
248
+ env: "OTEL_COLLECTOR_IMAGE",
249
+ pinnedImage: "update.askexe.com/askexe/otel-collector-contrib:0.114.0@sha256:37fa87091cfaaec7234a27e4e395a40c31c2bfaea97a349a4afef6d9e9681197",
250
+ category: "infra"
251
+ }
252
+ ]);
253
+ function stackServiceSpecs(specs = STACK_SERVICE_SPECS) {
254
+ return specs.filter((s) => s.deployment === "stack");
255
+ }
256
+ var DIGEST_RE = /@sha256:[0-9a-f]{64}$/i;
257
+ function isDigestPinned(ref) {
258
+ return typeof ref === "string" && DIGEST_RE.test(ref.trim());
259
+ }
260
+ function tagOf(ref) {
261
+ if (typeof ref !== "string" || ref.trim() === "") return void 0;
262
+ const raw = ref.trim();
263
+ const at = raw.indexOf("@");
264
+ const withoutDigest = at === -1 ? raw : raw.slice(0, at);
265
+ const slash = withoutDigest.lastIndexOf("/");
266
+ const colon = withoutDigest.lastIndexOf(":");
267
+ if (colon <= slash) return void 0;
268
+ const tag = withoutDigest.slice(colon + 1);
269
+ return tag === "" ? void 0 : tag;
270
+ }
271
+ function parseVersionCore(tag) {
272
+ if (typeof tag !== "string") return null;
273
+ const stripped = tag.trim().replace(/^v/i, "");
274
+ if (stripped === "") return null;
275
+ const core = stripped.split("-")[0];
276
+ const parts = core.split(".");
277
+ const nums = [];
278
+ for (const p of parts) {
279
+ if (!/^\d+$/.test(p)) return null;
280
+ nums.push(Number(p));
281
+ }
282
+ return nums.length > 0 ? nums : null;
283
+ }
284
+ function compareVersionTags(a, b) {
285
+ const ca = parseVersionCore(a);
286
+ const cb = parseVersionCore(b);
287
+ if (!ca || !cb) return null;
288
+ const len = Math.max(ca.length, cb.length);
289
+ for (let i = 0; i < len; i++) {
290
+ const x = ca[i] ?? 0;
291
+ const y = cb[i] ?? 0;
292
+ if (x < y) return -1;
293
+ if (x > y) return 1;
294
+ }
295
+ return 0;
296
+ }
297
+ var REQUIRED_IMAGE_LABELS = Object.freeze([
298
+ "org.opencontainers.image.version",
299
+ "org.opencontainers.image.revision"
300
+ ]);
301
+ function evaluateService(spec, facts = {}, options = {}) {
302
+ const refuse = (reason) => ({ ok: false, service: spec.key, reason });
303
+ const sourceName = spec.sourceImageName ?? spec.imageName;
304
+ const commitName = spec.commitImageName ?? sourceName;
305
+ if (facts.deployed?.ref) {
306
+ const deployedTag = tagOf(facts.deployed.ref);
307
+ const deployedVersion = facts.deployed.versionLabel?.trim();
308
+ if (!deployedTag || !deployedVersion) {
309
+ const missing = [
310
+ !deployedVersion ? "no org.opencontainers.image.version label" : null,
311
+ !deployedTag ? "matches no release tag (bare digest)" : null
312
+ ].filter(Boolean).join(" and ");
313
+ return refuse(
314
+ `deployed image ${facts.deployed.ref} has ${missing}; provenance unresolved. Trace the running image and cut a real release before ${spec.key} can be manifest-governed. Re-pinning it to a tag we cannot prove it came from would be a change of unknown scope.`
315
+ );
316
+ }
317
+ }
318
+ if (spec.origin === "upstream-pinned") {
319
+ if (!spec.pinnedImage) {
320
+ return refuse(
321
+ `upstream-pinned service declares no pinnedImage. Third-party artifacts are not tag-resolved, so their digest pin must be stated in STACK_SERVICE_SPECS and changed by code review.`
322
+ );
323
+ }
324
+ if (!isDigestPinned(spec.pinnedImage)) {
325
+ return refuse(
326
+ `upstream pin "${spec.pinnedImage}" is not digest-pinned. Tags move, digests do not \u2014 pin third-party images by @sha256 digest.`
327
+ );
328
+ }
329
+ const prev = facts.previousImageRef;
330
+ if (prev && !options.allowDowngrade?.includes(spec.key)) {
331
+ const cmp = compareVersionTags(tagOf(spec.pinnedImage), tagOf(prev));
332
+ if (cmp === -1) {
333
+ return refuse(
334
+ `DOWNGRADE REFUSED: upstream pin ${tagOf(spec.pinnedImage)} is LOWER than the currently pinned ${tagOf(prev)}. Roll third-party images backwards only with an explicit, named --allow-downgrade ${spec.key}.`
335
+ );
336
+ }
337
+ }
338
+ return { ok: true, service: spec.key, image: spec.pinnedImage, version: tagOf(spec.pinnedImage) };
339
+ }
340
+ if (!spec.ghRepo) {
341
+ return refuse(
342
+ `no source repo identified \u2014 ${spec.key} is deployed from ${spec.imageName} but no repository in the AskExe org builds it. Identify (or create) the source repo and cut a tagged release. This is a block, not an exemption: the repo name must not be guessed.`
343
+ );
344
+ }
345
+ if (spec.releaseLane === "none") {
346
+ return refuse(
347
+ `not wired into the release lane \u2014 ${spec.ghRepo} builds ${spec.imageName}, but only as floating refs (:main / :sha-<sha>) with no version stamp, and no release descriptor references it. There is no released artifact to pin. Give its workflow a versioned tag plus org.opencontainers.image.version/.revision stamps and add it to the release descriptor.`
348
+ );
349
+ }
350
+ if (!facts.latestTag) {
351
+ return refuse(
352
+ `no release tag found for ${spec.ghRepo}. The manifest pins released versions only \u2014 tag a release before this service can be manifest-governed.`
353
+ );
354
+ }
355
+ if (!facts.tagCommit) {
356
+ return refuse(
357
+ `could not resolve ${spec.ghRepo}@${facts.latestTag} to a commit. Provenance is anchored to the COMMIT a tag names, never to the tag string, so an unresolvable tag cannot be pinned.`
358
+ );
359
+ }
360
+ const resolvedDigest = facts.digestByCommit ?? facts.digestByTag;
361
+ if (!resolvedDigest || !/^sha256:[0-9a-f]{64}$/i.test(resolvedDigest)) {
362
+ return refuse(
363
+ `no resolvable image for release ${facts.latestTag}: neither ${commitName}:sha-${facts.tagCommit} (commit-addressed) nor ${sourceName}:${facts.latestTag} could be resolved to a digest. A release with no artifact cannot be deployed \u2014 fix the release workflow rather than hand-pinning an older image.`
364
+ );
365
+ }
366
+ if (facts.digestByTag && facts.digestByCommit && facts.digestByTag.toLowerCase() !== facts.digestByCommit.toLowerCase()) {
367
+ return refuse(
368
+ `TAG/COMMIT MISMATCH: the image tagged ${facts.latestTag} is ${facts.digestByTag}, but the image built from the commit that tag names (${facts.tagCommit}) is ${facts.digestByCommit}. The image called ${facts.latestTag} was not built from the commit called ${facts.latestTag}. A version tag in this registry is not provenance \u2014 refusing to pin either until the release workflow is fixed so the two agree.`
369
+ );
370
+ }
371
+ const missingLabels = REQUIRED_IMAGE_LABELS.filter((l) => !facts.labels?.[l]?.trim());
372
+ if (missingLabels.length > 0) {
373
+ return refuse(
374
+ `image ${sourceName}@${resolvedDigest} is missing ${missingLabels.join(" and ")}. An unlabelled image is an unreproducible build \u2014 it cannot prove which source it was built from.`
375
+ );
376
+ }
377
+ const norm = (v) => (v ?? "").trim().toLowerCase();
378
+ const claimed = norm(facts.imageCommit);
379
+ const expected = norm(facts.tagCommit);
380
+ const prefixLen = Math.min(claimed.length, expected.length);
381
+ if (!claimed || prefixLen < 7 || claimed.slice(0, prefixLen) !== expected.slice(0, prefixLen)) {
382
+ return refuse(
383
+ claimed ? `image ${resolvedDigest} says it was built from commit ${facts.imageCommit}, but ${facts.latestTag} is commit ${facts.tagCommit}. The artifact's own record contradicts the release it would be pinned as.` : `image ${resolvedDigest} carries no source-commit label, so nothing corroborates that it was built from ${facts.tagCommit}. Unverified provenance fails closed.`
384
+ );
385
+ }
386
+ if (facts.commitIsAncestorOfTag !== true) {
387
+ return refuse(
388
+ facts.commitIsAncestorOfTag === false ? `commit ${facts.tagCommit} is NOT an ancestor of ${spec.ghRepo}@${facts.latestTag} \u2014 the image was built from code outside that release's history.` : `could not verify that commit ${facts.tagCommit} is an ancestor of ${spec.ghRepo}@${facts.latestTag}. An unverifiable ancestry is not a passing ancestry \u2014 fail closed.`
389
+ );
390
+ }
391
+ const image = `${spec.imageName}:${facts.latestTag}@${resolvedDigest}`;
392
+ if (facts.previousImageRef && !options.allowDowngrade?.includes(spec.key)) {
393
+ const previousTag = tagOf(facts.previousImageRef);
394
+ const cmp = compareVersionTags(facts.latestTag, previousTag);
395
+ if (cmp === -1) {
396
+ return refuse(
397
+ `DOWNGRADE REFUSED: candidate ${facts.latestTag} is LOWER than the currently pinned ${previousTag}. Applying it would roll ${spec.key} backwards. If that is genuinely intended, re-run with an explicit --allow-downgrade ${spec.key}.`
398
+ );
399
+ }
400
+ if (cmp === null) {
401
+ return refuse(
402
+ `cannot order candidate ${facts.latestTag} against the currently pinned ${previousTag ?? "(untagged)"}, so a downgrade cannot be ruled out. Fail-closed: re-run with --allow-downgrade ${spec.key} only after confirming by hand that this is a roll-forward.`
403
+ );
404
+ }
405
+ }
406
+ return {
407
+ ok: true,
408
+ service: spec.key,
409
+ image,
410
+ version: facts.labels?.["org.opencontainers.image.version"],
411
+ revision: facts.labels?.["org.opencontainers.image.revision"]
412
+ };
413
+ }
414
+ var ManifestGenerationRefused = class extends Error {
415
+ refusals;
416
+ constructor(refusals) {
417
+ super(
418
+ `Manifest generation REFUSED \u2014 ${refusals.length} service(s) failed the fail-closed guards. No manifest was written (a partial manifest is never emitted):
419
+ ` + refusals.map((r) => ` \u2717 ${r.service}: ${r.reason}`).join("\n")
420
+ );
421
+ this.name = "ManifestGenerationRefused";
422
+ this.refusals = refusals;
423
+ }
424
+ };
425
+ function generateStackServices(specs, factsByKey, options = {}) {
426
+ const services = {};
427
+ const resolved = [];
428
+ const refusals = [];
429
+ for (const spec of stackServiceSpecs(specs)) {
430
+ const verdict = evaluateService(spec, factsByKey[spec.key] ?? {}, options);
431
+ if (!verdict.ok) {
432
+ refusals.push({ service: verdict.service, reason: verdict.reason });
433
+ continue;
434
+ }
435
+ const entry = { image: verdict.image };
436
+ if (spec.env) entry.env = spec.env;
437
+ if (spec.composeServices[0]) entry.composeService = spec.composeServices[0];
438
+ if (spec.healthUrl) entry.healthUrl = spec.healthUrl;
439
+ if (spec.healthHost) entry.healthHost = spec.healthHost;
440
+ if (spec.required !== void 0) entry.required = spec.required;
441
+ if (spec.category) entry.category = spec.category;
442
+ if (spec.description) entry.description = spec.description;
443
+ if (verdict.revision) entry.gitSha = verdict.revision;
444
+ services[spec.key] = entry;
445
+ resolved.push({ service: spec.key, image: verdict.image });
446
+ }
447
+ if (refusals.length > 0) throw new ManifestGenerationRefused(refusals);
448
+ return { services, resolved };
449
+ }
450
+ function extractComposeImagePins(composeYaml) {
451
+ const lines = composeYaml.split("\n");
452
+ const pins = [];
453
+ let inServices = false;
454
+ let current;
455
+ for (const line of lines) {
456
+ if (/^services:\s*$/.test(line)) {
457
+ inServices = true;
458
+ continue;
459
+ }
460
+ if (/^[a-zA-Z_-]+:\s*$/.test(line)) {
461
+ inServices = /^services:/.test(line);
462
+ current = void 0;
463
+ continue;
464
+ }
465
+ if (!inServices) continue;
466
+ const svc = line.match(/^ {2}([A-Za-z0-9._-]+):\s*$/);
467
+ if (svc) {
468
+ current = svc[1];
469
+ continue;
470
+ }
471
+ const img = line.match(/^\s+image:\s*(.+?)\s*$/);
472
+ if (img && current) {
473
+ const raw = img[1];
474
+ const envMatch = raw.match(/\$\{([A-Za-z_][A-Za-z0-9_]*)/);
475
+ pins.push({ service: current, envVar: envMatch?.[1], raw });
476
+ }
477
+ }
478
+ return pins;
479
+ }
480
+ function assertServiceCoverage(pins, specs = STACK_SERVICE_SPECS) {
481
+ const byComposeService = /* @__PURE__ */ new Set();
482
+ const byEnv = /* @__PURE__ */ new Set();
483
+ for (const spec of specs) {
484
+ for (const cs of spec.composeServices) byComposeService.add(cs);
485
+ if (spec.env) byEnv.add(spec.env);
486
+ }
487
+ const gaps = [];
488
+ for (const pin of pins) {
489
+ if (/^\$\{[A-Za-z_][A-Za-z0-9_]*:-\}$/.test(pin.raw.trim())) continue;
490
+ const covered = byComposeService.has(pin.service) || pin.envVar !== void 0 && byEnv.has(pin.envVar);
491
+ if (!covered) {
492
+ gaps.push({
493
+ service: pin.service,
494
+ envVar: pin.envVar,
495
+ reason: `compose deploys an image for "${pin.service}"${pin.envVar ? ` (pinned by ${pin.envVar})` : ""} but no STACK_SERVICE_SPECS entry governs it`
496
+ });
497
+ }
498
+ }
499
+ if (gaps.length > 0) {
500
+ throw new Error(
501
+ `Stack manifest coverage GAP \u2014 ${gaps.length} deployed service(s) are not manifest-governed. A manifest that silently omits a running service is the exact failure mode being eliminated. Add an entry to STACK_SERVICE_SPECS for each:
502
+ ` + gaps.map((g) => ` \u2717 ${g.reason}`).join("\n")
503
+ );
504
+ }
505
+ }
506
+ function nextStackVersion(latest) {
507
+ const parts = latest.split(".").map((p) => Number(p));
508
+ if (parts.length !== 3 || parts.some((n) => !Number.isFinite(n))) {
509
+ throw new Error(`Cannot derive the next stack version from latest="${latest}" (expected x.y.z).`);
510
+ }
511
+ return `${parts[0]}.${parts[1]}.${(parts[2] ?? 0) + 1}`;
512
+ }
513
+ function previousImageRefs(manifest) {
514
+ const entry = manifest.stacks?.[manifest.latest];
515
+ const out = {};
516
+ for (const [key, svc] of Object.entries(entry?.services ?? {})) {
517
+ if (typeof svc?.image === "string") out[key] = svc.image;
518
+ }
519
+ return out;
520
+ }
521
+ function buildStackEntry(input) {
522
+ return {
523
+ version: input.version,
524
+ releasedAt: input.releasedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
525
+ notes: input.notes ?? `Generated from published releases by stack-generate-manifest.`,
526
+ ...input.npmVersion ? { npmVersion: input.npmVersion } : {},
527
+ breakingChanges: [],
528
+ services: input.services,
529
+ rolloutStage: input.canary ? "canary" : "ga"
530
+ };
531
+ }
532
+
533
+ // src/bin/stack-generate-manifest.ts
534
+ var execFile = promisify(execFileCb);
535
+ function repoRoot() {
536
+ let dir = path.dirname(new URL(import.meta.url).pathname);
537
+ for (let i = 0; i < 6; i++) {
538
+ if (existsSync(path.join(dir, "deploy", "stack-manifests", "v0.9.json"))) return dir;
539
+ dir = path.dirname(dir);
540
+ }
541
+ return process.cwd();
542
+ }
543
+ function parseGenerateArgs(argv, root = repoRoot()) {
544
+ const opts = {
545
+ manifestPath: path.join(root, "deploy", "stack-manifests", "v0.9.json"),
546
+ composePath: path.join(root, "deploy", "compose", "docker-compose.yml"),
547
+ allowDowngrade: [],
548
+ canary: false,
549
+ dryRun: false
550
+ };
551
+ for (let i = 0; i < argv.length; i++) {
552
+ const arg = argv[i];
553
+ const take = () => argv[++i] ?? "";
554
+ if (arg === "--manifest") opts.manifestPath = take();
555
+ else if (arg === "--compose") opts.composePath = take();
556
+ else if (arg === "--stack-version") opts.stackVersion = take();
557
+ else if (arg === "--allow-downgrade") opts.allowDowngrade.push(take());
558
+ else if (arg.startsWith("--allow-downgrade=")) opts.allowDowngrade.push(arg.slice("--allow-downgrade=".length));
559
+ else if (arg === "--deployed-state") opts.deployedStatePath = take();
560
+ else if (arg === "--notes") opts.notes = take();
561
+ else if (arg === "--canary") opts.canary = true;
562
+ else if (arg === "--dry-run") opts.dryRun = true;
563
+ }
564
+ return opts;
565
+ }
566
+ async function run(cmd, args) {
567
+ try {
568
+ const { stdout } = await execFile(cmd, args, { maxBuffer: 16 * 1024 * 1024 });
569
+ return { ok: true, stdout: stdout.toString().trim() };
570
+ } catch {
571
+ return { ok: false, stdout: "" };
572
+ }
573
+ }
574
+ var MAX_TAG_PROBES = 50;
575
+ async function tagCreatorEmail(ghRepo, tag) {
576
+ const ref = await run("gh", [
577
+ "api",
578
+ `repos/${ghRepo}/git/refs/tags/${tag}`,
579
+ "--jq",
580
+ ".object.sha,.object.type"
581
+ ]);
582
+ if (!ref.ok) return void 0;
583
+ const [sha, type] = ref.stdout.split("\n").map((v) => v.trim());
584
+ if (!sha) return void 0;
585
+ const res = type === "tag" ? await run("gh", ["api", `repos/${ghRepo}/git/tags/${sha}`, "--jq", ".tagger.email"]) : await run("gh", ["api", `repos/${ghRepo}/git/commits/${sha}`, "--jq", ".author.email"]);
586
+ return res.ok && res.stdout.trim() !== "" ? res.stdout.trim() : void 0;
587
+ }
588
+ async function fetchLatestTag(ghRepo) {
589
+ const { inReleaseNamespace, isOurIdentity } = await import("./ref-provenance-gate-M4AQO4OT.js");
590
+ const res = await run("gh", [
591
+ "api",
592
+ `repos/${ghRepo}/git/refs/tags`,
593
+ "--paginate",
594
+ "--jq",
595
+ ".[].ref"
596
+ ]);
597
+ if (!res.ok) return void 0;
598
+ const candidates = res.stdout.split("\n").map((r) => r.trim().replace(/^refs\/tags\//, "")).filter((t) => t !== "" && inReleaseNamespace(t) && !t.startsWith("stack-v")).sort((a, b) => compareVersionTags(a, b) ?? 0).reverse();
599
+ for (const tag of candidates.slice(0, MAX_TAG_PROBES)) {
600
+ if (isOurIdentity(await tagCreatorEmail(ghRepo, tag))) return tag;
601
+ }
602
+ return void 0;
603
+ }
604
+ async function resolveTagCommit(ghRepo, tag) {
605
+ const res = await run("gh", [
606
+ "api",
607
+ `repos/${ghRepo}/git/refs/tags/${tag}`,
608
+ "--jq",
609
+ ".object.sha,.object.type"
610
+ ]);
611
+ if (!res.ok) return void 0;
612
+ const [sha, type] = res.stdout.split("\n").map((v) => v.trim());
613
+ if (!sha) return void 0;
614
+ if (type !== "tag") return sha;
615
+ const deref = await run("gh", ["api", `repos/${ghRepo}/git/tags/${sha}`, "--jq", ".object.sha"]);
616
+ return deref.ok && deref.stdout.trim() !== "" ? deref.stdout.trim() : void 0;
617
+ }
618
+ async function commitIsAncestorOfTag(ghRepo, commit, tag) {
619
+ const res = await run("gh", [
620
+ "api",
621
+ `repos/${ghRepo}/compare/${tag}...${commit}`,
622
+ "--jq",
623
+ ".status"
624
+ ]);
625
+ if (!res.ok) return void 0;
626
+ const status = res.stdout.trim();
627
+ if (status === "identical" || status === "behind") return true;
628
+ if (status === "ahead" || status === "diverged") return false;
629
+ return void 0;
630
+ }
631
+ async function resolveImageDigest(ref) {
632
+ const res = await run("docker", ["buildx", "imagetools", "inspect", ref]);
633
+ if (!res.ok) return void 0;
634
+ const match = res.stdout.match(/^\s*Digest:\s*(sha256:[0-9a-f]{64})\s*$/m);
635
+ return match?.[1];
636
+ }
637
+ async function readProvenanceLabels(ref) {
638
+ const { resolveImageLabels } = await import("./resolve-image-labels-ZI6UBW5W.js");
639
+ return resolveImageLabels(ref, [
640
+ "org.opencontainers.image.version",
641
+ "org.opencontainers.image.revision",
642
+ "org.exe.git_sha"
643
+ ]);
644
+ }
645
+ function loadDeployedState(filePath) {
646
+ if (!filePath) return {};
647
+ if (!existsSync(filePath)) {
648
+ throw new Error(`--deployed-state file not found: ${filePath}`);
649
+ }
650
+ return JSON.parse(readFileSync(filePath, "utf8"));
651
+ }
652
+ async function gatherFacts(spec, previous, deployed) {
653
+ const facts = {
654
+ previousImageRef: previous[spec.key],
655
+ deployed: deployed[spec.key]
656
+ };
657
+ if (spec.origin === "upstream-pinned" || !spec.ghRepo || spec.releaseLane === "none") return facts;
658
+ facts.latestTag = await fetchLatestTag(spec.ghRepo);
659
+ if (!facts.latestTag) return facts;
660
+ facts.tagCommit = await resolveTagCommit(spec.ghRepo, facts.latestTag);
661
+ if (!facts.tagCommit) return facts;
662
+ const source = spec.sourceImageName ?? spec.imageName;
663
+ const commitSource = spec.commitImageName ?? source;
664
+ facts.digestByCommit = await resolveImageDigest(`${commitSource}:sha-${facts.tagCommit}`);
665
+ facts.digestByTag = await resolveImageDigest(`${source}:${facts.latestTag}`);
666
+ const resolved = facts.digestByCommit ?? facts.digestByTag;
667
+ if (!resolved) return facts;
668
+ facts.labels = await readProvenanceLabels(
669
+ `${facts.digestByCommit ? commitSource : source}@${resolved}`
670
+ );
671
+ facts.imageCommit = facts.labels["org.exe.git_sha"] ?? facts.labels["org.opencontainers.image.revision"];
672
+ facts.commitIsAncestorOfTag = await commitIsAncestorOfTag(
673
+ spec.ghRepo,
674
+ facts.tagCommit,
675
+ facts.latestTag
676
+ );
677
+ return facts;
678
+ }
679
+ function printUsage() {
680
+ console.log(`
681
+ Usage: exe-os stack-generate-manifest [options]
682
+
683
+ Generate the stack manifest from each repo's latest PUBLISHED release. The
684
+ manifest is the single source of truth: the VPS and the live site pull only
685
+ from it, .env is derived from it, and compose carries no fallback defaults.
686
+
687
+ Options:
688
+ --manifest <path> Manifest to update (default deploy/stack-manifests/v0.9.json)
689
+ --compose <path> Compose file whose deployed surface must be fully covered
690
+ --stack-version <x.y.z> Version for the new entry (default: patch-bump of latest)
691
+ --deployed-state <path> JSON snapshot of what production runs (enables the
692
+ deployed-provenance guard)
693
+ --allow-downgrade <svc> Explicitly permit ONE named service to move backwards.
694
+ Repeatable. The only override \u2014 it cannot manufacture
695
+ provenance for a missing repo, label, or digest.
696
+ --notes <text> Release notes for the entry
697
+ --canary Publish without bumping manifest.latest
698
+ --dry-run Resolve and report; write nothing
699
+ --help Show this message
700
+
701
+ FAIL-CLOSED: the run REFUSES (and writes nothing) when a repo has no published
702
+ release, a release has no published image, a digest cannot be resolved, an image
703
+ lacks org.opencontainers.image.version/.revision, a candidate is LOWER than the
704
+ current pin, or compose deploys a service the roster does not govern.
705
+ `);
706
+ }
707
+ async function runStackGenerateManifestCli(argv) {
708
+ if (argv.includes("--help") || argv.includes("-h")) {
709
+ printUsage();
710
+ return 0;
711
+ }
712
+ const opts = parseGenerateArgs(argv);
713
+ if (!existsSync(opts.manifestPath)) {
714
+ console.error(`[stack-generate-manifest] Manifest not found: ${opts.manifestPath}`);
715
+ return 1;
716
+ }
717
+ const manifest = JSON.parse(readFileSync(opts.manifestPath, "utf8"));
718
+ if (existsSync(opts.composePath)) {
719
+ try {
720
+ assertServiceCoverage(extractComposeImagePins(readFileSync(opts.composePath, "utf8")));
721
+ } catch (err) {
722
+ console.error(`[stack-generate-manifest] ${err instanceof Error ? err.message : String(err)}`);
723
+ return 1;
724
+ }
725
+ } else {
726
+ console.warn(`[stack-generate-manifest] compose file not found (${opts.composePath}) \u2014 coverage NOT verified.`);
727
+ }
728
+ const previous = previousImageRefs(manifest);
729
+ let deployed;
730
+ try {
731
+ deployed = loadDeployedState(opts.deployedStatePath);
732
+ } catch (err) {
733
+ console.error(`[stack-generate-manifest] ${err instanceof Error ? err.message : String(err)}`);
734
+ return 1;
735
+ }
736
+ const specs = stackServiceSpecs(STACK_SERVICE_SPECS);
737
+ const factsByKey = {};
738
+ for (const spec of specs) {
739
+ process.stderr.write(`[stack-generate-manifest] resolving ${spec.key}\u2026
740
+ `);
741
+ factsByKey[spec.key] = await gatherFacts(spec, previous, deployed);
742
+ }
743
+ let services;
744
+ let resolved;
745
+ try {
746
+ ({ services, resolved } = generateStackServices(specs, factsByKey, {
747
+ allowDowngrade: opts.allowDowngrade
748
+ }));
749
+ } catch (err) {
750
+ if (err instanceof ManifestGenerationRefused) {
751
+ console.error(`
752
+ [stack-generate-manifest] ${err.message}
753
+ `);
754
+ console.error(
755
+ `[stack-generate-manifest] Nothing was written. Fix the provenance above (or, for a genuine roll-back only, re-run with an explicit --allow-downgrade <service>).`
756
+ );
757
+ return 1;
758
+ }
759
+ throw err;
760
+ }
761
+ const version = opts.stackVersion ?? nextStackVersion(manifest.latest);
762
+ const entry = buildStackEntry({
763
+ version,
764
+ services,
765
+ notes: opts.notes,
766
+ npmVersion: readNpmVersion(),
767
+ canary: opts.canary
768
+ });
769
+ console.log(`
770
+ [stack-generate-manifest] Resolved ${resolved.length} service(s) for stack ${version}:`);
771
+ for (const r of resolved) console.log(` \u2713 ${r.service.padEnd(20)} ${r.image}`);
772
+ if (opts.dryRun) {
773
+ console.log(`
774
+ [stack-generate-manifest] --dry-run: nothing written.`);
775
+ return 0;
776
+ }
777
+ manifest.stacks[version] = entry;
778
+ if (!opts.canary) manifest.latest = version;
779
+ writeSignedStackManifest(opts.manifestPath, manifest);
780
+ console.log(
781
+ `
782
+ [stack-generate-manifest] \u2713 Wrote stack ${version}${opts.canary ? " (CANARY \u2014 latest unchanged)" : ` (latest -> ${version})`} to ${opts.manifestPath}`
783
+ );
784
+ return 0;
785
+ }
786
+ function readNpmVersion() {
787
+ const pkgPath = path.join(repoRoot(), "package.json");
788
+ if (!existsSync(pkgPath)) return void 0;
789
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
790
+ return pkg.version;
791
+ }
792
+ if (isMainModule(import.meta.url) && process.argv[1]?.includes("stack-generate-manifest")) {
793
+ runStackGenerateManifestCli(process.argv.slice(2)).then((code) => {
794
+ process.exitCode = code;
795
+ }).catch((err) => {
796
+ console.error(`[stack-generate-manifest] Fatal: ${err instanceof Error ? err.message : String(err)}`);
797
+ process.exitCode = 1;
798
+ });
799
+ }
800
+ export {
801
+ commitIsAncestorOfTag,
802
+ fetchLatestTag,
803
+ gatherFacts,
804
+ loadDeployedState,
805
+ parseGenerateArgs,
806
+ readProvenanceLabels,
807
+ resolveImageDigest,
808
+ resolveTagCommit,
809
+ runStackGenerateManifestCli
810
+ };