@askexenow/exe-os 0.9.340 → 0.9.342

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 (417) hide show
  1. package/README.md +159 -196
  2. package/deploy/compose/.env.customer.example +1 -0
  3. package/deploy/compose/.env.example +1 -0
  4. package/deploy/compose/docker-compose.yml +13 -4
  5. package/deploy/compose/generate-env.ts +4 -0
  6. package/dist/{active-agent-EC6M7KTX.js → active-agent-PVGE57FY.js} +5 -5
  7. package/dist/{active-agent-WHIUCHLA.js → active-agent-TNIO6IY3.js} +5 -5
  8. package/dist/{agentic-ontology-RNSXGXW4.js → agentic-ontology-3FXYMHKW.js} +1 -1
  9. package/dist/{backfill-gate-J7UXFNXU.js → backfill-gate-65LSYVE5.js} +3 -3
  10. package/dist/{backfill-metadata-MFY6BHKE.js → backfill-metadata-ZSMZC45J.js} +8 -8
  11. package/dist/{background-jobs-STURKDCS.js → background-jobs-EXR5RVGG.js} +3 -3
  12. package/dist/backup-verify-3Y2FHGZU.js +425 -0
  13. package/dist/{behaviors-HLZUJSMP.js → behaviors-KYRB3NGJ.js} +9 -9
  14. package/dist/bin/age-ontology-load.js +3 -3
  15. package/dist/bin/agentic-ontology-backfill.js +10 -10
  16. package/dist/bin/agentic-reflection-backfill.js +11 -11
  17. package/dist/bin/agentic-semantic-label.js +10 -10
  18. package/dist/bin/backfill-conversations.js +10 -10
  19. package/dist/bin/backfill-responses.js +10 -10
  20. package/dist/bin/backfill-vectors.js +14 -14
  21. package/dist/bin/bulk-sync-postgres.js +19 -19
  22. package/dist/bin/cc-doctor.js +10 -8
  23. package/dist/bin/cleanup-stale-review-tasks.js +26 -24
  24. package/dist/bin/cli.js +111 -25
  25. package/dist/bin/customer-readiness.js +1 -1
  26. package/dist/bin/deferred-daemon-restart.js +97 -90
  27. package/dist/bin/exe-agent-config.js +9 -8
  28. package/dist/bin/exe-agent.js +20 -20
  29. package/dist/bin/exe-assign.js +12 -12
  30. package/dist/bin/exe-boot.js +201 -68
  31. package/dist/bin/exe-call.js +7 -7
  32. package/dist/bin/exe-cloud.js +20 -20
  33. package/dist/bin/exe-config-dump.js +9 -8
  34. package/dist/bin/exe-dispatch.js +26 -24
  35. package/dist/bin/exe-doctor.js +10 -6
  36. package/dist/bin/exe-export-behaviors.js +11 -11
  37. package/dist/bin/exe-forget.js +12 -10
  38. package/dist/bin/exe-gateway.js +15 -10
  39. package/dist/bin/exe-grant.js +5 -5
  40. package/dist/bin/exe-healthcheck.js +14 -8
  41. package/dist/bin/exe-heartbeat.js +29 -28
  42. package/dist/bin/exe-kill.js +31 -29
  43. package/dist/bin/exe-launch-agent.js +129 -68
  44. package/dist/bin/exe-memory-reads.js +257 -0
  45. package/dist/bin/exe-new-employee.js +12 -11
  46. package/dist/bin/exe-pending-messages.js +27 -25
  47. package/dist/bin/exe-pending-notifications.js +26 -24
  48. package/dist/bin/exe-pending-reviews.js +26 -24
  49. package/dist/bin/exe-rename.js +7 -7
  50. package/dist/bin/exe-review.js +30 -28
  51. package/dist/bin/exe-search.js +11 -9
  52. package/dist/bin/exe-session-cleanup.js +116 -86
  53. package/dist/bin/exe-settings.js +24 -23
  54. package/dist/bin/exe-start-codex.js +163 -41
  55. package/dist/bin/exe-start-opencode.js +15 -15
  56. package/dist/bin/exe-status.js +27 -25
  57. package/dist/bin/exe-support.js +5 -5
  58. package/dist/bin/exe-team.js +5 -5
  59. package/dist/bin/exe-timers.js +32 -213
  60. package/dist/bin/exe-watchdog.js +6 -5
  61. package/dist/bin/git-sweep.js +27 -25
  62. package/dist/bin/graph-backfill.js +9 -9
  63. package/dist/bin/graph-export.js +9 -9
  64. package/dist/bin/import-history.js +11 -11
  65. package/dist/bin/install.js +102 -95
  66. package/dist/bin/intercom-check.js +4 -4
  67. package/dist/bin/mcp-sessions.js +2 -2
  68. package/dist/bin/orchestration-metrics.js +6 -6
  69. package/dist/bin/postgres-agentic-reflection-backfill.js +5 -5
  70. package/dist/bin/postgres-agentic-semantic-backfill.js +7 -7
  71. package/dist/bin/pre-publish.js +5 -3
  72. package/dist/bin/reconcile-backlog.js +484 -0
  73. package/dist/bin/registry-proxy.js +1 -1
  74. package/dist/bin/scan-tasks.js +26 -24
  75. package/dist/bin/setup.js +6 -5
  76. package/dist/bin/shard-migrate.js +9 -9
  77. package/dist/bin/stack-update.js +15 -9
  78. package/dist/bin/update.js +1 -1
  79. package/dist/bin/vps-health-gate.js +1 -1
  80. package/dist/boot-generation-BL2ISK4U.js +22 -0
  81. package/dist/boot-review-sections-DBMQJT5N.js +107 -0
  82. package/dist/branch-hygiene-TZWK6QCF.js +224 -0
  83. package/dist/{branding-JTEOF4ZV.js → branding-DVXBGVDH.js} +3 -3
  84. package/dist/{browser-session-store-CXQMOSEC.js → browser-session-store-B2NR3LIX.js} +2 -1
  85. package/dist/{capability-cards-YOKVMMOL.js → capability-cards-DN5UIKVN.js} +4 -4
  86. package/dist/{capacity-monitor-S54IOWRL.js → capacity-monitor-ZG5GGFR2.js} +27 -25
  87. package/dist/{catchup-brief-DRRQCMKA.js → catchup-brief-D6HH6DWS.js} +32 -29
  88. package/dist/{support-outbox-MGUVVGHT.js → chunk-25X4JD2V.js} +28 -12
  89. package/dist/{chunk-IYB2NIW3.js → chunk-2KZNGDSW.js} +1 -1
  90. package/dist/{chunk-FUIIVSW6.js → chunk-2WAVZ5UJ.js} +1 -1
  91. package/dist/{chunk-K5WFKEXQ.js → chunk-2ZYO73KO.js} +4 -3
  92. package/dist/{chunk-CLAYNAXC.js → chunk-3EUMUSLE.js} +1 -1
  93. package/dist/{chunk-BVV6NHKQ.js → chunk-3SW4OEHB.js} +5 -5
  94. package/dist/{task-enforcement-VI7L43DC.js → chunk-4CMVFVFC.js} +173 -69
  95. package/dist/{chunk-BU2QQWBQ.js → chunk-4J4PMPXZ.js} +3 -2
  96. package/dist/{chunk-JD5S5AAV.js → chunk-4N2NRGCM.js} +2 -2
  97. package/dist/chunk-4QCFFW2H.js +378 -0
  98. package/dist/{chunk-7EA7LYW4.js → chunk-4VSV5P4D.js} +4 -4
  99. package/dist/{chunk-52KNOQMK.js → chunk-4ZCD2UWW.js} +39 -10
  100. package/dist/{chunk-DZ6OQM67.js → chunk-5ERDIOV3.js} +2 -2
  101. package/dist/chunk-5H47VHB7.js +30 -0
  102. package/dist/{chunk-UCQITDLM.js → chunk-5TY4FPH6.js} +1 -1
  103. package/dist/{chunk-R44Z32O2.js → chunk-6CH3TPHR.js} +2 -2
  104. package/dist/{chunk-WYLV4S6A.js → chunk-6WQ3NNCE.js} +3 -3
  105. package/dist/{chunk-HHIBOU3P.js → chunk-6XWTQUO4.js} +1 -1
  106. package/dist/chunk-76CJBM36.js +88 -0
  107. package/dist/{chunk-H2L4PHGH.js → chunk-7CTRGNLW.js} +2 -2
  108. package/dist/{chunk-XUKPALWT.js → chunk-7V4JADD6.js} +2 -2
  109. package/dist/{chunk-RMOBQ6A5.js → chunk-AD2VCHSS.js} +1 -1
  110. package/dist/{chunk-QXSBB26A.js → chunk-AJYCFKJR.js} +1 -1
  111. package/dist/chunk-AM7S2TY6.js +54 -0
  112. package/dist/{chunk-HEPR6QTL.js → chunk-AOHXREB7.js} +334 -66
  113. package/dist/{chunk-FNZR3B7U.js → chunk-ASAFVDVR.js} +1 -1
  114. package/dist/{chunk-TALWBVZE.js → chunk-BUCXNV32.js} +1 -1
  115. package/dist/{chunk-SHIICYJW.js → chunk-BYTDMAGB.js} +4 -2
  116. package/dist/{chunk-32SXNM3G.js → chunk-C5QAPURN.js} +1 -1
  117. package/dist/{chunk-XCTGRD4S.js → chunk-CE7F6RHG.js} +587 -77
  118. package/dist/{chunk-7WPOJDTA.js → chunk-CNVBKDEY.js} +21 -15
  119. package/dist/{chunk-KPIN44GZ.js → chunk-CWXVH7WV.js} +1 -1
  120. package/dist/chunk-D74XYSA3.js +621 -0
  121. package/dist/{chunk-A47MXY2I.js → chunk-EQHQF5IM.js} +50 -32
  122. package/dist/{chunk-AOO77BDE.js → chunk-EUS4QUKP.js} +1 -1
  123. package/dist/{chunk-RLRT2BVM.js → chunk-EV46QTD3.js} +1 -1
  124. package/dist/{chunk-PAEXYFMY.js → chunk-F27XXN6C.js} +1 -1
  125. package/dist/{chunk-XQNNB5GY.js → chunk-F55P3H4S.js} +37 -2
  126. package/dist/{chunk-MWZFF3Q7.js → chunk-F5O7V7UK.js} +1 -1
  127. package/dist/{chunk-LMZISHSJ.js → chunk-FPFPLPUY.js} +6 -6
  128. package/dist/{chunk-7TS64TBG.js → chunk-G4RGKBCA.js} +8 -3
  129. package/dist/{chunk-4IYSBPX3.js → chunk-G5T6KDG4.js} +1 -1
  130. package/dist/{chunk-7WDXEKUL.js → chunk-GBTTBXAF.js} +4 -4
  131. package/dist/{chunk-6MRWJMI5.js → chunk-GDIJE6D7.js} +1 -1
  132. package/dist/{chunk-AVKXCSBI.js → chunk-GG5NDQNN.js} +2 -2
  133. package/dist/{chunk-I3XKO3KQ.js → chunk-GJ26DULE.js} +2 -2
  134. package/dist/chunk-GL57PO3K.js +104 -0
  135. package/dist/chunk-GWDSB25T.js +6 -0
  136. package/dist/{chunk-F55JF43M.js → chunk-H6BV5TKD.js} +39 -24
  137. package/dist/{chunk-HCJCW7X4.js → chunk-H7I47RS5.js} +34 -1
  138. package/dist/{chunk-65SVQELL.js → chunk-HA5R6USD.js} +31 -5
  139. package/dist/{chunk-VJHUVFIW.js → chunk-HAF2DJYV.js} +3 -3
  140. package/dist/chunk-HJ447YER.js +224 -0
  141. package/dist/chunk-HV4KESRY.js +395 -0
  142. package/dist/{chunk-B76TSEP3.js → chunk-I26FWCSP.js} +216 -9
  143. package/dist/{chunk-X2FHTDIU.js → chunk-IBYL4DHM.js} +1 -1
  144. package/dist/{chunk-JCBKARSK.js → chunk-IOEUAQWP.js} +1 -1
  145. package/dist/{chunk-MW2GJJ53.js → chunk-JGIPOUIK.js} +3 -3
  146. package/dist/{chunk-2233TQCA.js → chunk-JLZ4RYSD.js} +2 -2
  147. package/dist/{chunk-Q7L6G6KV.js → chunk-JMYHW3AL.js} +2 -2
  148. package/dist/{chunk-OJTJYEMX.js → chunk-JPUZPAAF.js} +4 -4
  149. package/dist/{chunk-XWHE4LZK.js → chunk-JTBIS4R5.js} +21 -2
  150. package/dist/{chunk-5Z5NATNS.js → chunk-K7KFGDWF.js} +1 -1
  151. package/dist/{chunk-UIV2WPBT.js → chunk-KGWRTRKC.js} +2 -2
  152. package/dist/{chunk-KTPG4XKI.js → chunk-KP3U5QGJ.js} +1 -1
  153. package/dist/{chunk-TLYAEISW.js → chunk-KW2SD2FL.js} +2 -2
  154. package/dist/{chunk-X7H3HMFH.js → chunk-KWZMQACA.js} +11 -7
  155. package/dist/{chunk-OFX5B2S7.js → chunk-L2R3LN2P.js} +1 -1
  156. package/dist/{chunk-T4KZ2Z2N.js → chunk-L4A5DL6Z.js} +3 -3
  157. package/dist/{chunk-X425OEYF.js → chunk-LU2FALL6.js} +3 -3
  158. package/dist/{chunk-6M36JFFD.js → chunk-MKYFAKDW.js} +4 -4
  159. package/dist/{chunk-I5RLNOFK.js → chunk-MOPUCPXK.js} +12 -4
  160. package/dist/{chunk-ZIVEA3NB.js → chunk-MR6LHP4F.js} +1 -1
  161. package/dist/chunk-MVYB76QG.js +341 -0
  162. package/dist/{chunk-2SG2UGCH.js → chunk-MZM6EJCU.js} +4 -4
  163. package/dist/{chunk-ZREGOV2Q.js → chunk-N7QJKQMX.js} +258 -14
  164. package/dist/{chunk-QLFRCA6I.js → chunk-NBZL5CGA.js} +93 -12
  165. package/dist/{chunk-QFPTDSY2.js → chunk-NN2B2QKU.js} +1 -1
  166. package/dist/chunk-NX5INHHG.js +40 -0
  167. package/dist/{chunk-B75BOKEI.js → chunk-NXUSDL37.js} +2 -2
  168. package/dist/{chunk-TPHCZDE3.js → chunk-O5V57XYE.js} +1 -1
  169. package/dist/chunk-O7LWR36Z.js +269 -0
  170. package/dist/{chunk-ATOU6CYR.js → chunk-OLMQ4UOF.js} +57 -11
  171. package/dist/{chunk-6HBURYON.js → chunk-OTF44GXL.js} +4 -4
  172. package/dist/{chunk-DILD54TU.js → chunk-OZEBAGKR.js} +277 -137
  173. package/dist/{chunk-DADMPMYX.js → chunk-P5HIWY2E.js} +1 -1
  174. package/dist/{chunk-EIF2LQHZ.js → chunk-PDWS3E22.js} +55 -4
  175. package/dist/{chunk-KTY7I7UH.js → chunk-PPCDBE6Z.js} +1 -1
  176. package/dist/{chunk-XACL67CS.js → chunk-PQIDGXSG.js} +13 -4
  177. package/dist/chunk-PWUFMX75.js +186 -0
  178. package/dist/{chunk-UPWE5NOG.js → chunk-QDGZJ653.js} +3 -3
  179. package/dist/{chunk-MQRFKSLI.js → chunk-QOO5RW3K.js} +6 -5
  180. package/dist/{chunk-KCC5A7YL.js → chunk-QQ4E2RYW.js} +95 -18
  181. package/dist/{chunk-BPC5LZ6Y.js → chunk-QRYVCDWS.js} +2 -2
  182. package/dist/{chunk-Z42MXYWW.js → chunk-QWVXN224.js} +110 -28
  183. package/dist/{chunk-542EWGY3.js → chunk-QYZJHTNE.js} +26 -27
  184. package/dist/{chunk-I7Z6KTGF.js → chunk-R2NN3JKH.js} +43 -6
  185. package/dist/{chunk-3OBWSCJN.js → chunk-RACAOE2Z.js} +14 -14
  186. package/dist/{chunk-5RACW3LX.js → chunk-RAXVPNMR.js} +1 -1
  187. package/dist/{chunk-2HZY3ECT.js → chunk-RHWZUUS4.js} +6 -6
  188. package/dist/{chunk-RNAYCUNM.js → chunk-S3THSOWV.js} +1 -1
  189. package/dist/{chunk-W7DHFGCB.js → chunk-S7QUM2UK.js} +2 -2
  190. package/dist/{chunk-SSTLTIF3.js → chunk-SKGMF2SO.js} +25 -2
  191. package/dist/{chunk-GN45PBWI.js → chunk-SQKXKV2Y.js} +2 -2
  192. package/dist/{chunk-QZLIZAS7.js → chunk-TLT7NZCW.js} +4 -4
  193. package/dist/chunk-TTCUG2CF.js +91 -0
  194. package/dist/chunk-UEA3LXOB.js +40 -0
  195. package/dist/{chunk-DRCRZIIJ.js → chunk-UNXQBELK.js} +1 -1
  196. package/dist/{chunk-PLRIJALF.js → chunk-UP75Z5X7.js} +921 -176
  197. package/dist/{chunk-TNJRWUCE.js → chunk-USSB56WK.js} +1 -1
  198. package/dist/{chunk-KMBEL7VB.js → chunk-UUEKJDK6.js} +90 -10
  199. package/dist/{chunk-XJI7Z6LZ.js → chunk-UUQBZPJJ.js} +1 -1
  200. package/dist/{chunk-RRWDYOQS.js → chunk-V3EEVY4L.js} +1 -1
  201. package/dist/{chunk-N5I7RL3I.js → chunk-VPZHJCKW.js} +2 -2
  202. package/dist/chunk-VRAQTFD6.js +265 -0
  203. package/dist/{chunk-H37HHX3E.js → chunk-VSRPS3J7.js} +14 -14
  204. package/dist/{chunk-5ZNY7IZI.js → chunk-WMESXBJM.js} +37 -3
  205. package/dist/{chunk-54QCG45Y.js → chunk-WOYADZF5.js} +56 -5
  206. package/dist/{chunk-7Y5UDEVM.js → chunk-WZHZCDDO.js} +6 -5
  207. package/dist/{chunk-3NGZ4PL7.js → chunk-X2Q5NLUL.js} +11 -2
  208. package/dist/{chunk-YE7NH53A.js → chunk-X33NYQYJ.js} +2 -2
  209. package/dist/{chunk-UXBD22CD.js → chunk-XHK3FS3W.js} +3 -2
  210. package/dist/{chunk-3QDSCJ3F.js → chunk-XZXBB3TN.js} +2 -2
  211. package/dist/{chunk-JSKBHUR7.js → chunk-YCANDMI2.js} +2 -2
  212. package/dist/{chunk-JBSCL2XT.js → chunk-YLXTKI6M.js} +1 -1
  213. package/dist/{chunk-G7WO77Z2.js → chunk-YTCFACP4.js} +812 -896
  214. package/dist/{chunk-LTVCRHHD.js → chunk-Z6RSN7KS.js} +7 -6
  215. package/dist/{cleanup-graph-garbage-KUABW6LS.js → cleanup-graph-garbage-XWUFAMFO.js} +6 -6
  216. package/dist/{co-activation-XMPHKGHR.js → co-activation-ZCHPLLP6.js} +4 -4
  217. package/dist/{co-occurrence-SHKSJ6CV.js → co-occurrence-KG3LKALN.js} +4 -4
  218. package/dist/{code-context-index-EXXDY3QZ.js → code-context-index-WSOJQ72R.js} +5 -5
  219. package/dist/{content-extractor-RHITF2KM.js → content-extractor-NXYNEF5K.js} +2 -2
  220. package/dist/{conversation-wiki-populator-WU4HEQ7C.js → conversation-wiki-populator-WQN3IUU6.js} +1 -1
  221. package/dist/{crdt-sync-UJELKSNX.js → crdt-sync-4PFGPZXV.js} +8 -1
  222. package/dist/{crm-webhook-HHNBS7LY.js → crm-webhook-II7Z45Q6.js} +2 -2
  223. package/dist/cto-delegation-gate-JWWOJPNC.js +669 -0
  224. package/dist/{daemon-auth-7IFSV5FG.js → daemon-auth-3FEAHFWC.js} +5 -3
  225. package/dist/{daemon-orchestration-7QB6QOXT.js → daemon-orchestration-FX4XZDR5.js} +46 -27
  226. package/dist/{daemon-ready-5XI5BIJD.js → daemon-ready-4JTSFKAY.js} +1 -1
  227. package/dist/{daemon-ready-signal-E7VMIQ6I.js → daemon-ready-signal-LPAZWQOV.js} +5 -1
  228. package/dist/daemon-restart-circuit-breaker-PEGEIP6H.js +35 -0
  229. package/dist/daemon-timer-report-NM44WQRH.js +25 -0
  230. package/dist/{db-backup-DLD4QZBO.js → db-backup-W2QFSYQC.js} +15 -5
  231. package/dist/{db-restore-events-JVEEP52Z.js → db-restore-events-MQ2DBGEQ.js} +2 -2
  232. package/dist/dispatch-ack-VYH3ONSS.js +27 -0
  233. package/dist/{doc-graph-extractor-3TRLGD7M.js → doc-graph-extractor-F6ODFIID.js} +4 -4
  234. package/dist/{documents-FHIBU7KJ.js → documents-23WX2FPQ.js} +12 -12
  235. package/dist/dreaming-NWD22UQ5.js +46 -0
  236. package/dist/{exe-drift-KY2KHZEL.js → exe-drift-CW72FBGE.js} +5 -5
  237. package/dist/{exe-export-SP6G3QF6.js → exe-export-AUJ7CV7G.js} +11 -11
  238. package/dist/{exe-import-KJU7FBVQ.js → exe-import-JX4I52VE.js} +11 -11
  239. package/dist/{exe-key-M6TYHNUW.js → exe-key-2N6LY2BU.js} +241 -226
  240. package/dist/{exe-org-BGZNNE4H.js → exe-org-X4CSNCKS.js} +3 -3
  241. package/dist/{exe-snapshot-ZNPGUKRZ.js → exe-snapshot-XZ7FVCYZ.js} +31 -29
  242. package/dist/{fast-db-init-QQB6IVWV.js → fast-db-init-4CWHSOOR.js} +1 -1
  243. package/dist/{founder-context-PQR3BUS7.js → founder-context-7L3CFPYN.js} +4 -4
  244. package/dist/gateway/index.js +14 -14
  245. package/dist/{gateway-client-GRBOJQYC.js → gateway-client-7LMZKHTH.js} +1 -1
  246. package/dist/git-main-guard-UZP3KXYI.js +39 -0
  247. package/dist/{git-staleness-UGB5J3K7.js → git-staleness-CI2R4QOJ.js} +4 -4
  248. package/dist/{global-procedures-R7KRREEK.js → global-procedures-XQX3LUH6.js} +6 -6
  249. package/dist/{graph-auto-extract-LKIQ57PL.js → graph-auto-extract-OURWMGBS.js} +4 -4
  250. package/dist/{hook-integrity-WURH6DS3.js → hook-integrity-XY47IM7G.js} +1 -1
  251. package/dist/hook-prefetch-PHRRKY4C.js +137 -0
  252. package/dist/hooks/bug-report-worker.js +32 -28
  253. package/dist/hooks/codex-stop-task-finalizer.js +32 -28
  254. package/dist/hooks/commit-complete.js +29 -27
  255. package/dist/hooks/error-recall.js +12 -11
  256. package/dist/hooks/exe-heartbeat-hook.js +6 -6
  257. package/dist/hooks/ingest-worker.js +11 -11
  258. package/dist/hooks/ingest.js +18 -18
  259. package/dist/hooks/instructions-loaded.js +7 -7
  260. package/dist/hooks/manifest.json +20 -20
  261. package/dist/hooks/notification.js +7 -7
  262. package/dist/hooks/post-compact.js +28 -26
  263. package/dist/hooks/post-tool-combined.js +12 -12
  264. package/dist/hooks/pre-compact.js +29 -27
  265. package/dist/hooks/pre-tool-use.js +180 -47
  266. package/dist/hooks/prompt-submit.js +324 -273
  267. package/dist/hooks/session-end.js +35 -33
  268. package/dist/hooks/session-start.js +28 -21
  269. package/dist/hooks/stop.js +35 -33
  270. package/dist/hooks/subagent-stop.js +28 -26
  271. package/dist/hooks/summary-worker.js +36 -34
  272. package/dist/index.js +39 -37
  273. package/dist/{installer-SB2N5NKH.js → installer-G3JAO3NT.js} +9 -9
  274. package/dist/{installer-MZWWBXM6.js → installer-JND3RJ6Q.js} +9 -9
  275. package/dist/{installer-MNPXDLGG.js → installer-L7EVH5U5.js} +9 -9
  276. package/dist/{intercom-queue-VU2G6F5R.js → intercom-queue-ZFEQALR3.js} +25 -23
  277. package/dist/{key-backup-status-TNEHXA2X.js → key-backup-status-LOSMVATJ.js} +2 -2
  278. package/dist/lib/agent-config.js +4 -3
  279. package/dist/lib/cloud-sync.js +19 -19
  280. package/dist/lib/config.js +2 -2
  281. package/dist/lib/consolidation.js +9 -9
  282. package/dist/lib/crypto.js +3 -3
  283. package/dist/lib/database.js +6 -4
  284. package/dist/lib/db-daemon-client.js +5 -5
  285. package/dist/lib/db-read-worker-client.js +9 -3
  286. package/dist/lib/db.js +6 -4
  287. package/dist/lib/device-registry.js +3 -3
  288. package/dist/lib/embed-worker.js +2 -2
  289. package/dist/lib/embedder.js +5 -5
  290. package/dist/lib/employee-templates.js +7 -7
  291. package/dist/lib/employees.js +10 -4
  292. package/dist/lib/exe-daemon-client.js +4 -4
  293. package/dist/lib/exe-daemon.js +651 -158
  294. package/dist/lib/hybrid-search.js +11 -9
  295. package/dist/lib/identity.js +4 -4
  296. package/dist/lib/keychain.js +1 -1
  297. package/dist/lib/license.js +4 -4
  298. package/dist/lib/messaging.js +28 -24
  299. package/dist/lib/post-tool-memory.js +3 -3
  300. package/dist/lib/registry-proxy.js +1 -1
  301. package/dist/lib/reminders.js +15 -7
  302. package/dist/lib/schedules.js +9 -9
  303. package/dist/lib/session-registry.js +6 -6
  304. package/dist/lib/skill-learning.js +10 -10
  305. package/dist/lib/status-brief.js +4 -4
  306. package/dist/lib/store.js +8 -8
  307. package/dist/lib/task-router.js +5 -5
  308. package/dist/lib/tasks.js +29 -25
  309. package/dist/lib/tmux-routing.js +56 -25
  310. package/dist/lib/tmux-status.js +9 -3
  311. package/dist/lib/tmux-transport.js +1 -1
  312. package/dist/lib/token-spend.js +5 -5
  313. package/dist/lib/transport.js +2 -2
  314. package/dist/lib/ws-client.js +1 -1
  315. package/dist/{license-gate-BYDMFMFT.js → license-gate-QTRQHV4F.js} +5 -5
  316. package/dist/{license-sync-N3RNYVP2.js → license-sync-N3UJFWAW.js} +4 -4
  317. package/dist/mcp/register-tools.js +96 -89
  318. package/dist/mcp/server.js +98 -91
  319. package/dist/mcp/tools/complete-reminder.js +6 -6
  320. package/dist/mcp/tools/create-reminder.js +6 -6
  321. package/dist/mcp/tools/create-task.js +37 -28
  322. package/dist/mcp/tools/deactivate-behavior.js +11 -11
  323. package/dist/mcp/tools/list-reminders.js +6 -6
  324. package/dist/mcp/tools/list-tasks.js +35 -29
  325. package/dist/mcp/tools/send-message.js +28 -26
  326. package/dist/mcp/tools/update-task.js +34 -28
  327. package/dist/{mcp-http-config-EMAVS2JI.js → mcp-http-config-BDL36JZ3.js} +6 -6
  328. package/dist/{mcp-port-config-FFAMMLLE.js → mcp-port-config-6HYY6J7K.js} +2 -2
  329. package/dist/mcp-session-identity-T7H2EKFQ.js +177 -0
  330. package/dist/{memory-cards-TQRLZI4D.js → memory-cards-ZRDW7QBX.js} +8 -8
  331. package/dist/{memory-graph-extractor-IWGNVAFU.js → memory-graph-extractor-QLXDMHRS.js} +5 -5
  332. package/dist/{memory-poisoning-defense-T4ITBGSG.js → memory-poisoning-defense-HJTXYCWH.js} +4 -4
  333. package/dist/{memory-pressure-watchdog-RRIAXPXQ.js → memory-pressure-watchdog-HN5X7AVN.js} +76 -37
  334. package/dist/{memory-queue-X2CSEAKE.js → memory-queue-2UOOF27L.js} +5 -3
  335. package/dist/{memory-queue-client-BKQHTYTH.js → memory-queue-client-O5U6F6XP.js} +6 -6
  336. package/dist/{memory-reflection-6N4J2FL7.js → memory-reflection-WVNFBJAA.js} +4 -4
  337. package/dist/{monitor-grants-RZOVSYVO.js → monitor-grants-E3ELDEWD.js} +5 -5
  338. package/dist/{monitor-identity-MOXISYNG.js → monitor-identity-GLFZSEAH.js} +2 -2
  339. package/dist/notification-ledger-SZEPGJQ7.js +409 -0
  340. package/dist/{notifications-KONB3C62.js → notifications-4UT53CDG.js} +25 -23
  341. package/dist/{orchestration-events-5SIJOE4H.js → orchestration-events-WV4NWKZH.js} +5 -5
  342. package/dist/{orchestration-phase-CXRCBCK7.js → orchestration-phase-AWBXPO52.js} +3 -3
  343. package/dist/orchestrator-UAC3RW2T.js +47 -0
  344. package/dist/{pipeline-router-O6HU7DKH.js → pipeline-router-LM53NMWJ.js} +5 -5
  345. package/dist/{plan-limits-GRNBOBB3.js → plan-limits-2FEY2GOS.js} +7 -7
  346. package/dist/platform-procedures-X5DFJFV7.js +13 -0
  347. package/dist/{preferences-TYTGDXQZ.js → preferences-TWIXZBKS.js} +2 -2
  348. package/dist/{project-boot-SD7GM24K.js → project-boot-4NUH5FRU.js} +2 -2
  349. package/dist/{projection-worker-ZVOFHTXT.js → projection-worker-FZ7YSN3G.js} +5 -5
  350. package/dist/{prospective-memory-W6S67LZZ.js → prospective-memory-6D2ASWM3.js} +4 -4
  351. package/dist/{push-notifications-W5JRXLKJ.js → push-notifications-U6FIBQRW.js} +3 -3
  352. package/dist/{reranker-QATGTAPC.js → reranker-GYYRPANK.js} +3 -3
  353. package/dist/{retrieval-health-TWHKYCRK.js → retrieval-health-4Z242P3B.js} +1 -1
  354. package/dist/{review-polling-PCMD5BFN.js → review-polling-HXAFJZDA.js} +26 -24
  355. package/dist/runtime/index.js +37 -35
  356. package/dist/{session-events-3LCVQEL7.js → session-events-O3BV56ZX.js} +26 -24
  357. package/dist/{session-kill-telemetry-CZSPN5V6.js → session-kill-telemetry-AELE4JDK.js} +26 -24
  358. package/dist/session-mcp-config-YKNXG5DW.js +50 -0
  359. package/dist/{session-scope-CFHVSVAQ.js → session-scope-5EAPUT45.js} +25 -23
  360. package/dist/setup-wizard-NB6R4QVS.js +14 -0
  361. package/dist/{shard-manager-MBWQEYNG.js → shard-manager-35PWFR3B.js} +3 -3
  362. package/dist/{skill-refinement-74T6VDFM.js → skill-refinement-DVSYXBBP.js} +5 -5
  363. package/dist/stack-promote-RSOWO6EY.js +130 -0
  364. package/dist/{stack-release-XXMV7SPX.js → stack-release-HGFFFCGC.js} +112 -22
  365. package/dist/{stack-update-E2TKHHSQ.js → stack-update-ATCJFOEK.js} +7 -5
  366. package/dist/{steward-gate-WT7WXQIE.js → steward-gate-3GQ5XKMJ.js} +5 -5
  367. package/dist/support-inbox-4L62P4EP.js +33 -0
  368. package/dist/support-outbox-WHGPUYL2.js +16 -0
  369. package/dist/task-enforcement-IPIZX2MM.js +90 -0
  370. package/dist/{task-scope-CQEG5SSJ.js → task-scope-FOIW25HR.js} +27 -23
  371. package/dist/{tasks-crud-UGK5A25L.js → tasks-crud-HBDKE6C5.js} +35 -23
  372. package/dist/tasks-notify-G2U2U2YA.js +53 -0
  373. package/dist/{tasks-review-JKBRACII.js → tasks-review-27SFX5XN.js} +27 -23
  374. package/dist/{telemetry-upload-7LBYGPCB.js → telemetry-upload-ZOXHRWR5.js} +9 -9
  375. package/dist/tmux-command-guard-KSJKIX3C.js +117 -0
  376. package/dist/{token-budget-QBRJR4M5.js → token-budget-5Y4YPDO3.js} +5 -5
  377. package/dist/{tool-capability-index-Q6YQDL7I.js → tool-capability-index-VYF5GNJ2.js} +1 -1
  378. package/dist/{tool-telemetry-ULIDUK3P.js → tool-telemetry-KBXSBDTK.js} +1 -1
  379. package/dist/tui/App.js +40 -38
  380. package/dist/{tui-data-NPTGKT37.js → tui-data-NLFMBIQI.js} +25 -23
  381. package/dist/{update-check-HFO4VHO4.js → update-check-3FHAWIG2.js} +7 -3
  382. package/dist/update-support-UVUSZG7R.js +355 -0
  383. package/dist/{whatsapp-accounts-BWRZUY23.js → whatsapp-accounts-BFIOXYW5.js} +1 -1
  384. package/dist/{whatsapp-config-GOSELKTE.js → whatsapp-config-FAX6EA5K.js} +20 -13
  385. package/dist/{worker-gate-MXUQUG4M.js → worker-gate-3KUBAU32.js} +3 -3
  386. package/dist/{workflow-engine-EWCOLD47.js → workflow-engine-YITHXZR5.js} +2 -2
  387. package/dist/{working-memory-PY4AG577.js → working-memory-NUVB5SFV.js} +1 -1
  388. package/dist/worktree-LL62PLQB.js +47 -0
  389. package/dist/{worktree-sweep-ZAG3V24E.js → worktree-sweep-WTK3MTKH.js} +7 -7
  390. package/package.json +3 -2
  391. package/release-notes.json +86 -76
  392. package/dist/branch-hygiene-R5NVTRAY.js +0 -138
  393. package/dist/chunk-6IRVGOUL.js +0 -30
  394. package/dist/chunk-HMP5VT6A.js +0 -118
  395. package/dist/chunk-PVYR4FCQ.js +0 -113
  396. package/dist/chunk-UFAXZ2PY.js +0 -138
  397. package/dist/chunk-Y25OJWOQ.js +0 -45
  398. package/dist/chunk-YGAAZN3E.js +0 -47
  399. package/dist/cto-delegation-gate-DXNF5HVW.js +0 -290
  400. package/dist/dispatch-ack-4S44HBWB.js +0 -15
  401. package/dist/dreaming-OMFUEUCQ.js +0 -44
  402. package/dist/orchestrator-DUUX7FQV.js +0 -45
  403. package/dist/setup-wizard-TOFEJPLF.js +0 -13
  404. package/dist/tasks-notify-SMLDFBWM.js +0 -50
  405. package/dist/worktree-GVF2I5FP.js +0 -31
  406. /package/dist/{chunk-FLNSJ2TC.js → chunk-GIBYNT6W.js} +0 -0
  407. /package/dist/{chunk-NQBRGXYR.js → chunk-JRM4TAGS.js} +0 -0
  408. /package/dist/{chunk-WHRTDN5J.js → chunk-MGGOSFCR.js} +0 -0
  409. /package/dist/{chunk-D3QASX2W.js → chunk-QIFYLIUF.js} +0 -0
  410. /package/dist/{chunk-OADURIIN.js → chunk-WTH4CSAP.js} +0 -0
  411. /package/dist/{core-memory-VO5ZIBKH.js → core-memory-GAC6EWOQ.js} +0 -0
  412. /package/dist/{entity-boost-DNI4A5I7.js → entity-boost-NT6UO2Z3.js} +0 -0
  413. /package/dist/{message-queue-client-Q5BW3O5W.js → message-queue-client-4EOQRUXW.js} +0 -0
  414. /package/dist/{oauth-server-ROQFOEMM.js → oauth-server-67YBDP32.js} +0 -0
  415. /package/dist/{webhook-pipe-FZYLO6RR.js → webhook-pipe-LEXMUQ5B.js} +0 -0
  416. /package/dist/{wiki-acl-JA5UCQZ4.js → wiki-acl-74BLWG6J.js} +0 -0
  417. /package/dist/{wiki-client-VNDOBK63.js → wiki-client-EAN7F5LV.js} +0 -0
@@ -1,15 +1,23 @@
1
1
  import {
2
- clearDaemonReady,
3
- writeDaemonReady
4
- } from "../chunk-I5RLNOFK.js";
2
+ readBreakerAlert,
3
+ recordDaemonRestart,
4
+ restartBootsInWindow,
5
+ restartBreakerAlertPath,
6
+ writeDaemonExitBreadcrumb
7
+ } from "../chunk-HJ447YER.js";
5
8
  import {
6
9
  pushNotifyAsync
7
- } from "../chunk-BVV6NHKQ.js";
10
+ } from "../chunk-3SW4OEHB.js";
11
+ import {
12
+ clearDaemonReady,
13
+ eventLoopHeartbeatPath,
14
+ writeDaemonReady
15
+ } from "../chunk-MOPUCPXK.js";
8
16
  import {
9
17
  getMcpToolFamily,
10
18
  inferMcpRuntime,
11
19
  recordMcpHttpEvent
12
- } from "../chunk-5RACW3LX.js";
20
+ } from "../chunk-RAXVPNMR.js";
13
21
  import {
14
22
  deserializeArgs,
15
23
  serializeResultSet
@@ -21,8 +29,11 @@ import {
21
29
  findScopedDuplicate,
22
30
  governMemoryRecord,
23
31
  schedulePostWriteMemoryHygiene
24
- } from "../chunk-HHIBOU3P.js";
25
- import "../chunk-Y25OJWOQ.js";
32
+ } from "../chunk-6XWTQUO4.js";
33
+ import "../chunk-4QCFFW2H.js";
34
+ import {
35
+ BUSY_PATTERN
36
+ } from "../chunk-GWDSB25T.js";
26
37
  import {
27
38
  attributeSignalSource,
28
39
  consumeRestartIntentDetail,
@@ -30,10 +41,11 @@ import {
30
41
  requestRestart
31
42
  } from "../chunk-AFNRE2RV.js";
32
43
  import {
44
+ assessInitialBindIdentity,
33
45
  ensureDaemonToken,
34
46
  reconcileSessionAgentIdentity,
35
47
  shouldEnforceSessionIdentity
36
- } from "../chunk-3NGZ4PL7.js";
48
+ } from "../chunk-X2Q5NLUL.js";
37
49
  import {
38
50
  DAEMON_RSS_RESTART_DEBOUNCE,
39
51
  DAEMON_RSS_STARTUP_GRACE_MS,
@@ -70,8 +82,8 @@ import {
70
82
  EXE_AI_DIR,
71
83
  MODELS_DIR,
72
84
  resolveEmbedModelFile
73
- } from "../chunk-7Y5UDEVM.js";
74
- import "../chunk-SHIICYJW.js";
85
+ } from "../chunk-WZHZCDDO.js";
86
+ import "../chunk-BYTDMAGB.js";
75
87
  import "../chunk-MLKGABMK.js";
76
88
 
77
89
  // src/lib/exe-daemon.ts
@@ -79,11 +91,41 @@ import os2 from "os";
79
91
  import net from "net";
80
92
  import v8 from "v8";
81
93
  import { createServer as createHttpServer, request as httpRequest } from "http";
82
- import { randomUUID } from "crypto";
94
+ import { randomUUID, timingSafeEqual } from "crypto";
83
95
  import { writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2, existsSync as existsSync4, readFileSync as readFileSync4, chmodSync, readdirSync, renameSync, statSync } from "fs";
84
96
  import { writeFile } from "fs/promises";
85
97
  import { execSync as execSyncNode, execFile as execFileNode } from "child_process";
86
98
  import { promisify } from "util";
99
+
100
+ // src/lib/coo-respawn.ts
101
+ var NPM_ROOT_RETRY_MS = (() => {
102
+ const raw = process.env.EXE_NPM_ROOT_RETRY_MS;
103
+ const n = raw !== void 0 ? Number(raw) : NaN;
104
+ return Number.isFinite(n) && n >= 0 ? n : 5 * 6e4;
105
+ })();
106
+ function createMemoizedNpmGlobalRootResolver(execFile, log = (m) => void process.stderr.write(m), opts = {}) {
107
+ const retryMs = opts.retryMs ?? NPM_ROOT_RETRY_MS;
108
+ const now = opts.now ?? (() => Date.now());
109
+ let memo = null;
110
+ let failedAt = null;
111
+ return async () => {
112
+ if (memo !== null) return memo;
113
+ if (failedAt !== null && now() - failedAt < retryMs) return null;
114
+ try {
115
+ const { stdout } = await execFile("npm", ["root", "-g"], { timeout: 5e3, encoding: "utf8" });
116
+ memo = stdout.trim();
117
+ failedAt = null;
118
+ return memo;
119
+ } catch (err) {
120
+ failedAt = now();
121
+ log(`[exed] npm root -g resolution failed (memoized, retry after ${Math.round(retryMs / 1e3)}s): ${err instanceof Error ? err.message : String(err)}
122
+ `);
123
+ return null;
124
+ }
125
+ };
126
+ }
127
+
128
+ // src/lib/exe-daemon.ts
87
129
  import path3 from "path";
88
130
  import { fileURLToPath } from "url";
89
131
  import { fork, spawn } from "child_process";
@@ -192,6 +234,10 @@ function validateWriteShape(maskedSql) {
192
234
  }
193
235
  return null;
194
236
  }
237
+ function isOffloadableDaemonReadSql(sql) {
238
+ const masked = maskSqlLiteralsAndComments(sql.trim());
239
+ return DAEMON_READ_SQL_RE.test(masked);
240
+ }
195
241
  function validateDaemonDbSql(sql) {
196
242
  const original = sql.trim();
197
243
  if (!original) return "empty SQL is not allowed";
@@ -330,6 +376,20 @@ async function awaitPendingMcpInit(ownerKey, requestSessionId, deps, transientMa
330
376
  return null;
331
377
  }
332
378
 
379
+ // src/lib/daemon-self-heal-dispatch.ts
380
+ function dispatchSelfHealRestart(lagMs, trigger, deps) {
381
+ deps.writeBreadcrumb(lagMs, trigger);
382
+ deps.shutdown(75);
383
+ }
384
+ function resolveSelfHealThresholds(env = process.env) {
385
+ return {
386
+ singleMs: parseFloat(env.EXE_SELF_HEAL_SINGLE_MS ?? "") || 12e4,
387
+ thresholdMs: parseFloat(env.EXE_SELF_HEAL_THRESHOLD_MS ?? "") || 3e4,
388
+ consecutive: parseInt(env.EXE_SELF_HEAL_CONSECUTIVE ?? "") || 3,
389
+ starvationRatio: parseFloat(env.EXE_STARVATION_LOAD_RATIO ?? "1.5")
390
+ };
391
+ }
392
+
333
393
  // src/lib/daemon-restart-backoff.ts
334
394
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, unlinkSync, mkdirSync } from "fs";
335
395
  import { createHash } from "crypto";
@@ -815,7 +875,7 @@ async function capturePaneAsync(session, lines = 20) {
815
875
  }
816
876
  }
817
877
  function classifyPaneState(pane) {
818
- const busyPattern = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
878
+ const busyPattern = BUSY_PATTERN;
819
879
  if (!pane.includes("\u276F") && !pane.includes("Claude Code") && !busyPattern.test(pane) && !/Running…/.test(pane)) {
820
880
  if (/\$\s*$/.test(pane) || /% $/.test(pane.trimEnd())) return "no_claude";
821
881
  }
@@ -884,7 +944,7 @@ async function batchPaneAlive(sessions) {
884
944
  }
885
945
  return alive;
886
946
  }
887
- var CACHED_SESSION_BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
947
+ var CACHED_SESSION_BUSY_PATTERN = BUSY_PATTERN;
888
948
  function getCachedSessionState(sessionName, paneCache, aliveSessions) {
889
949
  if (!aliveSessions.has(sessionName)) return "offline";
890
950
  const pane = paneCache.get(sessionName);
@@ -974,6 +1034,46 @@ function shouldTraceDaemonTimer(durationMs = 0) {
974
1034
  return Date.now() - _startedAt2 < TIMER_TRACE_BOOT_WINDOW_MS || durationMs >= TIMER_TRACE_SLOW_MS;
975
1035
  }
976
1036
  var yieldToEventLoop = () => new Promise((resolve) => setImmediate(resolve));
1037
+ var _lastBlockingTimer = null;
1038
+ function getLastBlockingTimer() {
1039
+ return _lastBlockingTimer;
1040
+ }
1041
+ var _exitBreadcrumbWritten = false;
1042
+ function recordExitBreadcrumb(kind, exitCode, reason, extra) {
1043
+ if (_exitBreadcrumbWritten) return;
1044
+ _exitBreadcrumbWritten = true;
1045
+ let rssBytes;
1046
+ try {
1047
+ rssBytes = process.memoryUsage().rss;
1048
+ } catch {
1049
+ }
1050
+ const info = {
1051
+ exitCode,
1052
+ reason,
1053
+ kind,
1054
+ ts: Date.now(),
1055
+ uptimeMs: Date.now() - _startedAt2,
1056
+ ...rssBytes !== void 0 ? { rssBytes } : {},
1057
+ ...extra
1058
+ };
1059
+ writeDaemonExitBreadcrumb(info);
1060
+ }
1061
+ function recordSelfHealBreadcrumb(lagMs, trigger) {
1062
+ const blk = _lastBlockingTimer && Date.now() - _lastBlockingTimer.ts < 6e4 ? _lastBlockingTimer : null;
1063
+ recordExitBreadcrumb("self_heal", 75, `self_heal_event_loop_lag:${trigger}`, {
1064
+ lagMs: Math.round(lagMs),
1065
+ ...blk ? { timerName: blk.name, timerDurationMs: blk.durationMs } : {}
1066
+ });
1067
+ }
1068
+ var SELF_HEAL_ACTION_DEPS = {
1069
+ writeBreadcrumb: recordSelfHealBreadcrumb,
1070
+ shutdown: (code) => {
1071
+ void shutdown(code);
1072
+ },
1073
+ exit: (code) => {
1074
+ process.exit(code);
1075
+ }
1076
+ };
977
1077
  async function traceDaemonTimer(name, fn) {
978
1078
  if (_timerInFlight.has(name)) {
979
1079
  process.stderr.write(`[exed] Timer SKIPPED (overlap): ${name} \u2014 previous tick still running
@@ -988,6 +1088,7 @@ async function traceDaemonTimer(name, fn) {
988
1088
  `);
989
1089
  }
990
1090
  const timeoutHandle = setTimeout(() => {
1091
+ _lastBlockingTimer = { name, durationMs: TIMER_TIMEOUT_MS, ts: Date.now() };
991
1092
  process.stderr.write(
992
1093
  `[exed] Timer TIMEOUT WARNING: ${name} has been running for >${TIMER_TIMEOUT_MS / 1e3}s \u2014 likely blocking the event loop
993
1094
  `
@@ -1008,6 +1109,9 @@ async function traceDaemonTimer(name, fn) {
1008
1109
  const span = measureSpan(probe);
1009
1110
  const durationMs = Math.round(span.monoMs);
1010
1111
  const slept = span.sleptMs > 1e3;
1112
+ if (!slept && durationMs >= TIMER_TIMEOUT_MS) {
1113
+ _lastBlockingTimer = { name, durationMs, ts: Date.now() };
1114
+ }
1011
1115
  if (shouldTraceDaemonTimer(durationMs)) {
1012
1116
  const sleepNote = slept ? ` (wall ${Math.round(span.wallMs)}ms \u2014 host slept/clock-stepped ${Math.round(span.sleptMs)}ms; not an event-loop block)` : "";
1013
1117
  const msg = `[exed] Timer duration: ${name} ${durationMs}ms${sleepNote}`;
@@ -1166,9 +1270,6 @@ function isEventLoopBlockedNow(freshMs = EVENT_LOOP_BLOCKED_FRESH_MS) {
1166
1270
  return false;
1167
1271
  }
1168
1272
  }
1169
- function eventLoopHeartbeatPath() {
1170
- return path3.join(os2.homedir(), ".exe-os", "session-cache", "event-loop-heartbeat");
1171
- }
1172
1273
  function touchEventLoopHeartbeat() {
1173
1274
  try {
1174
1275
  const p = eventLoopHeartbeatPath();
@@ -1438,7 +1539,7 @@ async function loadModel() {
1438
1539
  void (async () => {
1439
1540
  try {
1440
1541
  if (_storeInitialized) {
1441
- const { writeNotification } = await import("../notifications-KONB3C62.js");
1542
+ const { writeNotification } = await import("../notifications-4UT53CDG.js");
1442
1543
  await writeNotification({
1443
1544
  agentId: "exe",
1444
1545
  agentRole: "system",
@@ -1554,7 +1655,7 @@ function disableEmbeddingsForInferenceTimeouts() {
1554
1655
  void (async () => {
1555
1656
  try {
1556
1657
  if (_storeInitialized) {
1557
- const { writeNotification } = await import("../notifications-KONB3C62.js");
1658
+ const { writeNotification } = await import("../notifications-4UT53CDG.js");
1558
1659
  await writeNotification({
1559
1660
  agentId: "exe",
1560
1661
  agentRole: "system",
@@ -1723,10 +1824,12 @@ function checkIdle() {
1723
1824
  _idleTimer.unref();
1724
1825
  }
1725
1826
  }
1726
- async function shutdown(exitCode = 0) {
1827
+ async function shutdown(exitCode = 0, reason = null) {
1727
1828
  if (_shuttingDown) return;
1728
1829
  _shuttingDown = true;
1729
1830
  _drainingWrites = true;
1831
+ const _exitKind = exitCode === 0 && !reason ? "clean" : reason ? "self_exit" : "restart-intent";
1832
+ recordExitBreadcrumb(_exitKind, exitCode, reason);
1730
1833
  clearDaemonReady();
1731
1834
  if (exitCode !== 0) {
1732
1835
  recordDaemonCrash();
@@ -1765,12 +1868,58 @@ async function shutdown(exitCode = 0) {
1765
1868
  }
1766
1869
  }
1767
1870
  try {
1768
- const { createBackupAsync, enforceRetention, hasRecentBackup } = await import("../db-backup-DLD4QZBO.js");
1769
- const PRE_RESTART_DEDUP_MS = 2 * 60 * 1e3;
1770
- if (hasRecentBackup("pre-restart", PRE_RESTART_DEDUP_MS)) {
1871
+ const {
1872
+ createBackupAsync,
1873
+ enforceRetention,
1874
+ hasRecentBackup,
1875
+ preRestartDedupWindowMs,
1876
+ findActiveDb,
1877
+ shouldSkipBackupUnderMemoryPressure
1878
+ } = await import("../db-backup-W2QFSYQC.js");
1879
+ const PRE_RESTART_DEDUP_MS = preRestartDedupWindowMs();
1880
+ const PRE_RESTART_STORM_CAP = (() => {
1881
+ const v = Number(process.env.EXE_PRE_RESTART_STORM_CAP);
1882
+ return Number.isFinite(v) && v > 0 ? Math.floor(v) : 3;
1883
+ })();
1884
+ let stormSkip = false;
1885
+ try {
1886
+ const recentRestarts = restartBootsInWindow();
1887
+ if (recentRestarts >= PRE_RESTART_STORM_CAP) {
1888
+ stormSkip = true;
1889
+ process.stderr.write(
1890
+ `[exed] Pre-restart backup SKIPPED \u2014 restart storm (${recentRestarts} restarts in breaker window \u2265 cap ${PRE_RESTART_STORM_CAP}). Bounding total 1.7GB backup bytes; last snapshot + daily backups remain (data-safe).
1891
+ `
1892
+ );
1893
+ }
1894
+ } catch {
1895
+ }
1896
+ let memoryGateSkip = false;
1897
+ try {
1898
+ const dbPath = findActiveDb();
1899
+ let dbBytes = 0;
1900
+ try {
1901
+ dbBytes = dbPath ? statSync(dbPath).size : 0;
1902
+ } catch {
1903
+ }
1904
+ const { getAvailableMemoryBytesSync } = await import("../memory-pressure-watchdog-HN5X7AVN.js");
1905
+ const freeBytes = getAvailableMemoryBytesSync();
1906
+ if (shouldSkipBackupUnderMemoryPressure(freeBytes, dbBytes)) {
1907
+ memoryGateSkip = true;
1908
+ process.stderr.write(
1909
+ `[exed] Pre-restart backup SKIPPED under memory pressure \u2014 ${Math.round(freeBytes / 1024 / 1024)}MB free vs ${Math.round(dbBytes / 1024 / 1024)}MB DB. Skipping the copy is data-safe; OOM-killing the machine mid-copy is not.
1910
+ `
1911
+ );
1912
+ }
1913
+ } catch {
1914
+ }
1915
+ if (stormSkip) {
1916
+ enforceRetention("pre-restart");
1917
+ } else if (hasRecentBackup("pre-restart", PRE_RESTART_DEDUP_MS)) {
1771
1918
  const deleted = enforceRetention("pre-restart");
1772
1919
  process.stderr.write(`[exed] Pre-restart backup skipped \u2014 recent snapshot exists (crash-loop dedup)${deleted > 0 ? `; rotated ${deleted} old` : ""}.
1773
1920
  `);
1921
+ } else if (memoryGateSkip) {
1922
+ enforceRetention("pre-restart");
1774
1923
  } else {
1775
1924
  const backupPath = await createBackupAsync("pre-restart");
1776
1925
  if (backupPath) {
@@ -1796,12 +1945,12 @@ async function shutdown(exitCode = 0) {
1796
1945
  `);
1797
1946
  }
1798
1947
  try {
1799
- const { stopProjectionWorker } = await import("../projection-worker-ZVOFHTXT.js");
1948
+ const { stopProjectionWorker } = await import("../projection-worker-FZ7YSN3G.js");
1800
1949
  stopProjectionWorker();
1801
1950
  } catch {
1802
1951
  }
1803
1952
  try {
1804
- const { disposeShards } = await import("../shard-manager-MBWQEYNG.js");
1953
+ const { disposeShards } = await import("../shard-manager-35PWFR3B.js");
1805
1954
  disposeShards();
1806
1955
  } catch {
1807
1956
  }
@@ -1862,7 +2011,7 @@ async function handleHealthCheck(socket, requestId) {
1862
2011
  let pipelineStatus = "unknown";
1863
2012
  if (dbConnected) {
1864
2013
  try {
1865
- await import("../pipeline-router-O6HU7DKH.js");
2014
+ await import("../pipeline-router-LM53NMWJ.js");
1866
2015
  pipelineStatus = "ok";
1867
2016
  } catch {
1868
2017
  pipelineStatus = "unavailable";
@@ -1967,6 +2116,18 @@ async function handleDbExecute(socket, requestId, sql, args) {
1967
2116
  sendResponse(socket, { id: requestId, error: "DB not initialized" });
1968
2117
  return;
1969
2118
  }
2119
+ if (isOffloadableDaemonReadSql(sql)) {
2120
+ try {
2121
+ const { isDbReadWorkerReady, runReadQueryInWorkerSerialized } = await import("./db-read-worker-client.js");
2122
+ if (isDbReadWorkerReady()) {
2123
+ const serialized = await runReadQueryInWorkerSerialized(sql, args);
2124
+ _dbRequestsServed++;
2125
+ sendResponse(socket, { id: requestId, db: serialized });
2126
+ return;
2127
+ }
2128
+ } catch {
2129
+ }
2130
+ }
1970
2131
  const { getClient } = await import("./database.js");
1971
2132
  const client = getClient();
1972
2133
  const deserializedArgs = deserializeArgs(args);
@@ -2258,7 +2419,7 @@ async function _writeMemoryRecordInner(entry) {
2258
2419
  const vRow = await client.execute({ sql: "SELECT version FROM memories WHERE id = ?", args: [id] });
2259
2420
  const version = Number(vRow.rows[0]?.version) || 0;
2260
2421
  try {
2261
- const { insertOntologyForMemory } = await import("../agentic-ontology-RNSXGXW4.js");
2422
+ const { insertOntologyForMemory } = await import("../agentic-ontology-3FXYMHKW.js");
2262
2423
  await insertOntologyForMemory({
2263
2424
  id,
2264
2425
  agent_id: record.agent_id,
@@ -2287,37 +2448,34 @@ function startMemoryQueueDrain() {
2287
2448
  fired("memory_queue_drain");
2288
2449
  if (!await ensureStoreForPolling()) return;
2289
2450
  try {
2290
- const { ackQueue, claimQueue, retryQueueEntries } = await import("../memory-queue-X2CSEAKE.js");
2451
+ const { ackQueue, claimQueue, retryQueueEntries, processQueueEntries } = await import("../memory-queue-2UOOF27L.js");
2291
2452
  const lease = claimQueue();
2292
2453
  if (!lease || lease.entries.length === 0) return;
2293
2454
  acted("memory_queue_drain");
2294
2455
  const entries = lease.entries;
2295
- let processed = 0;
2296
- const retryEntries = [];
2297
- let sinceYield = 0;
2298
- for (const entry of entries) {
2299
- if (!entry.raw_text || entry.raw_text.length < 10) continue;
2300
- try {
2301
- await writeMemoryRecord(entry);
2302
- processed++;
2303
- } catch (err) {
2304
- retryEntries.push(entry);
2456
+ const result = await processQueueEntries(entries, (entry) => writeMemoryRecord(entry), {
2457
+ isDraining: () => _drainingWrites,
2458
+ batchSize: MEMORY_DRAIN_BATCH,
2459
+ yieldFn: yieldToEventLoop,
2460
+ onWriteError: (_entry, err) => {
2305
2461
  process.stderr.write(
2306
2462
  `[exed] Queue drain write error: ${err instanceof Error ? err.message : String(err)}
2463
+ `
2464
+ );
2465
+ },
2466
+ onShutdownPreserve: (count) => {
2467
+ process.stderr.write(
2468
+ `[exed] Queue drain interrupted by shutdown \u2014 ${count} entr${count === 1 ? "y" : "ies"} preserved in lease for replay after restart
2307
2469
  `
2308
2470
  );
2309
2471
  }
2310
- if (++sinceYield >= MEMORY_DRAIN_BATCH) {
2311
- sinceYield = 0;
2312
- await yieldToEventLoop();
2313
- }
2314
- }
2315
- if (retryEntries.length === 0) {
2472
+ });
2473
+ if (result.retryEntries.length === 0) {
2316
2474
  ackQueue(lease.leasePath);
2317
2475
  } else {
2318
- retryQueueEntries(lease.leasePath, retryEntries);
2476
+ retryQueueEntries(lease.leasePath, result.retryEntries);
2319
2477
  }
2320
- process.stderr.write(`[exed] Queue drain: processed ${processed}/${entries.length} memories
2478
+ process.stderr.write(`[exed] Queue drain: processed ${result.processed}/${entries.length} memories${result.preserved > 0 ? ` (${result.preserved} preserved for replay)` : ""}
2321
2479
  `);
2322
2480
  } catch (err) {
2323
2481
  process.stderr.write(
@@ -2348,7 +2506,7 @@ function startMessageQueueDrain() {
2348
2506
  fired("message_queue_drain");
2349
2507
  if (!await ensureStoreForPolling()) return;
2350
2508
  try {
2351
- const { claimMessageQueue, ackMessageQueue } = await import("../message-queue-client-Q5BW3O5W.js");
2509
+ const { claimMessageQueue, ackMessageQueue } = await import("../message-queue-client-4EOQRUXW.js");
2352
2510
  const lease = claimMessageQueue();
2353
2511
  if (!lease || lease.entries.length === 0) return;
2354
2512
  acted("message_queue_drain");
@@ -2994,7 +3152,7 @@ async function startMcpHttpServer() {
2994
3152
  process.stderr.write("[exed] MCP HTTP: DB ready\n");
2995
3153
  setBootPhase("db_ready");
2996
3154
  _storeInitialized = true;
2997
- const { initLicenseGate, getCachedLicenseGate } = await import("../license-gate-BYDMFMFT.js");
3155
+ const { initLicenseGate, getCachedLicenseGate } = await import("../license-gate-QTRQHV4F.js");
2998
3156
  const gateResult = await initLicenseGate();
2999
3157
  if (!gateResult.hasKey) {
3000
3158
  process.stderr.write(
@@ -3009,13 +3167,13 @@ async function startMcpHttpServer() {
3009
3167
  let _cachedWrapTelemetry = null;
3010
3168
  async function getWrapTelemetry() {
3011
3169
  if (!_cachedWrapTelemetry) {
3012
- const { wrapServerWithTelemetry } = await import("../tool-telemetry-ULIDUK3P.js");
3170
+ const { wrapServerWithTelemetry } = await import("../tool-telemetry-KBXSBDTK.js");
3013
3171
  _cachedWrapTelemetry = wrapServerWithTelemetry;
3014
3172
  }
3015
3173
  return _cachedWrapTelemetry;
3016
3174
  }
3017
3175
  Promise.all([
3018
- import("../tool-capability-index-Q6YQDL7I.js"),
3176
+ import("../tool-capability-index-VYF5GNJ2.js"),
3019
3177
  import("../tool-gates-3IC7DK4R.js")
3020
3178
  ]).then(async ([{ getToolCapabilityIndex }, { TOOL_CATEGORIES }]) => {
3021
3179
  const gateState = getCachedLicenseGate();
@@ -3077,9 +3235,11 @@ async function startMcpHttpServer() {
3077
3235
  if (!header) return false;
3078
3236
  const token = header.replace(/^Bearer\s+/i, "");
3079
3237
  if (!token || token === header) return false;
3080
- if (token === _daemonToken) return true;
3238
+ const tokenBuf = Buffer.from(token);
3239
+ const expectedBuf = Buffer.from(_daemonToken);
3240
+ if (tokenBuf.length === expectedBuf.length && timingSafeEqual(tokenBuf, expectedBuf)) return true;
3081
3241
  try {
3082
- const { verifyAccessToken } = await import("../oauth-server-ROQFOEMM.js");
3242
+ const { verifyAccessToken } = await import("../oauth-server-67YBDP32.js");
3083
3243
  const result = verifyAccessToken(token);
3084
3244
  return result.valid;
3085
3245
  } catch {
@@ -3295,6 +3455,14 @@ async function startMcpHttpServer() {
3295
3455
  version: PACKAGE_VERSION,
3296
3456
  eventLoopLagMs: Math.round(elLag),
3297
3457
  eventLoopBlockedNow: blockedNow,
3458
+ // Feature 9ddc55b2 (timer health dashboard): expose the names of the
3459
+ // timers executing RIGHT NOW. This is a plain read of the existing
3460
+ // in-memory overlap-guard Set (≤ ~96 short strings) on an existing
3461
+ // request handler — it adds ZERO work to the timer hot path. Without
3462
+ // it "is this timer in-flight?" is unanswerable from outside the
3463
+ // process: traceDaemonTimer writes tick *starts* to stderr only, never
3464
+ // durably. When a tick blocks the loop this is the field that names it.
3465
+ timersInFlight: [..._timerInFlight],
3298
3466
  ...blockedNow && { warning: "Event loop blocked marker is fresh \u2014 /mcp returning 503 Retry-After until marker clears (~10s)" },
3299
3467
  ...!blockedNow && degraded && { warning: `Event loop lag ${Math.round(elLag)}ms exceeds 5000ms threshold \u2014 daemon may be unresponsive` }
3300
3468
  }));
@@ -3324,7 +3492,7 @@ async function startMcpHttpServer() {
3324
3492
  return;
3325
3493
  }
3326
3494
  try {
3327
- const { handleOAuthRoute } = await import("../oauth-server-ROQFOEMM.js");
3495
+ const { handleOAuthRoute } = await import("../oauth-server-67YBDP32.js");
3328
3496
  const handled = await handleOAuthRoute(req, res, url, MCP_HTTP_PORT);
3329
3497
  if (handled) return;
3330
3498
  } catch (err) {
@@ -3356,7 +3524,7 @@ async function startMcpHttpServer() {
3356
3524
  for await (const chunk of req) chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
3357
3525
  const rawBody = Buffer.concat(chunks);
3358
3526
  try {
3359
- const { loadWebhookConfig, verifyHmac, processWebhook } = await import("../webhook-pipe-FZYLO6RR.js");
3527
+ const { loadWebhookConfig, verifyHmac, processWebhook } = await import("../webhook-pipe-LEXMUQ5B.js");
3360
3528
  const webhookConfig = await loadWebhookConfig();
3361
3529
  const serviceConfig = webhookConfig[serviceName];
3362
3530
  if (!serviceConfig) {
@@ -3452,7 +3620,7 @@ async function startMcpHttpServer() {
3452
3620
  contextPct: body.context_pct
3453
3621
  });
3454
3622
  if (body.context_pct !== void 0 && body.context_pct > 70) {
3455
- void import("../orchestration-events-5SIJOE4H.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
3623
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
3456
3624
  recordOE({
3457
3625
  eventType: "context.pressure",
3458
3626
  source: "exe-daemon.heartbeat",
@@ -3535,36 +3703,70 @@ async function startMcpHttpServer() {
3535
3703
  }
3536
3704
  const projectNameHeader = req.headers["x-project-name"] || "";
3537
3705
  let sessionHint = req.headers["x-exe-session-name"] || req.headers["x-exe-session"] || "";
3538
- if (sessionHint.includes("$(") || sessionHint.includes("#{") || sessionHint.includes("tmux")) {
3539
- sessionHint = "";
3706
+ if (sessionHint) {
3707
+ try {
3708
+ const { sanitizeSessionHintHeader, rejectForgedSessionHint } = await import("../mcp-session-identity-T7H2EKFQ.js");
3709
+ const rawHint = sessionHint;
3710
+ sessionHint = sanitizeSessionHintHeader(sessionHint);
3711
+ if (!sessionHint) {
3712
+ process.stderr.write(
3713
+ `[daemon] WARN: discarded malformed session identity header ${JSON.stringify(rawHint)} from agent "${agentId}"
3714
+ `
3715
+ );
3716
+ } else {
3717
+ try {
3718
+ const { listSessions: listRegistrySessions } = await import("./session-registry.js");
3719
+ const verdict = rejectForgedSessionHint({
3720
+ agentId,
3721
+ hint: sessionHint,
3722
+ registrySessions: listRegistrySessions()
3723
+ });
3724
+ if (verdict.rejected) {
3725
+ process.stderr.write(`[daemon] WARN: ${verdict.reason}
3726
+ `);
3727
+ sessionHint = "";
3728
+ }
3729
+ } catch {
3730
+ }
3731
+ }
3732
+ } catch {
3733
+ if (sessionHint.includes("$(") || sessionHint.includes("#{") || sessionHint.includes("tmux")) {
3734
+ sessionHint = "";
3735
+ }
3736
+ }
3540
3737
  }
3541
3738
  const clientProvidedSessionHint = Boolean(sessionHint);
3542
3739
  if (!sessionHint && agentId) {
3543
3740
  try {
3544
3741
  const liveSessions = await getTmuxSessionsAsync();
3545
- const agentSessions = liveSessions.filter((s) => s.startsWith(agentId + "-"));
3546
- if (agentSessions.length === 1) {
3547
- sessionHint = agentSessions[0];
3742
+ const paneCommands = await getPaneCommandsAsync();
3743
+ const { resolveMcpSessionHint } = await import("../mcp-session-identity-T7H2EKFQ.js");
3744
+ let registrySessions = [];
3745
+ try {
3746
+ const { listSessions: listRegistrySessions } = await import("./session-registry.js");
3747
+ registrySessions = listRegistrySessions();
3748
+ } catch {
3548
3749
  }
3549
- if (!sessionHint) {
3550
- const paneCommands = await getPaneCommandsAsync();
3551
- const roots = liveSessions.filter(
3552
- (s) => !s.includes("-") && /^[a-z]+\d*$/.test(s) && coordinatorPaneHasLiveAgent(s, paneCommands)
3553
- );
3554
- if (roots.length === 1) {
3555
- sessionHint = roots[0];
3556
- } else if (roots.length > 1 && agentId) {
3557
- const agentRoots = roots.filter((r) => r.startsWith(agentId));
3558
- if (agentRoots.length === 1) {
3559
- sessionHint = agentRoots[0];
3560
- }
3561
- if (!sessionHint) {
3562
- process.stderr.write(
3563
- `[daemon] WARN: ${roots.length} coordinator sessions (${roots.join(", ")}), cannot auto-resolve for agent "${agentId}". Use per-session MCP config.
3564
- `
3565
- );
3566
- }
3567
- }
3750
+ let isCoordinator = false;
3751
+ try {
3752
+ const { isCoordinatorName } = await import("./employees.js");
3753
+ isCoordinator = isCoordinatorName(agentId);
3754
+ } catch {
3755
+ }
3756
+ const resolution = resolveMcpSessionHint({
3757
+ agentId,
3758
+ isCoordinator,
3759
+ liveTmuxSessions: liveSessions,
3760
+ registrySessions,
3761
+ // Only count coordinators that still host a LIVE agent. Orphaned
3762
+ // coordinator shells (agent exited, tmux shell lingers) would otherwise
3763
+ // inflate the count forever and spam "cannot auto-resolve" (bug 6c46d301).
3764
+ coordinatorHasLiveAgent: (s) => coordinatorPaneHasLiveAgent(s, paneCommands)
3765
+ });
3766
+ sessionHint = resolution.sessionHint;
3767
+ if (resolution.warning) {
3768
+ process.stderr.write(`[daemon] WARN: ${resolution.warning}
3769
+ `);
3568
3770
  }
3569
3771
  } catch {
3570
3772
  }
@@ -3662,6 +3864,54 @@ async function startMcpHttpServer() {
3662
3864
  } catch (dbInitErr) {
3663
3865
  process.stderr.write(`[exed] DB init on new session FAILED: ${dbInitErr instanceof Error ? dbInitErr.message : String(dbInitErr)}
3664
3866
  `);
3867
+ }
3868
+ try {
3869
+ const { isManagementIdentity } = await import("./employees.js");
3870
+ if (isManagementIdentity(agentId)) {
3871
+ let bindRegistry = [];
3872
+ let bindLive = [];
3873
+ try {
3874
+ const { listSessions: listRegistrySessions } = await import("./session-registry.js");
3875
+ bindRegistry = listRegistrySessions();
3876
+ bindLive = await getTmuxSessionsAsync();
3877
+ } catch {
3878
+ }
3879
+ const { isLauncherCorroboratedIdentity } = await import("../mcp-session-identity-T7H2EKFQ.js");
3880
+ const corroborated = isLauncherCorroboratedIdentity({
3881
+ agentId,
3882
+ registrySessions: bindRegistry,
3883
+ liveTmuxSessions: bindLive
3884
+ });
3885
+ const assessment = assessInitialBindIdentity({
3886
+ agentId,
3887
+ privileged: true,
3888
+ corroborated,
3889
+ enforce: shouldEnforceSessionIdentity()
3890
+ });
3891
+ if (assessment.flagged) {
3892
+ process.stderr.write(`[exed] SECURITY: ${assessment.reason}
3893
+ `);
3894
+ recordMcpHttpEvent({
3895
+ level: "warn",
3896
+ message: assessment.reject ? "initial_bind_identity_rejected" : "initial_bind_identity_uncorroborated",
3897
+ method: req.method,
3898
+ agentId,
3899
+ agentRole,
3900
+ runtime
3901
+ });
3902
+ }
3903
+ if (assessment.reject) {
3904
+ sendJsonRpcError2(
3905
+ res,
3906
+ 403,
3907
+ `Refusing to bind privileged identity "${agentId}" to a new MCP session: the X-Agent-Id header claims a management role but no launcher-written session-registry entry corroborates it (bug 2138232d). Launch the agent through exe-os, or set EXE_ENFORCE_SESSION_IDENTITY=0 for warn-only.`,
3908
+ getJsonRpcId2(parsedBody),
3909
+ { agentId, agentRole }
3910
+ );
3911
+ return;
3912
+ }
3913
+ }
3914
+ } catch {
3665
3915
  }
3666
3916
  const initIsTransient = !clientProvidedSessionHint;
3667
3917
  const initOwnerKey = mcpSessionOwnerKey2({ agentId, runtime, sessionHint, transient: initIsTransient });
@@ -3868,6 +4118,25 @@ async function startMcpHttpServer() {
3868
4118
  effectiveSessionHint = stored.sessionHint;
3869
4119
  }
3870
4120
  }
4121
+ try {
4122
+ const { reconcileHintWithRegistryIdentity } = await import("../mcp-session-identity-T7H2EKFQ.js");
4123
+ const { listSessions: listRegistrySessions } = await import("./session-registry.js");
4124
+ const recon = reconcileHintWithRegistryIdentity({
4125
+ agentId,
4126
+ hint: effectiveSessionHint,
4127
+ clientProvided: clientProvidedSessionHint,
4128
+ registrySessions: listRegistrySessions(),
4129
+ liveTmuxSessions: await getTmuxSessionsAsync()
4130
+ });
4131
+ if (recon.message) process.stderr.write(`[daemon] ${recon.message}
4132
+ `);
4133
+ if (recon.corrected) {
4134
+ effectiveSessionHint = recon.sessionHint;
4135
+ const stored = activeRequestSessionId ? sessionDetails.get(activeRequestSessionId) : void 0;
4136
+ if (stored && recon.sessionHint) stored.sessionHint = recon.sessionHint;
4137
+ }
4138
+ } catch {
4139
+ }
3871
4140
  try {
3872
4141
  await runWithAgent({ agentId, agentRole, sessionHint: effectiveSessionHint, projectName: projectNameHeader || void 0 }, async () => {
3873
4142
  if (wantsJsonOnly) {
@@ -3988,7 +4257,7 @@ async function startMcpHttpServer() {
3988
4257
  `);
3989
4258
  _boundMcpPort = MCP_HTTP_PORT;
3990
4259
  writeDaemonReady({ pid: process.pid, port: MCP_HTTP_PORT });
3991
- void import("../mcp-port-config-FFAMMLLE.js").then(({ persistMcpPortToConfig }) => persistMcpPortToConfig(String(MCP_HTTP_PORT))).catch(() => {
4260
+ void import("../mcp-port-config-6HYY6J7K.js").then(({ persistMcpPortToConfig }) => persistMcpPortToConfig(String(MCP_HTTP_PORT))).catch(() => {
3992
4261
  });
3993
4262
  recordMcpHttpEvent({
3994
4263
  level: "info",
@@ -4046,6 +4315,20 @@ async function ensureStoreForPolling() {
4046
4315
  }
4047
4316
  await initDatabase({ dbPath: config.dbPath, encryptionKey: masterKey.toString("hex") });
4048
4317
  await ensureSchema();
4318
+ try {
4319
+ const { isLedgerEnabled } = await import("../notification-ledger-SZEPGJQ7.js");
4320
+ if (isLedgerEnabled()) {
4321
+ const { bumpBootGeneration } = await import("../boot-generation-BL2ISK4U.js");
4322
+ const { setDaemonReadyGeneration } = await import("../daemon-ready-signal-LPAZWQOV.js");
4323
+ const generation = await bumpBootGeneration();
4324
+ setDaemonReadyGeneration(generation);
4325
+ process.stderr.write(`[exed] notification ledger enabled \u2014 boot generation ${generation}
4326
+ `);
4327
+ }
4328
+ } catch (e) {
4329
+ process.stderr.write(`[exed] boot-generation bump failed (non-fatal): ${e instanceof Error ? e.message : String(e)}
4330
+ `);
4331
+ }
4049
4332
  try {
4050
4333
  const { spawnDbReadWorker } = await import("./db-read-worker-client.js");
4051
4334
  spawnDbReadWorker(config.dbPath, masterKey.toString("hex"));
@@ -4065,13 +4348,13 @@ async function ensureStoreForPolling() {
4065
4348
  }
4066
4349
  }
4067
4350
  async function startReviewPolling() {
4068
- const polling = await import("../review-polling-PCMD5BFN.js");
4351
+ const polling = await import("../review-polling-HXAFJZDA.js");
4069
4352
  const state = {
4070
4353
  lastIntercomSent: /* @__PURE__ */ new Map(),
4071
4354
  lastNudgeSent: /* @__PURE__ */ new Map(),
4072
4355
  intervalMs: REVIEW_POLL_INTERVAL_MS
4073
4356
  };
4074
- const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-7QB6QOXT.js");
4357
+ const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-FX4XZDR5.js");
4075
4358
  const nudgeState = loadNudgeState();
4076
4359
  const tick = async () => traceDaemonTimer("review_polling", async () => {
4077
4360
  fired("review_polling");
@@ -4109,16 +4392,17 @@ async function startReviewPolling() {
4109
4392
  }
4110
4393
  var SESSION_TTL_INTERVAL_MS = 5 * 60 * 1e3;
4111
4394
  var SESSION_REGISTRY_MAINTENANCE_INTERVAL_MS = 5 * 60 * 1e3;
4395
+ var _wedgeObservations = /* @__PURE__ */ new Map();
4112
4396
  function startSessionTTL() {
4113
4397
  const tick = async () => traceDaemonTimer("session_ttl", async () => {
4114
4398
  fired("session_ttl");
4115
- if (!await ensureStoreForPolling()) return;
4116
- if (inPostRestartDestructiveGrace("session_ttl")) return;
4117
4399
  try {
4400
+ if (!await ensureStoreForPolling()) return;
4401
+ if (inPostRestartDestructiveGrace("session_ttl")) return;
4118
4402
  const { getClient } = await import("./database.js");
4119
- const { checkSessionTTL, createSessionTTLRealDeps } = await import("../daemon-orchestration-7QB6QOXT.js");
4403
+ const { checkSessionTTL, createSessionTTLRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
4120
4404
  const deps = createSessionTTLRealDeps(getClient);
4121
- const killed = await checkSessionTTL(deps);
4405
+ const killed = await checkSessionTTL(deps, _wedgeObservations);
4122
4406
  if (killed.length > 0) acted("session_ttl");
4123
4407
  } catch (err) {
4124
4408
  process.stderr.write(`[exed] Session TTL error: ${err instanceof Error ? err.message : String(err)}
@@ -4131,6 +4415,9 @@ function startSessionTTL() {
4131
4415
  `);
4132
4416
  }
4133
4417
  var COO_RESTART_COOLDOWN_MS = 5 * 6e4;
4418
+ var _resolveNpmGlobalRoot = createMemoizedNpmGlobalRootResolver(
4419
+ (file, args, opts) => execFileAsync(file, args, opts)
4420
+ );
4134
4421
  var _idleTickCounts = /* @__PURE__ */ new Map();
4135
4422
  function startIdleKill() {
4136
4423
  const tick = async () => traceDaemonTimer("idle_kill", async () => {
@@ -4165,7 +4452,7 @@ function startIdleKill() {
4165
4452
  const cfg = await getCachedConfig();
4166
4453
  if (!cfg) return;
4167
4454
  const { getClient } = await import("./database.js");
4168
- const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-7QB6QOXT.js");
4455
+ const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
4169
4456
  const { sessions: liveSessions, paneCache, aliveSessions } = await getSharedOrchestrationCaches();
4170
4457
  const realDeps = createIdleKillRealDeps(
4171
4458
  getClient,
@@ -4238,7 +4525,7 @@ function startConsolidation() {
4238
4525
  `);
4239
4526
  }
4240
4527
  try {
4241
- const { createBackupAsync, enforceRetention } = await import("../db-backup-DLD4QZBO.js");
4528
+ const { createBackupAsync, enforceRetention } = await import("../db-backup-W2QFSYQC.js");
4242
4529
  const p = await createBackupAsync("pre-consolidation");
4243
4530
  if (p) enforceRetention("pre-consolidation");
4244
4531
  } catch (e) {
@@ -4471,7 +4758,7 @@ function startSkillRefinement() {
4471
4758
  if (!shouldRunHeavyJob("skill_refinement")) return;
4472
4759
  try {
4473
4760
  if (!await ensureStoreForPolling()) return;
4474
- const { runSkillRefinement } = await import("../skill-refinement-74T6VDFM.js");
4761
+ const { runSkillRefinement } = await import("../skill-refinement-DVSYXBBP.js");
4475
4762
  const result = await runSkillRefinement();
4476
4763
  if (result.reviewed > 0) {
4477
4764
  acted("skill_refinement");
@@ -4497,8 +4784,8 @@ function startStaleBranchSweep() {
4497
4784
  const tick = async () => {
4498
4785
  fired("stale_branch_sweep");
4499
4786
  try {
4500
- const { discoverRepoPaths } = await import("../worktree-sweep-ZAG3V24E.js");
4501
- const { scanUnmergedBranches } = await import("../branch-hygiene-R5NVTRAY.js");
4787
+ const { discoverRepoPaths } = await import("../worktree-sweep-WTK3MTKH.js");
4788
+ const { scanUnmergedBranchesCached } = await import("../branch-hygiene-TZWK6QCF.js");
4502
4789
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4503
4790
  for (const k of _staleBranchAlertedToday) {
4504
4791
  if (!k.endsWith(today)) _staleBranchAlertedToday.delete(k);
@@ -4513,7 +4800,11 @@ function startStaleBranchSweep() {
4513
4800
  await yieldToEventLoop();
4514
4801
  let scan;
4515
4802
  try {
4516
- scan = await scanUnmergedBranches(repo, { staleHours: STALE_BRANCH_HOURS });
4803
+ scan = await scanUnmergedBranchesCached(
4804
+ repo,
4805
+ { staleHours: STALE_BRANCH_HOURS },
4806
+ { forceRefresh: true }
4807
+ );
4517
4808
  } catch {
4518
4809
  continue;
4519
4810
  }
@@ -4525,13 +4816,13 @@ function startStaleBranchSweep() {
4525
4816
  if (!_storeInitialized) continue;
4526
4817
  const stale = scan.branches.filter((b) => b.ageHours >= STALE_BRANCH_HOURS).slice(0, 5).map((b) => `${b.name} (+${b.ahead} commits, ${(b.ageHours / 24).toFixed(1)}d)`).join("; ");
4527
4818
  try {
4528
- const { writeNotification } = await import("../notifications-KONB3C62.js");
4819
+ const { writeNotification } = await import("../notifications-4UT53CDG.js");
4529
4820
  await writeNotification({
4530
4821
  agentId: "exe",
4531
4822
  agentRole: "system",
4532
4823
  event: "error_spike",
4533
4824
  project: repoName,
4534
- summary: `${scan.staleCount} unmerged remote branch(es) in ${repoName} are >${STALE_BRANCH_HOURS}h old with unique work \u2014 check before starting new work to avoid redoing it. Oldest: ${stale}. Review with: exe-os git-sweep --dry-run`,
4825
+ summary: `${scan.staleCount} unmerged remote branch(es) in ${repoName} are >${STALE_BRANCH_HOURS}h old with unique work \u2014 check before starting new work to avoid redoing it. Oldest: ${stale}. List them with: git branch -r --no-merged origin/main`,
4535
4826
  sessionScope: null
4536
4827
  });
4537
4828
  acted("stale_branch_sweep");
@@ -4982,7 +5273,7 @@ function startReflectionSweep() {
4982
5273
  );
4983
5274
  let runReflection;
4984
5275
  try {
4985
- ({ runReflection } = await import("../memory-reflection-6N4J2FL7.js"));
5276
+ ({ runReflection } = await import("../memory-reflection-WVNFBJAA.js"));
4986
5277
  } catch (importErr) {
4987
5278
  _reflectionImportFailed = true;
4988
5279
  process.stderr.write(`[exed] Reflection module unavailable (stale chunk hash?) \u2014 disabled until daemon restart: ${importErr instanceof Error ? importErr.message : String(importErr)}
@@ -5023,7 +5314,7 @@ function startReflectionSweep() {
5023
5314
  if (memories > 100 && cards < memories * 0.1) {
5024
5315
  process.stderr.write(`[exed] Memory cards sparse (${cards} cards / ${memories} memories) \u2014 running backfill...
5025
5316
  `);
5026
- const { insertMemoryCardsForBatch } = await import("../memory-cards-TQRLZI4D.js");
5317
+ const { insertMemoryCardsForBatch } = await import("../memory-cards-ZRDW7QBX.js");
5027
5318
  const batchSize = 500;
5028
5319
  let offset = 0;
5029
5320
  let totalCards = 0;
@@ -5062,13 +5353,25 @@ function startReflectionSweep() {
5062
5353
  process.stderr.write(`[exed] Reflection sweep started (every 6h)
5063
5354
  `);
5064
5355
  }
5065
- var DB_BACKUP_INTERVAL_MS = 24 * 60 * 60 * 1e3;
5356
+ var DB_BACKUP_TARGET_WINDOW_MS = Number(process.env.EXE_DB_BACKUP_TARGET_WINDOW_MS) || 6 * 60 * 60 * 1e3;
5357
+ var DB_BACKUP_INTERVAL_MS = Math.min(60 * 60 * 1e3, DB_BACKUP_TARGET_WINDOW_MS);
5066
5358
  function startDatabaseBackup() {
5067
5359
  const tick = async () => {
5068
5360
  fired("db_backup");
5069
- if (!shouldRunHeavyJob("db_backup")) return;
5070
5361
  try {
5071
- const { createBackupAsync, enforceRetention, hasBackupToday } = await import("../db-backup-DLD4QZBO.js");
5362
+ const { createBackupAsync, enforceRetention, hasBackupToday, hasRecentBackup } = await import("../db-backup-W2QFSYQC.js");
5363
+ if (!hasRecentBackup("guaranteed", DB_BACKUP_TARGET_WINDOW_MS)) {
5364
+ const guaranteedPath = await createBackupAsync("guaranteed");
5365
+ if (guaranteedPath) {
5366
+ acted("db_backup");
5367
+ const deleted = enforceRetention("guaranteed");
5368
+ process.stderr.write(
5369
+ `[exed] DB backup guaranteed: ${guaranteedPath.split("/").pop()} (target window ${Math.round(DB_BACKUP_TARGET_WINDOW_MS / 36e5)}h)${deleted > 0 ? ` (rotated ${deleted} old)` : ""}
5370
+ `
5371
+ );
5372
+ }
5373
+ }
5374
+ if (!shouldRunHeavyJob("db_backup_daily")) return;
5072
5375
  if (hasBackupToday("daily")) return;
5073
5376
  const backupPath = await createBackupAsync("daily");
5074
5377
  if (backupPath) {
@@ -5078,6 +5381,22 @@ function startDatabaseBackup() {
5078
5381
  `[exed] DB backup: ${backupPath.split("/").pop()}${deleted > 0 ? ` (rotated ${deleted} old)` : ""}
5079
5382
  `
5080
5383
  );
5384
+ try {
5385
+ const { maybeVerifyDailyBackup } = await import("../backup-verify-3Y2FHGZU.js");
5386
+ const verdict = await maybeVerifyDailyBackup(backupPath);
5387
+ if (verdict && !verdict.ok) {
5388
+ process.stderr.write(
5389
+ `[exed] DB backup VERIFY FAIL: ${verdict.backup} \u2014 ${verdict.reason}${verdict.detail ? `: ${verdict.detail}` : ""}
5390
+ `
5391
+ );
5392
+ } else if (verdict) {
5393
+ process.stderr.write(`[exed] DB backup verified OK (${verdict.source})
5394
+ `);
5395
+ }
5396
+ } catch (verr) {
5397
+ process.stderr.write(`[exed] DB backup verify skipped: ${verr instanceof Error ? verr.message : String(verr)}
5398
+ `);
5399
+ }
5081
5400
  }
5082
5401
  } catch (err) {
5083
5402
  process.stderr.write(`[exed] DB backup error: ${err instanceof Error ? err.message : String(err)}
@@ -5087,8 +5406,10 @@ function startDatabaseBackup() {
5087
5406
  tick();
5088
5407
  const timer = setInterval(() => void traceDaemonTimer("db_backup", tick), DB_BACKUP_INTERVAL_MS);
5089
5408
  timer.unref();
5090
- process.stderr.write(`[exed] Database backup started (daily, keep 3 days)
5091
- `);
5409
+ process.stderr.write(
5410
+ `[exed] Database backup started (guaranteed every \u2264${Math.round(DB_BACKUP_TARGET_WINDOW_MS / 36e5)}h; daily verify window retained)
5411
+ `
5412
+ );
5092
5413
  }
5093
5414
  var PURGE_INTERVAL_MS = 6 * 60 * 60 * 1e3;
5094
5415
  function startSoftDeletePurge() {
@@ -5138,7 +5459,7 @@ function startSessionEventsRetention() {
5138
5459
  if (!await ensureStoreForPolling()) return;
5139
5460
  try {
5140
5461
  const { getClient } = await import("./database.js");
5141
- const { sweepExpiredSessionEvents, DEFAULT_SESSION_EVENTS_RETENTION_DAYS } = await import("../session-events-3LCVQEL7.js");
5462
+ const { sweepExpiredSessionEvents, DEFAULT_SESSION_EVENTS_RETENTION_DAYS } = await import("../session-events-O3BV56ZX.js");
5142
5463
  const days = SESSION_EVENTS_RETENTION_DAYS ?? DEFAULT_SESSION_EVENTS_RETENTION_DAYS;
5143
5464
  const count = await sweepExpiredSessionEvents(getClient(), days);
5144
5465
  if (count > 0) {
@@ -5169,11 +5490,15 @@ function startIntercomQueueDrain() {
5169
5490
  const tick = async () => traceDaemonTimer("intercom_queue_drain", async () => {
5170
5491
  fired("intercom_queue_drain");
5171
5492
  try {
5172
- const { drainQueueAsync, readQueue } = await import("../intercom-queue-VU2G6F5R.js");
5493
+ const { drainQueueAsync, readQueue } = await import("../intercom-queue-ZFEQALR3.js");
5173
5494
  const {
5174
5495
  sendIntercomAsync: centralSendIntercomAsync,
5175
- decideQueuedNudgeDrain,
5176
- countScopedPendingReviews
5496
+ countScopedPendingReviews,
5497
+ countScopedOpenTasks,
5498
+ dispositionWedgedSessionTask,
5499
+ decideDrainSend,
5500
+ offlineIfEmpty,
5501
+ paneHasPendingInput
5177
5502
  } = await import("./tmux-routing.js");
5178
5503
  const { baseAgentName, getCoordinatorName } = await import("./employees.js");
5179
5504
  const agentsWithEmptyInbox = /* @__PURE__ */ new Set();
@@ -5206,6 +5531,18 @@ function startIntercomQueueDrain() {
5206
5531
  if (count !== null) pendingReviewCounts.set(target, count);
5207
5532
  }
5208
5533
  }
5534
+ const openTaskCounts = /* @__PURE__ */ new Map();
5535
+ {
5536
+ const queue = readQueue();
5537
+ const taskTargets = new Set(
5538
+ queue.filter((q) => q.intercomReason === "nudge" || q.intercomReason === "signal" || !q.intercomReason).map((q) => q.targetSession)
5539
+ );
5540
+ for (const target of taskTargets) {
5541
+ const agent = baseAgentName(target.split("-")[0] ?? target);
5542
+ const count = await countScopedOpenTasks(target, agent);
5543
+ if (count !== null) openTaskCounts.set(target, count);
5544
+ }
5545
+ }
5209
5546
  const result = await drainQueueAsync(
5210
5547
  // Bug ddbfc3f6: async busy check via the shared async pane cache —
5211
5548
  // no sync execFileSync("tmux") per queue item on the event loop.
@@ -5217,24 +5554,52 @@ function startIntercomQueueDrain() {
5217
5554
  try {
5218
5555
  const agentRaw = session.split("-")[0] ?? session;
5219
5556
  const agent = baseAgentName(agentRaw);
5220
- const decision = decideQueuedNudgeDrain(item.intercomReason, {
5221
- hasUnreadMessages: !agentsWithEmptyInbox.has(agent),
5222
- pendingReviewCount: pendingReviewCounts.get(session) ?? null,
5223
- hasInProgressTask: false
5557
+ const pane = await capturePaneAsync(session, 8);
5558
+ return await decideDrainSend(item, {
5559
+ pane,
5560
+ paneState: classifyPaneState(pane),
5561
+ hasPendingInput: paneHasPendingInput(pane),
5562
+ nudgeState: {
5563
+ hasUnreadMessages: !agentsWithEmptyInbox.has(agent),
5564
+ pendingReviewCount: pendingReviewCounts.get(session) ?? null,
5565
+ openTaskCount: openTaskCounts.get(session) ?? null,
5566
+ hasInProgressTask: false
5567
+ },
5568
+ deliver: (s, reason) => centralSendIntercomAsync(s, { reason }),
5569
+ disposition: dispositionWedgedSessionTask
5224
5570
  });
5225
- if (decision.action === "drop") {
5226
- process.stderr.write(`[exe-daemon] dropping stale ${item.intercomReason ?? "nudge"} intercom for ${session} (${decision.reason})
5227
- `);
5228
- return true;
5229
- }
5230
- const outcome = await centralSendIntercomAsync(session, {
5231
- reason: item.intercomReason ?? "nudge"
5232
- });
5233
- return outcome === "delivered" || outcome === "debounced" || outcome === "skipped_exe";
5234
5571
  } catch (e) {
5235
5572
  process.stderr.write("[exe-daemon] intercom send to " + session + ": " + (e instanceof Error ? e.message : String(e)) + "\n");
5236
5573
  return false;
5237
5574
  }
5575
+ },
5576
+ void 0,
5577
+ // notifyExpiry — use the module default (notifyExpiredIntercom)
5578
+ 10,
5579
+ // Terminal disposition (bug e9c19ffe + e7880e0e): a nudge that has
5580
+ // exhausted its retry budget (or TTL-expired) against a wedged EMPLOYEE
5581
+ // session routes that session's in_progress task to blocked. Pure DB
5582
+ // write — never a keystroke, never a buffer clear — so a human
5583
+ // mid-typing can never be clobbered. Round 4: an empty/uncapturable pane
5584
+ // is OFFLINE (⇒ wedged), and only a CONFIRMED "dispositioned" removes the
5585
+ // item; "error" returns false so drainQueueAsync keeps it for retry.
5586
+ async (item) => {
5587
+ try {
5588
+ const pane = await capturePaneAsync(item.targetSession, 8);
5589
+ const state = offlineIfEmpty(pane, classifyPaneState(pane));
5590
+ const hasPendingInput = paneHasPendingInput(pane);
5591
+ const outcome = await dispositionWedgedSessionTask(
5592
+ item.targetSession,
5593
+ `Auto-blocked: intercom (${item.intercomReason ?? "nudge"}) undeliverable after retry budget exhausted \u2014 session wedged (state=${state}, pendingInput=${hasPendingInput}; ${item.reason}). Re-dispatch after clearing the pane.`,
5594
+ { state, hasPendingInput }
5595
+ );
5596
+ if (outcome === "dispositioned") return "dispositioned";
5597
+ if (outcome === "error") return "error";
5598
+ return "declined";
5599
+ } catch (e) {
5600
+ process.stderr.write("[exe-daemon] intercom disposition for " + item.targetSession + ": " + (e instanceof Error ? e.message : String(e)) + "\n");
5601
+ return "error";
5602
+ }
5238
5603
  }
5239
5604
  );
5240
5605
  if (result.drained > 0 || result.failed > 0) {
@@ -5253,12 +5618,50 @@ function startIntercomQueueDrain() {
5253
5618
  process.stderr.write(`[exed] Intercom queue drain started (every ${QUEUE_DRAIN_INTERVAL_MS / 1e3}s)
5254
5619
  `);
5255
5620
  }
5621
+ function startLedgerDrain() {
5622
+ const tick = async () => traceDaemonTimer("ledger_drain", async () => {
5623
+ fired("ledger_drain");
5624
+ try {
5625
+ const { isLedgerEnabled, drainLedger } = await import("../notification-ledger-SZEPGJQ7.js");
5626
+ if (!isLedgerEnabled()) return;
5627
+ const result = await drainLedger({
5628
+ // Shadow "would-deliver": idle target = would-deliver, busy = retry.
5629
+ // No real send here — the legacy intercom path owns actual delivery.
5630
+ attemptDelivery: async (row) => {
5631
+ const session = row.targetSession;
5632
+ if (!session) return false;
5633
+ const state = classifyPaneState(await capturePaneAsync(session, 5));
5634
+ const busy = state === "thinking" || state === "tool";
5635
+ if (busy) return false;
5636
+ process.stderr.write(
5637
+ `[exed] ledger(shadow) WOULD deliver ${row.kind} \u2192 ${session} (id ${row.id}, retries ${row.retryCount})
5638
+ `
5639
+ );
5640
+ return true;
5641
+ }
5642
+ });
5643
+ if (result.delivered || result.retried || result.expired || result.escalated) {
5644
+ acted("ledger_drain");
5645
+ process.stderr.write(
5646
+ `[exed] Ledger(shadow): ${result.delivered} would-deliver, ${result.retried} retry, ${result.expired} expired, ${result.escalated} escalated
5647
+ `
5648
+ );
5649
+ }
5650
+ } catch (e) {
5651
+ process.stderr.write("[exe-daemon] ledger drain: " + (e instanceof Error ? e.message : String(e)) + "\n");
5652
+ }
5653
+ });
5654
+ const timer = setInterval(tick, QUEUE_DRAIN_INTERVAL_MS);
5655
+ timer.unref();
5656
+ process.stderr.write(`[exed] Notification ledger drain started (shadow, every ${QUEUE_DRAIN_INTERVAL_MS / 1e3}s)
5657
+ `);
5658
+ }
5256
5659
  var ORPHAN_REAP_INTERVAL_MS = 5 * 60 * 1e3;
5257
5660
  function startOrphanReaper() {
5258
5661
  const tick = async () => traceDaemonTimer("orphan_reaper", async () => {
5259
5662
  fired("orphan_reaper");
5260
5663
  try {
5261
- const { reapOrphanedMcpProcesses, createOrphanReaperRealDepsAsync } = await import("../daemon-orchestration-7QB6QOXT.js");
5664
+ const { reapOrphanedMcpProcesses, createOrphanReaperRealDepsAsync } = await import("../daemon-orchestration-FX4XZDR5.js");
5262
5665
  const deps = await createOrphanReaperRealDepsAsync();
5263
5666
  const reaped = await reapOrphanedMcpProcesses(deps);
5264
5667
  if (reaped.length > 0) acted("orphan_reaper");
@@ -5283,7 +5686,7 @@ function startZombieAgentReaper() {
5283
5686
  const tick = async () => traceDaemonTimer("zombie_agent_reaper", async () => {
5284
5687
  fired("zombie_agent_reaper");
5285
5688
  try {
5286
- const { reapZombieAgentProcesses, createZombieAgentReaperRealDepsAsync } = await import("../daemon-orchestration-7QB6QOXT.js");
5689
+ const { reapZombieAgentProcesses, createZombieAgentReaperRealDepsAsync } = await import("../daemon-orchestration-FX4XZDR5.js");
5287
5690
  const deps = await createZombieAgentReaperRealDepsAsync();
5288
5691
  const reaped = reapZombieAgentProcesses(deps);
5289
5692
  if (reaped.length > 0) acted("zombie_agent_reaper");
@@ -5307,7 +5710,7 @@ async function startDaemonMemoryPressureWatchdog() {
5307
5710
  try {
5308
5711
  const cfg = await getCachedConfig();
5309
5712
  if (!cfg) return;
5310
- const { startMemoryPressureWatchdog: startWatchdog, MEMORY_PRESSURE_WATCHDOG_DEFAULTS } = await import("../memory-pressure-watchdog-RRIAXPXQ.js");
5713
+ const { startMemoryPressureWatchdog: startWatchdog, MEMORY_PRESSURE_WATCHDOG_DEFAULTS } = await import("../memory-pressure-watchdog-HN5X7AVN.js");
5311
5714
  const watchdogCfg = {
5312
5715
  ...MEMORY_PRESSURE_WATCHDOG_DEFAULTS,
5313
5716
  ...cfg.memoryPressureWatchdog ?? {}
@@ -5338,7 +5741,7 @@ function startWorktreeReaper() {
5338
5741
  const tick = async () => traceDaemonTimer("worktree_reaper", async () => {
5339
5742
  fired("worktree_reaper");
5340
5743
  try {
5341
- const { reapOrphanedWorktrees, createWorktreeReaperRealDeps } = await import("../daemon-orchestration-7QB6QOXT.js");
5744
+ const { reapOrphanedWorktrees, createWorktreeReaperRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
5342
5745
  const deps = await createWorktreeReaperRealDeps();
5343
5746
  const result = await reapOrphanedWorktrees(deps);
5344
5747
  if (result.pruned.length > 0) {
@@ -5378,9 +5781,9 @@ function startWorktreeReaper() {
5378
5781
  }
5379
5782
  continue;
5380
5783
  }
5381
- const { cleanupAgentWorktree } = await import("../worktree-sweep-ZAG3V24E.js");
5382
- const { getMainRepoRoot } = await import("../worktree-GVF2I5FP.js");
5383
- const repoRoot = getMainRepoRoot(signal.worktreePath);
5784
+ const { cleanupAgentWorktree } = await import("../worktree-sweep-WTK3MTKH.js");
5785
+ const { getMainRepoRootAsync } = await import("../worktree-LL62PLQB.js");
5786
+ const repoRoot = await getMainRepoRootAsync(signal.worktreePath);
5384
5787
  if (repoRoot && signal.agentId) {
5385
5788
  const notes = await cleanupAgentWorktree(repoRoot, signal.agentId);
5386
5789
  if (notes) {
@@ -5412,7 +5815,7 @@ function startAutoWake() {
5412
5815
  if (!await ensureStoreForPolling()) return;
5413
5816
  try {
5414
5817
  const { getClient } = await import("./database.js");
5415
- const { pollOrphanedTasks, createAutoWakeRealDeps } = await import("../daemon-orchestration-7QB6QOXT.js");
5818
+ const { pollOrphanedTasks, createAutoWakeRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
5416
5819
  const deps = createAutoWakeRealDeps(getClient, process.cwd(), getTmuxSessionsAsync);
5417
5820
  const woken = await pollOrphanedTasks(deps);
5418
5821
  if (woken.length > 0) acted("auto_wake");
@@ -5424,7 +5827,7 @@ function startAutoWake() {
5424
5827
  const signalBase = path3.join(os2.homedir(), ".exe-os", "task-signals");
5425
5828
  if (existsSync4(signalBase)) {
5426
5829
  const { readdirSync: readdirSync2, statSync: statSyncFs } = await import("fs");
5427
- const { sendIntercomAsync } = await import("./tmux-routing.js");
5830
+ const { sendIntercomAsync, extractRootExe } = await import("./tmux-routing.js");
5428
5831
  const sessionCache = path3.join(os2.homedir(), ".exe-os", "session-cache");
5429
5832
  const sessions = await getTmuxSessionsAsync();
5430
5833
  const signalDirs = [];
@@ -5463,7 +5866,7 @@ function startAutoWake() {
5463
5866
  if (age > 60 * 60 * 1e3) {
5464
5867
  try {
5465
5868
  unlinkSync2(signalPath);
5466
- void import("../orchestration-events-5SIJOE4H.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
5869
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
5467
5870
  recordOE({ eventType: "signal.stale", source: "exe-daemon.autoWake", severity: "warn", payload: { file, ageMinutes: Math.round(age / 6e4) } });
5468
5871
  }).catch(() => {
5469
5872
  });
@@ -5492,9 +5895,17 @@ function startAutoWake() {
5492
5895
  `
5493
5896
  );
5494
5897
  } else {
5495
- await sendIntercomAsync(match, { force: true, reason: "signal" });
5496
- process.stderr.write(`[exed] Signal-nudge: sent intercom to ${match} (signal age ${Math.round(age / 1e3)}s)
5898
+ const nudgeScope = scope ?? extractRootExe(match) ?? null;
5899
+ const result = await sendIntercomAsync(match, { force: true, reason: "signal", callerSessionScope: nudgeScope });
5900
+ if (result === "failed") {
5901
+ process.stderr.write(
5902
+ `[exed] Signal-nudge: delivery FAILED to ${match} (signal age ${Math.round(age / 1e3)}s, scope=${nudgeScope ?? "none"}) \u2014 signal kept; will retry next tick
5903
+ `
5904
+ );
5905
+ } else {
5906
+ process.stderr.write(`[exed] Signal-nudge: ${result} intercom to ${match} (signal age ${Math.round(age / 1e3)}s)
5497
5907
  `);
5908
+ }
5498
5909
  }
5499
5910
  }
5500
5911
  }
@@ -5523,7 +5934,7 @@ function startWalCheckpoint() {
5523
5934
  try {
5524
5935
  const { getClient, runWalCheckpoint } = await import("./database.js");
5525
5936
  const client = getClient();
5526
- const { findActiveDb } = await import("../db-backup-DLD4QZBO.js");
5937
+ const { findActiveDb } = await import("../db-backup-W2QFSYQC.js");
5527
5938
  const dbPath = findActiveDb();
5528
5939
  const started = Date.now();
5529
5940
  const result = await runWalCheckpoint(client, dbPath, true);
@@ -5601,7 +6012,7 @@ function startStuckTaskRelease() {
5601
6012
  createStuckTaskRealDeps,
5602
6013
  escalateStuckBlockedTasks,
5603
6014
  createStuckBlockedRealDeps
5604
- } = await import("../daemon-orchestration-7QB6QOXT.js");
6015
+ } = await import("../daemon-orchestration-FX4XZDR5.js");
5605
6016
  const deps = createStuckTaskRealDeps(getClient);
5606
6017
  const released = await releaseStuckTasks(deps);
5607
6018
  if (released.length > 0) {
@@ -5796,12 +6207,12 @@ function startTaskEnforcementScanner() {
5796
6207
  const tick = async () => traceDaemonTimer("task_enforcement", async () => {
5797
6208
  fired("task_enforcement");
5798
6209
  try {
5799
- const { runTaskEnforcementTick } = await import("../task-enforcement-VI7L43DC.js");
6210
+ const { runTaskEnforcementTick } = await import("../task-enforcement-IPIZX2MM.js");
5800
6211
  const { getTransport } = await import("./transport.js");
5801
6212
  const { loadAgentConfig } = await import("./agent-config.js");
5802
6213
  const { getClient } = await import("./database.js");
5803
6214
  const { loadEmployeesSync } = await import("./employees.js");
5804
- const { sessionScopeFilter } = await import("../task-scope-CQEG5SSJ.js");
6215
+ const { sessionScopeFilter } = await import("../task-scope-FOIW25HR.js");
5805
6216
  const transport = getTransport();
5806
6217
  const { sessions: allSessions, paneCache, aliveSessions } = await getSharedOrchestrationCaches();
5807
6218
  await yieldToEventLoop();
@@ -5812,10 +6223,10 @@ function startTaskEnforcementScanner() {
5812
6223
  sendKeysLiteral: transport.sendKeysLiteral?.bind(transport),
5813
6224
  isAlive: (session) => aliveSessions.has(session)
5814
6225
  };
5815
- const { checkAutoWakeGates } = await import("../daemon-orchestration-7QB6QOXT.js");
5816
- const { ensureEmployeeAsync, employeeSessionName } = await import("./tmux-routing.js");
6226
+ const { checkAutoWakeGates } = await import("../daemon-orchestration-FX4XZDR5.js");
6227
+ const { ensureEmployeeAsync, employeeSessionName, sendIntercomAsync } = await import("./tmux-routing.js");
5817
6228
  const { shouldAutoInstance } = await import("./employees.js");
5818
- const { recordOrchestrationEventBestEffort } = await import("../orchestration-events-5SIJOE4H.js");
6229
+ const { recordOrchestrationEventBestEffort } = await import("../orchestration-events-WV4NWKZH.js");
5819
6230
  const projectDir = process.cwd();
5820
6231
  await runTaskEnforcementTick({
5821
6232
  transport: enforcementTransport,
@@ -5840,6 +6251,16 @@ function startTaskEnforcementScanner() {
5840
6251
  `));
5841
6252
  return { status: "intercom_unprocessed", sessionName: employeeSessionName(reviewerName, sessionScope) };
5842
6253
  },
6254
+ // Bug 018aaf31: wake a LIVE-but-idle reviewer/coordinator that owns a
6255
+ // needs_review item. Same intercom funnel as the worker-nudge; reason
6256
+ // "completion" renders "An employee completed work — review it". The
6257
+ // input-buffer/busy/idle/debounce guards inside sendIntercom decide
6258
+ // whether to type, queue, or defer — so this never splices into a founder
6259
+ // keystroke and never piles onto a busy reviewer.
6260
+ reviewerNudge: (reviewerSession, sessionScope) => {
6261
+ void sendIntercomAsync(reviewerSession, { callerSessionScope: sessionScope, reason: "completion" }).catch((err) => process.stderr.write(`[exed] Reviewer nudge async failed for ${reviewerSession}: ${err instanceof Error ? err.message : String(err)}
6262
+ `));
6263
+ },
5843
6264
  zombieWorkerRecover: async (session, agentName, sessionScope, reason) => {
5844
6265
  const gateReason = checkAutoWakeGates(`mcp-zombie::${agentName}::${sessionScope || session}`, Date.now());
5845
6266
  if (gateReason) {
@@ -6097,7 +6518,7 @@ function startBackgroundJobGuardrails() {
6097
6518
  const tick = async () => traceDaemonTimer("background_job_guardrails", async () => {
6098
6519
  fired("background_job_guardrails");
6099
6520
  try {
6100
- const { enforceBackgroundJobGuardrailsAsync } = await import("../background-jobs-STURKDCS.js");
6521
+ const { enforceBackgroundJobGuardrailsAsync } = await import("../background-jobs-EXR5RVGG.js");
6101
6522
  const actions = await enforceBackgroundJobGuardrailsAsync();
6102
6523
  if (actions.length > 0) {
6103
6524
  acted("background_job_guardrails");
@@ -6130,11 +6551,14 @@ function handleSignalShutdown() {
6130
6551
  ...signalAttribution
6131
6552
  });
6132
6553
  logShutdown(restartIntent ? "restart shutdown" : "graceful shutdown", "SIGTERM/SIGINT", signalAttribution);
6133
- void shutdown(restartIntent ? 75 : 0);
6554
+ void shutdown(restartIntent ? 75 : 0, restartIntent ? reason ?? "restart-intent" : null);
6134
6555
  }
6135
6556
  process.on("SIGINT", handleSignalShutdown);
6136
6557
  process.on("SIGTERM", handleSignalShutdown);
6137
6558
  process.on("exit", (code) => {
6559
+ if (_bootPhase !== "ready" && code !== 0) {
6560
+ recordExitBreadcrumb("boot-abort", code, `boot_abort:${_bootPhase}`);
6561
+ }
6138
6562
  if (_bootPhase === "ready") return;
6139
6563
  try {
6140
6564
  logDaemonHealth({
@@ -6252,7 +6676,7 @@ function startBugAutoFix() {
6252
6676
  for (const exeSession of exeSessions) {
6253
6677
  const ctoSession = `${ctoName}-${exeSession}`;
6254
6678
  if (sessions.includes(ctoSession)) {
6255
- await sendIntercomAsync(ctoSession);
6679
+ await sendIntercomAsync(ctoSession, { callerSessionScope: exeSession });
6256
6680
  break;
6257
6681
  }
6258
6682
  }
@@ -6428,9 +6852,9 @@ function startAutoUpdateCheck() {
6428
6852
  const effectiveChannel = updateChannel ?? "stable";
6429
6853
  if (effectiveChannel === "pinned") return;
6430
6854
  if (!autoInstall && !config.autoUpdate.checkOnBoot) return;
6431
- const { checkForUpdate, channelToInstallTag } = await import("../update-check-HFO4VHO4.js");
6855
+ const { checkForUpdateAsync, channelToInstallTag } = await import("../update-check-3FHAWIG2.js");
6432
6856
  const packageRoot = new URL("../..", import.meta.url).pathname;
6433
- const result = checkForUpdate(packageRoot, effectiveChannel);
6857
+ const result = await checkForUpdateAsync(packageRoot, effectiveChannel);
6434
6858
  if (!result.updateAvailable) return;
6435
6859
  acted("auto_update_check");
6436
6860
  const channelLabel = effectiveChannel === "canary" ? " (canary)" : "";
@@ -6531,7 +6955,7 @@ if (process.platform === "darwin") {
6531
6955
  logBoot({ socketPath: SOCKET_PATH, pidPath: PID_PATH });
6532
6956
  void (async () => {
6533
6957
  try {
6534
- const { cleanupCrashDebris } = await import("../db-backup-DLD4QZBO.js");
6958
+ const { cleanupCrashDebris } = await import("../db-backup-W2QFSYQC.js");
6535
6959
  const removed = cleanupCrashDebris();
6536
6960
  if (removed > 0) {
6537
6961
  process.stderr.write(`[exed] Startup cleanup: pruned ${removed} crash-debris file(s) (backups/quarantine).
@@ -6677,9 +7101,7 @@ function startEventLoopLagDetector() {
6677
7101
  const SELF_INFLICTED_ROLLING_WINDOW_MS = parseFloat(process.env.EXE_SELF_INFLICTED_ROLLING_WINDOW_MS ?? "") || 3e5;
6678
7102
  const LAG_WARN_MS = 3e3;
6679
7103
  const LAG_CRITICAL_MS = 1e4;
6680
- const SELF_HEAL_SINGLE_MS = parseFloat(process.env.EXE_SELF_HEAL_SINGLE_MS ?? "") || 12e4;
6681
- const SELF_HEAL_CONSECUTIVE = parseInt(process.env.EXE_SELF_HEAL_CONSECUTIVE ?? "") || 3;
6682
- const SELF_HEAL_THRESHOLD_MS = parseFloat(process.env.EXE_SELF_HEAL_THRESHOLD_MS ?? "") || 3e4;
7104
+ const { singleMs: SELF_HEAL_SINGLE_MS, consecutive: SELF_HEAL_CONSECUTIVE, thresholdMs: SELF_HEAL_THRESHOLD_MS } = resolveSelfHealThresholds();
6683
7105
  let consecutiveSevereBlocks = 0;
6684
7106
  let selfInflictedWindow = [];
6685
7107
  touchEventLoopHeartbeat();
@@ -6707,7 +7129,7 @@ function startEventLoopLagDetector() {
6707
7129
  const msg = `[exed] EVENT LOOP BLOCKED ${(lag / 1e3).toFixed(1)}s \u2014 MCP UNRESPONSIVE. Sessions will die.`;
6708
7130
  process.stderr.write(msg + "\n");
6709
7131
  logDaemonHealth({ event: "event_loop_blocked", pid: process.pid, message: msg, data: { lagMs: lag } });
6710
- void import("../orchestration-events-5SIJOE4H.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
7132
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
6711
7133
  recordOE({ eventType: "daemon.event_loop_blocked", source: "exe-daemon.lagDetector", severity: "error", durationMs: lag });
6712
7134
  }).catch(() => {
6713
7135
  });
@@ -6730,7 +7152,7 @@ function startEventLoopLagDetector() {
6730
7152
  }
6731
7153
  const load1m = os2.loadavg()[0] ?? 0;
6732
7154
  const cpuCount = os2.cpus().length || 1;
6733
- const starvationRatio = parseFloat(process.env.EXE_STARVATION_LOAD_RATIO ?? "1.5");
7155
+ const starvationRatio = resolveSelfHealThresholds().starvationRatio;
6734
7156
  const catchUpActive = inBootCatchUpGrace();
6735
7157
  const decision = decideDaemonSelfHeal({
6736
7158
  lagMs: lag,
@@ -6808,7 +7230,7 @@ function startEventLoopLagDetector() {
6808
7230
  _lastSelfHealShutdownAtMs = Date.now();
6809
7231
  process.stderr.write(healMsg + "\n");
6810
7232
  logDaemonHealth({ event: "self_heal_restart", pid: process.pid, message: healMsg, data: { lagMs: lag, reason: "single_block" } });
6811
- void shutdown(75);
7233
+ dispatchSelfHealRestart(lag, "single_block", SELF_HEAL_ACTION_DEPS);
6812
7234
  return;
6813
7235
  }
6814
7236
  if (decision.restart && decision.reason === "consecutive_blocks") {
@@ -6822,7 +7244,7 @@ function startEventLoopLagDetector() {
6822
7244
  _lastSelfHealShutdownAtMs = Date.now();
6823
7245
  process.stderr.write(healMsg + "\n");
6824
7246
  logDaemonHealth({ event: "self_heal_restart", pid: process.pid, message: healMsg, data: { lagMs: lag, reason: "consecutive_blocks", count: consecutiveSevereBlocks } });
6825
- void shutdown(75);
7247
+ dispatchSelfHealRestart(lag, "consecutive_blocks", SELF_HEAL_ACTION_DEPS);
6826
7248
  return;
6827
7249
  }
6828
7250
  } else if (lag > LAG_WARN_MS) {
@@ -6889,7 +7311,7 @@ function startTaskFileResync() {
6889
7311
  });
6890
7312
  if (Number(res.rowsAffected ?? 0) > 0) {
6891
7313
  synced++;
6892
- void import("../orchestration-events-5SIJOE4H.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
7314
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
6893
7315
  recordOE({
6894
7316
  eventType: "task_file.resynced",
6895
7317
  source: "exe-daemon.taskFileResync",
@@ -6926,7 +7348,7 @@ function startTaskGroupBarriers() {
6926
7348
  fired("task_group_barriers");
6927
7349
  if (!await ensureStoreForPolling()) return;
6928
7350
  try {
6929
- const { pollTaskGroupBarriers } = await import("../daemon-orchestration-7QB6QOXT.js");
7351
+ const { pollTaskGroupBarriers } = await import("../daemon-orchestration-FX4XZDR5.js");
6930
7352
  const firedCount = await pollTaskGroupBarriers();
6931
7353
  if (firedCount > 0) {
6932
7354
  acted("task_group_barriers");
@@ -6948,7 +7370,7 @@ function startCheckpointGc() {
6948
7370
  fired("checkpoint_gc");
6949
7371
  if (!await ensureStoreForPolling()) return;
6950
7372
  try {
6951
- const { gcStaleCheckpoints } = await import("../daemon-orchestration-7QB6QOXT.js");
7373
+ const { gcStaleCheckpoints } = await import("../daemon-orchestration-FX4XZDR5.js");
6952
7374
  const cleared = await gcStaleCheckpoints();
6953
7375
  if (cleared > 0) {
6954
7376
  acted("checkpoint_gc");
@@ -6979,7 +7401,7 @@ function startDaemonHeartbeat() {
6979
7401
  function startDispatchAckCleanup() {
6980
7402
  setInterval(async () => {
6981
7403
  try {
6982
- const { cleanStaleDispatchAcks } = await import("../dispatch-ack-4S44HBWB.js");
7404
+ const { cleanStaleDispatchAcks } = await import("../dispatch-ack-VYH3ONSS.js");
6983
7405
  cleanStaleDispatchAcks();
6984
7406
  } catch {
6985
7407
  }
@@ -6988,14 +7410,14 @@ function startDispatchAckCleanup() {
6988
7410
  function startProjectionWorkerDeferred() {
6989
7411
  setTimeout(async () => {
6990
7412
  try {
6991
- const { startProjectionWorker } = await import("../projection-worker-ZVOFHTXT.js");
7413
+ const { startProjectionWorker } = await import("../projection-worker-FZ7YSN3G.js");
6992
7414
  startProjectionWorker();
6993
7415
  } catch {
6994
7416
  }
6995
7417
  }, 2e4);
6996
7418
  }
6997
7419
  async function startToolTelemetry() {
6998
- const { startToolTelemetryFlush } = await import("../tool-telemetry-ULIDUK3P.js");
7420
+ const { startToolTelemetryFlush } = await import("../tool-telemetry-KBXSBDTK.js");
6999
7421
  startToolTelemetryFlush();
7000
7422
  process.stderr.write("[exed] Tool telemetry started (flush every 5m)\n");
7001
7423
  }
@@ -7026,6 +7448,7 @@ function startLocalFirstTimers() {
7026
7448
  setTimeout(() => void retryPendingMessages(), 15e3);
7027
7449
  void drainIngestOutbox();
7028
7450
  startIntercomQueueDrain();
7451
+ startLedgerDrain();
7029
7452
  startReviewPolling();
7030
7453
  startSessionTTL();
7031
7454
  startTaskEnforcementScanner();
@@ -7160,7 +7583,7 @@ function startLocalFirstTimers() {
7160
7583
  fired("orphan_task_cleanup");
7161
7584
  try {
7162
7585
  if (!await ensureStoreForPolling()) return;
7163
- const { cleanOrphanedTaskFiles } = await import("../tasks-crud-UGK5A25L.js");
7586
+ const { cleanOrphanedTaskFiles } = await import("../tasks-crud-HBDKE6C5.js");
7164
7587
  const count = await cleanOrphanedTaskFiles();
7165
7588
  if (count > 0) {
7166
7589
  acted("orphan_task_cleanup");
@@ -7176,7 +7599,7 @@ function startLocalFirstTimers() {
7176
7599
  fired("task_file_consistency");
7177
7600
  try {
7178
7601
  if (!await ensureStoreForPolling()) return;
7179
- const { checkTaskFileConsistency } = await import("../tasks-crud-UGK5A25L.js");
7602
+ const { checkTaskFileConsistency } = await import("../tasks-crud-HBDKE6C5.js");
7180
7603
  const mismatches = await checkTaskFileConsistency();
7181
7604
  if (mismatches > 0) {
7182
7605
  acted("task_file_consistency");
@@ -7195,7 +7618,7 @@ function startLocalFirstTimers() {
7195
7618
  const TELEMETRY_DAILY_MS = 24 * 60 * 60 * 1e3;
7196
7619
  const telemetryDaily = async () => {
7197
7620
  try {
7198
- const { sendTelemetry, isTelemetryEnabled } = await import("../telemetry-upload-7LBYGPCB.js");
7621
+ const { sendTelemetry, isTelemetryEnabled } = await import("../telemetry-upload-ZOXHRWR5.js");
7199
7622
  if (!isTelemetryEnabled()) return;
7200
7623
  const { upstream } = await sendTelemetry(24);
7201
7624
  if (upstream.startsWith("sent")) {
@@ -7307,7 +7730,76 @@ function startLocalFirstTimers() {
7307
7730
  }
7308
7731
  }, 3e4);
7309
7732
  }
7733
+ async function enterDegradedBreakerMode(crashCount) {
7734
+ const requestedHost = process.env.EXE_MCP_HOST || "127.0.0.1";
7735
+ const isRemote = !["127.0.0.1", "::1", "localhost"].includes(requestedHost);
7736
+ const allowRemote = /^(1|true|yes|on)$/i.test(process.env.EXE_MCP_ALLOW_REMOTE ?? "");
7737
+ const host = isRemote && !allowRemote ? "127.0.0.1" : requestedHost;
7738
+ let port = 48739;
7739
+ try {
7740
+ port = await resolveAndClaimPort();
7741
+ } catch {
7742
+ }
7743
+ const degradedBody = () => JSON.stringify({
7744
+ jsonrpc: "2.0",
7745
+ error: {
7746
+ code: -32002,
7747
+ message: `exe-os daemon is DEGRADED \u2014 restart circuit breaker OPEN after ${crashCount} crash restarts (bug 2fee6110). Heavy work is suspended to protect system memory. Recover: 'exe-os daemon reset-breaker' then relaunch. Details: 'exe-os daemon status'.`
7748
+ },
7749
+ id: null
7750
+ });
7751
+ const srv = createHttpServer((req, res) => {
7752
+ try {
7753
+ res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1");
7754
+ const p = (req.url || "/").split("?")[0];
7755
+ if (req.method === "GET" && p === "/health") {
7756
+ res.writeHead(200, { "Content-Type": "application/json" });
7757
+ res.end(JSON.stringify({
7758
+ status: "degraded",
7759
+ reason: "restart_circuit_breaker_tripped",
7760
+ crashRestartsInWindow: crashCount,
7761
+ version: PACKAGE_VERSION,
7762
+ alert: readBreakerAlert() ?? void 0,
7763
+ recovery: "exe-os daemon reset-breaker"
7764
+ }));
7765
+ return;
7766
+ }
7767
+ res.writeHead(503, { "Content-Type": "application/json", "Retry-After": "300" });
7768
+ res.end(degradedBody());
7769
+ } catch {
7770
+ }
7771
+ });
7772
+ await new Promise((resolve) => {
7773
+ srv.once("error", (err) => {
7774
+ process.stderr.write(`[exed] Degraded health server bind failed (${err.code || err.message}) \u2014 staying alive without it.
7775
+ `);
7776
+ resolve();
7777
+ });
7778
+ srv.listen(port, host, () => {
7779
+ process.stderr.write(`[exed] DEGRADED health server on ${host}:${port} (breaker tripped \u2014 503 + /health only).
7780
+ `);
7781
+ resolve();
7782
+ });
7783
+ });
7784
+ setInterval(() => {
7785
+ process.stderr.write(
7786
+ `[exed] DEGRADED (breaker open, ${crashCount} crashes). No DB/backups/timers. Recover: 'exe-os daemon reset-breaker'. Alert: ${restartBreakerAlertPath()}
7787
+ `
7788
+ );
7789
+ }, 5 * 60 * 1e3);
7790
+ }
7310
7791
  try {
7792
+ const breaker = recordDaemonRestart();
7793
+ process.stderr.write(
7794
+ `[exed] Boot classified as ${breaker.bootClass} (${breaker.reasonLabel}); crashes=${breaker.crashInWindow}/${5}, restarts=${breaker.restartsInWindow} in window.
7795
+ `
7796
+ );
7797
+ if (breaker.trip) {
7798
+ logRestartEvent("daemon_restart_breaker_tripped", { crash_in_window: breaker.crashInWindow, restarts_in_window: breaker.restartsInWindow });
7799
+ await enterDegradedBreakerMode(breaker.crashInWindow);
7800
+ await new Promise(() => {
7801
+ });
7802
+ }
7311
7803
  const mcpRegPath = new URL("../mcp/register-tools.js", import.meta.url).href;
7312
7804
  const { registerAllTools: regFn } = await import(
7313
7805
  /* @vite-ignore */
@@ -7350,6 +7842,7 @@ try {
7350
7842
  }
7351
7843
  export {
7352
7844
  decidePortHolderAction,
7845
+ getLastBlockingTimer,
7353
7846
  injectRegisterAllTools,
7354
7847
  isCrashLoopBreakerActive,
7355
7848
  isEventLoopBlockedNow,