@askexenow/exe-os 0.9.256 → 0.9.259

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 (272) hide show
  1. package/deploy/compose/.env.customer.example +13 -13
  2. package/deploy/compose/.env.example +8 -8
  3. package/deploy/compose/docker-compose.yml +18 -18
  4. package/deploy/compose/generate-env.ts +22 -18
  5. package/deploy/compose/init-db.sql +221 -20
  6. package/deploy/stack-manifests/v0.9.json +1207 -1136
  7. package/dist/{active-agent-DTZ6VJIR.js → active-agent-IGZXTTV4.js} +3 -3
  8. package/dist/{active-agent-7QNK5CJZ.js → active-agent-OYUXMTHS.js} +3 -3
  9. package/dist/{agentic-ontology-UZK33N6I.js → agentic-ontology-5WT23SLZ.js} +1 -1
  10. package/dist/{backfill-metadata-R7PNZ5TX.js → backfill-metadata-EG52U3GF.js} +4 -4
  11. package/dist/{behaviors-G6QHSQBN.js → behaviors-2TZCFJLU.js} +3 -3
  12. package/dist/bin/age-ontology-load.js +2 -2
  13. package/dist/bin/agentic-ontology-backfill.js +5 -5
  14. package/dist/bin/agentic-reflection-backfill.js +6 -6
  15. package/dist/bin/agentic-semantic-label.js +5 -5
  16. package/dist/bin/backfill-conversations.js +6 -5
  17. package/dist/bin/backfill-responses.js +6 -5
  18. package/dist/bin/backfill-vectors.js +7 -6
  19. package/dist/bin/bulk-sync-postgres.js +6 -6
  20. package/dist/bin/cleanup-stale-review-tasks.js +9 -9
  21. package/dist/bin/cli.js +17 -17
  22. package/dist/bin/deferred-daemon-restart.js +4 -1
  23. package/dist/bin/exe-agent-config.js +2 -2
  24. package/dist/bin/exe-agent.js +4 -4
  25. package/dist/bin/exe-assign.js +8 -7
  26. package/dist/bin/exe-boot.js +16 -16
  27. package/dist/bin/exe-call.js +4 -4
  28. package/dist/bin/exe-cloud.js +4 -4
  29. package/dist/bin/exe-dispatch.js +9 -9
  30. package/dist/bin/exe-doctor.js +1 -1
  31. package/dist/bin/exe-export-behaviors.js +7 -7
  32. package/dist/bin/exe-forget.js +6 -6
  33. package/dist/bin/exe-gateway.js +9 -9
  34. package/dist/bin/exe-heartbeat.js +9 -9
  35. package/dist/bin/exe-kill.js +12 -12
  36. package/dist/bin/exe-launch-agent.js +16 -16
  37. package/dist/bin/exe-new-employee.js +6 -6
  38. package/dist/bin/exe-pending-messages.js +11 -10
  39. package/dist/bin/exe-pending-notifications.js +9 -9
  40. package/dist/bin/exe-pending-reviews.js +11 -9
  41. package/dist/bin/exe-rename.js +4 -4
  42. package/dist/bin/exe-review.js +11 -11
  43. package/dist/bin/exe-search.js +5 -5
  44. package/dist/bin/exe-session-cleanup.js +14 -14
  45. package/dist/bin/exe-settings.js +4 -4
  46. package/dist/bin/exe-start-codex.js +11 -11
  47. package/dist/bin/exe-start-opencode.js +8 -8
  48. package/dist/bin/exe-status.js +10 -10
  49. package/dist/bin/exe-support.js +3 -1
  50. package/dist/bin/exe-team.js +3 -3
  51. package/dist/bin/git-sweep.js +71 -11
  52. package/dist/bin/graph-backfill.js +4 -4
  53. package/dist/bin/graph-export.js +5 -5
  54. package/dist/bin/graph-layer-benchmark.js +7 -7
  55. package/dist/bin/import-history.js +7 -7
  56. package/dist/bin/install.js +12 -9
  57. package/dist/bin/intercom-check.js +4 -4
  58. package/dist/bin/mcp-sessions.js +2 -2
  59. package/dist/bin/orchestration-metrics.js +4 -4
  60. package/dist/bin/postgres-agentic-reflection-backfill.js +7 -7
  61. package/dist/bin/postgres-agentic-semantic-backfill.js +7 -7
  62. package/dist/bin/scan-tasks.js +9 -9
  63. package/dist/bin/setup.js +1 -1
  64. package/dist/bin/shard-migrate.js +4 -4
  65. package/dist/bin/stack-update.js +20 -3
  66. package/dist/bin/vps-health-gate.js +1 -1
  67. package/dist/{capacity-monitor-QMKII67L.js → capacity-monitor-CTFWWTCR.js} +10 -10
  68. package/dist/{catchup-brief-CNISNLV7.js → catchup-brief-UML47LXI.js} +11 -11
  69. package/dist/{chunk-QP4FHME2.js → chunk-235ZCOYB.js} +18 -6
  70. package/dist/{chunk-2NEQQCRC.js → chunk-25JAXHON.js} +1 -1
  71. package/dist/{chunk-MU6ESLYL.js → chunk-2PFNATXD.js} +1 -1
  72. package/dist/chunk-2XZ6X3PJ.js +13 -0
  73. package/dist/chunk-3XX3CDKF.js +9 -0
  74. package/dist/{chunk-ZTB6E2ZL.js → chunk-4FGTT26Q.js} +1 -1
  75. package/dist/{chunk-YYSQAM4W.js → chunk-4TYAHVDI.js} +8 -8
  76. package/dist/{chunk-2QKNXGII.js → chunk-4VECWOUO.js} +2 -2
  77. package/dist/{chunk-YXMXP45V.js → chunk-57C3MZPQ.js} +2 -2
  78. package/dist/{chunk-FTNNNAMH.js → chunk-5JYCTIQD.js} +1 -1
  79. package/dist/{chunk-CS267UMH.js → chunk-5LDTCWYX.js} +79 -19
  80. package/dist/{chunk-FQVITYVF.js → chunk-6D2IZ5MB.js} +2 -2
  81. package/dist/{chunk-ZG3HADWE.js → chunk-7UJRF4WF.js} +1 -1
  82. package/dist/{chunk-JFVITKXI.js → chunk-A2UPDE3J.js} +1 -1
  83. package/dist/{chunk-KOCQAMAM.js → chunk-ANYOAZCZ.js} +238 -5
  84. package/dist/{chunk-PSQNT5DS.js → chunk-AQS2B3HC.js} +8 -8
  85. package/dist/{chunk-ABNALOLM.js → chunk-BGEXTWGR.js} +3 -3
  86. package/dist/{chunk-LPK5JPME.js → chunk-BPZL5YOM.js} +1 -1
  87. package/dist/{chunk-RLDOG7DI.js → chunk-C6SSCNOC.js} +2516 -2289
  88. package/dist/{chunk-JGEGEOVP.js → chunk-COKTAJUZ.js} +1 -1
  89. package/dist/{chunk-MRZE5IOP.js → chunk-CXOX7TRG.js} +1 -1
  90. package/dist/{chunk-6LFFIEDM.js → chunk-DU64OESH.js} +1 -1
  91. package/dist/{chunk-LYIUESG2.js → chunk-DYURFBPS.js} +10 -10
  92. package/dist/{chunk-X3SS45PO.js → chunk-FPXZY3FY.js} +1 -1
  93. package/dist/{chunk-TVTRMINO.js → chunk-FUGZF7VR.js} +1 -1
  94. package/dist/{chunk-O7SFCX5B.js → chunk-GB4FI66P.js} +2 -2
  95. package/dist/{chunk-VGWQBI76.js → chunk-GBR4MAAK.js} +1 -1
  96. package/dist/chunk-GH4LVBQM.js +371 -0
  97. package/dist/{chunk-AIXZ5O7U.js → chunk-GIHMDOSK.js} +1 -1
  98. package/dist/{chunk-RDCE652I.js → chunk-HDWVXSGO.js} +1 -1
  99. package/dist/{chunk-RF54NGPJ.js → chunk-IJ7R3MXE.js} +3 -5
  100. package/dist/{chunk-R7FBOZT5.js → chunk-ISL3NSVX.js} +1 -1
  101. package/dist/{chunk-5B2AEXVA.js → chunk-IVSRRIRG.js} +1 -1
  102. package/dist/{chunk-SD2R3SEA.js → chunk-J3YNCJ4A.js} +1 -1
  103. package/dist/{chunk-5IZYSS3M.js → chunk-JE4C74EE.js} +4 -4
  104. package/dist/{chunk-VRVHIVUE.js → chunk-KSR2PNRW.js} +2 -2
  105. package/dist/{chunk-LL2ARYTZ.js → chunk-L3PY4NFQ.js} +1 -1
  106. package/dist/{chunk-VFATLVRX.js → chunk-L5VPUOB6.js} +1 -1
  107. package/dist/{chunk-3VLFVOM7.js → chunk-LRKJGSNH.js} +2 -2
  108. package/dist/{chunk-4FT3SQAS.js → chunk-LVY74L2J.js} +2 -2
  109. package/dist/{chunk-X4T7LR2X.js → chunk-M7PZFYHE.js} +2 -2
  110. package/dist/{chunk-CIX64N7D.js → chunk-MGTVPIEZ.js} +1 -1
  111. package/dist/{chunk-MXCBORCC.js → chunk-MKTEGZ37.js} +3 -3
  112. package/dist/chunk-MMRUBN3I.js +36 -0
  113. package/dist/{chunk-4MONXPWR.js → chunk-MPXLF7TA.js} +1 -1
  114. package/dist/{chunk-6QMXKKFD.js → chunk-N27CTUFU.js} +1 -1
  115. package/dist/{chunk-YDHPC4PX.js → chunk-N4ES27RI.js} +3 -3
  116. package/dist/{chunk-WIRJ574R.js → chunk-NGQQRGLP.js} +2 -2
  117. package/dist/{chunk-AQOCHSIR.js → chunk-OCJ5GZKV.js} +4 -4
  118. package/dist/{chunk-O477L4LV.js → chunk-OSPS5N2I.js} +1 -1
  119. package/dist/{chunk-5WEH43HH.js → chunk-PQHA6X6Y.js} +1 -1
  120. package/dist/{chunk-DJYIBHN5.js → chunk-PQQTSNXS.js} +3 -3
  121. package/dist/{chunk-LGFB67MY.js → chunk-Q3GLQDZI.js} +1 -1
  122. package/dist/{chunk-7GR7VBBW.js → chunk-QUC27OCW.js} +1 -1
  123. package/dist/{chunk-5NBOFYJG.js → chunk-QYNFWFFH.js} +4 -4
  124. package/dist/{chunk-X7I6NLIA.js → chunk-T2EUNNUX.js} +5 -5
  125. package/dist/{chunk-VRWOLLKN.js → chunk-T4NFOOPB.js} +2 -2
  126. package/dist/{chunk-2YJSDJEH.js → chunk-TZPHTI5Q.js} +1 -1
  127. package/dist/{chunk-CQSFIQGN.js → chunk-UOZ5KUNN.js} +1 -1
  128. package/dist/{chunk-5R4R743Q.js → chunk-V2UVWYHO.js} +17 -15
  129. package/dist/{chunk-VKCZ3OGM.js → chunk-VD676VIC.js} +4 -4
  130. package/dist/{chunk-USLVSLQ5.js → chunk-VDCPKJUQ.js} +1 -1
  131. package/dist/{chunk-Y7NMPQXZ.js → chunk-VLX6AHTD.js} +8 -8
  132. package/dist/{chunk-ITPIBVSG.js → chunk-WMZTSHNX.js} +83 -1
  133. package/dist/{chunk-5U7WB4YG.js → chunk-WVBZ3QBR.js} +2 -2
  134. package/dist/{chunk-3EMZZZNU.js → chunk-X2RKYKTP.js} +1 -1
  135. package/dist/{chunk-XTIHYH64.js → chunk-YY2BCIAP.js} +2 -2
  136. package/dist/{chunk-Z6GHDYQI.js → chunk-Z2AEOVEZ.js} +30 -6
  137. package/dist/{chunk-PHTRZQR4.js → chunk-ZBDAFYDD.js} +4 -4
  138. package/dist/{chunk-E4CCKWZN.js → chunk-ZKFTDL4M.js} +1 -1
  139. package/dist/{co-activation-AIVMI5U2.js → co-activation-UNVL5JCP.js} +2 -2
  140. package/dist/{co-occurrence-L6QOQTJB.js → co-occurrence-ETAVWYVE.js} +2 -2
  141. package/dist/{code-context-index-DYHYVJHX.js → code-context-index-DCQYAYA2.js} +3 -2
  142. package/dist/{crdt-sync-YBMDPFNT.js → crdt-sync-AH7N6QOE.js} +1 -1
  143. package/dist/{crm-webhook-QO3ZESKR.js → crm-webhook-R6546T3Y.js} +2 -2
  144. package/dist/{cto-delegation-gate-UFPVFLIW.js → cto-delegation-gate-VB4TMZ3I.js} +8 -8
  145. package/dist/{daemon-orchestration-6XAISQ7B.js → daemon-orchestration-YAJKIL6Q.js} +12 -12
  146. package/dist/{db-backup-7UMCTS44.js → db-backup-2RG6VHT7.js} +11 -3
  147. package/dist/{dreaming-FJ75QVGZ.js → dreaming-WMBTSXGD.js} +9 -9
  148. package/dist/{exe-drift-OH3WV2ZQ.js → exe-drift-MQZGYHEN.js} +3 -3
  149. package/dist/{exe-export-UYKYNVBU.js → exe-export-E4BDIHOC.js} +5 -5
  150. package/dist/{exe-import-Q4FNSMLJ.js → exe-import-IWAD4HN6.js} +5 -5
  151. package/dist/{exe-key-22LOIIUX.js → exe-key-L2RV7XJX.js} +2 -2
  152. package/dist/{exe-snapshot-J7CL6QEL.js → exe-snapshot-IOGN4ARV.js} +12 -12
  153. package/dist/{fast-db-init-QXGL2PKQ.js → fast-db-init-GCY3F74H.js} +1 -1
  154. package/dist/gateway/index.js +8 -8
  155. package/dist/{git-staleness-YVWDCFIE.js → git-staleness-BQIFNZIU.js} +2 -2
  156. package/dist/{git-task-sweep-RRCOTTIS.js → git-task-sweep-GSKS6WKR.js} +9 -9
  157. package/dist/{global-procedures-FCGWAFES.js → global-procedures-3DJUA5OX.js} +3 -3
  158. package/dist/{graph-auto-extract-RUQC5IIS.js → graph-auto-extract-2I44WRDY.js} +2 -2
  159. package/dist/hooks/bug-report-worker.js +11 -11
  160. package/dist/hooks/codex-stop-task-finalizer.js +11 -11
  161. package/dist/hooks/commit-complete.js +11 -11
  162. package/dist/hooks/error-recall.js +6 -6
  163. package/dist/hooks/exe-heartbeat-hook.js +3 -3
  164. package/dist/hooks/ingest-worker.js +3 -2
  165. package/dist/hooks/ingest.js +6 -6
  166. package/dist/hooks/instructions-loaded.js +4 -4
  167. package/dist/hooks/manifest.json +20 -20
  168. package/dist/hooks/notification.js +4 -4
  169. package/dist/hooks/post-compact.js +10 -10
  170. package/dist/hooks/post-tool-combined.js +6 -6
  171. package/dist/hooks/pre-compact.js +14 -13
  172. package/dist/hooks/pre-tool-use.js +14 -14
  173. package/dist/hooks/prompt-submit.js +22 -22
  174. package/dist/hooks/session-end.js +19 -18
  175. package/dist/hooks/session-start.js +11 -11
  176. package/dist/hooks/stop.js +70 -17
  177. package/dist/hooks/subagent-stop.js +10 -10
  178. package/dist/hooks/summary-worker.js +17 -16
  179. package/dist/index.js +17 -17
  180. package/dist/{installer-7SMJC3SX.js → installer-6MQCAHUG.js} +5 -5
  181. package/dist/{installer-GFZVC43I.js → installer-TCMPFSSP.js} +5 -5
  182. package/dist/{installer-34DCTB5B.js → installer-ZY2BKTEO.js} +5 -5
  183. package/dist/lib/cloud-sync.js +4 -4
  184. package/dist/lib/consolidation.js +5 -5
  185. package/dist/lib/database.js +2 -2
  186. package/dist/lib/db-daemon-client.js +58 -13
  187. package/dist/lib/db.js +2 -2
  188. package/dist/lib/embedder.js +3 -2
  189. package/dist/lib/employee-templates.js +4 -4
  190. package/dist/lib/employees.js +2 -2
  191. package/dist/lib/exe-daemon-client.js +2 -1
  192. package/dist/lib/exe-daemon.js +255 -104
  193. package/dist/lib/hybrid-search.js +5 -5
  194. package/dist/lib/identity.js +2 -2
  195. package/dist/lib/messaging.js +9 -9
  196. package/dist/lib/reminders.js +3 -3
  197. package/dist/lib/schedules.js +5 -5
  198. package/dist/lib/session-registry.js +4 -4
  199. package/dist/lib/skill-learning.js +4 -4
  200. package/dist/lib/store.js +4 -4
  201. package/dist/lib/task-router.js +3 -3
  202. package/dist/lib/tasks.js +10 -10
  203. package/dist/lib/tmux-routing.js +8 -8
  204. package/dist/lib/token-spend.js +3 -3
  205. package/dist/mcp/register-tools.js +59 -56
  206. package/dist/mcp/server.js +60 -57
  207. package/dist/mcp/tools/complete-reminder.js +4 -4
  208. package/dist/mcp/tools/create-reminder.js +4 -4
  209. package/dist/mcp/tools/create-task.js +12 -12
  210. package/dist/mcp/tools/deactivate-behavior.js +5 -5
  211. package/dist/mcp/tools/list-reminders.js +4 -4
  212. package/dist/mcp/tools/list-tasks.js +12 -12
  213. package/dist/mcp/tools/send-message.js +11 -11
  214. package/dist/mcp/tools/update-task.js +11 -11
  215. package/dist/{mcp-http-config-MZMHKMJC.js → mcp-http-config-VUDZ3D5D.js} +3 -3
  216. package/dist/{memory-cards-3SFXU6IP.js → memory-cards-ZOOPC2WF.js} +2 -2
  217. package/dist/{memory-graph-extractor-T57YQQCW.js → memory-graph-extractor-RRQMUBMI.js} +3 -3
  218. package/dist/{memory-poisoning-defense-O53AHMTZ.js → memory-poisoning-defense-UQMNLG6H.js} +2 -2
  219. package/dist/{memory-queue-client-ITWQIFSD.js → memory-queue-client-TPQDAA4D.js} +3 -2
  220. package/dist/{memory-reflection-YPP2JC2S.js → memory-reflection-GSGXAGXV.js} +2 -2
  221. package/dist/{notifications-BETWD6EK.js → notifications-ZKGLZVCU.js} +8 -8
  222. package/dist/{orchestration-events-A5D52NXX.js → orchestration-events-7RMWC5SS.js} +3 -3
  223. package/dist/{orchestrator-X564XCWC.js → orchestrator-A6MX2OHA.js} +10 -10
  224. package/dist/{pipeline-router-RVHLL7UA.js → pipeline-router-6ZBYJD2U.js} +3 -3
  225. package/dist/{plan-limits-ANAVC6PM.js → plan-limits-4XH4A7IA.js} +3 -3
  226. package/dist/{project-boot-ENMCAL7G.js → project-boot-7ZEIDWUG.js} +3 -2
  227. package/dist/{projection-worker-O3HBG5QK.js → projection-worker-YKKBNQZT.js} +130 -51
  228. package/dist/{reranker-SRJL4IWB.js → reranker-DN2A3H6O.js} +1 -1
  229. package/dist/{review-polling-5JTTHHEO.js → review-polling-PK3CY4NI.js} +9 -9
  230. package/dist/runtime/index.js +11 -11
  231. package/dist/{session-events-RCSYHQQ2.js → session-events-IYU6FYHH.js} +9 -9
  232. package/dist/{session-kill-telemetry-AL3H4ELS.js → session-kill-telemetry-G2VV4CAH.js} +3 -3
  233. package/dist/{session-scope-ZB4SR3AX.js → session-scope-DHTVH3D4.js} +8 -8
  234. package/dist/{setup-wizard-HXTADFXI.js → setup-wizard-IA5ISHQ2.js} +1 -1
  235. package/dist/{skill-refinement-TT4VDYYW.js → skill-refinement-6PBAFLWP.js} +2 -2
  236. package/dist/{stack-release-7WDKQOCO.js → stack-release-NW7MV3WV.js} +41 -11
  237. package/dist/{stack-update-F4CQWMGV.js → stack-update-5SM62R3O.js} +3 -1
  238. package/dist/{steward-gate-HSV67KLF.js → steward-gate-EQV6CZKY.js} +3 -3
  239. package/dist/support-outbox-SZVLHHZG.js +295 -0
  240. package/dist/{task-enforcement-A6AZTYAN.js → task-enforcement-2LS5DOXK.js} +8 -8
  241. package/dist/{task-scope-XKNAY5S7.js → task-scope-AKF3CSWO.js} +8 -8
  242. package/dist/{tasks-crud-F732BVOE.js → tasks-crud-KOIA5SAH.js} +8 -8
  243. package/dist/{tasks-notify-LJ65U7DF.js → tasks-notify-7ZTE4ZQM.js} +9 -9
  244. package/dist/{tasks-review-Y5F4HRAR.js → tasks-review-VMMMAK2Y.js} +8 -8
  245. package/dist/{telemetry-upload-HVYO6FL3.js → telemetry-upload-YLW4NAUF.js} +15 -8
  246. package/dist/{token-budget-VODGJYKX.js → token-budget-NA4OLFNP.js} +2 -2
  247. package/dist/{tool-capability-index-PZWWVABO.js → tool-capability-index-C73KVY5O.js} +1 -1
  248. package/dist/{tool-telemetry-5BSTF3P6.js → tool-telemetry-OVI5KL4S.js} +1 -1
  249. package/dist/tui/App.js +16 -16
  250. package/dist/{tui-data-EHJWRNRZ.js → tui-data-5NT24CC5.js} +8 -8
  251. package/dist/{worker-gate-4AS4K7G4.js → worker-gate-AQLJUQ5G.js} +1 -1
  252. package/dist/{workflow-engine-BXGNFNUW.js → workflow-engine-TRGGUNIZ.js} +2 -2
  253. package/dist/{worktree-3N5BPITS.js → worktree-NK7GZNEA.js} +4 -4
  254. package/dist/worktree-sweep-5XVZCH6A.js +18 -0
  255. package/package.json +3 -2
  256. package/release-notes.json +28 -27
  257. package/stack.release.json +48 -48
  258. package/dist/prediction-log-DOEOHDHS.js +0 -120
  259. package/dist/support-outbox-KEJ73I3F.js +0 -206
  260. /package/dist/{chunk-AWVDA2FL.js → chunk-2H3FVAN3.js} +0 -0
  261. /package/dist/{chunk-VPHOOQLR.js → chunk-3GHTBVZO.js} +0 -0
  262. /package/dist/{chunk-CCPCIW4Z.js → chunk-BBPRL2MP.js} +0 -0
  263. /package/dist/{chunk-X2E6W3DB.js → chunk-BRSI3FD6.js} +0 -0
  264. /package/dist/{chunk-Y2FVN7CX.js → chunk-EYLQRPHF.js} +0 -0
  265. /package/dist/{chunk-4S5TEBXD.js → chunk-H6QJT5O5.js} +0 -0
  266. /package/dist/{chunk-FCII2MMI.js → chunk-J5CAYOJU.js} +0 -0
  267. /package/dist/{chunk-LY2DYTDL.js → chunk-RFJESVEL.js} +0 -0
  268. /package/dist/{chunk-GBHQ5TXO.js → chunk-UOOCGJUE.js} +0 -0
  269. /package/dist/{core-memory-WFP2L52F.js → core-memory-VZFTGOFE.js} +0 -0
  270. /package/dist/{entity-boost-RTYXAOWV.js → entity-boost-OAB2PZQP.js} +0 -0
  271. /package/dist/{message-queue-client-2CACBUA4.js → message-queue-client-YTKTHAYO.js} +0 -0
  272. /package/dist/{wiki-acl-MS7QLQCR.js → wiki-acl-UCPOROPR.js} +0 -0
@@ -3,30 +3,30 @@ import {
3
3
  } from "./chunk-MLXJ5EZG.js";
4
4
  import {
5
5
  createTask
6
- } from "./chunk-5R4R743Q.js";
6
+ } from "./chunk-V2UVWYHO.js";
7
7
  import {
8
8
  getActiveAgent
9
- } from "./chunk-VGWQBI76.js";
9
+ } from "./chunk-GBR4MAAK.js";
10
10
  import {
11
11
  ensureEmployee,
12
12
  logTaskDispatch,
13
13
  resolveExeSession
14
- } from "./chunk-CS267UMH.js";
14
+ } from "./chunk-5LDTCWYX.js";
15
15
  import {
16
16
  recordOrchestrationEventBestEffort
17
- } from "./chunk-USLVSLQ5.js";
17
+ } from "./chunk-VDCPKJUQ.js";
18
18
  import {
19
19
  getAgentRuntime
20
20
  } from "./chunk-XJUUWHVN.js";
21
21
  import {
22
22
  getLicenseSync
23
- } from "./chunk-VFATLVRX.js";
23
+ } from "./chunk-L5VPUOB6.js";
24
24
  import {
25
25
  getAgentContext
26
26
  } from "./chunk-GJV3WDWM.js";
27
27
  import {
28
28
  isCoordinatorName
29
- } from "./chunk-5U7WB4YG.js";
29
+ } from "./chunk-WVBZ3QBR.js";
30
30
 
31
31
  // src/mcp/tools/create-task.ts
32
32
  import { z } from "zod";
@@ -275,7 +275,7 @@ function registerCreateTask(server) {
275
275
  session_scope: sessionScope,
276
276
  created_at: (/* @__PURE__ */ new Date()).toISOString()
277
277
  }), "utf-8");
278
- const { recordOrchestrationEventBestEffort: recordOE } = await import("./orchestration-events-A5D52NXX.js");
278
+ const { recordOrchestrationEventBestEffort: recordOE } = await import("./orchestration-events-7RMWC5SS.js");
279
279
  recordOE({
280
280
  eventType: "signal.created",
281
281
  source: "create-task.mcp",
@@ -307,7 +307,7 @@ function registerCreateTask(server) {
307
307
  let projectConflictOpts = {};
308
308
  try {
309
309
  const { getClient } = await import("./lib/database.js");
310
- const { sessionScopeFilter } = await import("./task-scope-XKNAY5S7.js");
310
+ const { sessionScopeFilter } = await import("./task-scope-AKF3CSWO.js");
311
311
  const client = getClient();
312
312
  const scope = sessionScopeFilter(task.sessionScope || callerRoot || exeSession || null);
313
313
  const existing = await client.execute({
@@ -2,10 +2,10 @@ import {
2
2
  listWorkflowDefinitions,
3
3
  runWorkflow,
4
4
  startWorkflow
5
- } from "./chunk-MU6ESLYL.js";
5
+ } from "./chunk-2PFNATXD.js";
6
6
  import {
7
7
  ingest
8
- } from "./chunk-3EMZZZNU.js";
8
+ } from "./chunk-X2RKYKTP.js";
9
9
  import {
10
10
  initCRMBridge
11
11
  } from "./chunk-ONKIWA3R.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  vectorToBlob
3
- } from "./chunk-PSQNT5DS.js";
3
+ } from "./chunk-AQS2B3HC.js";
4
4
  import {
5
5
  extractKeywords,
6
6
  keywordsToString
7
7
  } from "./chunk-CHCA3ZM2.js";
8
8
  import {
9
9
  isCoordinatorName
10
- } from "./chunk-5U7WB4YG.js";
10
+ } from "./chunk-WVBZ3QBR.js";
11
11
 
12
12
  // src/lib/consolidation.ts
13
13
  import { randomUUID } from "crypto";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-K77WC6HA.js";
5
5
  import {
6
6
  getClient
7
- } from "./chunk-5U7WB4YG.js";
7
+ } from "./chunk-WVBZ3QBR.js";
8
8
 
9
9
  // src/lib/global-procedures.ts
10
10
  import { randomUUID } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ensureWorktree
3
- } from "./chunk-6LFFIEDM.js";
3
+ } from "./chunk-DU64OESH.js";
4
4
  import {
5
5
  queueIntercom
6
6
  } from "./chunk-5CHYEKMH.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-4JERP7NT.js";
11
11
  import {
12
12
  registerSession
13
- } from "./chunk-SD2R3SEA.js";
13
+ } from "./chunk-J3YNCJ4A.js";
14
14
  import {
15
15
  getTransport
16
16
  } from "./chunk-MVW62NIZ.js";
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-CX6GL3ZJ.js";
20
20
  import {
21
21
  recordOrchestrationEventBestEffort
22
- } from "./chunk-USLVSLQ5.js";
22
+ } from "./chunk-VDCPKJUQ.js";
23
23
  import {
24
24
  getAgentRuntime,
25
25
  normalizeCcModelName
@@ -30,7 +30,7 @@ import {
30
30
  import {
31
31
  PlanLimitError,
32
32
  assertEmployeeLimitSync
33
- } from "./chunk-VFATLVRX.js";
33
+ } from "./chunk-L5VPUOB6.js";
34
34
  import {
35
35
  getSessionKey
36
36
  } from "./chunk-CVYC6DUW.js";
@@ -45,7 +45,7 @@ import {
45
45
  } from "./chunk-MP2AFCGL.js";
46
46
  import {
47
47
  ensureAgentSymlink
48
- } from "./chunk-R7FBOZT5.js";
48
+ } from "./chunk-ISL3NSVX.js";
49
49
  import {
50
50
  expandDualPrefixTools
51
51
  } from "./chunk-HYZV25LY.js";
@@ -57,7 +57,7 @@ import {
57
57
  isCoordinatorName,
58
58
  loadEmployees,
59
59
  loadEmployeesSync
60
- } from "./chunk-5U7WB4YG.js";
60
+ } from "./chunk-WVBZ3QBR.js";
61
61
  import {
62
62
  loadDeviceId
63
63
  } from "./chunk-MOZ2YQ54.js";
@@ -398,6 +398,52 @@ function checkLaneAffinity(title, context, assigneeName) {
398
398
  }
399
399
  async function resolveTask(client, identifier, scopeSession) {
400
400
  const scope = sessionScopeFilter(scopeSession);
401
+ const currentScope = typeof scope.args[0] === "string" ? String(scope.args[0]) : null;
402
+ const crossSessionError = (rows) => {
403
+ if (!currentScope || rows.length === 0) return null;
404
+ const unique = /* @__PURE__ */ new Map();
405
+ for (const row of rows) unique.set(String(row.id), row);
406
+ const crossSessionRows = [...unique.values()].filter((row) => {
407
+ const rowScope = row.session_scope === null || row.session_scope === void 0 ? null : String(row.session_scope);
408
+ return rowScope !== null && rowScope !== currentScope;
409
+ });
410
+ if (crossSessionRows.length === 0) return null;
411
+ const matches = crossSessionRows.slice(0, 5).map((row) => `${String(row.id).slice(0, 8)} "${String(row.title)}" [session:${String(row.session_scope)}]`).join(", ");
412
+ return new Error(
413
+ `Cross-session task mutation blocked: "${identifier}" belongs to another coordinator session. Current session: ${currentScope}. Matching task(s): ${matches}. Use task(action="list", cross_session=true) for read-only diagnostics, or switch to the owning session to update/close.`
414
+ );
415
+ };
416
+ const findUnscopedMatches = async () => {
417
+ const matches = [];
418
+ const pushRows = (rows) => {
419
+ for (const row of rows) {
420
+ if (!matches.some((m) => String(m.id) === String(row.id))) matches.push(row);
421
+ }
422
+ };
423
+ let result2 = await client.execute({
424
+ sql: "SELECT * FROM tasks WHERE id = ? LIMIT 10",
425
+ args: [identifier]
426
+ });
427
+ pushRows(result2.rows);
428
+ if (/^[a-f0-9]{7,12}$/i.test(identifier)) {
429
+ result2 = await client.execute({
430
+ sql: "SELECT * FROM tasks WHERE id LIKE ? LIMIT 10",
431
+ args: [`${identifier}%`]
432
+ });
433
+ pushRows(result2.rows);
434
+ }
435
+ result2 = await client.execute({
436
+ sql: "SELECT * FROM tasks WHERE task_file LIKE ? LIMIT 10",
437
+ args: [`%${identifier}%`]
438
+ });
439
+ pushRows(result2.rows);
440
+ result2 = await client.execute({
441
+ sql: "SELECT * FROM tasks WHERE title LIKE ? LIMIT 10",
442
+ args: [`%${identifier}%`]
443
+ });
444
+ pushRows(result2.rows);
445
+ return matches;
446
+ };
401
447
  let result = await client.execute({
402
448
  sql: `SELECT * FROM tasks WHERE id = ?${scope.sql}`,
403
449
  args: [identifier, ...scope.args]
@@ -409,10 +455,19 @@ async function resolveTask(client, identifier, scopeSession) {
409
455
  args: [`${identifier}%`, ...scope.args]
410
456
  });
411
457
  if (result.rows.length === 0) {
412
- result = await client.execute({
413
- sql: `SELECT * FROM tasks WHERE id LIKE ?`,
414
- args: [`${identifier}%`]
415
- });
458
+ if (currentScope) {
459
+ const unscoped = await client.execute({
460
+ sql: `SELECT * FROM tasks WHERE id LIKE ?`,
461
+ args: [`${identifier}%`]
462
+ });
463
+ const err2 = crossSessionError(unscoped.rows);
464
+ if (err2) throw err2;
465
+ } else {
466
+ result = await client.execute({
467
+ sql: `SELECT * FROM tasks WHERE id LIKE ?`,
468
+ args: [`${identifier}%`]
469
+ });
470
+ }
416
471
  }
417
472
  if (result.rows.length === 1) return result.rows[0];
418
473
  if (result.rows.length > 1) {
@@ -457,7 +512,10 @@ async function resolveTask(client, identifier, scopeSession) {
457
512
  `Multiple tasks match "${identifier}": ${matches}. Use a UUID to disambiguate.`
458
513
  );
459
514
  }
460
- throw new Error(`Task not found: ${identifier}`);
515
+ const unscopedMatches = await findUnscopedMatches();
516
+ const err = crossSessionError(unscopedMatches);
517
+ if (err) throw err;
518
+ throw new Error(`Task not found in current session: ${identifier}`);
461
519
  }
462
520
  function renderTaskMarkdown(f) {
463
521
  return `# ${f.title}
@@ -527,7 +585,7 @@ async function createTaskCore(input) {
527
585
  if (isCoordinatorSession) {
528
586
  earlySessionScope = resolved;
529
587
  } else {
530
- const { getSessionProject } = await import("./session-scope-ZB4SR3AX.js");
588
+ const { getSessionProject } = await import("./session-scope-DHTVH3D4.js");
531
589
  const sessionProject = getSessionProject(resolved);
532
590
  if (sessionProject && sessionProject !== input.projectName) {
533
591
  scopeMismatchWarning = `session/project mismatch: session "${resolved}" owns "${sessionProject}" but task targets "${input.projectName}". Routed to default scope.`;
@@ -994,7 +1052,7 @@ async function updateTaskStatus(input) {
994
1052
  } catch {
995
1053
  }
996
1054
  try {
997
- const { writeNotification: writeNotification2 } = await import("./notifications-BETWD6EK.js");
1055
+ const { writeNotification: writeNotification2 } = await import("./notifications-ZKGLZVCU.js");
998
1056
  await writeNotification2({
999
1057
  agentId: reviewer,
1000
1058
  agentRole: isCoordinatorName(reviewer) ? "COO" : "manager",
@@ -1332,7 +1390,7 @@ ${input.result ?? ""}`;
1332
1390
  sql: "SELECT assertions FROM tasks WHERE id = ?",
1333
1391
  args: [taskId]
1334
1392
  });
1335
- let merged = { assertions: [], resolved: [] };
1393
+ const merged = { assertions: [], resolved: [] };
1336
1394
  if (existing.rows.length > 0 && existing.rows[0]?.assertions) {
1337
1395
  try {
1338
1396
  const prev = JSON.parse(String(existing.rows[0].assertions));
@@ -1409,7 +1467,7 @@ ${input.result ?? ""}`;
1409
1467
  }
1410
1468
  if (shouldWriteCompletionMemory && input.result) {
1411
1469
  try {
1412
- const { writeMemoryViaDaemon } = await import("./memory-queue-client-ITWQIFSD.js");
1470
+ const { writeMemoryViaDaemon } = await import("./memory-queue-client-TPQDAA4D.js");
1413
1471
  await writeMemoryViaDaemon({
1414
1472
  raw_text: input.result,
1415
1473
  agent_id: String(row.assigned_to),
@@ -1512,7 +1570,7 @@ ${input.result ?? ""}`;
1512
1570
  }
1513
1571
  if (input.status === "done" || input.status === "needs_review") {
1514
1572
  try {
1515
- const { incrementSkillSuccess } = await import("./skill-refinement-TT4VDYYW.js");
1573
+ const { incrementSkillSuccess } = await import("./skill-refinement-6PBAFLWP.js");
1516
1574
  await incrementSkillSuccess(
1517
1575
  String(row.assigned_to),
1518
1576
  row.project_name ? String(row.project_name) : null
@@ -2997,7 +3055,7 @@ async function verifyPaneAtCapacity(sessionName) {
2997
3055
  reason: `capture-pane failed: ${err instanceof Error ? err.message : String(err)}`
2998
3056
  };
2999
3057
  }
3000
- const { isAtCapacity } = await import("./capacity-monitor-QMKII67L.js");
3058
+ const { isAtCapacity } = await import("./capacity-monitor-CTFWWTCR.js");
3001
3059
  if (!isAtCapacity(pane)) {
3002
3060
  return {
3003
3061
  atCapacity: false,
@@ -3264,7 +3322,8 @@ function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitl
3264
3322
  if (pending instanceof Promise) {
3265
3323
  pending.then((count) => {
3266
3324
  if (count > 0) {
3267
- logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}", ${count} reviews pending \u2014 hook will surface)`);
3325
+ logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}", ${count} reviews pending \u2014 sending intercom)`);
3326
+ sendIntercom(coordinatorSession, { force: true, reason: "completion" });
3268
3327
  }
3269
3328
  }).catch(() => {
3270
3329
  });
@@ -3272,7 +3331,8 @@ function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitl
3272
3331
  }
3273
3332
  } catch {
3274
3333
  }
3275
- logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}") \u2014 review count unavailable, skipping intercom (hook will catch it)`);
3334
+ logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}") \u2014 review count unavailable, sending intercom as fallback`);
3335
+ sendIntercom(coordinatorSession, { force: true, reason: "completion" });
3276
3336
  return true;
3277
3337
  } catch (e) {
3278
3338
  process.stderr.write("[tmux-routing] notifyCoordinatorTaskCompletion for " + coordinatorSession + ": " + (e instanceof Error ? e.message : String(e)) + "\n");
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  sendMessage
3
- } from "./chunk-MXCBORCC.js";
3
+ } from "./chunk-MKTEGZ37.js";
4
4
  import {
5
5
  getActiveAgent
6
- } from "./chunk-VGWQBI76.js";
6
+ } from "./chunk-GBR4MAAK.js";
7
7
 
8
8
  // src/mcp/tools/send-message.ts
9
9
  import { z } from "zod";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listBehaviors
3
- } from "./chunk-2NEQQCRC.js";
3
+ } from "./chunk-25JAXHON.js";
4
4
  import {
5
5
  loadConfigSync
6
6
  } from "./chunk-VXIMSRTO.js";
@@ -204,7 +204,7 @@ async function main(args) {
204
204
  console.log("[health-gate] Starting rollback...");
205
205
  restorePreDeployBackup();
206
206
  try {
207
- const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-F4CQWMGV.js");
207
+ const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-5SM62R3O.js");
208
208
  const paths = defaultStackPaths();
209
209
  await rollbackStackUpdate({
210
210
  manifestRef: paths.manifestRef,
@@ -142,13 +142,14 @@ function createStackUpdatePlan(manifest, envRaw, targetVersion) {
142
142
  }
143
143
  var ASKEXE_GHCR_IMAGE = /^(?:ghcr\.io\/askexe|update\.askexe\.com\/askexe)\/[a-z0-9._/-]+(?:(?::[^:@$/{]+)(?:@sha256:[a-f0-9]{64})?|@sha256:[a-f0-9]{64})$/i;
144
144
  var OFFICIAL_COMPOSE_IMAGE = /^(?:postgres|pgvector\/pgvector|clickhouse\/clickhouse-server|redis|nginx|postgrest\/postgrest|supabase\/gotrue|cloudflare\/cloudflared):[^:@$/{]+(?:@sha256:[a-f0-9]{64})?$/i;
145
- function validatePinnedGhcrImage(image, label) {
145
+ function validatePinnedGhcrImage(image, label, requireDigest = false) {
146
146
  const trimmed = image.trim().replace(/^['"]|['"]$/g, "");
147
147
  if (!trimmed) return `${label} is empty`;
148
148
  if (trimmed.includes("${")) return null;
149
149
  if (!trimmed.startsWith("ghcr.io/askexe/") && !trimmed.startsWith("update.askexe.com/askexe/")) return `${label} must use ghcr.io/askexe/* or update.askexe.com/askexe/*, got ${trimmed}`;
150
150
  if (/:latest(?:$|[\s#])/.test(trimmed)) return `${label} must not use :latest (${trimmed})`;
151
151
  if (!ASKEXE_GHCR_IMAGE.test(trimmed)) return `${label} must be pinned with an explicit tag or sha256 digest from ghcr.io/askexe or update.askexe.com/askexe, got ${trimmed}`;
152
+ if (requireDigest && !/@sha256:[a-f0-9]{64}/.test(trimmed)) return `${label} must include @sha256: digest for supply-chain integrity, got ${trimmed}`;
152
153
  return null;
153
154
  }
154
155
  function validateComposeImageLiteral(image, label) {
@@ -427,7 +428,7 @@ function bootstrapStackHost(options) {
427
428
  );
428
429
  const brandingDest = path.join(path.dirname(options.envFile), "branding.json");
429
430
  copyTemplateIfMissing("deploy/compose/gateway.json", path.join(path.dirname(options.envFile), "gateway.json"), createdFiles);
430
- if (!existsSync(brandingDest)) writeFileSync(brandingDest, JSON.stringify({ brandName: "Hygo", productName: "Hygo OS" }, null, 2) + "\n", { mode: 384 });
431
+ if (!existsSync(brandingDest)) writeFileSync(brandingDest, JSON.stringify({ brandName: "Exe", productName: "Exe OS" }, null, 2) + "\n", { mode: 384 });
431
432
  copyTemplateIfMissing(
432
433
  "deploy/compose/cloudflared/config.yml.example",
433
434
  path.join(path.dirname(options.composeFile), "cloudflared", "config.yml.example"),
@@ -474,6 +475,199 @@ function assertHostReadyForApply(report) {
474
475
  if (blockers.length > 0) throw new Error(`Stack host is not ready:
475
476
  - ${blockers.join("\n- ")}`);
476
477
  }
478
+ function hardenHost(exec) {
479
+ const run = exec ?? defaultExec;
480
+ const result = {
481
+ skipped: false,
482
+ ufw: { changed: false, actions: [] },
483
+ ssh: { changed: false, actions: [] }
484
+ };
485
+ if (process.platform !== "linux") {
486
+ result.skipped = true;
487
+ result.reason = "Host hardening only runs on Linux (skipped on " + process.platform + ")";
488
+ console.log(`[stack-update] ${result.reason}`);
489
+ return result;
490
+ }
491
+ hardenUfw(run, result);
492
+ hardenSsh(run, result);
493
+ return result;
494
+ }
495
+ function hardenUfw(exec, result) {
496
+ const whichUfw = spawnSync("which", ["ufw"], { stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 });
497
+ const ufwInstalled = whichUfw.status === 0;
498
+ if (!ufwInstalled) {
499
+ if (!existsSync("/etc/os-release")) {
500
+ result.ufw.actions.push("ufw_not_installed_unknown_distro");
501
+ console.warn("[stack-update] UFW not installed and OS not detected \u2014 skipping firewall hardening");
502
+ return;
503
+ }
504
+ const osRelease = readFileSync("/etc/os-release", "utf8");
505
+ if (!/ID=(ubuntu|debian)|ID_LIKE=.*debian/.test(osRelease)) {
506
+ result.ufw.actions.push("ufw_not_installed_unsupported_distro");
507
+ console.warn("[stack-update] UFW not installed on non-Debian OS \u2014 skipping firewall hardening");
508
+ return;
509
+ }
510
+ console.log("[stack-update] Installing UFW...");
511
+ try {
512
+ exec("apt-get", ["install", "-y", "ufw"]);
513
+ result.ufw.actions.push("installed_ufw");
514
+ } catch (err) {
515
+ const reason = err instanceof Error ? err.message : String(err);
516
+ console.warn(`[stack-update] Failed to install UFW: ${reason}`);
517
+ result.ufw.actions.push("install_failed");
518
+ return;
519
+ }
520
+ }
521
+ const statusResult = spawnSync("ufw", ["status", "verbose"], {
522
+ encoding: "utf8",
523
+ stdio: ["pipe", "pipe", "pipe"],
524
+ timeout: 1e4
525
+ });
526
+ const statusOutput = statusResult.stdout ?? "";
527
+ const isActive = /Status:\s*active/i.test(statusOutput);
528
+ const has22 = /22\/tcp\s+ALLOW/i.test(statusOutput);
529
+ const has80 = /80\/tcp\s+ALLOW/i.test(statusOutput);
530
+ const has443 = /443\/tcp\s+ALLOW/i.test(statusOutput);
531
+ const defaultDeny = /Default:\s*deny\s*\(incoming\)/i.test(statusOutput);
532
+ if (isActive && has22 && has80 && has443 && defaultDeny) {
533
+ result.ufw.actions.push("already_hardened");
534
+ console.log("[stack-update] UFW already active with correct rules \u2014 skipping");
535
+ return;
536
+ }
537
+ console.log("[stack-update] Configuring UFW firewall...");
538
+ try {
539
+ if (!defaultDeny) {
540
+ exec("ufw", ["default", "deny", "incoming"]);
541
+ result.ufw.actions.push("set_default_deny_incoming");
542
+ }
543
+ exec("ufw", ["default", "allow", "outgoing"]);
544
+ result.ufw.actions.push("set_default_allow_outgoing");
545
+ if (!has22) {
546
+ exec("ufw", ["allow", "22/tcp"]);
547
+ result.ufw.actions.push("allow_22_tcp");
548
+ }
549
+ if (!has80) {
550
+ exec("ufw", ["allow", "80/tcp"]);
551
+ result.ufw.actions.push("allow_80_tcp");
552
+ }
553
+ if (!has443) {
554
+ exec("ufw", ["allow", "443/tcp"]);
555
+ result.ufw.actions.push("allow_443_tcp");
556
+ }
557
+ if (!isActive) {
558
+ exec("ufw", ["--force", "enable"]);
559
+ result.ufw.actions.push("enabled_ufw");
560
+ }
561
+ result.ufw.changed = true;
562
+ console.log("[stack-update] \u2713 UFW firewall configured: deny incoming, allow 22/80/443");
563
+ } catch (err) {
564
+ const reason = err instanceof Error ? err.message : String(err);
565
+ console.warn(`[stack-update] UFW configuration failed (non-fatal): ${reason}`);
566
+ result.ufw.actions.push("configuration_failed");
567
+ }
568
+ }
569
+ function hardenSsh(exec, result) {
570
+ const sshdConfig = "/etc/ssh/sshd_config";
571
+ if (!existsSync(sshdConfig)) {
572
+ result.ssh.actions.push("sshd_config_not_found");
573
+ console.warn("[stack-update] /etc/ssh/sshd_config not found \u2014 skipping SSH hardening");
574
+ return;
575
+ }
576
+ let configRaw;
577
+ try {
578
+ configRaw = readFileSync(sshdConfig, "utf8");
579
+ } catch (err) {
580
+ const reason = err instanceof Error ? err.message : String(err);
581
+ result.ssh.actions.push("sshd_config_unreadable");
582
+ console.warn(`[stack-update] Cannot read sshd_config: ${reason}`);
583
+ return;
584
+ }
585
+ let modified = configRaw;
586
+ let needsReload = false;
587
+ const passwordAuthMatch = modified.match(/^\s*PasswordAuthentication\s+(yes|no)\s*$/m);
588
+ const passwordAuthCurrently = passwordAuthMatch?.[1]?.toLowerCase();
589
+ if (passwordAuthCurrently === "yes") {
590
+ modified = modified.replace(
591
+ /^\s*PasswordAuthentication\s+yes\s*$/m,
592
+ "PasswordAuthentication no"
593
+ );
594
+ result.ssh.actions.push("set_password_auth_no");
595
+ needsReload = true;
596
+ } else if (!passwordAuthMatch) {
597
+ if (/^#\s*PasswordAuthentication\s/m.test(modified)) {
598
+ modified = modified.replace(
599
+ /^#\s*PasswordAuthentication\s.*$/m,
600
+ "PasswordAuthentication no"
601
+ );
602
+ } else {
603
+ modified += "\nPasswordAuthentication no\n";
604
+ }
605
+ result.ssh.actions.push("set_password_auth_no");
606
+ needsReload = true;
607
+ } else {
608
+ result.ssh.actions.push("password_auth_already_no");
609
+ }
610
+ const rootLoginMatch = modified.match(/^\s*PermitRootLogin\s+(\S+)\s*$/m);
611
+ const rootLoginCurrently = rootLoginMatch?.[1]?.toLowerCase();
612
+ if (rootLoginCurrently === "yes") {
613
+ modified = modified.replace(
614
+ /^\s*PermitRootLogin\s+yes\s*$/m,
615
+ "PermitRootLogin prohibit-password"
616
+ );
617
+ result.ssh.actions.push("set_root_login_prohibit_password");
618
+ needsReload = true;
619
+ } else if (!rootLoginMatch) {
620
+ if (/^#\s*PermitRootLogin\s/m.test(modified)) {
621
+ modified = modified.replace(
622
+ /^#\s*PermitRootLogin\s.*$/m,
623
+ "PermitRootLogin prohibit-password"
624
+ );
625
+ } else {
626
+ modified += "\nPermitRootLogin prohibit-password\n";
627
+ }
628
+ result.ssh.actions.push("set_root_login_prohibit_password");
629
+ needsReload = true;
630
+ } else if (rootLoginCurrently === "prohibit-password" || rootLoginCurrently === "without-password" || rootLoginCurrently === "no") {
631
+ result.ssh.actions.push("root_login_already_restricted");
632
+ } else {
633
+ modified = modified.replace(
634
+ /^\s*PermitRootLogin\s+\S+\s*$/m,
635
+ "PermitRootLogin prohibit-password"
636
+ );
637
+ result.ssh.actions.push("set_root_login_prohibit_password");
638
+ needsReload = true;
639
+ }
640
+ if (!needsReload) {
641
+ console.log("[stack-update] SSH already hardened \u2014 skipping");
642
+ return;
643
+ }
644
+ try {
645
+ writeFileSync(sshdConfig, modified, { mode: 384 });
646
+ result.ssh.changed = true;
647
+ } catch (err) {
648
+ const reason = err instanceof Error ? err.message : String(err);
649
+ console.warn(`[stack-update] Failed to write sshd_config: ${reason}`);
650
+ result.ssh.actions.push("write_failed");
651
+ return;
652
+ }
653
+ try {
654
+ exec("systemctl", ["reload", "ssh"]);
655
+ result.ssh.actions.push("reloaded_ssh");
656
+ } catch {
657
+ try {
658
+ exec("systemctl", ["reload", "sshd"]);
659
+ result.ssh.actions.push("reloaded_sshd");
660
+ } catch (err) {
661
+ const reason = err instanceof Error ? err.message : String(err);
662
+ console.warn(`[stack-update] SSH reload failed (changes will apply on next restart): ${reason}`);
663
+ result.ssh.actions.push("reload_failed");
664
+ }
665
+ }
666
+ const sshSummary = result.ssh.actions.filter((a) => a.startsWith("set_")).map((a) => a.replace("set_", "").replaceAll("_", " ")).join(", ");
667
+ if (sshSummary) {
668
+ console.log(`[stack-update] \u2713 SSH hardened: ${sshSummary}`);
669
+ }
670
+ }
477
671
  function areStackContainersRunning(composeFile, envFile) {
478
672
  try {
479
673
  const result = spawnSync("docker", ["compose", "--file", composeFile, "--env-file", envFile, "ps", "-q"], {
@@ -493,8 +687,15 @@ var CRITICAL_BIND_MOUNTS = [
493
687
  var CRITICAL_VOLUMES = [
494
688
  "postgres_data",
495
689
  "gateway_data",
690
+ "gateway_whatsapp_auth",
496
691
  "wiki_data",
497
- "exe_os_data"
692
+ "exe_os_data",
693
+ "crm_data",
694
+ "monitor_hub_data",
695
+ "monitor_agent_data",
696
+ "redis_data",
697
+ "clickhouse_data",
698
+ "erp_sites"
498
699
  ];
499
700
  function assertBindMountsExist(stackDir) {
500
701
  const missing = [];
@@ -862,10 +1063,41 @@ async function runStackUpdate(options) {
862
1063
  throw new Error("verifyStack hook not provided");
863
1064
  }
864
1065
  const verifyReport = await options.verifyStack({ composeFile: options.composeFile, envFile: options.envFile });
1066
+ const securityFailures = [];
865
1067
  for (const r of verifyReport.results) {
866
- if (r.status === "fail") console.warn(`[verify-stack] FAIL: ${r.check}: ${r.message}`);
1068
+ if (r.status === "fail") {
1069
+ console.warn(`[verify-stack] FAIL: ${r.check}: ${r.message}`);
1070
+ if (/security|auth|signup|password|ssl|tls|bind|exposed/i.test(r.check)) {
1071
+ securityFailures.push(`${r.check}: ${r.message}`);
1072
+ }
1073
+ }
867
1074
  }
868
- } catch {
1075
+ if (securityFailures.length > 0) {
1076
+ throw new Error(`Security verification failed:
1077
+ - ${securityFailures.join("\n - ")}
1078
+ Fix these before the stack is safe to operate.`);
1079
+ }
1080
+ } catch (verifyErr) {
1081
+ if (verifyErr instanceof Error && verifyErr.message.startsWith("Security verification failed")) {
1082
+ throw verifyErr;
1083
+ }
1084
+ console.warn("[stack-update] Post-deploy verification skipped (module not available)");
1085
+ }
1086
+ if (!options.skipHardening) {
1087
+ try {
1088
+ const hardenResult = hardenHost(exec);
1089
+ if (!hardenResult.skipped) {
1090
+ const actions = [...hardenResult.ufw.actions, ...hardenResult.ssh.actions].filter(Boolean);
1091
+ if (actions.length > 0) {
1092
+ console.log(`[stack-update] Host hardening: ${actions.join(", ")}`);
1093
+ }
1094
+ }
1095
+ } catch (hardenErr) {
1096
+ const reason = hardenErr instanceof Error ? hardenErr.message : String(hardenErr);
1097
+ console.warn(`[stack-update] Host hardening failed (non-fatal): ${reason}`);
1098
+ }
1099
+ } else {
1100
+ console.log("[stack-update] Host hardening skipped (--skip-hardening)");
869
1101
  }
870
1102
  writeFileSync(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, previousVersion, updatedAt: now().toISOString(), backupEnvFile, services: plan.release.services }, null, 2) + "\n");
871
1103
  await postDeployAudit(options, "success", plan.targetVersion, previousVersion, void 0, { changes: plan.changes.length });
@@ -1078,6 +1310,7 @@ export {
1078
1310
  pairMonitorAgent,
1079
1311
  bootstrapStackHost,
1080
1312
  assertHostReadyForApply,
1313
+ hardenHost,
1081
1314
  runStackUpdate,
1082
1315
  readCurrentStackVersion,
1083
1316
  listAvailableVersions,