@askexenow/exe-os 0.9.346 → 0.9.348

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 (316) hide show
  1. package/deploy/compose/cloudflared/config.yml.example +9 -6
  2. package/deploy/compose/docker-compose.yml +16 -9
  3. package/deploy/compose/sso-edge/default.conf.template +26 -0
  4. package/deploy/stack-manifests/v0.9.json +1 -1
  5. package/dist/{active-agent-Y7B6SUEV.js → active-agent-PX6KAEEQ.js} +4 -3
  6. package/dist/{active-agent-JXJFAZMM.js → active-agent-QVLZKWR2.js} +4 -3
  7. package/dist/{agentic-ontology-AUJAVTHS.js → agentic-ontology-6MEXY5L7.js} +1 -1
  8. package/dist/{backfill-metadata-3LUJK7D4.js → backfill-metadata-MCFBGWKX.js} +6 -5
  9. package/dist/{backup-verify-6UAZ5ETR.js → backup-verify-RGB3KKD4.js} +2 -1
  10. package/dist/{behaviors-BVOBYS73.js → behaviors-6GI6VND2.js} +7 -6
  11. package/dist/bin/agentic-ontology-backfill.js +7 -6
  12. package/dist/bin/agentic-reflection-backfill.js +8 -7
  13. package/dist/bin/agentic-semantic-label.js +7 -6
  14. package/dist/bin/backfill-conversations.js +6 -5
  15. package/dist/bin/backfill-responses.js +6 -5
  16. package/dist/bin/backfill-vectors.js +7 -6
  17. package/dist/bin/bulk-sync-postgres.js +11 -10
  18. package/dist/bin/cc-doctor.js +5 -4
  19. package/dist/bin/cleanup-stale-review-tasks.js +16 -15
  20. package/dist/bin/cli.js +16 -16
  21. package/dist/bin/deferred-daemon-restart.js +107 -94
  22. package/dist/bin/exe-agent-config.js +5 -4
  23. package/dist/bin/exe-agent.js +6 -5
  24. package/dist/bin/exe-assign.js +7 -6
  25. package/dist/bin/exe-boot.js +31 -30
  26. package/dist/bin/exe-call.js +6 -5
  27. package/dist/bin/exe-cloud.js +26 -15
  28. package/dist/bin/exe-config-dump.js +5 -4
  29. package/dist/bin/exe-dispatch.js +16 -15
  30. package/dist/bin/exe-doctor.js +5 -4
  31. package/dist/bin/exe-export-behaviors.js +9 -8
  32. package/dist/bin/exe-forget.js +8 -7
  33. package/dist/bin/exe-gateway.js +8 -7
  34. package/dist/bin/exe-healthcheck.js +5 -4
  35. package/dist/bin/exe-heartbeat.js +18 -17
  36. package/dist/bin/exe-kill.js +20 -19
  37. package/dist/bin/exe-launch-agent.js +26 -25
  38. package/dist/bin/exe-memory-reads.js +6 -5
  39. package/dist/bin/exe-new-employee.js +10 -9
  40. package/dist/bin/exe-os-mcp-proxy.js +4 -3
  41. package/dist/bin/exe-pending-messages.js +17 -16
  42. package/dist/bin/exe-pending-notifications.js +16 -15
  43. package/dist/bin/exe-pending-reviews.js +16 -15
  44. package/dist/bin/exe-rename.js +6 -5
  45. package/dist/bin/exe-review.js +19 -18
  46. package/dist/bin/exe-search.js +7 -6
  47. package/dist/bin/exe-session-cleanup.js +20 -19
  48. package/dist/bin/exe-settings.js +13 -12
  49. package/dist/bin/exe-start-codex.js +102 -21
  50. package/dist/bin/exe-start-opencode.js +11 -10
  51. package/dist/bin/exe-status.js +17 -16
  52. package/dist/bin/exe-support.js +3 -3
  53. package/dist/bin/exe-team.js +4 -3
  54. package/dist/bin/git-sweep.js +17 -16
  55. package/dist/bin/graph-backfill.js +7 -6
  56. package/dist/bin/graph-export.js +7 -6
  57. package/dist/bin/import-history.js +10 -9
  58. package/dist/bin/install.js +73 -73
  59. package/dist/bin/intercom-check.js +4 -4
  60. package/dist/bin/mcp-sessions.js +2 -2
  61. package/dist/bin/orchestration-metrics.js +5 -4
  62. package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
  63. package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
  64. package/dist/bin/pre-publish.js +1 -1
  65. package/dist/bin/reconcile-backlog.js +2 -2
  66. package/dist/bin/registry-proxy.js +1 -1
  67. package/dist/bin/scan-tasks.js +16 -15
  68. package/dist/bin/setup.js +2 -2
  69. package/dist/bin/shard-migrate.js +6 -5
  70. package/dist/bin/stack-update.js +7 -6
  71. package/dist/bin/vps-health-gate.js +1 -1
  72. package/dist/{boot-generation-IF4J6UEJ.js → boot-generation-FB2J53IG.js} +4 -3
  73. package/dist/{boot-review-sections-WEEFCSBX.js → boot-review-sections-QF5MZGJI.js} +15 -14
  74. package/dist/{capability-cards-C65NRVTL.js → capability-cards-YADEM2KN.js} +3 -2
  75. package/dist/{capacity-monitor-PGYDR35M.js → capacity-monitor-CG2IGONS.js} +17 -16
  76. package/dist/{catchup-brief-QB7M3OY7.js → catchup-brief-QFVNMTU5.js} +20 -19
  77. package/dist/{chunk-H5RS3XRJ.js → chunk-23O6LHII.js} +1 -1
  78. package/dist/{chunk-RLULWMUL.js → chunk-27REQ7KR.js} +1 -1
  79. package/dist/{chunk-GGPLVRYZ.js → chunk-2AD2GAPC.js} +1 -1
  80. package/dist/{chunk-25CXLXZQ.js → chunk-2WJYLXPF.js} +1 -1
  81. package/dist/{chunk-CFA4T2HP.js → chunk-43RTUMUT.js} +1 -1
  82. package/dist/{chunk-RYTY7KNZ.js → chunk-5C46Y4AK.js} +1 -1
  83. package/dist/{chunk-X7NSCRCD.js → chunk-5KCC26FB.js} +2 -2
  84. package/dist/{chunk-44ZGOBMU.js → chunk-5RPCWLXE.js} +1 -1
  85. package/dist/{chunk-ZASZQDAI.js → chunk-6GSYN262.js} +1 -1
  86. package/dist/{chunk-QS6KVXUN.js → chunk-6JQTSKDR.js} +263 -111
  87. package/dist/{chunk-QCM3YWL7.js → chunk-6QRS3IZF.js} +1 -1
  88. package/dist/{chunk-X2PLFBVG.js → chunk-6WFXNQDJ.js} +1 -1
  89. package/dist/{chunk-LUQ57SRM.js → chunk-7QRMFYOV.js} +23 -9
  90. package/dist/{chunk-HBJAMWHT.js → chunk-7WQ3WHPW.js} +195 -153
  91. package/dist/{chunk-OIF65HXR.js → chunk-A3YHWWE6.js} +10 -6
  92. package/dist/{chunk-OZLNCLS3.js → chunk-A42356G7.js} +1 -1
  93. package/dist/{chunk-24BHZNOP.js → chunk-A43SIGAO.js} +3 -3
  94. package/dist/{chunk-LSTIMHL4.js → chunk-AFY4V4N3.js} +1 -1
  95. package/dist/{chunk-Y7GJ6HXA.js → chunk-AJIXH5JF.js} +79 -25
  96. package/dist/{chunk-EU2GUT67.js → chunk-AMC2OPYP.js} +1 -1
  97. package/dist/{chunk-N4XVAP7Z.js → chunk-AQ24P2O7.js} +4 -4
  98. package/dist/{chunk-KQ3HRA6Q.js → chunk-AUILJKSM.js} +2 -2
  99. package/dist/{chunk-OQB5SKO4.js → chunk-AXNUMBLO.js} +3 -3
  100. package/dist/{chunk-SQIH3TDK.js → chunk-BOQUXG7N.js} +4 -4
  101. package/dist/{chunk-4A6RX2N6.js → chunk-BTP7BORU.js} +1 -1
  102. package/dist/{chunk-LYNELMA2.js → chunk-BUUGFQHL.js} +2 -2
  103. package/dist/{chunk-6OEMGMOV.js → chunk-CCOKYSJA.js} +3 -3
  104. package/dist/{chunk-6F3OMSZJ.js → chunk-DAODOSH4.js} +1 -1
  105. package/dist/{chunk-MWXXVXJL.js → chunk-DJYJDK53.js} +7 -7
  106. package/dist/{chunk-ZK6I3PUX.js → chunk-DXMTJJP3.js} +4 -4
  107. package/dist/{chunk-CMTS2MLG.js → chunk-E3BNUQHW.js} +2 -2
  108. package/dist/{chunk-YKIQF6EY.js → chunk-EFHGK6JP.js} +1 -1
  109. package/dist/{chunk-Q6ZQIX7L.js → chunk-FE6WBI2M.js} +5 -1
  110. package/dist/{chunk-6YABSGAW.js → chunk-FENYNW52.js} +1 -1
  111. package/dist/{chunk-4KLQ4GH5.js → chunk-FFCPSPNK.js} +1 -1
  112. package/dist/{chunk-FEIACXDV.js → chunk-FPK753IZ.js} +16 -16
  113. package/dist/{chunk-NCMFMJMZ.js → chunk-GA655CUD.js} +2 -2
  114. package/dist/{chunk-BDFRAQG5.js → chunk-GJ6KIHOM.js} +4 -4
  115. package/dist/{chunk-CR7XPLLC.js → chunk-GKNWKQFY.js} +1 -1
  116. package/dist/{chunk-VQLGFSML.js → chunk-GLOWJP5H.js} +2 -2
  117. package/dist/{chunk-XTGZDP2L.js → chunk-H3TA23PH.js} +4 -4
  118. package/dist/{chunk-GGHH54QD.js → chunk-H5QNVWU4.js} +18 -10
  119. package/dist/{chunk-WKUX5PFV.js → chunk-HL24OHHS.js} +9 -9
  120. package/dist/{chunk-3WELJGZN.js → chunk-HYZE3MNS.js} +1 -1
  121. package/dist/{chunk-HVZKJMJX.js → chunk-JORPYG4O.js} +1 -1
  122. package/dist/{chunk-JNEVNS5R.js → chunk-JW5XS35A.js} +9 -9
  123. package/dist/{chunk-OM2XM5HU.js → chunk-KIMAQNSM.js} +3 -3
  124. package/dist/{chunk-TIZE727O.js → chunk-KZUU6MNF.js} +1 -1
  125. package/dist/{chunk-OELDRRCZ.js → chunk-L36RX54F.js} +104 -11
  126. package/dist/{chunk-ZZQ4AEYB.js → chunk-M7PBRIRH.js} +1 -1
  127. package/dist/{chunk-4JDRUXQV.js → chunk-MGMXYI7Y.js} +2 -2
  128. package/dist/{chunk-4BQYN4IJ.js → chunk-MH5HWMVH.js} +1 -1
  129. package/dist/{chunk-BUDVHNV2.js → chunk-MMOONM6D.js} +1 -1
  130. package/dist/{chunk-CQN4IKRB.js → chunk-MMXIE6HV.js} +1 -1
  131. package/dist/{chunk-LNMTCTSH.js → chunk-MOZY4IQO.js} +1 -1
  132. package/dist/{chunk-EYGMCOTV.js → chunk-MVZLF27P.js} +2 -2
  133. package/dist/{chunk-HMVGXC4I.js → chunk-NY6DU5RB.js} +1 -1
  134. package/dist/{chunk-WMJK4GBF.js → chunk-O522M4YZ.js} +1 -1
  135. package/dist/{chunk-EDC57TDH.js → chunk-OBWIVRD6.js} +1 -1
  136. package/dist/{chunk-Q7UHMUCE.js → chunk-PAXAF2UY.js} +35 -15
  137. package/dist/{chunk-YLLUGK6J.js → chunk-PBLDPW4U.js} +2 -2
  138. package/dist/{chunk-D74XYSA3.js → chunk-QCQT5RXR.js} +5 -1
  139. package/dist/{chunk-3QYE5U6D.js → chunk-QNKR7WEL.js} +20 -6
  140. package/dist/{chunk-E6TLQG2T.js → chunk-RBRGSOK5.js} +1 -1
  141. package/dist/{chunk-6I6OMBYY.js → chunk-RFRUDXOI.js} +2 -2
  142. package/dist/{chunk-MHZAUM7G.js → chunk-SLH2743O.js} +3 -3
  143. package/dist/{chunk-LP6EJVVN.js → chunk-SMQ642D3.js} +4 -4
  144. package/dist/{chunk-BCFWDNH7.js → chunk-SQ4WACH4.js} +1 -1
  145. package/dist/{chunk-6LLDY7AL.js → chunk-TF5E6O5Q.js} +1 -1
  146. package/dist/{chunk-IXIQSWHV.js → chunk-TLWYOMSS.js} +3 -3
  147. package/dist/{chunk-2LC2ASCN.js → chunk-UAKGNQWE.js} +1 -1
  148. package/dist/{chunk-2WEUQWFQ.js → chunk-UTQWVRU6.js} +5 -5
  149. package/dist/{chunk-VPY4CMD6.js → chunk-WL3IQJKN.js} +3 -3
  150. package/dist/{chunk-NGP6LSV2.js → chunk-WNBZJSQT.js} +10 -1
  151. package/dist/{chunk-MCZWZEVE.js → chunk-WUMWXU6B.js} +1 -1
  152. package/dist/{chunk-R6C6UGVG.js → chunk-WWT3E7DO.js} +3 -3
  153. package/dist/{chunk-ACYZER3P.js → chunk-WZJ3VYRJ.js} +3 -3
  154. package/dist/{chunk-2KOQKLDF.js → chunk-X6VEQ7MC.js} +1 -1
  155. package/dist/{chunk-HXIBVZC3.js → chunk-Y3JXLIZV.js} +3 -3
  156. package/dist/{chunk-2UA263BM.js → chunk-YAIFZXOM.js} +5 -5
  157. package/dist/{chunk-YGTKGAWM.js → chunk-YM6GJM2F.js} +4 -4
  158. package/dist/chunk-YMUZWC33.js +8 -0
  159. package/dist/{chunk-DKKMBEU6.js → chunk-YTPCJLEL.js} +1 -1
  160. package/dist/{chunk-RPAMFCPP.js → chunk-Z52QQB4Z.js} +2 -2
  161. package/dist/{chunk-PJOHJ7Q4.js → chunk-ZXSFUR77.js} +172 -35
  162. package/dist/{cleanup-graph-garbage-INHZJESS.js → cleanup-graph-garbage-XTSBQXD6.js} +8 -7
  163. package/dist/{cloud-sync-shutdown-HNQ7T3LA.js → cloud-sync-shutdown-A2QB74YM.js} +3 -2
  164. package/dist/{co-activation-IMZM3IXG.js → co-activation-S2FVGMQP.js} +3 -2
  165. package/dist/{co-occurrence-PZAEUDAP.js → co-occurrence-VQB6U5ME.js} +6 -5
  166. package/dist/{conversation-entity-extractor-AU55E6YT.js → conversation-entity-extractor-YF3ZLTEJ.js} +3 -3
  167. package/dist/{crdt-sync-LI6FL3DG.js → crdt-sync-2SGCDWC3.js} +1 -1
  168. package/dist/{crm-webhook-NOLMWTAP.js → crm-webhook-P64SXEHD.js} +2 -2
  169. package/dist/{cto-delegation-gate-SZCLR4PI.js → cto-delegation-gate-6KLGT2LB.js} +15 -14
  170. package/dist/{daemon-orchestration-R5HT252K.js → daemon-orchestration-JQGKEWPD.js} +20 -20
  171. package/dist/{dispatch-ack-VUGMAGNL.js → dispatch-ack-AZL3WKCK.js} +1 -2
  172. package/dist/{doc-graph-extractor-E5SXO6NZ.js → doc-graph-extractor-DCJMATVZ.js} +6 -5
  173. package/dist/{documents-PYKWTZBA.js → documents-7EPH3VPE.js} +7 -6
  174. package/dist/{dreaming-JAHOTVRJ.js → dreaming-O4P2W5E5.js} +19 -18
  175. package/dist/{exe-drift-DGIY5YBT.js → exe-drift-ED7FBS2C.js} +4 -3
  176. package/dist/{exe-export-A6MC7LZ7.js → exe-export-YJI4USGZ.js} +9 -8
  177. package/dist/{exe-import-HKA6LKHC.js → exe-import-SUTAYKUW.js} +9 -8
  178. package/dist/{exe-key-6QXOAVR4.js → exe-key-CRSDAOZD.js} +71 -71
  179. package/dist/{exe-snapshot-BUPXYKMH.js → exe-snapshot-KB4YYDCA.js} +20 -19
  180. package/dist/{fast-db-init-BXLBA6II.js → fast-db-init-3K2PV6GJ.js} +1 -1
  181. package/dist/{founder-context-5KQR3ER3.js → founder-context-JHHFM4GF.js} +2 -2
  182. package/dist/gateway/index.js +9 -8
  183. package/dist/{git-main-guard-UZP3KXYI.js → git-main-guard-TGK3RQY3.js} +1 -1
  184. package/dist/{git-staleness-OTIXXNBN.js → git-staleness-YPHGWE3B.js} +3 -2
  185. package/dist/{global-procedures-ACYUMLIG.js → global-procedures-PEWDBSPJ.js} +5 -4
  186. package/dist/{graph-auto-extract-QWVENG4K.js → graph-auto-extract-7OJYYV4G.js} +6 -5
  187. package/dist/{graph-rag-2I24BQC2.js → graph-rag-YFITUAVO.js} +3 -3
  188. package/dist/{hook-prefetch-22IJRGX4.js → hook-prefetch-O6ZCZCTX.js} +16 -15
  189. package/dist/hooks/bug-report-worker.js +18 -18
  190. package/dist/hooks/codex-stop-task-finalizer.js +19 -19
  191. package/dist/hooks/commit-complete.js +18 -17
  192. package/dist/hooks/error-recall.js +8 -7
  193. package/dist/hooks/exe-heartbeat-hook.js +4 -3
  194. package/dist/hooks/ingest.js +7 -6
  195. package/dist/hooks/instructions-loaded.js +5 -4
  196. package/dist/hooks/manifest.json +19 -19
  197. package/dist/hooks/notification.js +5 -4
  198. package/dist/hooks/post-compact.js +17 -16
  199. package/dist/hooks/post-tool-combined.js +9 -9
  200. package/dist/hooks/pre-compact.js +18 -17
  201. package/dist/hooks/pre-tool-use.js +38 -40
  202. package/dist/hooks/prompt-submit.js +31 -30
  203. package/dist/hooks/session-end.js +22 -21
  204. package/dist/hooks/session-start.js +13 -13
  205. package/dist/hooks/stop.js +21 -20
  206. package/dist/hooks/subagent-stop.js +19 -18
  207. package/dist/hooks/summary-worker.js +22 -21
  208. package/dist/index.js +25 -24
  209. package/dist/{installer-QYXL3HBG.js → installer-3ONNP5JV.js} +6 -5
  210. package/dist/{installer-RWPVEBMJ.js → installer-CY5PN7TN.js} +6 -5
  211. package/dist/{installer-NZ76KPYJ.js → installer-N4QXGINR.js} +6 -5
  212. package/dist/{intercom-queue-TAARE4O7.js → intercom-queue-A52WQOCD.js} +15 -14
  213. package/dist/lib/agent-config.js +2 -2
  214. package/dist/lib/cloud-sync.js +15 -10
  215. package/dist/lib/consolidation.js +8 -7
  216. package/dist/lib/database.js +5 -2
  217. package/dist/lib/db-backup.js +2 -1
  218. package/dist/lib/db-checkpoint-worker.js +9 -0
  219. package/dist/lib/db-read-worker-client.js +21 -8
  220. package/dist/lib/db-read-worker.js +15 -0
  221. package/dist/lib/db-write-worker-client.js +4 -1
  222. package/dist/lib/db-write-worker.js +21 -6
  223. package/dist/lib/db.js +5 -2
  224. package/dist/lib/device-registry.js +1 -1
  225. package/dist/lib/employee-templates.js +6 -5
  226. package/dist/lib/employees.js +3 -2
  227. package/dist/lib/exe-daemon.js +344 -179
  228. package/dist/lib/hybrid-search.js +7 -6
  229. package/dist/lib/identity.js +3 -2
  230. package/dist/lib/license.js +2 -2
  231. package/dist/lib/messaging.js +16 -15
  232. package/dist/lib/registry-proxy.js +1 -1
  233. package/dist/lib/reminders.js +4 -3
  234. package/dist/lib/runtime-table.js +9 -3
  235. package/dist/lib/schedules.js +7 -6
  236. package/dist/lib/session-registry.js +5 -4
  237. package/dist/lib/skill-learning.js +8 -7
  238. package/dist/lib/store.js +6 -5
  239. package/dist/lib/task-router.js +4 -3
  240. package/dist/lib/tasks.js +17 -17
  241. package/dist/lib/tmux-routing.js +15 -14
  242. package/dist/lib/token-spend.js +4 -3
  243. package/dist/{license-gate-CVHDQZJV.js → license-gate-ZRORTAQ2.js} +3 -3
  244. package/dist/{license-sync-72S7BWQY.js → license-sync-CQHBDUQE.js} +2 -2
  245. package/dist/mcp/register-tools.js +70 -70
  246. package/dist/mcp/server.js +71 -71
  247. package/dist/mcp/tools/complete-reminder.js +5 -4
  248. package/dist/mcp/tools/create-reminder.js +5 -4
  249. package/dist/mcp/tools/create-task.js +19 -19
  250. package/dist/mcp/tools/deactivate-behavior.js +9 -8
  251. package/dist/mcp/tools/list-reminders.js +5 -4
  252. package/dist/mcp/tools/list-tasks.js +19 -19
  253. package/dist/mcp/tools/send-message.js +18 -17
  254. package/dist/mcp/tools/update-task.js +18 -18
  255. package/dist/{mcp-http-config-JP3XSY2X.js → mcp-http-config-2A6HKQP5.js} +4 -3
  256. package/dist/{mcp-session-identity-DDAM464U.js → mcp-session-identity-OPRX32H5.js} +15 -14
  257. package/dist/{memory-cards-XJ2JMF3V.js → memory-cards-GFO2CSPV.js} +6 -5
  258. package/dist/{memory-graph-extractor-FJVF7RTG.js → memory-graph-extractor-2Z72HN5P.js} +7 -6
  259. package/dist/{memory-poisoning-defense-GM3GQPRI.js → memory-poisoning-defense-WZJ52KXT.js} +3 -2
  260. package/dist/{memory-pressure-watchdog-HB572OZG.js → memory-pressure-watchdog-IG7VRFIX.js} +16 -15
  261. package/dist/{memory-reflection-WIMMTW7M.js → memory-reflection-LTRHDGUL.js} +3 -2
  262. package/dist/{notification-ledger-5TQXBYY2.js → notification-ledger-KSCPGLQG.js} +16 -15
  263. package/dist/{notifications-LA3X57YT.js → notifications-YKHZPCXU.js} +15 -14
  264. package/dist/{orchestration-events-KFZMGU3D.js → orchestration-events-HAFDPTLV.js} +4 -3
  265. package/dist/{orchestrator-MOJEAZ3K.js → orchestrator-4MZEQULR.js} +17 -16
  266. package/dist/{pipeline-router-2V5NFQ2O.js → pipeline-router-RSRJPZNI.js} +4 -3
  267. package/dist/{plan-limits-2LHFEYOT.js → plan-limits-5QYYPIPT.js} +6 -5
  268. package/dist/{platform-procedures-G44IYUM2.js → platform-procedures-DZ6YABEK.js} +1 -1
  269. package/dist/{projection-worker-ZMHVILPW.js → projection-worker-SKAMSZJF.js} +2 -2
  270. package/dist/{prospective-memory-JEWS5GFU.js → prospective-memory-V7LFCPU4.js} +3 -2
  271. package/dist/{reranker-TBQV76K4.js → reranker-HXMJ7SKW.js} +1 -1
  272. package/dist/{retrieval-health-HYXDUNFE.js → retrieval-health-4NCBHUUS.js} +1 -1
  273. package/dist/{review-polling-OFGP5Q7M.js → review-polling-KQUALBEU.js} +16 -15
  274. package/dist/runtime/index.js +19 -18
  275. package/dist/{session-events-ABAI2KE3.js → session-events-3KL735DZ.js} +16 -15
  276. package/dist/{session-kill-telemetry-2MHLK4Z4.js → session-kill-telemetry-KVRGLYVI.js} +16 -15
  277. package/dist/{session-scope-MRIE7ZKS.js → session-scope-LBG6DT5O.js} +15 -14
  278. package/dist/{setup-wizard-UQ3B2E6D.js → setup-wizard-UL3AKI6E.js} +2 -2
  279. package/dist/{skill-refinement-46QDGAGE.js → skill-refinement-6HPISXQC.js} +4 -3
  280. package/dist/{stack-update-5BPENFJK.js → stack-update-WBDTJJEF.js} +7 -3
  281. package/dist/{steward-gate-GXINMHNV.js → steward-gate-CWPD4HEK.js} +4 -3
  282. package/dist/{support-inbox-TCOASPLK.js → support-inbox-HRIHHKPU.js} +3 -3
  283. package/dist/{task-enforcement-OJAG2BGJ.js → task-enforcement-OAOL7XFL.js} +16 -15
  284. package/dist/{task-scope-5GKJTQL2.js → task-scope-PSVAE3EM.js} +15 -14
  285. package/dist/{tasks-crud-ZWKPTGPU.js → tasks-crud-TLELWWUL.js} +17 -14
  286. package/dist/{tasks-notify-IUDI6SYJ.js → tasks-notify-7Q2XTDZ7.js} +16 -16
  287. package/dist/{tasks-review-INJKVN63.js → tasks-review-S6QB5KGS.js} +15 -14
  288. package/dist/{telemetry-upload-LIC7M7AY.js → telemetry-upload-LTL5SW24.js} +8 -7
  289. package/dist/{token-budget-PABF5ZBO.js → token-budget-SK32GKFZ.js} +4 -3
  290. package/dist/{tool-telemetry-PDHE36YD.js → tool-telemetry-QJGJAHOC.js} +1 -1
  291. package/dist/tui/App.js +24 -23
  292. package/dist/{tui-data-Y6X7A4U4.js → tui-data-3JSV56ME.js} +15 -14
  293. package/dist/{update-support-COJYGU2V.js → update-support-LMPGWJVG.js} +10 -9
  294. package/dist/{work-state-heartbeat-YV3MAIQY.js → work-state-heartbeat-MQQOCU54.js} +1 -1
  295. package/dist/{worker-gate-BLJENHMV.js → worker-gate-P2O64XMH.js} +1 -1
  296. package/dist/{workflow-engine-AAPPPMFS.js → workflow-engine-BLLQKA3O.js} +2 -2
  297. package/dist/{worktree-MGYTWKCA.js → worktree-FJZXHDCJ.js} +5 -4
  298. package/dist/{worktree-sweep-HNNHNAXN.js → worktree-sweep-SW4AG6JR.js} +6 -5
  299. package/package.json +1 -1
  300. package/release-notes.json +56 -104
  301. package/dist/chunk-GSIJL4YA.js +0 -58
  302. /package/dist/{chunk-GH5YKFE7.js → chunk-AQ6ECPUP.js} +0 -0
  303. /package/dist/{chunk-O3XAKSKI.js → chunk-DRHXISWL.js} +0 -0
  304. /package/dist/{chunk-A3MGVYSP.js → chunk-E42D2E5F.js} +0 -0
  305. /package/dist/{chunk-PDN25UJU.js → chunk-FXZRJT3H.js} +0 -0
  306. /package/dist/{chunk-CHDPANT4.js → chunk-GFIWADEH.js} +0 -0
  307. /package/dist/{chunk-W7JPRQM2.js → chunk-GPZQZTJB.js} +0 -0
  308. /package/dist/{chunk-WPQ5LWMW.js → chunk-H4JKOLXU.js} +0 -0
  309. /package/dist/{chunk-RYWVPACG.js → chunk-HTJKAAHD.js} +0 -0
  310. /package/dist/{chunk-PDWIUSQH.js → chunk-PIUDQ7P2.js} +0 -0
  311. /package/dist/{chunk-HIN6X5QB.js → chunk-QUOMJKVF.js} +0 -0
  312. /package/dist/{chunk-DY7WDHMC.js → chunk-XF2D4CDA.js} +0 -0
  313. /package/dist/{core-memory-TBLZ2YQQ.js → core-memory-Z7LPR3RX.js} +0 -0
  314. /package/dist/{oauth-server-IB7OWY4H.js → oauth-server-FSKABATB.js} +0 -0
  315. /package/dist/{project-boot-TI3PUQNN.js → project-boot-FVSC4VQC.js} +0 -0
  316. /package/dist/{wiki-acl-V5IRECJ3.js → wiki-acl-CW2UALTJ.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  loadLicense
3
- } from "./chunk-BUDVHNV2.js";
3
+ } from "./chunk-MMOONM6D.js";
4
4
 
5
5
  // src/lib/stack-update.ts
6
6
  import { execFileSync, spawnSync } from "child_process";
@@ -299,6 +299,8 @@ async function rollbackStackUpdate(options) {
299
299
  } catch {
300
300
  }
301
301
  const backupComposeFile = lockData?.backupComposeFile;
302
+ const backupComposeOverrideFile = lockData?.backupComposeOverrideFile;
303
+ const composeOverrideFile = composeOverrideFileFor(options.composeFile);
302
304
  if (!options.serviceName) {
303
305
  try {
304
306
  if (existsSync(options.composeFile)) {
@@ -307,27 +309,41 @@ async function rollbackStackUpdate(options) {
307
309
  } catch {
308
310
  }
309
311
  if (backupComposeFile && existsSync(backupComposeFile)) {
310
- console.log(
311
- `[stack-update] Keeping current (superset) docker-compose.yml for recovery so newly-added services are not dropped; rolling back image tags via .env. Previous compose preserved at ${backupComposeFile}.`
312
- );
312
+ copyFileSync(backupComposeFile, options.composeFile);
313
+ console.log(`[stack-update] Restored docker-compose.yml from ${backupComposeFile}`);
313
314
  } else {
314
315
  console.log("[stack-update] No backed-up docker-compose.yml in lock \u2014 rolling back image tags via .env on the current compose.");
315
316
  }
317
+ try {
318
+ if (backupComposeOverrideFile && existsSync(backupComposeOverrideFile)) {
319
+ copyFileSync(backupComposeOverrideFile, composeOverrideFile);
320
+ console.log(`[stack-update] Restored docker-compose.override.yml from ${backupComposeOverrideFile}`);
321
+ } else if (lockData?.hadComposeOverrideFile === false && existsSync(composeOverrideFile)) {
322
+ rmSync(composeOverrideFile, { force: true });
323
+ console.log("[stack-update] Removed docker-compose.override.yml because it was absent from the pre-update snapshot.");
324
+ }
325
+ } catch (overrideErr) {
326
+ const reason = overrideErr instanceof Error ? overrideErr.message : String(overrideErr);
327
+ console.warn(`[stack-update] Could not restore docker-compose.override.yml (${reason}); continuing rollback.`);
328
+ }
316
329
  }
317
330
  const scopedServiceNames = options.serviceName ? Object.entries(lockData?.services ?? {}).filter(([name, service]) => name === options.serviceName || (service.composeService ?? name) === options.serviceName).map(([name]) => name) : [];
318
331
  const rollbackEnvRaw = readFileSync(rollbackEnv, "utf8");
319
332
  if (scopedServiceNames.length > 0 && lockData?.services) {
320
333
  const rollbackEnvMap = parseEnv(rollbackEnvRaw);
334
+ const scopedEnvKeys = scopedServiceNames.map((serviceName) => lockData.services[serviceName].env).filter((key) => Boolean(key));
335
+ const mutatedEnvKeys = lockData.mutatedEnvKeys ?? [];
336
+ const restoreEnvKeys = [.../* @__PURE__ */ new Set([...scopedEnvKeys, ...mutatedEnvKeys])];
321
337
  const scopedUpdates = Object.fromEntries(
322
- scopedServiceNames.map((serviceName) => lockData.services[serviceName].env).filter((key) => Boolean(key)).map((key) => [key, rollbackEnvMap.get(key) ?? ""])
338
+ restoreEnvKeys.map((key) => [key, rollbackEnvMap.get(key) ?? ""])
323
339
  );
324
- console.log(`[stack-update] Restoring env keys for service ${scopedServiceNames.join(", ")} from ${rollbackEnv}`);
340
+ console.log(`[stack-update] Restoring env keys for service ${scopedServiceNames.join(", ")} from ${rollbackEnv}: ${restoreEnvKeys.join(", ")}`);
325
341
  writeSecretFile(options.envFile, patchEnv(readFileSync(options.envFile, "utf8"), scopedUpdates));
326
342
  } else {
327
343
  console.log(`[stack-update] Restoring env from ${rollbackEnv}`);
328
344
  writeSecretFile(options.envFile, rollbackEnvRaw);
329
345
  }
330
- const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
346
+ const composeArgs = composeArgsForStack(options.composeFile, options.envFile);
331
347
  if (lockData?.services) {
332
348
  for (const [serviceName, service] of Object.entries(lockData.services)) {
333
349
  if (scopedServiceNames.length > 0 && !scopedServiceNames.includes(serviceName)) continue;
@@ -440,6 +456,22 @@ function manifestImagesForPull(release) {
440
456
  Object.values(release.services).map((service) => imagePullRef(service.image.trim())).filter(Boolean)
441
457
  ));
442
458
  }
459
+ var COMPOSE_SIDECARS = {
460
+ // exe-crm-worker uses the same CRM_IMAGE_TAG as exe-crm but is a distinct
461
+ // compose service. Pull/restart it whenever the CRM API image changes so the
462
+ // API and worker cannot drift to different versions. (bug 9e324fd2)
463
+ "exe-crm": ["exe-crm-worker"],
464
+ "exe-erp": ["exe-erp-nginx", "exe-erp-websocket", "exe-erp-queue", "exe-erp-scheduler"]
465
+ };
466
+ function expandComposeServicesWithSidecars(primaryComposeServices) {
467
+ const expanded = [...primaryComposeServices];
468
+ for (const primary of primaryComposeServices) {
469
+ for (const sidecar of COMPOSE_SIDECARS[primary] ?? []) {
470
+ if (!expanded.includes(sidecar)) expanded.push(sidecar);
471
+ }
472
+ }
473
+ return expanded;
474
+ }
443
475
  function cloneReleaseWithServices(release, serviceNames) {
444
476
  const wanted = new Set(serviceNames);
445
477
  const services = {};
@@ -463,6 +495,18 @@ function readStackUpdateLock(lockFile) {
463
495
  function writeStackUpdateLock(lockFile, data) {
464
496
  writeFileSync(lockFile, JSON.stringify(data, null, 2) + "\n");
465
497
  }
498
+ function composeOverrideFileFor(composeFile) {
499
+ return path.join(path.dirname(composeFile), "docker-compose.override.yml");
500
+ }
501
+ function composeArgsForStack(composeFile, envFile, includeOverride = true) {
502
+ const args = ["compose", "--file", composeFile];
503
+ const overrideFile = composeOverrideFileFor(composeFile);
504
+ if (includeOverride && existsSync(overrideFile)) {
505
+ args.push("--file", overrideFile);
506
+ }
507
+ args.push("--env-file", envFile);
508
+ return args;
509
+ }
466
510
  function buildInitialServiceStatus(plan, envRaw, now, activeServices) {
467
511
  const env = parseEnv(envRaw);
468
512
  const at = now().toISOString();
@@ -991,26 +1035,64 @@ function parseManualRegistryCredentials(raw, sampleImage) {
991
1035
  if (!username || !password) return void 0;
992
1036
  return { registry: registryFromImage(sampleImage ?? ""), username, password };
993
1037
  }
1038
+ async function resolveStackImageCredentials(options, release) {
1039
+ const images = release ? manifestImagesForPull(release) : [];
1040
+ const sampleImage = images.find((image) => image.startsWith("update.askexe.com/")) ?? images.find((image) => image.startsWith("ghcr.io/")) ?? images[0] ?? "";
1041
+ const fetched = await fetchImageCredentials(options);
1042
+ if (fetched) return fetched;
1043
+ const manual = parseManualRegistryCredentials(options.registryCredentials || process.env.EXE_REGISTRY_CREDENTIALS, sampleImage);
1044
+ if (manual) return manual;
1045
+ if (images.some((image) => image.startsWith("update.askexe.com/"))) {
1046
+ const stackEnvPullTokensRaw = process.env.EXE_REGISTRY_PROXY_PULL_TOKENS || (options.envFile && existsSync(options.envFile) ? (() => {
1047
+ const envMap = parseEnv(readFileSync(options.envFile, "utf8"));
1048
+ return envMap.get("EXE_REGISTRY_PROXY_PULL_TOKENS") ?? "";
1049
+ })() : "");
1050
+ const firstPullToken = stackEnvPullTokensRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
1051
+ if (firstPullToken) {
1052
+ return { registry: "update.askexe.com", username: "token", password: firstPullToken };
1053
+ }
1054
+ const licenseKey = options.manifestAuthToken || options.licenseKey || process.env.EXE_LICENSE_KEY;
1055
+ if (licenseKey) {
1056
+ return { registry: "update.askexe.com", username: "license", password: licenseKey };
1057
+ }
1058
+ }
1059
+ return null;
1060
+ }
994
1061
  async function verifyManifestImagesAvailable(plan, options) {
995
1062
  const exec = options.exec ?? defaultExec;
996
1063
  const images = manifestImagesForPull(plan.release);
997
- const sampleImage = images[0];
1064
+ const maxAttempts = Math.max(1, Math.floor(options.verifyImageMaxAttempts ?? 3));
1065
+ const baseDelayMs = Math.max(0, Math.floor(options.verifyImageRetryBaseDelayMs ?? 1e3));
998
1066
  let registryForLogout;
999
- const creds = await fetchImageCredentials(options) ?? parseManualRegistryCredentials(options.registryCredentials || process.env.EXE_REGISTRY_CREDENTIALS, sampleImage);
1067
+ const creds = await resolveStackImageCredentials(options, plan.release);
1000
1068
  if (creds) {
1001
1069
  (options.dockerLogin ?? defaultDockerLogin)(creds);
1002
1070
  registryForLogout = creds.registry;
1003
1071
  }
1004
1072
  try {
1005
- return images.map((image) => {
1006
- try {
1007
- exec("docker", ["manifest", "inspect", image]);
1008
- return { image, ok: true };
1009
- } catch (err) {
1010
- const reason = err instanceof Error ? err.message : String(err);
1011
- return { image, ok: false, error: reason };
1073
+ const results = [];
1074
+ for (const image of images) {
1075
+ let lastError = "";
1076
+ let ok = false;
1077
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1078
+ try {
1079
+ exec("docker", ["manifest", "inspect", image]);
1080
+ ok = true;
1081
+ break;
1082
+ } catch (err) {
1083
+ lastError = err instanceof Error ? err.message : String(err);
1084
+ if (attempt < maxAttempts) {
1085
+ const delayMs = baseDelayMs * Math.pow(2, attempt - 1);
1086
+ console.warn(
1087
+ `[stack-update] manifest inspect failed for ${image} (attempt ${attempt}/${maxAttempts}): ${lastError}. Retrying in ${delayMs}ms.`
1088
+ );
1089
+ if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
1090
+ }
1091
+ }
1012
1092
  }
1013
- });
1093
+ results.push(ok ? { image, ok: true } : { image, ok: false, error: `manifest inspect failed after ${maxAttempts} attempt(s): ${lastError}` });
1094
+ }
1095
+ return results;
1014
1096
  } finally {
1015
1097
  if (registryForLogout) {
1016
1098
  try {
@@ -1020,6 +1102,54 @@ async function verifyManifestImagesAvailable(plan, options) {
1020
1102
  }
1021
1103
  }
1022
1104
  }
1105
+ function servicesForPullImage(release, image) {
1106
+ return Object.entries(release.services).filter(([, service]) => imagePullRef(service.image) === image).map(([serviceName, service]) => {
1107
+ const composeService = service.composeService ?? serviceName;
1108
+ return composeService === serviceName ? serviceName : `${serviceName} (${composeService})`;
1109
+ });
1110
+ }
1111
+ function serviceListForPullImage(release, image) {
1112
+ const services = servicesForPullImage(release, image);
1113
+ return services.length > 0 ? services.join(", ") : "unknown service";
1114
+ }
1115
+ function allServiceList(release) {
1116
+ return Object.keys(release.services).join(", ") || "unknown service";
1117
+ }
1118
+ function errorMessage(err) {
1119
+ return err instanceof Error ? err.message : String(err);
1120
+ }
1121
+ function packagedComposeTemplatePath(options) {
1122
+ return options.composeTemplateFileForUpdate ?? path.join(resolvePackageRoot(), "deploy", "compose", "docker-compose.yml");
1123
+ }
1124
+ function readStagedComposeTemplate(options, currentComposeRaw) {
1125
+ const templatePath = packagedComposeTemplatePath(options);
1126
+ if (!existsSync(templatePath)) {
1127
+ return { raw: currentComposeRaw, templatePath, templateFound: false, shouldRefresh: false };
1128
+ }
1129
+ const raw = readFileSync(templatePath, "utf8");
1130
+ return { raw, templatePath, templateFound: true, shouldRefresh: raw !== currentComposeRaw };
1131
+ }
1132
+ async function assertPreDeployImagesPullable(plan, options) {
1133
+ let results;
1134
+ try {
1135
+ results = await verifyManifestImagesAvailable(plan, options);
1136
+ } catch (err) {
1137
+ throw new Error(
1138
+ `Pre-deploy registry authentication check failed before any production service was changed. Aborting stack update for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
1139
+ );
1140
+ }
1141
+ const failed = results.filter((r) => !r.ok);
1142
+ if (failed.length === 0) return;
1143
+ const details = failed.map((failure) => {
1144
+ const services = serviceListForPullImage(plan.release, failure.image);
1145
+ return ` - ${services}: ${failure.image}${failure.error ? ` \u2014 ${failure.error}` : ""}`;
1146
+ }).join("\n");
1147
+ throw new Error(
1148
+ `Pre-deploy image pullability check failed \u2014 aborting before any production service was changed.
1149
+ ${details}
1150
+ Fix registry authentication or publish the missing image(s), then re-run stack-update.`
1151
+ );
1152
+ }
1023
1153
  function commandSucceeds(cmd, args = []) {
1024
1154
  const res = spawnSync(cmd, args, { stdio: "ignore" });
1025
1155
  return res.status === 0;
@@ -1179,6 +1309,18 @@ function backupStackConfig(stackDir, composeFile, envRaw, now = () => /* @__PURE
1179
1309
  } catch {
1180
1310
  backupComposeFile = void 0;
1181
1311
  }
1312
+ const composeOverrideFile = composeOverrideFileFor(composeFile);
1313
+ const hadComposeOverrideFile = existsSync(composeOverrideFile);
1314
+ let backupComposeOverrideFile;
1315
+ try {
1316
+ if (hadComposeOverrideFile) {
1317
+ backupComposeOverrideFile = path.join(updateBackupDir, "docker-compose.override.yml.bak");
1318
+ copyFileSync(composeOverrideFile, backupComposeOverrideFile);
1319
+ copyFileSync(composeOverrideFile, path.join(updateBackupDir, "docker-compose.override.yml"));
1320
+ }
1321
+ } catch {
1322
+ backupComposeOverrideFile = void 0;
1323
+ }
1182
1324
  for (const f of [...PROTECTED_CONFIG_FILES, ...BOOTSTRAP_OVERWRITTEN_CONFIG_FILES]) {
1183
1325
  const src = path.join(stackDir, f);
1184
1326
  try {
@@ -1212,7 +1354,7 @@ function backupStackConfig(stackDir, composeFile, envRaw, now = () => /* @__PURE
1212
1354
  } catch {
1213
1355
  }
1214
1356
  console.log(`[stack-update] Config backed up to ${updateBackupDir}`);
1215
- return { updateBackupDir, backupEnvFile, backupComposeFile };
1357
+ return { updateBackupDir, backupEnvFile, backupComposeFile, backupComposeOverrideFile, hadComposeOverrideFile };
1216
1358
  }
1217
1359
  function installDockerUbuntu(exec) {
1218
1360
  if (process.platform !== "linux") throw new Error("Docker auto-install is only supported on Linux. Install Docker manually, then retry.");
@@ -1584,7 +1726,7 @@ function hardenSsh(exec, result) {
1584
1726
  }
1585
1727
  function areStackContainersRunning(composeFile, envFile) {
1586
1728
  try {
1587
- const result = spawnSync("docker", ["compose", "--file", composeFile, "--env-file", envFile, "ps", "-q"], {
1729
+ const result = spawnSync("docker", [...composeArgsForStack(composeFile, envFile), "ps", "-q"], {
1588
1730
  stdio: ["pipe", "pipe", "pipe"],
1589
1731
  timeout: 15e3
1590
1732
  });
@@ -1795,6 +1937,7 @@ async function runStackUpdate(options) {
1795
1937
  const scopedServiceNames = options.serviceName ? [options.serviceName] : resumeServices;
1796
1938
  const effectiveTargetVersion = options.targetVersion ?? resumeLock?.stackVersion;
1797
1939
  const composeRaw = readFileSync(options.composeFile, "utf8");
1940
+ const stagedCompose = readStagedComposeTemplate(options, composeRaw);
1798
1941
  const plan = createStackUpdatePlan(manifest, envRaw, effectiveTargetVersion, scopedServiceNames, serviceSelection, composeRaw);
1799
1942
  const fullTargetPlan = scopedServiceNames.length > 0 ? createStackUpdatePlan(manifest, envRaw, effectiveTargetVersion, void 0, serviceSelection, composeRaw) : plan;
1800
1943
  assertRolloutStageAllowed(plan, {
@@ -1803,7 +1946,20 @@ async function runStackUpdate(options) {
1803
1946
  });
1804
1947
  assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
1805
1948
  assertDeploymentScopeAllowed(plan, options.deploymentPersona ?? "customer");
1806
- const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
1949
+ const requiredEnvValidation = options.dryRun ? { derived: {}, unresolvable: [] } : detectMissingRequiredEnvVars(stagedCompose.raw, envRaw);
1950
+ const migratedEnvVars = requiredEnvValidation.derived;
1951
+ if (requiredEnvValidation.unresolvable.length > 0) {
1952
+ const lines = requiredEnvValidation.unresolvable.map((r) => ` - ${r.key}${r.message ? ` (${r.message})` : ""}`);
1953
+ throw new Error(
1954
+ `Stack update aborted before any changes: the updated compose template requires env vars that are missing from ${options.envFile} and cannot be derived automatically.
1955
+ Set these in ${options.envFile}, then re-run stack-update:
1956
+ ${lines.join("\n")}`
1957
+ );
1958
+ }
1959
+ const plannedEnvRaw = patchEnv(envRaw, {
1960
+ ...migratedEnvVars,
1961
+ ...Object.fromEntries(plan.changes.map((c) => [c.key, c.after]))
1962
+ });
1807
1963
  assertProductionDeployGate(plan, plannedEnvRaw, composeRaw, {
1808
1964
  breakGlassReason: options.breakGlassReason,
1809
1965
  breakGlassAuditFile: options.breakGlassAuditFile,
@@ -1830,6 +1986,11 @@ async function runStackUpdate(options) {
1830
1986
  if (options.dryRun || !options.resume && plan.changes.length === 0 && containersRunning) {
1831
1987
  return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
1832
1988
  }
1989
+ if (!options.skipImageAvailabilityCheck) {
1990
+ console.log("[stack-update] Pre-deploy image auth/pullability check started");
1991
+ await assertPreDeployImagesPullable(plan, options);
1992
+ console.log("[stack-update] \u2713 Pre-deploy image auth/pullability check passed");
1993
+ }
1833
1994
  await postDeployAudit(options, "started", plan.targetVersion, previousVersion);
1834
1995
  try {
1835
1996
  if (!options.preDeployBackup) {
@@ -1843,13 +2004,13 @@ async function runStackUpdate(options) {
1843
2004
  const updateBackupDir = configBackup.updateBackupDir;
1844
2005
  const backupEnvFile = configBackup.backupEnvFile;
1845
2006
  const backupComposeFile = configBackup.backupComposeFile;
2007
+ const backupComposeOverrideFile = configBackup.backupComposeOverrideFile;
2008
+ const hadComposeOverrideFile = configBackup.hadComposeOverrideFile;
1846
2009
  try {
1847
- const templateCompose = path.join(resolvePackageRoot(), "deploy", "compose", "docker-compose.yml");
1848
- if (existsSync(templateCompose)) {
1849
- const templateRaw = readFileSync(templateCompose, "utf8");
1850
- if (templateRaw !== composeRaw) {
2010
+ if (stagedCompose.templateFound) {
2011
+ if (stagedCompose.shouldRefresh) {
1851
2012
  const tmpCompose = `${options.composeFile}.tmp-${process.pid}`;
1852
- writeFileSync(tmpCompose, templateRaw, { mode: 420 });
2013
+ writeFileSync(tmpCompose, stagedCompose.raw, { mode: 420 });
1853
2014
  renameSync(tmpCompose, options.composeFile);
1854
2015
  console.log(
1855
2016
  `[stack-update] Refreshed docker-compose.yml from packaged template (old saved to ${path.join(updateBackupDir, "docker-compose.yml")}). Customer overrides should live in docker-compose.override.yml.`
@@ -1857,44 +2018,19 @@ async function runStackUpdate(options) {
1857
2018
  }
1858
2019
  } else {
1859
2020
  console.warn(
1860
- `[stack-update] Packaged compose template not found at ${templateCompose}; keeping existing docker-compose.yml. Shipped compose fixes will not apply.`
2021
+ `[stack-update] Packaged compose template not found at ${stagedCompose.templatePath}; keeping existing docker-compose.yml. Shipped compose fixes will not apply.`
1861
2022
  );
1862
2023
  }
1863
2024
  } catch (err) {
1864
2025
  const reason = err instanceof Error ? err.message : String(err);
1865
2026
  console.warn(`[stack-update] Could not refresh docker-compose.yml (${reason}); using existing compose.`);
1866
2027
  }
1867
- let migratedEnvVars = {};
1868
- try {
1869
- const refreshedComposeRaw = readFileSync(options.composeFile, "utf8");
1870
- const { derived, unresolvable } = detectMissingRequiredEnvVars(refreshedComposeRaw, envRaw);
1871
- if (unresolvable.length > 0) {
1872
- const lines = unresolvable.map((r) => ` - ${r.key}${r.message ? ` (${r.message})` : ""}`);
1873
- throw new Error(
1874
- `Stack update aborted before any changes: the updated compose template requires env vars that are missing from ${options.envFile} and cannot be derived automatically.
1875
- Set these in ${options.envFile}, then re-run stack-update:
1876
- ${lines.join("\n")}`
1877
- );
1878
- }
1879
- migratedEnvVars = derived;
1880
- if (Object.keys(derived).length > 0) {
1881
- console.log(
1882
- `[stack-update] Migrating ${Object.keys(derived).length} newly-required env var(s) into ${options.envFile} with derived defaults: ${Object.keys(derived).join(", ")}`
1883
- );
1884
- }
1885
- } catch (err) {
1886
- throw err instanceof Error ? err : new Error(String(err));
2028
+ if (Object.keys(migratedEnvVars).length > 0) {
2029
+ console.log(
2030
+ `[stack-update] Migrating ${Object.keys(migratedEnvVars).length} newly-required env var(s) into ${options.envFile} with derived defaults: ${Object.keys(migratedEnvVars).join(", ")}`
2031
+ );
1887
2032
  }
1888
2033
  const initialServiceStatus = options.resume && resumeLock?.serviceStatus ? resumeLock.serviceStatus : buildInitialServiceStatus(fullTargetPlan, envRaw, now, new Set(Object.keys(plan.release.services)));
1889
- writeStackUpdateLock(lockFile, {
1890
- stackVersion: plan.targetVersion,
1891
- previousVersion,
1892
- updatedAt: now().toISOString(),
1893
- backupEnvFile: resumeLock?.backupEnvFile ?? backupEnvFile,
1894
- backupComposeFile: resumeLock?.backupComposeFile ?? backupComposeFile,
1895
- services: { ...fullTargetPlan.release.services, ...resumeLock?.services ?? {}, ...plan.release.services },
1896
- serviceStatus: initialServiceStatus
1897
- });
1898
2034
  try {
1899
2035
  const { spawnSync: sp } = await import("child_process");
1900
2036
  const backupSh = path.join(stackDir, "backup.sh");
@@ -1939,6 +2075,19 @@ ${lines.join("\n")}`
1939
2075
  if (overrideResolution.warn) console.warn(overrideResolution.notice);
1940
2076
  else console.log(overrideResolution.notice);
1941
2077
  }
2078
+ const mutatedEnvKeys = Object.keys(updates);
2079
+ writeStackUpdateLock(lockFile, {
2080
+ stackVersion: plan.targetVersion,
2081
+ previousVersion,
2082
+ updatedAt: now().toISOString(),
2083
+ backupEnvFile: resumeLock?.backupEnvFile ?? backupEnvFile,
2084
+ backupComposeFile: resumeLock?.backupComposeFile ?? backupComposeFile,
2085
+ backupComposeOverrideFile: resumeLock?.backupComposeOverrideFile ?? backupComposeOverrideFile,
2086
+ hadComposeOverrideFile: resumeLock?.hadComposeOverrideFile ?? hadComposeOverrideFile,
2087
+ mutatedEnvKeys: [.../* @__PURE__ */ new Set([...resumeLock?.mutatedEnvKeys ?? [], ...mutatedEnvKeys])],
2088
+ services: { ...fullTargetPlan.release.services, ...resumeLock?.services ?? {}, ...plan.release.services },
2089
+ serviceStatus: initialServiceStatus
2090
+ });
1942
2091
  const patched = patchEnv(envRaw, updates);
1943
2092
  const tmp = `${options.envFile}.tmp-${process.pid}`;
1944
2093
  writeSecretFile(tmp, patched);
@@ -1946,47 +2095,19 @@ ${lines.join("\n")}`
1946
2095
  for (const serviceName of Object.keys(plan.release.services)) {
1947
2096
  updateServiceStatus(lockFile, serviceName, "env_patched", now);
1948
2097
  }
1949
- const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
2098
+ const composeArgs = composeArgsForStack(options.composeFile, options.envFile);
1950
2099
  let registryForLogout;
1951
2100
  try {
1952
2101
  let credsLogged = false;
1953
2102
  const resolveRegistryCredentials = async () => {
1954
- let resolved = await fetchImageCredentials(options);
1955
- if (!resolved) {
1956
- const manual = options.registryCredentials || process.env.EXE_REGISTRY_CREDENTIALS;
1957
- if (manual) {
1958
- const [username, ...rest] = manual.split(":");
1959
- const password = rest.join(":");
1960
- if (username && password) {
1961
- const sampleImage = Object.values(plan.release.services)[0]?.image ?? "";
1962
- const registry = sampleImage.startsWith("update.askexe.com") ? "update.askexe.com" : "ghcr.io";
1963
- resolved = { registry, username, password };
1964
- if (!credsLogged) console.log(`[stack-update] Using manual registry credentials for ${registry}.`);
1965
- }
1966
- }
1967
- }
1968
- if (!resolved) {
1969
- const sampleImage = Object.values(plan.release.services)[0]?.image ?? "";
1970
- if (sampleImage.startsWith("update.askexe.com")) {
1971
- const stackEnvPullTokensRaw = process.env.EXE_REGISTRY_PROXY_PULL_TOKENS || (existsSync(options.envFile) ? (() => {
1972
- const envMap = parseEnv(readFileSync(options.envFile, "utf8"));
1973
- return envMap.get("EXE_REGISTRY_PROXY_PULL_TOKENS") ?? "";
1974
- })() : "");
1975
- const firstPullToken = stackEnvPullTokensRaw.split(/[\n,]/).map((s) => s.trim()).find(Boolean);
1976
- if (firstPullToken) {
1977
- resolved = { registry: "update.askexe.com", username: "token", password: firstPullToken };
1978
- if (!credsLogged) console.log("[stack-update] Using EXE_REGISTRY_PROXY_PULL_TOKENS for update.askexe.com registry auth.");
1979
- }
1980
- }
1981
- }
1982
- if (!resolved) {
1983
- const sampleImage = Object.values(plan.release.services)[0]?.image ?? "";
1984
- if (sampleImage.startsWith("update.askexe.com")) {
1985
- const licenseKey = options.manifestAuthToken || options.licenseKey || process.env.EXE_LICENSE_KEY;
1986
- if (licenseKey) {
1987
- resolved = { registry: "update.askexe.com", username: "license", password: licenseKey };
1988
- if (!credsLogged) console.log("[stack-update] Using license key for update.askexe.com registry auth.");
1989
- }
2103
+ const resolved = await resolveStackImageCredentials(options, plan.release);
2104
+ if (resolved && !credsLogged) {
2105
+ if (options.registryCredentials || process.env.EXE_REGISTRY_CREDENTIALS) {
2106
+ console.log(`[stack-update] Using manual registry credentials for ${resolved.registry}.`);
2107
+ } else if (resolved.registry === "update.askexe.com" && resolved.username === "token") {
2108
+ console.log("[stack-update] Using EXE_REGISTRY_PROXY_PULL_TOKENS for update.askexe.com registry auth.");
2109
+ } else if (resolved.registry === "update.askexe.com" && resolved.username === "license") {
2110
+ console.log("[stack-update] Using license key for update.askexe.com registry auth.");
1990
2111
  }
1991
2112
  }
1992
2113
  if (resolved) credsLogged = true;
@@ -1994,7 +2115,13 @@ ${lines.join("\n")}`
1994
2115
  };
1995
2116
  let creds = await resolveRegistryCredentials();
1996
2117
  if (creds) {
1997
- (options.dockerLogin ?? defaultDockerLogin)(creds);
2118
+ try {
2119
+ (options.dockerLogin ?? defaultDockerLogin)(creds);
2120
+ } catch (err) {
2121
+ throw new Error(
2122
+ `Docker registry login failed for ${creds.registry}; aborting before image pull for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
2123
+ );
2124
+ }
1998
2125
  registryForLogout = creds.registry;
1999
2126
  }
2000
2127
  const runImageAvailabilityCheck = !options.skipImageAvailabilityCheck && !options.exec;
@@ -2029,10 +2156,19 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
2029
2156
  (options.dockerLogin ?? defaultDockerLogin)(fresh);
2030
2157
  creds = fresh;
2031
2158
  registryForLogout = fresh.registry;
2032
- } catch {
2159
+ } catch (err) {
2160
+ throw new Error(
2161
+ `Docker registry re-login failed before pulling ${image} for service(s) ${serviceListForPullImage(plan.release, image)}; aborting before container swap: ${errorMessage(err)}`
2162
+ );
2033
2163
  }
2034
2164
  }
2035
- exec("docker", ["pull", image]);
2165
+ try {
2166
+ exec("docker", ["pull", image]);
2167
+ } catch (err) {
2168
+ throw new Error(
2169
+ `Image pull failed before container swap for service(s) ${serviceListForPullImage(plan.release, image)} using ${image}: ${errorMessage(err)}`
2170
+ );
2171
+ }
2036
2172
  for (const [serviceName, service] of Object.entries(plan.release.services)) {
2037
2173
  if (imagePullRef(service.image) === image) updateServiceStatus(lockFile, serviceName, "pulled", now);
2038
2174
  }
@@ -2045,14 +2181,25 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
2045
2181
  (options.dockerLogin ?? defaultDockerLogin)(fresh);
2046
2182
  creds = fresh;
2047
2183
  registryForLogout = fresh.registry;
2048
- } catch {
2184
+ } catch (err) {
2185
+ throw new Error(
2186
+ `Docker registry re-login failed before docker compose pull for service(s) ${allServiceList(plan.release)}; aborting before container swap: ${errorMessage(err)}`
2187
+ );
2049
2188
  }
2050
2189
  }
2051
- const composePullTargets = Object.entries(plan.release.services).map(([name, svc]) => svc.composeService ?? name);
2052
- if (composePullTargets.length > 0) {
2053
- exec("docker", [...composeArgs, "pull", ...composePullTargets]);
2054
- } else {
2055
- exec("docker", [...composeArgs, "pull"]);
2190
+ const composePullTargets = expandComposeServicesWithSidecars(
2191
+ Object.entries(plan.release.services).map(([name, svc]) => svc.composeService ?? name)
2192
+ );
2193
+ try {
2194
+ if (composePullTargets.length > 0) {
2195
+ exec("docker", [...composeArgs, "pull", ...composePullTargets]);
2196
+ } else {
2197
+ exec("docker", [...composeArgs, "pull"]);
2198
+ }
2199
+ } catch (err) {
2200
+ throw new Error(
2201
+ `Docker compose pull failed before container swap for service(s) ${allServiceList(plan.release)}: ${errorMessage(err)}`
2202
+ );
2056
2203
  }
2057
2204
  endComposePull();
2058
2205
  progress.endPhase();
@@ -2154,16 +2301,8 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
2154
2301
  "cloudflared"
2155
2302
  // tunnel — restarted last so services are healthy before it connects
2156
2303
  ];
2157
- const COMPOSE_SIDECARS = {
2158
- "exe-erp": ["exe-erp-nginx", "exe-erp-websocket", "exe-erp-queue", "exe-erp-scheduler"]
2159
- };
2160
2304
  const primaryComposeServices = Object.entries(plan.release.services).map(([serviceName, service]) => service.composeService ?? serviceName);
2161
- const scopedComposeServices = [...primaryComposeServices];
2162
- for (const primary of primaryComposeServices) {
2163
- for (const sidecar of COMPOSE_SIDECARS[primary] ?? []) {
2164
- if (!scopedComposeServices.includes(sidecar)) scopedComposeServices.push(sidecar);
2165
- }
2166
- }
2305
+ const scopedComposeServices = expandComposeServicesWithSidecars(primaryComposeServices);
2167
2306
  const restartOrder = [
2168
2307
  ...RESTART_ORDER.filter((service) => scopedComposeServices.includes(service)),
2169
2308
  ...scopedComposeServices.filter((service) => !RESTART_ORDER.includes(service))
@@ -2329,7 +2468,18 @@ Fix these before the stack is safe to operate.`);
2329
2468
  progress.logOverallSummary();
2330
2469
  printPhaseSummary();
2331
2470
  const finalLock = readStackUpdateLock(lockFile) ?? {};
2332
- writeStackUpdateLock(lockFile, { ...finalLock, stackVersion: plan.targetVersion, previousVersion, updatedAt: now().toISOString(), backupEnvFile: finalLock.backupEnvFile ?? backupEnvFile, services: { ...fullTargetPlan.release.services, ...finalLock.services ?? {}, ...plan.release.services } });
2471
+ writeStackUpdateLock(lockFile, {
2472
+ ...finalLock,
2473
+ stackVersion: plan.targetVersion,
2474
+ previousVersion,
2475
+ updatedAt: now().toISOString(),
2476
+ backupEnvFile: finalLock.backupEnvFile ?? backupEnvFile,
2477
+ backupComposeFile: finalLock.backupComposeFile ?? backupComposeFile,
2478
+ backupComposeOverrideFile: finalLock.backupComposeOverrideFile ?? backupComposeOverrideFile,
2479
+ hadComposeOverrideFile: finalLock.hadComposeOverrideFile ?? hadComposeOverrideFile,
2480
+ mutatedEnvKeys: finalLock.mutatedEnvKeys ?? mutatedEnvKeys,
2481
+ services: { ...fullTargetPlan.release.services, ...finalLock.services ?? {}, ...plan.release.services }
2482
+ });
2333
2483
  await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
2334
2484
  return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile, serviceStatus: readStackUpdateLock(lockFile)?.serviceStatus };
2335
2485
  } catch (err) {
@@ -2866,6 +3016,8 @@ export {
2866
3016
  buildReleaseMigrationArgs,
2867
3017
  runReleaseMigrations,
2868
3018
  isExecFormMigration,
3019
+ expandComposeServicesWithSidecars,
3020
+ composeArgsForStack,
2869
3021
  parseStackManifest,
2870
3022
  loadStackManifest,
2871
3023
  parseEnv,
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  flushBatch,
6
6
  writeMemory
7
- } from "./chunk-GGHH54QD.js";
7
+ } from "./chunk-H5QNVWU4.js";
8
8
  import {
9
9
  redactSecrets
10
10
  } from "./chunk-4QCFFW2H.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listBehaviors
3
- } from "./chunk-4JDRUXQV.js";
3
+ } from "./chunk-MGMXYI7Y.js";
4
4
  import {
5
5
  loadConfigSync
6
6
  } from "./chunk-BCZF3AGJ.js";
@@ -1,3 +1,7 @@
1
+ import {
2
+ isPostgresBackendEnabled
3
+ } from "./chunk-YMUZWC33.js";
4
+
1
5
  // src/lib/db-write-worker-client.ts
2
6
  import { fork } from "child_process";
3
7
  import { existsSync } from "fs";
@@ -10,6 +14,18 @@ var _spawnAttempts = 0;
10
14
  var MAX_SPAWN_ATTEMPTS = 5;
11
15
  var WRITE_TIMEOUT_MS = 6e4;
12
16
  var _pending = /* @__PURE__ */ new Map();
17
+ function buildDbWriteWorkerEnv(dbPath, encryptionKey, source = process.env) {
18
+ const env = {
19
+ ...source,
20
+ EXE_IS_DAEMON: "",
21
+ EXE_DB_DIRECT: "1",
22
+ EXE_BOOT_FAST: "1",
23
+ EXE_DB_NO_CHECKPOINT_TIMER: "1"
24
+ };
25
+ if (dbPath) env.EXE_DB_WRITE_WORKER_PATH = dbPath;
26
+ if (encryptionKey) env.EXE_DB_WRITE_WORKER_KEY = encryptionKey;
27
+ return env;
28
+ }
13
29
  function rejectAllPending(reason) {
14
30
  for (const [id, cb] of _pending) {
15
31
  clearTimeout(cb.timer);
@@ -31,15 +47,12 @@ function spawnDbWriteWorker(dbPath, encryptionKey) {
31
47
  `);
32
48
  return;
33
49
  }
34
- const env = {
35
- ...process.env,
36
- EXE_DB_WRITE_WORKER_PATH: dbPath,
37
- EXE_IS_DAEMON: "",
38
- EXE_DB_DIRECT: "1",
39
- EXE_BOOT_FAST: "1",
40
- EXE_DB_NO_CHECKPOINT_TIMER: "1"
41
- };
42
- if (encryptionKey) env.EXE_DB_WRITE_WORKER_KEY = encryptionKey;
50
+ const env = buildDbWriteWorkerEnv(dbPath, encryptionKey);
51
+ if (!isPostgresBackendEnabled(env) && !env.EXE_DB_WRITE_WORKER_PATH) {
52
+ process.stderr.write("[db-write-worker-client] no SQLite db path for write worker - memory writes will run on the event loop.\n");
53
+ _spawnAttempts = Math.max(0, _spawnAttempts - 1);
54
+ return;
55
+ }
43
56
  try {
44
57
  _worker = fork(workerPath, [], { stdio: ["ignore", "ignore", "inherit", "ipc"], env });
45
58
  } catch (err) {
@@ -118,6 +131,7 @@ function disposeDbWriteWorker() {
118
131
  }
119
132
 
120
133
  export {
134
+ buildDbWriteWorkerEnv,
121
135
  isWriteWorkerEnabled,
122
136
  spawnDbWriteWorker,
123
137
  isDbWriteWorkerReady,