@askexenow/exe-os 0.9.341 → 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 (419) 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-AIQP4DFL.js → active-agent-PVGE57FY.js} +5 -5
  7. package/dist/{active-agent-LW45DSJ4.js → active-agent-TNIO6IY3.js} +5 -5
  8. package/dist/{agentic-ontology-RVUNRCQY.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-ZSDJ4O2T.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-ZAJLEL4X.js → backup-verify-3Y2FHGZU.js} +4 -4
  13. package/dist/{behaviors-EO7KCP3H.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 +25 -23
  24. package/dist/bin/cli.js +79 -25
  25. package/dist/bin/customer-readiness.js +1 -1
  26. package/dist/bin/deferred-daemon-restart.js +98 -92
  27. package/dist/bin/exe-agent-config.js +9 -8
  28. package/dist/bin/exe-agent.js +17 -17
  29. package/dist/bin/exe-assign.js +12 -12
  30. package/dist/bin/exe-boot.js +200 -67
  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 +25 -23
  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 +28 -27
  42. package/dist/bin/exe-kill.js +30 -28
  43. package/dist/bin/exe-launch-agent.js +128 -67
  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 +26 -24
  47. package/dist/bin/exe-pending-notifications.js +25 -23
  48. package/dist/bin/exe-pending-reviews.js +25 -23
  49. package/dist/bin/exe-rename.js +7 -7
  50. package/dist/bin/exe-review.js +29 -27
  51. package/dist/bin/exe-search.js +11 -9
  52. package/dist/bin/exe-session-cleanup.js +115 -85
  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 +26 -24
  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 +26 -24
  62. package/dist/bin/graph-backfill.js +11 -11
  63. package/dist/bin/graph-export.js +9 -9
  64. package/dist/bin/import-history.js +13 -13
  65. package/dist/bin/install.js +103 -97
  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 +2 -2
  73. package/dist/bin/registry-proxy.js +1 -1
  74. package/dist/bin/scan-tasks.js +25 -23
  75. package/dist/bin/setup.js +6 -5
  76. package/dist/bin/shard-migrate.js +9 -9
  77. package/dist/bin/stack-update.js +6 -6
  78. package/dist/bin/update.js +1 -1
  79. package/dist/bin/vps-health-gate.js +1 -1
  80. package/dist/{boot-generation-GSMPJOWM.js → boot-generation-BL2ISK4U.js} +5 -5
  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-OBYQNAKZ.js → capability-cards-DN5UIKVN.js} +4 -4
  86. package/dist/{capacity-monitor-MG3FTUD5.js → capacity-monitor-ZG5GGFR2.js} +26 -24
  87. package/dist/{catchup-brief-BVJOF3GL.js → catchup-brief-D6HH6DWS.js} +31 -28
  88. package/dist/{chunk-Q5AIPSSC.js → chunk-25X4JD2V.js} +10 -6
  89. package/dist/{chunk-6MVI4QH2.js → chunk-2KZNGDSW.js} +1 -1
  90. package/dist/{chunk-WH7XN5ER.js → chunk-2WAVZ5UJ.js} +1 -1
  91. package/dist/{chunk-PTJBWC77.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-X5QVL6RE.js → chunk-4CMVFVFC.js} +173 -69
  95. package/dist/{chunk-2YCFNBC4.js → chunk-4J4PMPXZ.js} +3 -2
  96. package/dist/{chunk-EDOO23B2.js → chunk-4N2NRGCM.js} +2 -2
  97. package/dist/chunk-4QCFFW2H.js +378 -0
  98. package/dist/{chunk-6MVC43X7.js → chunk-4VSV5P4D.js} +2 -2
  99. package/dist/{chunk-HJX6NCJF.js → chunk-4ZCD2UWW.js} +39 -10
  100. package/dist/{chunk-C445WRUX.js → chunk-5ERDIOV3.js} +2 -2
  101. package/dist/chunk-5H47VHB7.js +30 -0
  102. package/dist/{chunk-BJ23BNED.js → chunk-5TY4FPH6.js} +1 -1
  103. package/dist/{chunk-WD55PEBM.js → chunk-6CH3TPHR.js} +3 -3
  104. package/dist/{chunk-TIXTHUVJ.js → chunk-6WQ3NNCE.js} +3 -3
  105. package/dist/{chunk-7LF5DS3A.js → chunk-6XWTQUO4.js} +1 -1
  106. package/dist/chunk-76CJBM36.js +88 -0
  107. package/dist/{chunk-NFBW7N4D.js → chunk-7CTRGNLW.js} +2 -2
  108. package/dist/{chunk-ITMEE7PQ.js → chunk-7V4JADD6.js} +3 -3
  109. package/dist/{chunk-RMOBQ6A5.js → chunk-AD2VCHSS.js} +1 -1
  110. package/dist/{chunk-DNVFWFYF.js → chunk-AJYCFKJR.js} +1 -1
  111. package/dist/chunk-AM7S2TY6.js +54 -0
  112. package/dist/{chunk-RWSLVYTE.js → chunk-AOHXREB7.js} +295 -67
  113. package/dist/{chunk-DGGDUKH6.js → chunk-ASAFVDVR.js} +1 -1
  114. package/dist/{chunk-NTI22F3R.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-BMHQPIJ2.js → chunk-CE7F6RHG.js} +585 -75
  118. package/dist/{chunk-YWQMWFYR.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-YHUNDGVV.js → chunk-EUS4QUKP.js} +1 -1
  123. package/dist/{chunk-6D2PI4QD.js → chunk-EV46QTD3.js} +1 -1
  124. package/dist/{chunk-N7A5D25S.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-MC4ATFJV.js → chunk-FPFPLPUY.js} +6 -6
  128. package/dist/{chunk-UU4UINUX.js → chunk-G4RGKBCA.js} +2 -2
  129. package/dist/{chunk-HAZO7TRD.js → chunk-G5T6KDG4.js} +1 -1
  130. package/dist/{chunk-TWXZM34M.js → chunk-GBTTBXAF.js} +6 -6
  131. package/dist/{chunk-LA2Z6RMS.js → chunk-GDIJE6D7.js} +1 -1
  132. package/dist/{chunk-4QSJVMMT.js → chunk-GG5NDQNN.js} +2 -2
  133. package/dist/{chunk-6BQG7EKO.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-HSYJ6DZ2.js → chunk-H6BV5TKD.js} +39 -24
  137. package/dist/{chunk-HCJCW7X4.js → chunk-H7I47RS5.js} +34 -1
  138. package/dist/{chunk-GFDGDFBF.js → chunk-HA5R6USD.js} +22 -5
  139. package/dist/{chunk-L2YGXJGF.js → chunk-HAF2DJYV.js} +3 -3
  140. package/dist/chunk-HJ447YER.js +224 -0
  141. package/dist/{chunk-6QW6JHRE.js → chunk-HV4KESRY.js} +59 -32
  142. package/dist/{chunk-BJOBR6P2.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-2UGGBIDL.js → chunk-JGIPOUIK.js} +3 -3
  146. package/dist/{chunk-LLU6WZLK.js → chunk-JLZ4RYSD.js} +2 -2
  147. package/dist/{chunk-WWNQFOSP.js → chunk-JMYHW3AL.js} +2 -2
  148. package/dist/{chunk-KP4PY2Z2.js → chunk-JPUZPAAF.js} +4 -4
  149. package/dist/{chunk-4LWV633D.js → chunk-JTBIS4R5.js} +1 -1
  150. package/dist/{chunk-PPZOWQHP.js → chunk-K7KFGDWF.js} +1 -1
  151. package/dist/{chunk-HNLXMD2V.js → chunk-KGWRTRKC.js} +2 -2
  152. package/dist/{chunk-IB336P52.js → chunk-KP3U5QGJ.js} +1 -1
  153. package/dist/{chunk-OUEFW4RK.js → chunk-KW2SD2FL.js} +2 -2
  154. package/dist/{chunk-2P4WJNN5.js → chunk-KWZMQACA.js} +11 -7
  155. package/dist/{chunk-ATKW3SYL.js → chunk-L2R3LN2P.js} +1 -1
  156. package/dist/{chunk-IELUDZAA.js → chunk-L4A5DL6Z.js} +3 -3
  157. package/dist/{chunk-2C455MU3.js → chunk-LU2FALL6.js} +3 -3
  158. package/dist/{chunk-LOBCQXV5.js → chunk-MKYFAKDW.js} +4 -4
  159. package/dist/{chunk-3BRVLPPA.js → chunk-MOPUCPXK.js} +4 -0
  160. package/dist/{chunk-BR4423AS.js → chunk-MR6LHP4F.js} +1 -1
  161. package/dist/chunk-MVYB76QG.js +341 -0
  162. package/dist/{chunk-ZNE6H2JO.js → chunk-MZM6EJCU.js} +4 -4
  163. package/dist/{chunk-FOV57K47.js → chunk-N7QJKQMX.js} +258 -14
  164. package/dist/{chunk-AYLNJGCS.js → chunk-NBZL5CGA.js} +93 -12
  165. package/dist/{chunk-YLQXP7T7.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-BV6GBSRP.js → chunk-OLMQ4UOF.js} +42 -10
  171. package/dist/{chunk-UIU2DGRV.js → chunk-OTF44GXL.js} +4 -4
  172. package/dist/{chunk-GOGSWXNZ.js → chunk-OZEBAGKR.js} +277 -137
  173. package/dist/{chunk-NDSNM5OH.js → chunk-P5HIWY2E.js} +1 -1
  174. package/dist/{chunk-MJB5ZFQM.js → chunk-PDWS3E22.js} +55 -4
  175. package/dist/{chunk-4FJZ6SO7.js → chunk-PPCDBE6Z.js} +1 -1
  176. package/dist/{chunk-7SEC2AG5.js → chunk-PQIDGXSG.js} +13 -4
  177. package/dist/chunk-PWUFMX75.js +186 -0
  178. package/dist/{chunk-GPW32HVB.js → chunk-QDGZJ653.js} +3 -3
  179. package/dist/{chunk-CYA5S5OD.js → chunk-QOO5RW3K.js} +6 -5
  180. package/dist/{chunk-IXBIVKWZ.js → chunk-QQ4E2RYW.js} +95 -18
  181. package/dist/{chunk-2WMTTIAZ.js → chunk-QRYVCDWS.js} +2 -2
  182. package/dist/{chunk-Z42MXYWW.js → chunk-QWVXN224.js} +110 -28
  183. package/dist/{chunk-XSMRR4IW.js → chunk-QYZJHTNE.js} +26 -27
  184. package/dist/{chunk-I7ECEP3W.js → chunk-R2NN3JKH.js} +43 -6
  185. package/dist/{chunk-B7CUBLF7.js → chunk-RACAOE2Z.js} +13 -13
  186. package/dist/{chunk-5RACW3LX.js → chunk-RAXVPNMR.js} +1 -1
  187. package/dist/{chunk-CMR64RYM.js → chunk-RHWZUUS4.js} +17 -17
  188. package/dist/{chunk-RNAYCUNM.js → chunk-S3THSOWV.js} +1 -1
  189. package/dist/{chunk-U2MREVXQ.js → chunk-S7QUM2UK.js} +2 -2
  190. package/dist/{chunk-SSTLTIF3.js → chunk-SKGMF2SO.js} +25 -2
  191. package/dist/{chunk-J6SEDDOR.js → chunk-SQKXKV2Y.js} +2 -2
  192. package/dist/{chunk-DPFQ2WQX.js → chunk-TLT7NZCW.js} +4 -4
  193. package/dist/chunk-TTCUG2CF.js +91 -0
  194. package/dist/{chunk-W6K4XB6G.js → chunk-UEA3LXOB.js} +1 -1
  195. package/dist/{chunk-WNKVKNOM.js → chunk-UNXQBELK.js} +1 -1
  196. package/dist/{chunk-KKOLHBNC.js → chunk-UP75Z5X7.js} +904 -167
  197. package/dist/{chunk-Y3S4H77G.js → chunk-USSB56WK.js} +1 -1
  198. package/dist/{chunk-PVIH3ZGV.js → chunk-UUEKJDK6.js} +90 -10
  199. package/dist/{chunk-T2PYVVZ5.js → chunk-UUQBZPJJ.js} +1 -1
  200. package/dist/{chunk-32YHCHWW.js → chunk-V3EEVY4L.js} +1 -1
  201. package/dist/{chunk-2IWBY7XK.js → chunk-VPZHJCKW.js} +2 -2
  202. package/dist/chunk-VRAQTFD6.js +265 -0
  203. package/dist/{chunk-EDH54E5A.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-CCIEIRV2.js → chunk-X33NYQYJ.js} +2 -2
  209. package/dist/{chunk-K6KRBXQP.js → chunk-XHK3FS3W.js} +3 -2
  210. package/dist/{chunk-AP455LBW.js → chunk-XZXBB3TN.js} +2 -2
  211. package/dist/{chunk-JSKBHUR7.js → chunk-YCANDMI2.js} +2 -2
  212. package/dist/{chunk-YIIME2OW.js → chunk-YLXTKI6M.js} +1 -1
  213. package/dist/{chunk-LEJ25726.js → chunk-YTCFACP4.js} +650 -434
  214. package/dist/{chunk-HUSVERE6.js → chunk-Z6RSN7KS.js} +7 -6
  215. package/dist/{cleanup-graph-garbage-MXQ4Q2MA.js → cleanup-graph-garbage-XWUFAMFO.js} +8 -8
  216. package/dist/{co-activation-QI5BK4RT.js → co-activation-ZCHPLLP6.js} +4 -4
  217. package/dist/{co-occurrence-BYSQNZSV.js → co-occurrence-KG3LKALN.js} +6 -6
  218. package/dist/{code-context-index-BNBHDXHW.js → code-context-index-WSOJQ72R.js} +5 -5
  219. package/dist/{content-extractor-JRJDNIHP.js → content-extractor-NXYNEF5K.js} +2 -2
  220. package/dist/{conversation-entity-extractor-FPAMTL3C.js → conversation-entity-extractor-D3EFTLT4.js} +2 -2
  221. package/dist/{conversation-wiki-populator-WU4HEQ7C.js → conversation-wiki-populator-WQN3IUU6.js} +1 -1
  222. package/dist/{crdt-sync-ETPKNBCU.js → crdt-sync-4PFGPZXV.js} +8 -1
  223. package/dist/{crm-webhook-M566ZMZS.js → crm-webhook-II7Z45Q6.js} +2 -2
  224. package/dist/cto-delegation-gate-JWWOJPNC.js +669 -0
  225. package/dist/{daemon-auth-7IFSV5FG.js → daemon-auth-3FEAHFWC.js} +5 -3
  226. package/dist/{daemon-orchestration-XV5GN73R.js → daemon-orchestration-FX4XZDR5.js} +45 -26
  227. package/dist/{daemon-ready-RKKB4P6K.js → daemon-ready-4JTSFKAY.js} +1 -1
  228. package/dist/{daemon-ready-signal-WKEJQNRA.js → daemon-ready-signal-LPAZWQOV.js} +3 -1
  229. package/dist/daemon-restart-circuit-breaker-PEGEIP6H.js +35 -0
  230. package/dist/daemon-timer-report-NM44WQRH.js +25 -0
  231. package/dist/{db-backup-MX2G3CEK.js → db-backup-W2QFSYQC.js} +15 -5
  232. package/dist/{db-restore-events-JVEEP52Z.js → db-restore-events-MQ2DBGEQ.js} +2 -2
  233. package/dist/dispatch-ack-VYH3ONSS.js +27 -0
  234. package/dist/{doc-graph-extractor-LR5KMPH7.js → doc-graph-extractor-F6ODFIID.js} +6 -6
  235. package/dist/{documents-FA6N7QDA.js → documents-23WX2FPQ.js} +12 -12
  236. package/dist/dreaming-NWD22UQ5.js +46 -0
  237. package/dist/{exe-drift-TUKTCXZE.js → exe-drift-CW72FBGE.js} +5 -5
  238. package/dist/{exe-export-ZLHBXMZC.js → exe-export-AUJ7CV7G.js} +11 -11
  239. package/dist/{exe-import-VVKBZWSA.js → exe-import-JX4I52VE.js} +11 -11
  240. package/dist/{exe-key-QJXFBF6G.js → exe-key-2N6LY2BU.js} +242 -228
  241. package/dist/{exe-org-BGZNNE4H.js → exe-org-X4CSNCKS.js} +3 -3
  242. package/dist/{exe-snapshot-JRLUO645.js → exe-snapshot-XZ7FVCYZ.js} +30 -28
  243. package/dist/{fast-db-init-JKJEEHUI.js → fast-db-init-4CWHSOOR.js} +1 -1
  244. package/dist/{founder-context-HWPLMZVR.js → founder-context-7L3CFPYN.js} +4 -4
  245. package/dist/gateway/index.js +25 -25
  246. package/dist/{gateway-client-GRBOJQYC.js → gateway-client-7LMZKHTH.js} +1 -1
  247. package/dist/git-main-guard-UZP3KXYI.js +39 -0
  248. package/dist/{git-staleness-X5XZONX3.js → git-staleness-CI2R4QOJ.js} +4 -4
  249. package/dist/{global-procedures-VIIVWB6R.js → global-procedures-XQX3LUH6.js} +6 -6
  250. package/dist/{graph-auto-extract-HCQQF5AG.js → graph-auto-extract-OURWMGBS.js} +6 -6
  251. package/dist/{graph-rag-WAK2BRJH.js → graph-rag-JZZAB7PC.js} +2 -2
  252. package/dist/{hook-integrity-WURH6DS3.js → hook-integrity-XY47IM7G.js} +1 -1
  253. package/dist/hook-prefetch-PHRRKY4C.js +137 -0
  254. package/dist/hooks/bug-report-worker.js +31 -27
  255. package/dist/hooks/codex-stop-task-finalizer.js +31 -27
  256. package/dist/hooks/commit-complete.js +28 -26
  257. package/dist/hooks/error-recall.js +12 -11
  258. package/dist/hooks/exe-heartbeat-hook.js +6 -6
  259. package/dist/hooks/ingest-worker.js +11 -11
  260. package/dist/hooks/ingest.js +18 -18
  261. package/dist/hooks/instructions-loaded.js +7 -7
  262. package/dist/hooks/manifest.json +20 -20
  263. package/dist/hooks/notification.js +7 -7
  264. package/dist/hooks/post-compact.js +27 -25
  265. package/dist/hooks/post-tool-combined.js +12 -12
  266. package/dist/hooks/pre-compact.js +28 -26
  267. package/dist/hooks/pre-tool-use.js +179 -46
  268. package/dist/hooks/prompt-submit.js +323 -272
  269. package/dist/hooks/session-end.js +34 -32
  270. package/dist/hooks/session-start.js +28 -21
  271. package/dist/hooks/stop.js +34 -32
  272. package/dist/hooks/subagent-stop.js +27 -25
  273. package/dist/hooks/summary-worker.js +35 -33
  274. package/dist/index.js +40 -38
  275. package/dist/{installer-6IFVEQI4.js → installer-G3JAO3NT.js} +9 -9
  276. package/dist/{installer-NX2CLNV5.js → installer-JND3RJ6Q.js} +9 -9
  277. package/dist/{installer-T2LGHZKL.js → installer-L7EVH5U5.js} +9 -9
  278. package/dist/{intercom-queue-KYHXXZCQ.js → intercom-queue-ZFEQALR3.js} +24 -22
  279. package/dist/{key-backup-status-TNEHXA2X.js → key-backup-status-LOSMVATJ.js} +2 -2
  280. package/dist/lib/agent-config.js +4 -3
  281. package/dist/lib/cloud-sync.js +19 -19
  282. package/dist/lib/config.js +2 -2
  283. package/dist/lib/consolidation.js +11 -11
  284. package/dist/lib/crypto.js +3 -3
  285. package/dist/lib/database.js +6 -4
  286. package/dist/lib/db-daemon-client.js +5 -5
  287. package/dist/lib/db-read-worker-client.js +9 -3
  288. package/dist/lib/db.js +6 -4
  289. package/dist/lib/device-registry.js +3 -3
  290. package/dist/lib/embed-worker.js +2 -2
  291. package/dist/lib/embedder.js +5 -5
  292. package/dist/lib/employee-templates.js +7 -7
  293. package/dist/lib/employees.js +10 -4
  294. package/dist/lib/exe-daemon-client.js +4 -4
  295. package/dist/lib/exe-daemon.js +588 -164
  296. package/dist/lib/hybrid-search.js +11 -9
  297. package/dist/lib/identity.js +4 -4
  298. package/dist/lib/keychain.js +1 -1
  299. package/dist/lib/license.js +4 -4
  300. package/dist/lib/messaging.js +27 -23
  301. package/dist/lib/post-tool-memory.js +3 -3
  302. package/dist/lib/registry-proxy.js +1 -1
  303. package/dist/lib/reminders.js +15 -7
  304. package/dist/lib/schedules.js +9 -9
  305. package/dist/lib/session-registry.js +6 -6
  306. package/dist/lib/skill-learning.js +10 -10
  307. package/dist/lib/status-brief.js +4 -4
  308. package/dist/lib/store.js +8 -8
  309. package/dist/lib/task-router.js +5 -5
  310. package/dist/lib/tasks.js +28 -24
  311. package/dist/lib/tmux-routing.js +55 -24
  312. package/dist/lib/tmux-status.js +9 -3
  313. package/dist/lib/tmux-transport.js +1 -1
  314. package/dist/lib/token-spend.js +5 -5
  315. package/dist/lib/transport.js +2 -2
  316. package/dist/lib/ws-client.js +1 -1
  317. package/dist/{license-gate-MGDR4YNI.js → license-gate-QTRQHV4F.js} +5 -5
  318. package/dist/{license-sync-UWE6GEB4.js → license-sync-N3UJFWAW.js} +4 -4
  319. package/dist/mcp/register-tools.js +97 -91
  320. package/dist/mcp/server.js +99 -93
  321. package/dist/mcp/tools/complete-reminder.js +6 -6
  322. package/dist/mcp/tools/create-reminder.js +6 -6
  323. package/dist/mcp/tools/create-task.js +36 -27
  324. package/dist/mcp/tools/deactivate-behavior.js +11 -11
  325. package/dist/mcp/tools/list-reminders.js +6 -6
  326. package/dist/mcp/tools/list-tasks.js +34 -28
  327. package/dist/mcp/tools/send-message.js +27 -25
  328. package/dist/mcp/tools/update-task.js +33 -27
  329. package/dist/{mcp-http-config-RQLYEPTL.js → mcp-http-config-BDL36JZ3.js} +6 -6
  330. package/dist/{mcp-port-config-FFAMMLLE.js → mcp-port-config-6HYY6J7K.js} +2 -2
  331. package/dist/mcp-session-identity-T7H2EKFQ.js +177 -0
  332. package/dist/{memory-cards-VYQ5DPMR.js → memory-cards-ZRDW7QBX.js} +8 -8
  333. package/dist/{memory-graph-extractor-GX2HNYLU.js → memory-graph-extractor-QLXDMHRS.js} +7 -7
  334. package/dist/{memory-poisoning-defense-TX7627BD.js → memory-poisoning-defense-HJTXYCWH.js} +4 -4
  335. package/dist/{memory-pressure-watchdog-MLNNH26B.js → memory-pressure-watchdog-HN5X7AVN.js} +75 -36
  336. package/dist/{memory-queue-X2CSEAKE.js → memory-queue-2UOOF27L.js} +5 -3
  337. package/dist/{memory-queue-client-YRL6XTGU.js → memory-queue-client-O5U6F6XP.js} +6 -6
  338. package/dist/{memory-reflection-KIGEFSI4.js → memory-reflection-WVNFBJAA.js} +4 -4
  339. package/dist/{monitor-grants-RZOVSYVO.js → monitor-grants-E3ELDEWD.js} +5 -5
  340. package/dist/{monitor-identity-MOXISYNG.js → monitor-identity-GLFZSEAH.js} +2 -2
  341. package/dist/{notification-ledger-B6AVEGMV.js → notification-ledger-SZEPGJQ7.js} +25 -23
  342. package/dist/{notifications-DWXV7SVL.js → notifications-4UT53CDG.js} +24 -22
  343. package/dist/{orchestration-events-ZG7O4HRY.js → orchestration-events-WV4NWKZH.js} +5 -5
  344. package/dist/{orchestration-phase-CXRCBCK7.js → orchestration-phase-AWBXPO52.js} +3 -3
  345. package/dist/orchestrator-UAC3RW2T.js +47 -0
  346. package/dist/{pipeline-router-RTLAGZTA.js → pipeline-router-LM53NMWJ.js} +5 -5
  347. package/dist/{plan-limits-WLQZTCSF.js → plan-limits-2FEY2GOS.js} +7 -7
  348. package/dist/platform-procedures-X5DFJFV7.js +13 -0
  349. package/dist/{preferences-TYTGDXQZ.js → preferences-TWIXZBKS.js} +2 -2
  350. package/dist/{project-boot-6CGQ3EAH.js → project-boot-4NUH5FRU.js} +2 -2
  351. package/dist/{projection-worker-44SEKTZ5.js → projection-worker-FZ7YSN3G.js} +5 -5
  352. package/dist/{prospective-memory-UACFTYXK.js → prospective-memory-6D2ASWM3.js} +4 -4
  353. package/dist/{push-notifications-W5JRXLKJ.js → push-notifications-U6FIBQRW.js} +3 -3
  354. package/dist/{reranker-NL4YAV6R.js → reranker-GYYRPANK.js} +3 -3
  355. package/dist/{retrieval-health-4C2PO6HH.js → retrieval-health-4Z242P3B.js} +1 -1
  356. package/dist/{review-polling-W5AMHNLT.js → review-polling-HXAFJZDA.js} +25 -23
  357. package/dist/runtime/index.js +35 -33
  358. package/dist/{session-events-PGL5GJEB.js → session-events-O3BV56ZX.js} +25 -23
  359. package/dist/{session-kill-telemetry-6YDGEF27.js → session-kill-telemetry-AELE4JDK.js} +25 -23
  360. package/dist/session-mcp-config-YKNXG5DW.js +50 -0
  361. package/dist/{session-scope-3MEOO557.js → session-scope-5EAPUT45.js} +24 -22
  362. package/dist/setup-wizard-NB6R4QVS.js +14 -0
  363. package/dist/{shard-manager-MBWQEYNG.js → shard-manager-35PWFR3B.js} +3 -3
  364. package/dist/{skill-refinement-EOROTBPX.js → skill-refinement-DVSYXBBP.js} +5 -5
  365. package/dist/{stack-release-PR2XKJ4Q.js → stack-release-HGFFFCGC.js} +90 -15
  366. package/dist/{stack-update-LMDM27ZW.js → stack-update-ATCJFOEK.js} +5 -5
  367. package/dist/{steward-gate-4A2XHYFD.js → steward-gate-3GQ5XKMJ.js} +5 -5
  368. package/dist/{support-inbox-Z77ACQUY.js → support-inbox-4L62P4EP.js} +7 -6
  369. package/dist/{support-outbox-GB5SQFRJ.js → support-outbox-WHGPUYL2.js} +2 -2
  370. package/dist/task-enforcement-IPIZX2MM.js +90 -0
  371. package/dist/{task-scope-EKYDCVUF.js → task-scope-FOIW25HR.js} +26 -22
  372. package/dist/{tasks-crud-6LBNU43G.js → tasks-crud-HBDKE6C5.js} +34 -22
  373. package/dist/tasks-notify-G2U2U2YA.js +53 -0
  374. package/dist/{tasks-review-PBIUYXAL.js → tasks-review-27SFX5XN.js} +26 -22
  375. package/dist/{telemetry-upload-WQDFABTF.js → telemetry-upload-ZOXHRWR5.js} +9 -9
  376. package/dist/tmux-command-guard-KSJKIX3C.js +117 -0
  377. package/dist/{token-budget-KWGL5DY7.js → token-budget-5Y4YPDO3.js} +5 -5
  378. package/dist/{tool-capability-index-EH3HQVHU.js → tool-capability-index-VYF5GNJ2.js} +1 -1
  379. package/dist/{tool-telemetry-UC55LSIH.js → tool-telemetry-KBXSBDTK.js} +1 -1
  380. package/dist/tui/App.js +39 -37
  381. package/dist/{tui-data-M3RBSJL3.js → tui-data-NLFMBIQI.js} +24 -22
  382. package/dist/{update-check-HFO4VHO4.js → update-check-3FHAWIG2.js} +7 -3
  383. package/dist/{update-support-VPBD5SD2.js → update-support-UVUSZG7R.js} +93 -93
  384. package/dist/{whatsapp-accounts-BWRZUY23.js → whatsapp-accounts-BFIOXYW5.js} +1 -1
  385. package/dist/{whatsapp-config-GOSELKTE.js → whatsapp-config-FAX6EA5K.js} +20 -13
  386. package/dist/{worker-gate-4QLLMXZM.js → worker-gate-3KUBAU32.js} +3 -3
  387. package/dist/{workflow-engine-MMEHKUN4.js → workflow-engine-YITHXZR5.js} +2 -2
  388. package/dist/{working-memory-PY4AG577.js → working-memory-NUVB5SFV.js} +1 -1
  389. package/dist/worktree-LL62PLQB.js +47 -0
  390. package/dist/{worktree-sweep-5WKBU7E6.js → worktree-sweep-WTK3MTKH.js} +7 -7
  391. package/package.json +3 -2
  392. package/release-notes.json +75 -43
  393. package/dist/branch-hygiene-R5NVTRAY.js +0 -138
  394. package/dist/chunk-7YORGTXC.js +0 -138
  395. package/dist/chunk-CCPHEPLU.js +0 -30
  396. package/dist/chunk-HMP5VT6A.js +0 -118
  397. package/dist/chunk-PVYR4FCQ.js +0 -113
  398. package/dist/chunk-RP5GETX5.js +0 -140
  399. package/dist/chunk-YGAAZN3E.js +0 -47
  400. package/dist/cto-delegation-gate-S734XDXT.js +0 -290
  401. package/dist/dispatch-ack-4S44HBWB.js +0 -15
  402. package/dist/dreaming-UKGTQT6I.js +0 -44
  403. package/dist/orchestrator-PGHJDUUT.js +0 -45
  404. package/dist/setup-wizard-CJIYDSSP.js +0 -13
  405. package/dist/tasks-notify-TFJLSQ3B.js +0 -50
  406. package/dist/worktree-YXBDRYOC.js +0 -31
  407. package/dist/{chunk-7UMCQQWS.js → chunk-A4DVMPYB.js} +3 -3
  408. /package/dist/{chunk-2KLAYDFB.js → chunk-GIBYNT6W.js} +0 -0
  409. /package/dist/{chunk-MC6VPZKS.js → chunk-JRM4TAGS.js} +0 -0
  410. /package/dist/{chunk-3NCZKWPO.js → chunk-MGGOSFCR.js} +0 -0
  411. /package/dist/{chunk-C2SRRCRK.js → chunk-QIFYLIUF.js} +0 -0
  412. /package/dist/{chunk-OADURIIN.js → chunk-WTH4CSAP.js} +0 -0
  413. /package/dist/{core-memory-3IBWM4WR.js → core-memory-GAC6EWOQ.js} +0 -0
  414. /package/dist/{entity-boost-DWAWXFKN.js → entity-boost-NT6UO2Z3.js} +0 -0
  415. /package/dist/{message-queue-client-3PTHPG5Q.js → message-queue-client-4EOQRUXW.js} +0 -0
  416. /package/dist/{oauth-server-M5TGXT6D.js → oauth-server-67YBDP32.js} +0 -0
  417. /package/dist/{webhook-pipe-FZYLO6RR.js → webhook-pipe-LEXMUQ5B.js} +0 -0
  418. /package/dist/{wiki-acl-7CROE3MJ.js → wiki-acl-74BLWG6J.js} +0 -0
  419. /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-3BRVLPPA.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-7LF5DS3A.js";
25
- import "../chunk-RP5GETX5.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-DWXV7SVL.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-DWXV7SVL.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-MX2G3CEK.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-44SEKTZ5.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-RTLAGZTA.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-RVUNRCQY.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-3PTHPG5Q.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-MGDR4YNI.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-UC55LSIH.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-EH3HQVHU.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-M5TGXT6D.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-M5TGXT6D.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-ZG7O4HRY.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",
@@ -4047,10 +4316,10 @@ async function ensureStoreForPolling() {
4047
4316
  await initDatabase({ dbPath: config.dbPath, encryptionKey: masterKey.toString("hex") });
4048
4317
  await ensureSchema();
4049
4318
  try {
4050
- const { isLedgerEnabled } = await import("../notification-ledger-B6AVEGMV.js");
4319
+ const { isLedgerEnabled } = await import("../notification-ledger-SZEPGJQ7.js");
4051
4320
  if (isLedgerEnabled()) {
4052
- const { bumpBootGeneration } = await import("../boot-generation-GSMPJOWM.js");
4053
- const { setDaemonReadyGeneration } = await import("../daemon-ready-signal-WKEJQNRA.js");
4321
+ const { bumpBootGeneration } = await import("../boot-generation-BL2ISK4U.js");
4322
+ const { setDaemonReadyGeneration } = await import("../daemon-ready-signal-LPAZWQOV.js");
4054
4323
  const generation = await bumpBootGeneration();
4055
4324
  setDaemonReadyGeneration(generation);
4056
4325
  process.stderr.write(`[exed] notification ledger enabled \u2014 boot generation ${generation}
@@ -4079,13 +4348,13 @@ async function ensureStoreForPolling() {
4079
4348
  }
4080
4349
  }
4081
4350
  async function startReviewPolling() {
4082
- const polling = await import("../review-polling-W5AMHNLT.js");
4351
+ const polling = await import("../review-polling-HXAFJZDA.js");
4083
4352
  const state = {
4084
4353
  lastIntercomSent: /* @__PURE__ */ new Map(),
4085
4354
  lastNudgeSent: /* @__PURE__ */ new Map(),
4086
4355
  intervalMs: REVIEW_POLL_INTERVAL_MS
4087
4356
  };
4088
- const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-XV5GN73R.js");
4357
+ const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-FX4XZDR5.js");
4089
4358
  const nudgeState = loadNudgeState();
4090
4359
  const tick = async () => traceDaemonTimer("review_polling", async () => {
4091
4360
  fired("review_polling");
@@ -4123,16 +4392,17 @@ async function startReviewPolling() {
4123
4392
  }
4124
4393
  var SESSION_TTL_INTERVAL_MS = 5 * 60 * 1e3;
4125
4394
  var SESSION_REGISTRY_MAINTENANCE_INTERVAL_MS = 5 * 60 * 1e3;
4395
+ var _wedgeObservations = /* @__PURE__ */ new Map();
4126
4396
  function startSessionTTL() {
4127
4397
  const tick = async () => traceDaemonTimer("session_ttl", async () => {
4128
4398
  fired("session_ttl");
4129
- if (!await ensureStoreForPolling()) return;
4130
- if (inPostRestartDestructiveGrace("session_ttl")) return;
4131
4399
  try {
4400
+ if (!await ensureStoreForPolling()) return;
4401
+ if (inPostRestartDestructiveGrace("session_ttl")) return;
4132
4402
  const { getClient } = await import("./database.js");
4133
- const { checkSessionTTL, createSessionTTLRealDeps } = await import("../daemon-orchestration-XV5GN73R.js");
4403
+ const { checkSessionTTL, createSessionTTLRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
4134
4404
  const deps = createSessionTTLRealDeps(getClient);
4135
- const killed = await checkSessionTTL(deps);
4405
+ const killed = await checkSessionTTL(deps, _wedgeObservations);
4136
4406
  if (killed.length > 0) acted("session_ttl");
4137
4407
  } catch (err) {
4138
4408
  process.stderr.write(`[exed] Session TTL error: ${err instanceof Error ? err.message : String(err)}
@@ -4145,6 +4415,9 @@ function startSessionTTL() {
4145
4415
  `);
4146
4416
  }
4147
4417
  var COO_RESTART_COOLDOWN_MS = 5 * 6e4;
4418
+ var _resolveNpmGlobalRoot = createMemoizedNpmGlobalRootResolver(
4419
+ (file, args, opts) => execFileAsync(file, args, opts)
4420
+ );
4148
4421
  var _idleTickCounts = /* @__PURE__ */ new Map();
4149
4422
  function startIdleKill() {
4150
4423
  const tick = async () => traceDaemonTimer("idle_kill", async () => {
@@ -4179,7 +4452,7 @@ function startIdleKill() {
4179
4452
  const cfg = await getCachedConfig();
4180
4453
  if (!cfg) return;
4181
4454
  const { getClient } = await import("./database.js");
4182
- const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-XV5GN73R.js");
4455
+ const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
4183
4456
  const { sessions: liveSessions, paneCache, aliveSessions } = await getSharedOrchestrationCaches();
4184
4457
  const realDeps = createIdleKillRealDeps(
4185
4458
  getClient,
@@ -4252,7 +4525,7 @@ function startConsolidation() {
4252
4525
  `);
4253
4526
  }
4254
4527
  try {
4255
- const { createBackupAsync, enforceRetention } = await import("../db-backup-MX2G3CEK.js");
4528
+ const { createBackupAsync, enforceRetention } = await import("../db-backup-W2QFSYQC.js");
4256
4529
  const p = await createBackupAsync("pre-consolidation");
4257
4530
  if (p) enforceRetention("pre-consolidation");
4258
4531
  } catch (e) {
@@ -4485,7 +4758,7 @@ function startSkillRefinement() {
4485
4758
  if (!shouldRunHeavyJob("skill_refinement")) return;
4486
4759
  try {
4487
4760
  if (!await ensureStoreForPolling()) return;
4488
- const { runSkillRefinement } = await import("../skill-refinement-EOROTBPX.js");
4761
+ const { runSkillRefinement } = await import("../skill-refinement-DVSYXBBP.js");
4489
4762
  const result = await runSkillRefinement();
4490
4763
  if (result.reviewed > 0) {
4491
4764
  acted("skill_refinement");
@@ -4511,8 +4784,8 @@ function startStaleBranchSweep() {
4511
4784
  const tick = async () => {
4512
4785
  fired("stale_branch_sweep");
4513
4786
  try {
4514
- const { discoverRepoPaths } = await import("../worktree-sweep-5WKBU7E6.js");
4515
- 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");
4516
4789
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4517
4790
  for (const k of _staleBranchAlertedToday) {
4518
4791
  if (!k.endsWith(today)) _staleBranchAlertedToday.delete(k);
@@ -4527,7 +4800,11 @@ function startStaleBranchSweep() {
4527
4800
  await yieldToEventLoop();
4528
4801
  let scan;
4529
4802
  try {
4530
- scan = await scanUnmergedBranches(repo, { staleHours: STALE_BRANCH_HOURS });
4803
+ scan = await scanUnmergedBranchesCached(
4804
+ repo,
4805
+ { staleHours: STALE_BRANCH_HOURS },
4806
+ { forceRefresh: true }
4807
+ );
4531
4808
  } catch {
4532
4809
  continue;
4533
4810
  }
@@ -4539,13 +4816,13 @@ function startStaleBranchSweep() {
4539
4816
  if (!_storeInitialized) continue;
4540
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("; ");
4541
4818
  try {
4542
- const { writeNotification } = await import("../notifications-DWXV7SVL.js");
4819
+ const { writeNotification } = await import("../notifications-4UT53CDG.js");
4543
4820
  await writeNotification({
4544
4821
  agentId: "exe",
4545
4822
  agentRole: "system",
4546
4823
  event: "error_spike",
4547
4824
  project: repoName,
4548
- 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`,
4549
4826
  sessionScope: null
4550
4827
  });
4551
4828
  acted("stale_branch_sweep");
@@ -4578,7 +4855,7 @@ function startGraphExtraction() {
4578
4855
  if (!await ensureStoreForPolling()) return;
4579
4856
  const { getClient } = await import("./database.js");
4580
4857
  const client = getClient();
4581
- const { extractBatch } = await import("../graph-rag-WAK2BRJH.js");
4858
+ const { extractBatch } = await import("../graph-rag-JZZAB7PC.js");
4582
4859
  const result = await extractBatch(client, 50, config.selfQueryModel);
4583
4860
  if (result.processed > 0) {
4584
4861
  acted("graph_extraction");
@@ -4996,7 +5273,7 @@ function startReflectionSweep() {
4996
5273
  );
4997
5274
  let runReflection;
4998
5275
  try {
4999
- ({ runReflection } = await import("../memory-reflection-KIGEFSI4.js"));
5276
+ ({ runReflection } = await import("../memory-reflection-WVNFBJAA.js"));
5000
5277
  } catch (importErr) {
5001
5278
  _reflectionImportFailed = true;
5002
5279
  process.stderr.write(`[exed] Reflection module unavailable (stale chunk hash?) \u2014 disabled until daemon restart: ${importErr instanceof Error ? importErr.message : String(importErr)}
@@ -5037,7 +5314,7 @@ function startReflectionSweep() {
5037
5314
  if (memories > 100 && cards < memories * 0.1) {
5038
5315
  process.stderr.write(`[exed] Memory cards sparse (${cards} cards / ${memories} memories) \u2014 running backfill...
5039
5316
  `);
5040
- const { insertMemoryCardsForBatch } = await import("../memory-cards-VYQ5DPMR.js");
5317
+ const { insertMemoryCardsForBatch } = await import("../memory-cards-ZRDW7QBX.js");
5041
5318
  const batchSize = 500;
5042
5319
  let offset = 0;
5043
5320
  let totalCards = 0;
@@ -5076,13 +5353,25 @@ function startReflectionSweep() {
5076
5353
  process.stderr.write(`[exed] Reflection sweep started (every 6h)
5077
5354
  `);
5078
5355
  }
5079
- 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);
5080
5358
  function startDatabaseBackup() {
5081
5359
  const tick = async () => {
5082
5360
  fired("db_backup");
5083
- if (!shouldRunHeavyJob("db_backup")) return;
5084
5361
  try {
5085
- const { createBackupAsync, enforceRetention, hasBackupToday } = await import("../db-backup-MX2G3CEK.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;
5086
5375
  if (hasBackupToday("daily")) return;
5087
5376
  const backupPath = await createBackupAsync("daily");
5088
5377
  if (backupPath) {
@@ -5093,7 +5382,7 @@ function startDatabaseBackup() {
5093
5382
  `
5094
5383
  );
5095
5384
  try {
5096
- const { maybeVerifyDailyBackup } = await import("../backup-verify-ZAJLEL4X.js");
5385
+ const { maybeVerifyDailyBackup } = await import("../backup-verify-3Y2FHGZU.js");
5097
5386
  const verdict = await maybeVerifyDailyBackup(backupPath);
5098
5387
  if (verdict && !verdict.ok) {
5099
5388
  process.stderr.write(
@@ -5117,8 +5406,10 @@ function startDatabaseBackup() {
5117
5406
  tick();
5118
5407
  const timer = setInterval(() => void traceDaemonTimer("db_backup", tick), DB_BACKUP_INTERVAL_MS);
5119
5408
  timer.unref();
5120
- process.stderr.write(`[exed] Database backup started (daily, keep 3 days)
5121
- `);
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
+ );
5122
5413
  }
5123
5414
  var PURGE_INTERVAL_MS = 6 * 60 * 60 * 1e3;
5124
5415
  function startSoftDeletePurge() {
@@ -5168,7 +5459,7 @@ function startSessionEventsRetention() {
5168
5459
  if (!await ensureStoreForPolling()) return;
5169
5460
  try {
5170
5461
  const { getClient } = await import("./database.js");
5171
- const { sweepExpiredSessionEvents, DEFAULT_SESSION_EVENTS_RETENTION_DAYS } = await import("../session-events-PGL5GJEB.js");
5462
+ const { sweepExpiredSessionEvents, DEFAULT_SESSION_EVENTS_RETENTION_DAYS } = await import("../session-events-O3BV56ZX.js");
5172
5463
  const days = SESSION_EVENTS_RETENTION_DAYS ?? DEFAULT_SESSION_EVENTS_RETENTION_DAYS;
5173
5464
  const count = await sweepExpiredSessionEvents(getClient(), days);
5174
5465
  if (count > 0) {
@@ -5199,11 +5490,15 @@ function startIntercomQueueDrain() {
5199
5490
  const tick = async () => traceDaemonTimer("intercom_queue_drain", async () => {
5200
5491
  fired("intercom_queue_drain");
5201
5492
  try {
5202
- const { drainQueueAsync, readQueue } = await import("../intercom-queue-KYHXXZCQ.js");
5493
+ const { drainQueueAsync, readQueue } = await import("../intercom-queue-ZFEQALR3.js");
5203
5494
  const {
5204
5495
  sendIntercomAsync: centralSendIntercomAsync,
5205
- decideQueuedNudgeDrain,
5206
- countScopedPendingReviews
5496
+ countScopedPendingReviews,
5497
+ countScopedOpenTasks,
5498
+ dispositionWedgedSessionTask,
5499
+ decideDrainSend,
5500
+ offlineIfEmpty,
5501
+ paneHasPendingInput
5207
5502
  } = await import("./tmux-routing.js");
5208
5503
  const { baseAgentName, getCoordinatorName } = await import("./employees.js");
5209
5504
  const agentsWithEmptyInbox = /* @__PURE__ */ new Set();
@@ -5236,6 +5531,18 @@ function startIntercomQueueDrain() {
5236
5531
  if (count !== null) pendingReviewCounts.set(target, count);
5237
5532
  }
5238
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
+ }
5239
5546
  const result = await drainQueueAsync(
5240
5547
  // Bug ddbfc3f6: async busy check via the shared async pane cache —
5241
5548
  // no sync execFileSync("tmux") per queue item on the event loop.
@@ -5247,24 +5554,52 @@ function startIntercomQueueDrain() {
5247
5554
  try {
5248
5555
  const agentRaw = session.split("-")[0] ?? session;
5249
5556
  const agent = baseAgentName(agentRaw);
5250
- const decision = decideQueuedNudgeDrain(item.intercomReason, {
5251
- hasUnreadMessages: !agentsWithEmptyInbox.has(agent),
5252
- pendingReviewCount: pendingReviewCounts.get(session) ?? null,
5253
- hasInProgressTask: false
5254
- });
5255
- if (decision.action === "drop") {
5256
- process.stderr.write(`[exe-daemon] dropping stale ${item.intercomReason ?? "nudge"} intercom for ${session} (${decision.reason})
5257
- `);
5258
- return true;
5259
- }
5260
- const outcome = await centralSendIntercomAsync(session, {
5261
- reason: item.intercomReason ?? "nudge"
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
5262
5570
  });
5263
- return outcome === "delivered" || outcome === "debounced" || outcome === "skipped_exe";
5264
5571
  } catch (e) {
5265
5572
  process.stderr.write("[exe-daemon] intercom send to " + session + ": " + (e instanceof Error ? e.message : String(e)) + "\n");
5266
5573
  return false;
5267
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
+ }
5268
5603
  }
5269
5604
  );
5270
5605
  if (result.drained > 0 || result.failed > 0) {
@@ -5287,7 +5622,7 @@ function startLedgerDrain() {
5287
5622
  const tick = async () => traceDaemonTimer("ledger_drain", async () => {
5288
5623
  fired("ledger_drain");
5289
5624
  try {
5290
- const { isLedgerEnabled, drainLedger } = await import("../notification-ledger-B6AVEGMV.js");
5625
+ const { isLedgerEnabled, drainLedger } = await import("../notification-ledger-SZEPGJQ7.js");
5291
5626
  if (!isLedgerEnabled()) return;
5292
5627
  const result = await drainLedger({
5293
5628
  // Shadow "would-deliver": idle target = would-deliver, busy = retry.
@@ -5326,7 +5661,7 @@ function startOrphanReaper() {
5326
5661
  const tick = async () => traceDaemonTimer("orphan_reaper", async () => {
5327
5662
  fired("orphan_reaper");
5328
5663
  try {
5329
- const { reapOrphanedMcpProcesses, createOrphanReaperRealDepsAsync } = await import("../daemon-orchestration-XV5GN73R.js");
5664
+ const { reapOrphanedMcpProcesses, createOrphanReaperRealDepsAsync } = await import("../daemon-orchestration-FX4XZDR5.js");
5330
5665
  const deps = await createOrphanReaperRealDepsAsync();
5331
5666
  const reaped = await reapOrphanedMcpProcesses(deps);
5332
5667
  if (reaped.length > 0) acted("orphan_reaper");
@@ -5351,7 +5686,7 @@ function startZombieAgentReaper() {
5351
5686
  const tick = async () => traceDaemonTimer("zombie_agent_reaper", async () => {
5352
5687
  fired("zombie_agent_reaper");
5353
5688
  try {
5354
- const { reapZombieAgentProcesses, createZombieAgentReaperRealDepsAsync } = await import("../daemon-orchestration-XV5GN73R.js");
5689
+ const { reapZombieAgentProcesses, createZombieAgentReaperRealDepsAsync } = await import("../daemon-orchestration-FX4XZDR5.js");
5355
5690
  const deps = await createZombieAgentReaperRealDepsAsync();
5356
5691
  const reaped = reapZombieAgentProcesses(deps);
5357
5692
  if (reaped.length > 0) acted("zombie_agent_reaper");
@@ -5375,7 +5710,7 @@ async function startDaemonMemoryPressureWatchdog() {
5375
5710
  try {
5376
5711
  const cfg = await getCachedConfig();
5377
5712
  if (!cfg) return;
5378
- const { startMemoryPressureWatchdog: startWatchdog, MEMORY_PRESSURE_WATCHDOG_DEFAULTS } = await import("../memory-pressure-watchdog-MLNNH26B.js");
5713
+ const { startMemoryPressureWatchdog: startWatchdog, MEMORY_PRESSURE_WATCHDOG_DEFAULTS } = await import("../memory-pressure-watchdog-HN5X7AVN.js");
5379
5714
  const watchdogCfg = {
5380
5715
  ...MEMORY_PRESSURE_WATCHDOG_DEFAULTS,
5381
5716
  ...cfg.memoryPressureWatchdog ?? {}
@@ -5406,7 +5741,7 @@ function startWorktreeReaper() {
5406
5741
  const tick = async () => traceDaemonTimer("worktree_reaper", async () => {
5407
5742
  fired("worktree_reaper");
5408
5743
  try {
5409
- const { reapOrphanedWorktrees, createWorktreeReaperRealDeps } = await import("../daemon-orchestration-XV5GN73R.js");
5744
+ const { reapOrphanedWorktrees, createWorktreeReaperRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
5410
5745
  const deps = await createWorktreeReaperRealDeps();
5411
5746
  const result = await reapOrphanedWorktrees(deps);
5412
5747
  if (result.pruned.length > 0) {
@@ -5446,9 +5781,9 @@ function startWorktreeReaper() {
5446
5781
  }
5447
5782
  continue;
5448
5783
  }
5449
- const { cleanupAgentWorktree } = await import("../worktree-sweep-5WKBU7E6.js");
5450
- const { getMainRepoRoot } = await import("../worktree-YXBDRYOC.js");
5451
- 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);
5452
5787
  if (repoRoot && signal.agentId) {
5453
5788
  const notes = await cleanupAgentWorktree(repoRoot, signal.agentId);
5454
5789
  if (notes) {
@@ -5480,7 +5815,7 @@ function startAutoWake() {
5480
5815
  if (!await ensureStoreForPolling()) return;
5481
5816
  try {
5482
5817
  const { getClient } = await import("./database.js");
5483
- const { pollOrphanedTasks, createAutoWakeRealDeps } = await import("../daemon-orchestration-XV5GN73R.js");
5818
+ const { pollOrphanedTasks, createAutoWakeRealDeps } = await import("../daemon-orchestration-FX4XZDR5.js");
5484
5819
  const deps = createAutoWakeRealDeps(getClient, process.cwd(), getTmuxSessionsAsync);
5485
5820
  const woken = await pollOrphanedTasks(deps);
5486
5821
  if (woken.length > 0) acted("auto_wake");
@@ -5492,7 +5827,7 @@ function startAutoWake() {
5492
5827
  const signalBase = path3.join(os2.homedir(), ".exe-os", "task-signals");
5493
5828
  if (existsSync4(signalBase)) {
5494
5829
  const { readdirSync: readdirSync2, statSync: statSyncFs } = await import("fs");
5495
- const { sendIntercomAsync } = await import("./tmux-routing.js");
5830
+ const { sendIntercomAsync, extractRootExe } = await import("./tmux-routing.js");
5496
5831
  const sessionCache = path3.join(os2.homedir(), ".exe-os", "session-cache");
5497
5832
  const sessions = await getTmuxSessionsAsync();
5498
5833
  const signalDirs = [];
@@ -5531,7 +5866,7 @@ function startAutoWake() {
5531
5866
  if (age > 60 * 60 * 1e3) {
5532
5867
  try {
5533
5868
  unlinkSync2(signalPath);
5534
- void import("../orchestration-events-ZG7O4HRY.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
5869
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
5535
5870
  recordOE({ eventType: "signal.stale", source: "exe-daemon.autoWake", severity: "warn", payload: { file, ageMinutes: Math.round(age / 6e4) } });
5536
5871
  }).catch(() => {
5537
5872
  });
@@ -5560,9 +5895,17 @@ function startAutoWake() {
5560
5895
  `
5561
5896
  );
5562
5897
  } else {
5563
- await sendIntercomAsync(match, { force: true, reason: "signal" });
5564
- 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)
5565
5907
  `);
5908
+ }
5566
5909
  }
5567
5910
  }
5568
5911
  }
@@ -5591,7 +5934,7 @@ function startWalCheckpoint() {
5591
5934
  try {
5592
5935
  const { getClient, runWalCheckpoint } = await import("./database.js");
5593
5936
  const client = getClient();
5594
- const { findActiveDb } = await import("../db-backup-MX2G3CEK.js");
5937
+ const { findActiveDb } = await import("../db-backup-W2QFSYQC.js");
5595
5938
  const dbPath = findActiveDb();
5596
5939
  const started = Date.now();
5597
5940
  const result = await runWalCheckpoint(client, dbPath, true);
@@ -5669,7 +6012,7 @@ function startStuckTaskRelease() {
5669
6012
  createStuckTaskRealDeps,
5670
6013
  escalateStuckBlockedTasks,
5671
6014
  createStuckBlockedRealDeps
5672
- } = await import("../daemon-orchestration-XV5GN73R.js");
6015
+ } = await import("../daemon-orchestration-FX4XZDR5.js");
5673
6016
  const deps = createStuckTaskRealDeps(getClient);
5674
6017
  const released = await releaseStuckTasks(deps);
5675
6018
  if (released.length > 0) {
@@ -5864,12 +6207,12 @@ function startTaskEnforcementScanner() {
5864
6207
  const tick = async () => traceDaemonTimer("task_enforcement", async () => {
5865
6208
  fired("task_enforcement");
5866
6209
  try {
5867
- const { runTaskEnforcementTick } = await import("../task-enforcement-X5QVL6RE.js");
6210
+ const { runTaskEnforcementTick } = await import("../task-enforcement-IPIZX2MM.js");
5868
6211
  const { getTransport } = await import("./transport.js");
5869
6212
  const { loadAgentConfig } = await import("./agent-config.js");
5870
6213
  const { getClient } = await import("./database.js");
5871
6214
  const { loadEmployeesSync } = await import("./employees.js");
5872
- const { sessionScopeFilter } = await import("../task-scope-EKYDCVUF.js");
6215
+ const { sessionScopeFilter } = await import("../task-scope-FOIW25HR.js");
5873
6216
  const transport = getTransport();
5874
6217
  const { sessions: allSessions, paneCache, aliveSessions } = await getSharedOrchestrationCaches();
5875
6218
  await yieldToEventLoop();
@@ -5880,10 +6223,10 @@ function startTaskEnforcementScanner() {
5880
6223
  sendKeysLiteral: transport.sendKeysLiteral?.bind(transport),
5881
6224
  isAlive: (session) => aliveSessions.has(session)
5882
6225
  };
5883
- const { checkAutoWakeGates } = await import("../daemon-orchestration-XV5GN73R.js");
5884
- 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");
5885
6228
  const { shouldAutoInstance } = await import("./employees.js");
5886
- const { recordOrchestrationEventBestEffort } = await import("../orchestration-events-ZG7O4HRY.js");
6229
+ const { recordOrchestrationEventBestEffort } = await import("../orchestration-events-WV4NWKZH.js");
5887
6230
  const projectDir = process.cwd();
5888
6231
  await runTaskEnforcementTick({
5889
6232
  transport: enforcementTransport,
@@ -5908,6 +6251,16 @@ function startTaskEnforcementScanner() {
5908
6251
  `));
5909
6252
  return { status: "intercom_unprocessed", sessionName: employeeSessionName(reviewerName, sessionScope) };
5910
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
+ },
5911
6264
  zombieWorkerRecover: async (session, agentName, sessionScope, reason) => {
5912
6265
  const gateReason = checkAutoWakeGates(`mcp-zombie::${agentName}::${sessionScope || session}`, Date.now());
5913
6266
  if (gateReason) {
@@ -6165,7 +6518,7 @@ function startBackgroundJobGuardrails() {
6165
6518
  const tick = async () => traceDaemonTimer("background_job_guardrails", async () => {
6166
6519
  fired("background_job_guardrails");
6167
6520
  try {
6168
- const { enforceBackgroundJobGuardrailsAsync } = await import("../background-jobs-STURKDCS.js");
6521
+ const { enforceBackgroundJobGuardrailsAsync } = await import("../background-jobs-EXR5RVGG.js");
6169
6522
  const actions = await enforceBackgroundJobGuardrailsAsync();
6170
6523
  if (actions.length > 0) {
6171
6524
  acted("background_job_guardrails");
@@ -6198,11 +6551,14 @@ function handleSignalShutdown() {
6198
6551
  ...signalAttribution
6199
6552
  });
6200
6553
  logShutdown(restartIntent ? "restart shutdown" : "graceful shutdown", "SIGTERM/SIGINT", signalAttribution);
6201
- void shutdown(restartIntent ? 75 : 0);
6554
+ void shutdown(restartIntent ? 75 : 0, restartIntent ? reason ?? "restart-intent" : null);
6202
6555
  }
6203
6556
  process.on("SIGINT", handleSignalShutdown);
6204
6557
  process.on("SIGTERM", handleSignalShutdown);
6205
6558
  process.on("exit", (code) => {
6559
+ if (_bootPhase !== "ready" && code !== 0) {
6560
+ recordExitBreadcrumb("boot-abort", code, `boot_abort:${_bootPhase}`);
6561
+ }
6206
6562
  if (_bootPhase === "ready") return;
6207
6563
  try {
6208
6564
  logDaemonHealth({
@@ -6320,7 +6676,7 @@ function startBugAutoFix() {
6320
6676
  for (const exeSession of exeSessions) {
6321
6677
  const ctoSession = `${ctoName}-${exeSession}`;
6322
6678
  if (sessions.includes(ctoSession)) {
6323
- await sendIntercomAsync(ctoSession);
6679
+ await sendIntercomAsync(ctoSession, { callerSessionScope: exeSession });
6324
6680
  break;
6325
6681
  }
6326
6682
  }
@@ -6496,9 +6852,9 @@ function startAutoUpdateCheck() {
6496
6852
  const effectiveChannel = updateChannel ?? "stable";
6497
6853
  if (effectiveChannel === "pinned") return;
6498
6854
  if (!autoInstall && !config.autoUpdate.checkOnBoot) return;
6499
- const { checkForUpdate, channelToInstallTag } = await import("../update-check-HFO4VHO4.js");
6855
+ const { checkForUpdateAsync, channelToInstallTag } = await import("../update-check-3FHAWIG2.js");
6500
6856
  const packageRoot = new URL("../..", import.meta.url).pathname;
6501
- const result = checkForUpdate(packageRoot, effectiveChannel);
6857
+ const result = await checkForUpdateAsync(packageRoot, effectiveChannel);
6502
6858
  if (!result.updateAvailable) return;
6503
6859
  acted("auto_update_check");
6504
6860
  const channelLabel = effectiveChannel === "canary" ? " (canary)" : "";
@@ -6599,7 +6955,7 @@ if (process.platform === "darwin") {
6599
6955
  logBoot({ socketPath: SOCKET_PATH, pidPath: PID_PATH });
6600
6956
  void (async () => {
6601
6957
  try {
6602
- const { cleanupCrashDebris } = await import("../db-backup-MX2G3CEK.js");
6958
+ const { cleanupCrashDebris } = await import("../db-backup-W2QFSYQC.js");
6603
6959
  const removed = cleanupCrashDebris();
6604
6960
  if (removed > 0) {
6605
6961
  process.stderr.write(`[exed] Startup cleanup: pruned ${removed} crash-debris file(s) (backups/quarantine).
@@ -6745,9 +7101,7 @@ function startEventLoopLagDetector() {
6745
7101
  const SELF_INFLICTED_ROLLING_WINDOW_MS = parseFloat(process.env.EXE_SELF_INFLICTED_ROLLING_WINDOW_MS ?? "") || 3e5;
6746
7102
  const LAG_WARN_MS = 3e3;
6747
7103
  const LAG_CRITICAL_MS = 1e4;
6748
- const SELF_HEAL_SINGLE_MS = parseFloat(process.env.EXE_SELF_HEAL_SINGLE_MS ?? "") || 12e4;
6749
- const SELF_HEAL_CONSECUTIVE = parseInt(process.env.EXE_SELF_HEAL_CONSECUTIVE ?? "") || 3;
6750
- 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();
6751
7105
  let consecutiveSevereBlocks = 0;
6752
7106
  let selfInflictedWindow = [];
6753
7107
  touchEventLoopHeartbeat();
@@ -6775,7 +7129,7 @@ function startEventLoopLagDetector() {
6775
7129
  const msg = `[exed] EVENT LOOP BLOCKED ${(lag / 1e3).toFixed(1)}s \u2014 MCP UNRESPONSIVE. Sessions will die.`;
6776
7130
  process.stderr.write(msg + "\n");
6777
7131
  logDaemonHealth({ event: "event_loop_blocked", pid: process.pid, message: msg, data: { lagMs: lag } });
6778
- void import("../orchestration-events-ZG7O4HRY.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
7132
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
6779
7133
  recordOE({ eventType: "daemon.event_loop_blocked", source: "exe-daemon.lagDetector", severity: "error", durationMs: lag });
6780
7134
  }).catch(() => {
6781
7135
  });
@@ -6798,7 +7152,7 @@ function startEventLoopLagDetector() {
6798
7152
  }
6799
7153
  const load1m = os2.loadavg()[0] ?? 0;
6800
7154
  const cpuCount = os2.cpus().length || 1;
6801
- const starvationRatio = parseFloat(process.env.EXE_STARVATION_LOAD_RATIO ?? "1.5");
7155
+ const starvationRatio = resolveSelfHealThresholds().starvationRatio;
6802
7156
  const catchUpActive = inBootCatchUpGrace();
6803
7157
  const decision = decideDaemonSelfHeal({
6804
7158
  lagMs: lag,
@@ -6876,7 +7230,7 @@ function startEventLoopLagDetector() {
6876
7230
  _lastSelfHealShutdownAtMs = Date.now();
6877
7231
  process.stderr.write(healMsg + "\n");
6878
7232
  logDaemonHealth({ event: "self_heal_restart", pid: process.pid, message: healMsg, data: { lagMs: lag, reason: "single_block" } });
6879
- void shutdown(75);
7233
+ dispatchSelfHealRestart(lag, "single_block", SELF_HEAL_ACTION_DEPS);
6880
7234
  return;
6881
7235
  }
6882
7236
  if (decision.restart && decision.reason === "consecutive_blocks") {
@@ -6890,7 +7244,7 @@ function startEventLoopLagDetector() {
6890
7244
  _lastSelfHealShutdownAtMs = Date.now();
6891
7245
  process.stderr.write(healMsg + "\n");
6892
7246
  logDaemonHealth({ event: "self_heal_restart", pid: process.pid, message: healMsg, data: { lagMs: lag, reason: "consecutive_blocks", count: consecutiveSevereBlocks } });
6893
- void shutdown(75);
7247
+ dispatchSelfHealRestart(lag, "consecutive_blocks", SELF_HEAL_ACTION_DEPS);
6894
7248
  return;
6895
7249
  }
6896
7250
  } else if (lag > LAG_WARN_MS) {
@@ -6957,7 +7311,7 @@ function startTaskFileResync() {
6957
7311
  });
6958
7312
  if (Number(res.rowsAffected ?? 0) > 0) {
6959
7313
  synced++;
6960
- void import("../orchestration-events-ZG7O4HRY.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
7314
+ void import("../orchestration-events-WV4NWKZH.js").then(({ recordOrchestrationEventBestEffort: recordOE }) => {
6961
7315
  recordOE({
6962
7316
  eventType: "task_file.resynced",
6963
7317
  source: "exe-daemon.taskFileResync",
@@ -6994,7 +7348,7 @@ function startTaskGroupBarriers() {
6994
7348
  fired("task_group_barriers");
6995
7349
  if (!await ensureStoreForPolling()) return;
6996
7350
  try {
6997
- const { pollTaskGroupBarriers } = await import("../daemon-orchestration-XV5GN73R.js");
7351
+ const { pollTaskGroupBarriers } = await import("../daemon-orchestration-FX4XZDR5.js");
6998
7352
  const firedCount = await pollTaskGroupBarriers();
6999
7353
  if (firedCount > 0) {
7000
7354
  acted("task_group_barriers");
@@ -7016,7 +7370,7 @@ function startCheckpointGc() {
7016
7370
  fired("checkpoint_gc");
7017
7371
  if (!await ensureStoreForPolling()) return;
7018
7372
  try {
7019
- const { gcStaleCheckpoints } = await import("../daemon-orchestration-XV5GN73R.js");
7373
+ const { gcStaleCheckpoints } = await import("../daemon-orchestration-FX4XZDR5.js");
7020
7374
  const cleared = await gcStaleCheckpoints();
7021
7375
  if (cleared > 0) {
7022
7376
  acted("checkpoint_gc");
@@ -7047,7 +7401,7 @@ function startDaemonHeartbeat() {
7047
7401
  function startDispatchAckCleanup() {
7048
7402
  setInterval(async () => {
7049
7403
  try {
7050
- const { cleanStaleDispatchAcks } = await import("../dispatch-ack-4S44HBWB.js");
7404
+ const { cleanStaleDispatchAcks } = await import("../dispatch-ack-VYH3ONSS.js");
7051
7405
  cleanStaleDispatchAcks();
7052
7406
  } catch {
7053
7407
  }
@@ -7056,14 +7410,14 @@ function startDispatchAckCleanup() {
7056
7410
  function startProjectionWorkerDeferred() {
7057
7411
  setTimeout(async () => {
7058
7412
  try {
7059
- const { startProjectionWorker } = await import("../projection-worker-44SEKTZ5.js");
7413
+ const { startProjectionWorker } = await import("../projection-worker-FZ7YSN3G.js");
7060
7414
  startProjectionWorker();
7061
7415
  } catch {
7062
7416
  }
7063
7417
  }, 2e4);
7064
7418
  }
7065
7419
  async function startToolTelemetry() {
7066
- const { startToolTelemetryFlush } = await import("../tool-telemetry-UC55LSIH.js");
7420
+ const { startToolTelemetryFlush } = await import("../tool-telemetry-KBXSBDTK.js");
7067
7421
  startToolTelemetryFlush();
7068
7422
  process.stderr.write("[exed] Tool telemetry started (flush every 5m)\n");
7069
7423
  }
@@ -7229,7 +7583,7 @@ function startLocalFirstTimers() {
7229
7583
  fired("orphan_task_cleanup");
7230
7584
  try {
7231
7585
  if (!await ensureStoreForPolling()) return;
7232
- const { cleanOrphanedTaskFiles } = await import("../tasks-crud-6LBNU43G.js");
7586
+ const { cleanOrphanedTaskFiles } = await import("../tasks-crud-HBDKE6C5.js");
7233
7587
  const count = await cleanOrphanedTaskFiles();
7234
7588
  if (count > 0) {
7235
7589
  acted("orphan_task_cleanup");
@@ -7245,7 +7599,7 @@ function startLocalFirstTimers() {
7245
7599
  fired("task_file_consistency");
7246
7600
  try {
7247
7601
  if (!await ensureStoreForPolling()) return;
7248
- const { checkTaskFileConsistency } = await import("../tasks-crud-6LBNU43G.js");
7602
+ const { checkTaskFileConsistency } = await import("../tasks-crud-HBDKE6C5.js");
7249
7603
  const mismatches = await checkTaskFileConsistency();
7250
7604
  if (mismatches > 0) {
7251
7605
  acted("task_file_consistency");
@@ -7264,7 +7618,7 @@ function startLocalFirstTimers() {
7264
7618
  const TELEMETRY_DAILY_MS = 24 * 60 * 60 * 1e3;
7265
7619
  const telemetryDaily = async () => {
7266
7620
  try {
7267
- const { sendTelemetry, isTelemetryEnabled } = await import("../telemetry-upload-WQDFABTF.js");
7621
+ const { sendTelemetry, isTelemetryEnabled } = await import("../telemetry-upload-ZOXHRWR5.js");
7268
7622
  if (!isTelemetryEnabled()) return;
7269
7623
  const { upstream } = await sendTelemetry(24);
7270
7624
  if (upstream.startsWith("sent")) {
@@ -7376,7 +7730,76 @@ function startLocalFirstTimers() {
7376
7730
  }
7377
7731
  }, 3e4);
7378
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
+ }
7379
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
+ }
7380
7803
  const mcpRegPath = new URL("../mcp/register-tools.js", import.meta.url).href;
7381
7804
  const { registerAllTools: regFn } = await import(
7382
7805
  /* @vite-ignore */
@@ -7419,6 +7842,7 @@ try {
7419
7842
  }
7420
7843
  export {
7421
7844
  decidePortHolderAction,
7845
+ getLastBlockingTimer,
7422
7846
  injectRegisterAllTools,
7423
7847
  isCrashLoopBreakerActive,
7424
7848
  isEventLoopBlockedNow,