abtars 0.3.4-alpha.8 → 0.3.4

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 (335) hide show
  1. package/bundle/{_registry.generated-YP5GLSG7.js → _registry.generated-AVR7DK2A.js} +15 -15
  2. package/bundle/{abmind-lazy-7Z44NODV.js → abmind-lazy-E3YCFKQ5.js} +15 -5
  3. package/bundle/abtars-browser.js +4 -4
  4. package/bundle/abtars-cli.js +23 -13
  5. package/bundle/abtars-cli.js.map +2 -2
  6. package/bundle/abtars-restart.js +3 -3
  7. package/bundle/abtars-task.js +3 -3
  8. package/bundle/abtars.js +385 -466
  9. package/bundle/abtars.js.map +4 -4
  10. package/bundle/{acp-raw-client-E6FM45NC.js → acp-raw-client-UCNK3OTU.js} +2 -2
  11. package/bundle/{action-gate-G2V47NHW.js → action-gate-V4FCBHFB.js} +2 -2
  12. package/bundle/{agent-api-adapter-WRGEQ6DV.js → agent-api-adapter-7HEPYSIN.js} +3 -3
  13. package/bundle/{agent-api-rate-limit-WCFXJMGY.js → agent-api-rate-limit-RZSAM3SW.js} +4 -4
  14. package/bundle/{agent-registry-GHNG2PH3.js → agent-registry-46A2R5KP.js} +7 -7
  15. package/bundle/{bootstrap-PZIDBPEJ.js → bootstrap-MIHJJSWU.js} +2 -2
  16. package/bundle/{bridge-lock-transport-4ZH7QTJP.js → bridge-lock-transport-7RSN7OLJ.js} +4 -4
  17. package/bundle/{browser-D3LZV7ZK.js → browser-F6BCWJWW.js} +6 -6
  18. package/bundle/{budget-45QOBDWA.js → budget-WUM3SPKW.js} +3 -3
  19. package/bundle/{capability-JFWX3IQF.js → capability-QVRKGRFC.js} +5 -5
  20. package/bundle/{chunk-YSKCQH6E.js → chunk-2IYJ4I66.js} +2 -2
  21. package/bundle/{chunk-W2R2HFOQ.js → chunk-2NLUT5S2.js} +6 -6
  22. package/bundle/chunk-3BG3AIDP.js +191 -0
  23. package/bundle/chunk-3BG3AIDP.js.map +7 -0
  24. package/bundle/{chunk-OKAQICWY.js → chunk-3GQX34S2.js} +3 -3
  25. package/bundle/{chunk-QROWBWLL.js → chunk-3XZ773BS.js} +2 -2
  26. package/bundle/{chunk-DYBW4XXL.js → chunk-467SRLLR.js} +2 -2
  27. package/bundle/{chunk-374NCXFZ.js → chunk-4AILRHUI.js} +10 -8
  28. package/bundle/chunk-4AILRHUI.js.map +7 -0
  29. package/bundle/{chunk-GPZNXY2U.js → chunk-4S3H4OK7.js} +4 -4
  30. package/bundle/{chunk-NDCRWEEJ.js → chunk-4Y5MJQRE.js} +6 -6
  31. package/bundle/{chunk-FRKW6LWB.js → chunk-55UWKI5C.js} +3 -3
  32. package/bundle/{chunk-7JN2MMU7.js → chunk-5PNJFDSW.js} +8 -8
  33. package/bundle/{chunk-LUNA6PM5.js → chunk-5RVOEFGT.js} +4 -2
  34. package/bundle/{chunk-LUNA6PM5.js.map → chunk-5RVOEFGT.js.map} +2 -2
  35. package/bundle/{chunk-OXTSWQCX.js → chunk-5Y3FJ2Y7.js} +2 -2
  36. package/bundle/{chunk-TMUYFERL.js → chunk-6B5ZFUPD.js} +2 -2
  37. package/bundle/{chunk-65VCEC32.js → chunk-6PA5JBUU.js} +2 -2
  38. package/bundle/{chunk-C7K6VZNY.js → chunk-BNXV7SZI.js} +21 -12
  39. package/bundle/chunk-BNXV7SZI.js.map +7 -0
  40. package/bundle/{chunk-AFREM7FX.js → chunk-CK7YTA2F.js} +2 -2
  41. package/bundle/{chunk-NRUSRJXR.js → chunk-DZJ5QZFD.js} +2 -2
  42. package/bundle/{chunk-YRSMGJFP.js → chunk-E67KESEG.js} +2 -2
  43. package/bundle/{chunk-ZV4IWKDJ.js → chunk-E7XD5UGB.js} +3 -3
  44. package/bundle/{chunk-CXXU3HAU.js → chunk-EAX5ZZUL.js} +63 -39
  45. package/bundle/chunk-EAX5ZZUL.js.map +7 -0
  46. package/bundle/{chunk-PEDX56EL.js → chunk-EFGBM555.js} +2 -2
  47. package/bundle/{chunk-EQSG2CRM.js → chunk-FGYDIX54.js} +22 -15
  48. package/bundle/chunk-FGYDIX54.js.map +7 -0
  49. package/bundle/{chunk-YPAQEQSC.js → chunk-GF6NVNA7.js} +15 -5
  50. package/bundle/chunk-GF6NVNA7.js.map +7 -0
  51. package/bundle/{chunk-UNM3OXHB.js → chunk-HGSHCQ5F.js} +110 -72
  52. package/bundle/{chunk-UNM3OXHB.js.map → chunk-HGSHCQ5F.js.map} +2 -2
  53. package/bundle/{chunk-VXCETPZU.js → chunk-IMIGG5EO.js} +39 -39
  54. package/bundle/chunk-IMIGG5EO.js.map +7 -0
  55. package/bundle/{chunk-P2K2K6XL.js → chunk-ITOFPJAV.js} +44 -32
  56. package/bundle/chunk-ITOFPJAV.js.map +7 -0
  57. package/bundle/{chunk-75ATTOW4.js → chunk-IY6UKLPS.js} +3 -3
  58. package/bundle/{chunk-EUZDKV3C.js → chunk-J4RUFAPK.js} +3 -3
  59. package/bundle/{chunk-HZDLFLRP.js → chunk-J7DRPVMU.js} +35 -5
  60. package/bundle/chunk-J7DRPVMU.js.map +7 -0
  61. package/bundle/{chunk-EGL6UMAO.js → chunk-JG4BKXBN.js} +7 -1
  62. package/bundle/chunk-JG4BKXBN.js.map +7 -0
  63. package/bundle/{chunk-N4EB6LA7.js → chunk-JLWYPGWI.js} +5 -5
  64. package/bundle/{chunk-5QUTMUIK.js → chunk-JXYWDAHD.js} +12 -12
  65. package/bundle/{chunk-GRVWZO4C.js → chunk-KOSFXW2S.js} +24 -3
  66. package/bundle/{chunk-GRVWZO4C.js.map → chunk-KOSFXW2S.js.map} +1 -1
  67. package/bundle/{chunk-M3JEX6L4.js → chunk-L72RIPEC.js} +9 -9
  68. package/bundle/{chunk-TEFZ4JA4.js → chunk-NHPLD3C7.js} +2 -2
  69. package/bundle/{chunk-2KC5G3EA.js → chunk-OWUO5RS3.js} +5 -5
  70. package/bundle/{chunk-4MULJ5SS.js → chunk-OY4Q6AMY.js} +71 -49
  71. package/bundle/chunk-OY4Q6AMY.js.map +7 -0
  72. package/bundle/{chunk-WBTJ2E62.js → chunk-P3NODAHF.js} +2 -5
  73. package/bundle/{chunk-WBTJ2E62.js.map → chunk-P3NODAHF.js.map} +2 -2
  74. package/bundle/{chunk-SMPHE3ZM.js → chunk-PB5GF4FG.js} +215 -163
  75. package/bundle/chunk-PB5GF4FG.js.map +7 -0
  76. package/bundle/{chunk-WYHGNI56.js → chunk-PMD5BLFS.js} +6 -6
  77. package/bundle/{chunk-URQPDCK5.js → chunk-Q66LQMMZ.js} +3 -3
  78. package/bundle/{chunk-IHYKTDIP.js → chunk-SC2Y5NR2.js} +36 -119
  79. package/bundle/chunk-SC2Y5NR2.js.map +7 -0
  80. package/bundle/chunk-SFL4EPCZ.js +555 -0
  81. package/bundle/chunk-SFL4EPCZ.js.map +7 -0
  82. package/bundle/{chunk-LDUOOKQY.js → chunk-SJPUNDZ3.js} +5 -5
  83. package/bundle/{chunk-LDUOOKQY.js.map → chunk-SJPUNDZ3.js.map} +1 -1
  84. package/bundle/{chunk-JQDJPUHM.js → chunk-TWB2ZGVH.js} +2 -2
  85. package/bundle/{chunk-IJT4KWXT.js → chunk-U4U47YE7.js} +2 -2
  86. package/bundle/{chunk-2FAZIA37.js → chunk-W546CU3A.js} +3 -3
  87. package/bundle/chunk-WC5O5KOE.js +211 -0
  88. package/bundle/chunk-WC5O5KOE.js.map +7 -0
  89. package/bundle/{chunk-JNIHEDKF.js → chunk-XPWYDNWL.js} +2 -2
  90. package/bundle/{chunk-GWILHZPT.js → chunk-XRTXYN66.js} +10 -7
  91. package/bundle/{chunk-GWILHZPT.js.map → chunk-XRTXYN66.js.map} +2 -2
  92. package/bundle/{chunk-EFJVUJBE.js → chunk-Y5FEFKGM.js} +6 -6
  93. package/bundle/chunk-YJZE4OK3.js +169 -0
  94. package/bundle/chunk-YJZE4OK3.js.map +7 -0
  95. package/bundle/{chunk-GVM5YU5I.js → chunk-Z4FZPB42.js} +2 -2
  96. package/bundle/{chunk-7BSQ5UQO.js → chunk-ZSIDQ66D.js} +3 -3
  97. package/bundle/{chunk-XX6BGTPO.js → chunk-ZZZCJJEO.js} +4 -4
  98. package/bundle/{commands-OIISYHTD.js → commands-2ZW6CMLC.js} +17 -16
  99. package/bundle/{config-M3P5IOAI.js → config-YMY5YHKN.js} +6 -6
  100. package/bundle/{context-2RJHC2LE.js → context-CL2RSLII.js} +7 -5
  101. package/bundle/context-CL2RSLII.js.map +7 -0
  102. package/bundle/{daemon-TB23FFWY.js → daemon-D7SU63OY.js} +3 -3
  103. package/bundle/{delegation-tools-YATZFKYO.js → delegation-tools-WS7Z56KZ.js} +12 -12
  104. package/bundle/{deploy-T6R45OZJ.js → deploy-AMTVKIMU.js} +2 -2
  105. package/bundle/{deps-WVK553KF.js → deps-T63AVJKJ.js} +3 -3
  106. package/bundle/{direct-api-transport-S2RDH2I7.js → direct-api-transport-QNNY2WWP.js} +51 -32
  107. package/bundle/direct-api-transport-QNNY2WWP.js.map +7 -0
  108. package/bundle/{discord-adapter-UTXUWX3A.js → discord-adapter-ABAD56Y2.js} +21 -20
  109. package/bundle/{discord-adapter-UTXUWX3A.js.map → discord-adapter-ABAD56Y2.js.map} +1 -1
  110. package/bundle/{dns-wakeup-IDOJIXBX.js → dns-wakeup-V3LEFXPE.js} +9 -33
  111. package/bundle/dns-wakeup-V3LEFXPE.js.map +7 -0
  112. package/bundle/{doctor-probes-B54JFIW3.js → doctor-probes-O6YI6XSZ.js} +6 -2
  113. package/bundle/{env-schema-4JXQUOH4.js → env-schema-B5RB32DC.js} +3 -3
  114. package/bundle/{gossip-3C3BSNPN.js → gossip-SKRCPOBS.js} +9 -5
  115. package/bundle/{guardrails-DL7ZSWVN.js → guardrails-64GQ5Y5K.js} +4 -4
  116. package/bundle/{heartbeat-system-MVTRS4GP.js → heartbeat-system-X4MUTKJD.js} +6 -6
  117. package/bundle/{heartbeat-tier3-6KH45CL6.js → heartbeat-tier3-2PTPWEQQ.js} +53 -76
  118. package/bundle/heartbeat-tier3-2PTPWEQQ.js.map +7 -0
  119. package/bundle/{hook-system-M3POLUIB.js → hook-system-YB635OC4.js} +3 -3
  120. package/bundle/{hotskills-FWX4QI7V.js → hotskills-Q75D2DK3.js} +5 -5
  121. package/bundle/{install-OS3CU7NF.js → install-RFKKFSGS.js} +17 -30
  122. package/bundle/install-RFKKFSGS.js.map +7 -0
  123. package/bundle/{install-manifest-5PPWMD2W.js → install-manifest-J7ICPCJN.js} +2 -2
  124. package/bundle/{irc-adapter-PTTZD32W.js → irc-adapter-TVEV4R6H.js} +3 -3
  125. package/bundle/{irc-config-CP7ZMUOX.js → irc-config-M676FOFI.js} +4 -4
  126. package/bundle/{kanban-board-M326B2XJ.js → kanban-board-DLEJUCNN.js} +9 -7
  127. package/bundle/{kanban-channel-IJ52OMNA.js → kanban-channel-XOLUHJZJ.js} +6 -6
  128. package/bundle/kanban-delivery-C4QPBNPX.js +45 -0
  129. package/bundle/kanban-delivery-C4QPBNPX.js.map +7 -0
  130. package/bundle/{lazy-require-KCRVT4SI.js → lazy-require-JKQSALXN.js} +3 -3
  131. package/bundle/{logger-OWCSNYCA.js → logger-3EGHBD4R.js} +2 -2
  132. package/bundle/{main-chat-ZNUZCTNS.js → main-chat-3H63REKK.js} +4 -4
  133. package/bundle/{master-user-HSKM4ZFN.js → master-user-MUBUP3KD.js} +5 -5
  134. package/bundle/{media-utils-3ZYOD7SK.js → media-utils-HUUIALAJ.js} +3 -3
  135. package/bundle/{message-pipeline-AUIUNM5R.js → message-pipeline-GRDRWONR.js} +17 -16
  136. package/bundle/meta.json +2773 -2241
  137. package/bundle/{metrics-collector-L3VPEHII.js → metrics-collector-YMUGY3PI.js} +31 -2
  138. package/bundle/metrics-collector-YMUGY3PI.js.map +7 -0
  139. package/bundle/{model-health-registry-MLEIZSTV.js → model-health-registry-QADMFQFQ.js} +2 -2
  140. package/bundle/{nerve-IGSXBKZZ.js → nerve-QPAEBRKX.js} +3 -3
  141. package/bundle/{notification-BFSIEECG.js → notification-3JICGXWU.js} +6 -6
  142. package/bundle/{openrouter-credits-NTVZDRYM.js → openrouter-credits-7NEIPYJN.js} +3 -3
  143. package/bundle/{orc-tools-TOD4WHTM.js → orc-tools-UZVPONKY.js} +5 -3
  144. package/bundle/{peer-auth-QC4EF2PM.js → peer-auth-RI43DKJE.js} +24 -15
  145. package/bundle/{peer-client-RGEU5HOK.js → peer-client-UITTMWJ2.js} +34 -29
  146. package/bundle/peer-client-UITTMWJ2.js.map +7 -0
  147. package/bundle/{peer-config-TN55LFDC.js → peer-config-URM7DCW6.js} +9 -4
  148. package/bundle/{peer-transport-5VKK2I7P.js → peer-transport-SI7I72DB.js} +12 -10
  149. package/bundle/{phase-transport-FS6NL4A5.js → phase-transport-ESWWACZI.js} +17 -17
  150. package/bundle/{reconcile-CTFCLQRN.js → reconcile-GFDQYNBD.js} +3 -3
  151. package/bundle/{reconciler-NZ4O4BCP.js → reconciler-IEUJXJN2.js} +12 -12
  152. package/bundle/{restore-IFHPI7I7.js → restore-FARTGLQQ.js} +3 -3
  153. package/bundle/{rollback-ANRI3T5Z.js → rollback-GEWPZABG.js} +2 -2
  154. package/bundle/{sandbox-runtime-QROWHDCS.js → sandbox-runtime-DV6E25J6.js} +2 -2
  155. package/bundle/{self-healer-utils-IFAYOQO2.js → self-healer-utils-P4SKNNEM.js} +3 -3
  156. package/bundle/{sha-tracker-ZWBP6CIJ.js → sha-tracker-77SHLYNY.js} +3 -3
  157. package/bundle/{skill-session-VJXTKOKL.js → skill-session-5HSMXY54.js} +3 -3
  158. package/bundle/{skill-stats-JORH5DGM.js → skill-stats-MI3RSWWL.js} +4 -4
  159. package/bundle/{skill-watcher-E4MGLKLS.js → skill-watcher-5L7JE6TN.js} +4 -4
  160. package/bundle/{sleep-BEWAUFCL.js → sleep-I4JFASCY.js} +11 -11
  161. package/bundle/{soul-bundle-VWAVHCZ6.js → soul-bundle-522C3IRH.js} +9 -8
  162. package/bundle/{spin-E3ZDEDKT.js → spin-VHNGNWTD.js} +11 -11
  163. package/bundle/{spin-notifications-SE2HVZI7.js → spin-notifications-7NC5XZEM.js} +5 -5
  164. package/bundle/{spin-types-OIE67MJK.js → spin-types-C5KOQOPD.js} +7 -3
  165. package/bundle/{sse-parser-anthropic-A6R4Z2TB.js → sse-parser-anthropic-MMTVWHLI.js} +3 -3
  166. package/bundle/{sse-parser-responses-HSZY3QGJ.js → sse-parser-responses-3AOFN64C.js} +3 -3
  167. package/bundle/{ssrf-guard-O6SHIK6Q.js → ssrf-guard-U2JA72TC.js} +3 -3
  168. package/bundle/{start-7QZIWO3S.js → start-H5IUFAWF.js} +4 -2
  169. package/bundle/{start-7QZIWO3S.js.map → start-H5IUFAWF.js.map} +2 -2
  170. package/bundle/{stt-LGVPXMVR.js → stt-PSOPPBV4.js} +4 -4
  171. package/bundle/{system-status-FAVNIUFJ.js → system-status-4LYGOFNO.js} +38 -24
  172. package/bundle/system-status-4LYGOFNO.js.map +7 -0
  173. package/bundle/{task-store-W5BFIAIH.js → task-store-MNCW42BW.js} +4 -4
  174. package/bundle/{telegram-adapter-4TX7QWKC.js → telegram-adapter-O6KIZDY6.js} +62 -45
  175. package/bundle/telegram-adapter-O6KIZDY6.js.map +7 -0
  176. package/bundle/{tool-registry-7FK3OQGL.js → tool-registry-JJMWCQKZ.js} +26 -24
  177. package/bundle/{tool-sandbox-4UC6GAKA.js → tool-sandbox-CNL6V6IH.js} +4 -4
  178. package/bundle/{transport-config-KBF5W2DP.js → transport-config-6MB2K2XC.js} +7 -7
  179. package/bundle/tribe-GDTFYJTK.js +111 -0
  180. package/bundle/tribe-GDTFYJTK.js.map +7 -0
  181. package/bundle/{update-CKFP6LBE.js → update-HGQAOC5L.js} +3 -3
  182. package/bundle/{usage-tracker-NXD364VX.js → usage-tracker-SR4BI6ZT.js} +2 -2
  183. package/bundle/{user-registry-35BW4XKM.js → user-registry-4PACZJIJ.js} +4 -4
  184. package/bundle/wire-platform-KKPWNNNQ.js +88 -0
  185. package/bundle/wire-platform-KKPWNNNQ.js.map +7 -0
  186. package/bundle/ws-peer-client-U3NNPOK7.js +370 -0
  187. package/bundle/ws-peer-client-U3NNPOK7.js.map +7 -0
  188. package/package.json +1 -1
  189. package/scripts/abtars-watchdog.sh +1 -5
  190. package/scripts/emergency-deploy.sh +2 -2
  191. package/scripts/emergency-update.sh +36 -37
  192. package/bundle/chunk-374NCXFZ.js.map +0 -7
  193. package/bundle/chunk-4MULJ5SS.js.map +0 -7
  194. package/bundle/chunk-4S554KLW.js +0 -105
  195. package/bundle/chunk-4S554KLW.js.map +0 -7
  196. package/bundle/chunk-C7K6VZNY.js.map +0 -7
  197. package/bundle/chunk-CXXU3HAU.js.map +0 -7
  198. package/bundle/chunk-EGL6UMAO.js.map +0 -7
  199. package/bundle/chunk-EQSG2CRM.js.map +0 -7
  200. package/bundle/chunk-HT2BPTZY.js +0 -241
  201. package/bundle/chunk-HT2BPTZY.js.map +0 -7
  202. package/bundle/chunk-HZDLFLRP.js.map +0 -7
  203. package/bundle/chunk-IHYKTDIP.js.map +0 -7
  204. package/bundle/chunk-IKUZPMVA.js +0 -82
  205. package/bundle/chunk-IKUZPMVA.js.map +0 -7
  206. package/bundle/chunk-P2K2K6XL.js.map +0 -7
  207. package/bundle/chunk-PU5HSKWH.js +0 -257
  208. package/bundle/chunk-PU5HSKWH.js.map +0 -7
  209. package/bundle/chunk-RWRRGE4U.js +0 -72
  210. package/bundle/chunk-RWRRGE4U.js.map +0 -7
  211. package/bundle/chunk-SMPHE3ZM.js.map +0 -7
  212. package/bundle/chunk-VUIX5AGB.js +0 -65
  213. package/bundle/chunk-VUIX5AGB.js.map +0 -7
  214. package/bundle/chunk-VXCETPZU.js.map +0 -7
  215. package/bundle/chunk-YPAQEQSC.js.map +0 -7
  216. package/bundle/context-2RJHC2LE.js.map +0 -7
  217. package/bundle/direct-api-transport-S2RDH2I7.js.map +0 -7
  218. package/bundle/dns-wakeup-IDOJIXBX.js.map +0 -7
  219. package/bundle/heartbeat-tier3-6KH45CL6.js.map +0 -7
  220. package/bundle/install-OS3CU7NF.js.map +0 -7
  221. package/bundle/metrics-collector-L3VPEHII.js.map +0 -7
  222. package/bundle/peer-client-RGEU5HOK.js.map +0 -7
  223. package/bundle/peer-jwt-NCCPXJRX.js +0 -18
  224. package/bundle/stream-single-RFJNUTL6.js +0 -34
  225. package/bundle/stream-single-RFJNUTL6.js.map +0 -7
  226. package/bundle/system-status-FAVNIUFJ.js.map +0 -7
  227. package/bundle/telegram-adapter-4TX7QWKC.js.map +0 -7
  228. package/bundle/user-registry-35BW4XKM.js.map +0 -7
  229. package/bundle/ws-peer-client-AIXCXF7V.js +0 -173
  230. package/bundle/ws-peer-client-AIXCXF7V.js.map +0 -7
  231. /package/bundle/{_registry.generated-YP5GLSG7.js.map → _registry.generated-AVR7DK2A.js.map} +0 -0
  232. /package/bundle/{abmind-lazy-7Z44NODV.js.map → abmind-lazy-E3YCFKQ5.js.map} +0 -0
  233. /package/bundle/{acp-raw-client-E6FM45NC.js.map → acp-raw-client-UCNK3OTU.js.map} +0 -0
  234. /package/bundle/{action-gate-G2V47NHW.js.map → action-gate-V4FCBHFB.js.map} +0 -0
  235. /package/bundle/{agent-api-adapter-WRGEQ6DV.js.map → agent-api-adapter-7HEPYSIN.js.map} +0 -0
  236. /package/bundle/{agent-api-rate-limit-WCFXJMGY.js.map → agent-api-rate-limit-RZSAM3SW.js.map} +0 -0
  237. /package/bundle/{agent-registry-GHNG2PH3.js.map → agent-registry-46A2R5KP.js.map} +0 -0
  238. /package/bundle/{bootstrap-PZIDBPEJ.js.map → bootstrap-MIHJJSWU.js.map} +0 -0
  239. /package/bundle/{bridge-lock-transport-4ZH7QTJP.js.map → bridge-lock-transport-7RSN7OLJ.js.map} +0 -0
  240. /package/bundle/{browser-D3LZV7ZK.js.map → browser-F6BCWJWW.js.map} +0 -0
  241. /package/bundle/{budget-45QOBDWA.js.map → budget-WUM3SPKW.js.map} +0 -0
  242. /package/bundle/{capability-JFWX3IQF.js.map → capability-QVRKGRFC.js.map} +0 -0
  243. /package/bundle/{chunk-YSKCQH6E.js.map → chunk-2IYJ4I66.js.map} +0 -0
  244. /package/bundle/{chunk-W2R2HFOQ.js.map → chunk-2NLUT5S2.js.map} +0 -0
  245. /package/bundle/{chunk-OKAQICWY.js.map → chunk-3GQX34S2.js.map} +0 -0
  246. /package/bundle/{chunk-QROWBWLL.js.map → chunk-3XZ773BS.js.map} +0 -0
  247. /package/bundle/{chunk-DYBW4XXL.js.map → chunk-467SRLLR.js.map} +0 -0
  248. /package/bundle/{chunk-GPZNXY2U.js.map → chunk-4S3H4OK7.js.map} +0 -0
  249. /package/bundle/{chunk-NDCRWEEJ.js.map → chunk-4Y5MJQRE.js.map} +0 -0
  250. /package/bundle/{chunk-FRKW6LWB.js.map → chunk-55UWKI5C.js.map} +0 -0
  251. /package/bundle/{chunk-7JN2MMU7.js.map → chunk-5PNJFDSW.js.map} +0 -0
  252. /package/bundle/{chunk-OXTSWQCX.js.map → chunk-5Y3FJ2Y7.js.map} +0 -0
  253. /package/bundle/{chunk-TMUYFERL.js.map → chunk-6B5ZFUPD.js.map} +0 -0
  254. /package/bundle/{chunk-65VCEC32.js.map → chunk-6PA5JBUU.js.map} +0 -0
  255. /package/bundle/{chunk-AFREM7FX.js.map → chunk-CK7YTA2F.js.map} +0 -0
  256. /package/bundle/{chunk-NRUSRJXR.js.map → chunk-DZJ5QZFD.js.map} +0 -0
  257. /package/bundle/{chunk-YRSMGJFP.js.map → chunk-E67KESEG.js.map} +0 -0
  258. /package/bundle/{chunk-ZV4IWKDJ.js.map → chunk-E7XD5UGB.js.map} +0 -0
  259. /package/bundle/{chunk-PEDX56EL.js.map → chunk-EFGBM555.js.map} +0 -0
  260. /package/bundle/{chunk-75ATTOW4.js.map → chunk-IY6UKLPS.js.map} +0 -0
  261. /package/bundle/{chunk-EUZDKV3C.js.map → chunk-J4RUFAPK.js.map} +0 -0
  262. /package/bundle/{chunk-N4EB6LA7.js.map → chunk-JLWYPGWI.js.map} +0 -0
  263. /package/bundle/{chunk-5QUTMUIK.js.map → chunk-JXYWDAHD.js.map} +0 -0
  264. /package/bundle/{chunk-M3JEX6L4.js.map → chunk-L72RIPEC.js.map} +0 -0
  265. /package/bundle/{chunk-TEFZ4JA4.js.map → chunk-NHPLD3C7.js.map} +0 -0
  266. /package/bundle/{chunk-2KC5G3EA.js.map → chunk-OWUO5RS3.js.map} +0 -0
  267. /package/bundle/{chunk-WYHGNI56.js.map → chunk-PMD5BLFS.js.map} +0 -0
  268. /package/bundle/{chunk-URQPDCK5.js.map → chunk-Q66LQMMZ.js.map} +0 -0
  269. /package/bundle/{chunk-JQDJPUHM.js.map → chunk-TWB2ZGVH.js.map} +0 -0
  270. /package/bundle/{chunk-IJT4KWXT.js.map → chunk-U4U47YE7.js.map} +0 -0
  271. /package/bundle/{chunk-2FAZIA37.js.map → chunk-W546CU3A.js.map} +0 -0
  272. /package/bundle/{chunk-JNIHEDKF.js.map → chunk-XPWYDNWL.js.map} +0 -0
  273. /package/bundle/{chunk-EFJVUJBE.js.map → chunk-Y5FEFKGM.js.map} +0 -0
  274. /package/bundle/{chunk-GVM5YU5I.js.map → chunk-Z4FZPB42.js.map} +0 -0
  275. /package/bundle/{chunk-7BSQ5UQO.js.map → chunk-ZSIDQ66D.js.map} +0 -0
  276. /package/bundle/{chunk-XX6BGTPO.js.map → chunk-ZZZCJJEO.js.map} +0 -0
  277. /package/bundle/{commands-OIISYHTD.js.map → commands-2ZW6CMLC.js.map} +0 -0
  278. /package/bundle/{config-M3P5IOAI.js.map → config-YMY5YHKN.js.map} +0 -0
  279. /package/bundle/{daemon-TB23FFWY.js.map → daemon-D7SU63OY.js.map} +0 -0
  280. /package/bundle/{delegation-tools-YATZFKYO.js.map → delegation-tools-WS7Z56KZ.js.map} +0 -0
  281. /package/bundle/{deploy-T6R45OZJ.js.map → deploy-AMTVKIMU.js.map} +0 -0
  282. /package/bundle/{deps-WVK553KF.js.map → deps-T63AVJKJ.js.map} +0 -0
  283. /package/bundle/{doctor-probes-B54JFIW3.js.map → doctor-probes-O6YI6XSZ.js.map} +0 -0
  284. /package/bundle/{env-schema-4JXQUOH4.js.map → env-schema-B5RB32DC.js.map} +0 -0
  285. /package/bundle/{gossip-3C3BSNPN.js.map → gossip-SKRCPOBS.js.map} +0 -0
  286. /package/bundle/{guardrails-DL7ZSWVN.js.map → guardrails-64GQ5Y5K.js.map} +0 -0
  287. /package/bundle/{heartbeat-system-MVTRS4GP.js.map → heartbeat-system-X4MUTKJD.js.map} +0 -0
  288. /package/bundle/{hook-system-M3POLUIB.js.map → hook-system-YB635OC4.js.map} +0 -0
  289. /package/bundle/{hotskills-FWX4QI7V.js.map → hotskills-Q75D2DK3.js.map} +0 -0
  290. /package/bundle/{install-manifest-5PPWMD2W.js.map → install-manifest-J7ICPCJN.js.map} +0 -0
  291. /package/bundle/{irc-adapter-PTTZD32W.js.map → irc-adapter-TVEV4R6H.js.map} +0 -0
  292. /package/bundle/{irc-config-CP7ZMUOX.js.map → irc-config-M676FOFI.js.map} +0 -0
  293. /package/bundle/{kanban-board-M326B2XJ.js.map → kanban-board-DLEJUCNN.js.map} +0 -0
  294. /package/bundle/{kanban-channel-IJ52OMNA.js.map → kanban-channel-XOLUHJZJ.js.map} +0 -0
  295. /package/bundle/{lazy-require-KCRVT4SI.js.map → lazy-require-JKQSALXN.js.map} +0 -0
  296. /package/bundle/{logger-OWCSNYCA.js.map → logger-3EGHBD4R.js.map} +0 -0
  297. /package/bundle/{main-chat-ZNUZCTNS.js.map → main-chat-3H63REKK.js.map} +0 -0
  298. /package/bundle/{master-user-HSKM4ZFN.js.map → master-user-MUBUP3KD.js.map} +0 -0
  299. /package/bundle/{media-utils-3ZYOD7SK.js.map → media-utils-HUUIALAJ.js.map} +0 -0
  300. /package/bundle/{message-pipeline-AUIUNM5R.js.map → message-pipeline-GRDRWONR.js.map} +0 -0
  301. /package/bundle/{model-health-registry-MLEIZSTV.js.map → model-health-registry-QADMFQFQ.js.map} +0 -0
  302. /package/bundle/{nerve-IGSXBKZZ.js.map → nerve-QPAEBRKX.js.map} +0 -0
  303. /package/bundle/{notification-BFSIEECG.js.map → notification-3JICGXWU.js.map} +0 -0
  304. /package/bundle/{openrouter-credits-NTVZDRYM.js.map → openrouter-credits-7NEIPYJN.js.map} +0 -0
  305. /package/bundle/{orc-tools-TOD4WHTM.js.map → orc-tools-UZVPONKY.js.map} +0 -0
  306. /package/bundle/{peer-auth-QC4EF2PM.js.map → peer-auth-RI43DKJE.js.map} +0 -0
  307. /package/bundle/{peer-config-TN55LFDC.js.map → peer-config-URM7DCW6.js.map} +0 -0
  308. /package/bundle/{peer-jwt-NCCPXJRX.js.map → peer-transport-SI7I72DB.js.map} +0 -0
  309. /package/bundle/{peer-transport-5VKK2I7P.js.map → phase-transport-ESWWACZI.js.map} +0 -0
  310. /package/bundle/{phase-transport-FS6NL4A5.js.map → reconcile-GFDQYNBD.js.map} +0 -0
  311. /package/bundle/{reconciler-NZ4O4BCP.js.map → reconciler-IEUJXJN2.js.map} +0 -0
  312. /package/bundle/{restore-IFHPI7I7.js.map → restore-FARTGLQQ.js.map} +0 -0
  313. /package/bundle/{reconcile-CTFCLQRN.js.map → rollback-GEWPZABG.js.map} +0 -0
  314. /package/bundle/{sandbox-runtime-QROWHDCS.js.map → sandbox-runtime-DV6E25J6.js.map} +0 -0
  315. /package/bundle/{self-healer-utils-IFAYOQO2.js.map → self-healer-utils-P4SKNNEM.js.map} +0 -0
  316. /package/bundle/{rollback-ANRI3T5Z.js.map → sha-tracker-77SHLYNY.js.map} +0 -0
  317. /package/bundle/{skill-session-VJXTKOKL.js.map → skill-session-5HSMXY54.js.map} +0 -0
  318. /package/bundle/{sha-tracker-ZWBP6CIJ.js.map → skill-stats-MI3RSWWL.js.map} +0 -0
  319. /package/bundle/{skill-stats-JORH5DGM.js.map → skill-watcher-5L7JE6TN.js.map} +0 -0
  320. /package/bundle/{skill-watcher-E4MGLKLS.js.map → sleep-I4JFASCY.js.map} +0 -0
  321. /package/bundle/{sleep-BEWAUFCL.js.map → soul-bundle-522C3IRH.js.map} +0 -0
  322. /package/bundle/{soul-bundle-VWAVHCZ6.js.map → spin-VHNGNWTD.js.map} +0 -0
  323. /package/bundle/{spin-notifications-SE2HVZI7.js.map → spin-notifications-7NC5XZEM.js.map} +0 -0
  324. /package/bundle/{spin-E3ZDEDKT.js.map → spin-types-C5KOQOPD.js.map} +0 -0
  325. /package/bundle/{sse-parser-anthropic-A6R4Z2TB.js.map → sse-parser-anthropic-MMTVWHLI.js.map} +0 -0
  326. /package/bundle/{sse-parser-responses-HSZY3QGJ.js.map → sse-parser-responses-3AOFN64C.js.map} +0 -0
  327. /package/bundle/{ssrf-guard-O6SHIK6Q.js.map → ssrf-guard-U2JA72TC.js.map} +0 -0
  328. /package/bundle/{spin-types-OIE67MJK.js.map → stt-PSOPPBV4.js.map} +0 -0
  329. /package/bundle/{stt-LGVPXMVR.js.map → task-store-MNCW42BW.js.map} +0 -0
  330. /package/bundle/{task-store-W5BFIAIH.js.map → tool-registry-JJMWCQKZ.js.map} +0 -0
  331. /package/bundle/{tool-registry-7FK3OQGL.js.map → tool-sandbox-CNL6V6IH.js.map} +0 -0
  332. /package/bundle/{tool-sandbox-4UC6GAKA.js.map → transport-config-6MB2K2XC.js.map} +0 -0
  333. /package/bundle/{transport-config-KBF5W2DP.js.map → update-HGQAOC5L.js.map} +0 -0
  334. /package/bundle/{update-CKFP6LBE.js.map → usage-tracker-SR4BI6ZT.js.map} +0 -0
  335. /package/bundle/{usage-tracker-NXD364VX.js.map → user-registry-4PACZJIJ.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/peer-transport/ws-peer-client.ts"],
4
+ "sourcesContent": ["/**\n * ws-peer-client.ts \u2014 Persistent outbound WebSocket to a peer (#972, #1293).\n *\n * #1293 changes:\n * - Auth: Ed25519 request signatures replacing JWT header\n * - Removed own ping setInterval (dead-detection via HB tick)\n * - setKeepAlive(true, 20_000) to hold NAT hole\n * - Durable outbound queue (persist to disk, drain on reconnect)\n */\nimport WebSocket from \"ws\";\nimport { randomUUID } from \"node:crypto\";\nimport { signRequest, verifyServerCert } from \"./peer-auth.js\";\nimport { loadPeerConfig, deriveVerifyKey, type PeerEntry } from \"../peer-config.js\";\nimport { logInfo, logWarn, logDebug } from \"../logger.js\";\nimport { existsSync, readFileSync, writeFileSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../../paths.js\";\n\nconst TAG = \"ws-peer\";\nconst MAX_BACKOFF_MS = 30_000;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst QUEUE_MAX = 200;\n\ntype PushHandler = (method: string, payload: unknown) => void;\ntype PendingRequest = { resolve: (v: unknown) => void; reject: (e: Error) => void; timer: ReturnType<typeof setTimeout> };\n\ninterface QueueEntry {\n method: string;\n payload: unknown;\n id: string;\n}\n\nexport class WsPeerClient {\n private ws: WebSocket | null = null;\n private readonly peerName: string;\n private readonly entry: PeerEntry;\n private backoff = 1000;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private pushHandler: PushHandler | null = null;\n private pending = new Map<string, PendingRequest>();\n private destroyed = false;\n /** Durable outbound queue: pending messages while disconnected. */\n private _queue: QueueEntry[] = [];\n private readonly queuePath: string;\n\n constructor(peerName: string, entry: PeerEntry) {\n this.peerName = peerName;\n this.entry = entry;\n this.queuePath = join(abtarsHome(), `ws-queue-${peerName}.json`);\n this.loadQueue();\n }\n\n onPush(handler: PushHandler): void { this.pushHandler = handler; }\n\n connect(): void {\n if (this.destroyed) return;\n if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {\n return; // already connected / connecting\n }\n\n const config = loadPeerConfig();\n if (!this.entry.verifyKey) {\n logWarn(TAG, `Cannot connect to ${this.peerName}: no verifyKey (not enrolled)`);\n return;\n }\n\n const url = `wss://${this.entry.host}:${this.entry.port}/v1/ws`;\n const sigHeaders = signRequest(\"GET\", \"/v1/ws\", \"\", config.self.signingKey, config.self.name);\n\n this.ws = new WebSocket(url, {\n headers: sigHeaders,\n minVersion: \"TLSv1.3\",\n rejectUnauthorized: true,\n checkServerIdentity: (_host: string, cert: { raw?: Buffer }) => {\n if (!cert.raw) return new Error(\"No cert from peer\");\n try {\n const { createPublicKey } = require(\"node:crypto\") as typeof import(\"node:crypto\");\n const keyObj = createPublicKey({ key: cert.raw, format: \"der\", type: \"spki\" });\n // Build PEM cert block from raw DER\n const certDerB64 = cert.raw.toString(\"base64\");\n const certPemBlock = `-----BEGIN CERTIFICATE-----\\n${certDerB64.match(/.{1,64}/g)!.join(\"\\n\")}\\n-----END CERTIFICATE-----\\n`;\n if (!verifyServerCert(certPemBlock, this.entry.verifyKey)) {\n return new Error(`${this.peerName} cert key != enrolled verifyKey`);\n }\n } catch (e) {\n return new Error(`Cert verify: ${e instanceof Error ? e.message : String(e)}`);\n }\n return undefined;\n },\n } as any);\n\n this.ws.on(\"open\", () => {\n logInfo(TAG, `Connected to ${this.peerName}`);\n this.backoff = 1000;\n // NAT keepalive: 20s idle probe\n (this.ws as any)._socket?.setKeepAlive(true, 20_000);\n this.drainQueue();\n });\n\n this.ws.on(\"message\", (data) => this.handleMessage(data.toString()));\n\n this.ws.on(\"close\", () => {\n this.cleanup();\n if (!this.destroyed) this.scheduleReconnect();\n });\n\n this.ws.on(\"error\", (err) => {\n logDebug(TAG, `WS error (${this.peerName}): ${err.message}`);\n this.ws?.close();\n });\n }\n\n /**\n * Send a message over the WS. If disconnected, enqueues it for delivery on reconnect.\n */\n async send(method: string, payload: unknown): Promise<unknown> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n // Enqueue instead of throwing\n return this.enqueue(method, payload);\n }\n return this.sendNow(method, payload);\n }\n\n get connected(): boolean { return this.ws?.readyState === WebSocket.OPEN; }\n\n destroy(): void {\n this.destroyed = true;\n if (this.reconnectTimer) clearTimeout(this.reconnectTimer);\n this.cleanup();\n this.ws?.close();\n this.clearPersistedQueue();\n }\n\n private async sendNow(method: string, payload: unknown): Promise<unknown> {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {\n throw new Error(`WS not connected to ${this.peerName}`);\n }\n const id = randomUUID();\n const config = loadPeerConfig();\n // Sign the serialized payload as a \"request\"\n const payloadStr = JSON.stringify(payload);\n const sigHeaders = signRequest(\"POST\", `/${method}`, payloadStr, config.self.signingKey, config.self.name);\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`WS request timeout (${this.peerName}/${method})`));\n }, REQUEST_TIMEOUT_MS);\n this.pending.set(id, { resolve, reject, timer });\n this.ws!.send(JSON.stringify({ type: \"request\", id, method, payload, ...sigHeaders }));\n });\n }\n\n private enqueue(method: string, payload: unknown): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (this._queue.length >= QUEUE_MAX) {\n const dropped = this._queue.shift()!;\n logWarn(TAG, `[warn] ws queue for ${this.peerName} full, dropping oldest (${dropped.method})`);\n }\n const entry: QueueEntry = { method, payload, id: randomUUID() };\n this._queue.push(entry);\n this.persistQueue();\n // We can't resolve/reject immediately for queued messages\n // Resolve immediately with a sentinel (fire-and-forget semantics)\n resolve({ queued: true, id: entry.id });\n });\n }\n\n private drainQueue(): void {\n if (this._queue.length === 0) return;\n logInfo(TAG, `Draining ${this._queue.length} queued message(s) for ${this.peerName}`);\n const queue = this._queue.splice(0);\n this.clearPersistedQueue();\n for (const entry of queue) {\n this.sendNow(entry.method, entry.payload).catch(err => {\n logWarn(TAG, `Queue drain failed for ${this.peerName}/${entry.method}: ${err.message}`);\n });\n }\n }\n\n private persistQueue(): void {\n try {\n writeFileSync(this.queuePath, JSON.stringify(this._queue), { encoding: \"utf-8\", mode: 0o600 });\n } catch { /* best effort */ }\n }\n\n private clearPersistedQueue(): void {\n try { if (existsSync(this.queuePath)) unlinkSync(this.queuePath); } catch { /* best effort */ }\n }\n\n private loadQueue(): void {\n try {\n if (existsSync(this.queuePath)) {\n const data = readFileSync(this.queuePath, \"utf-8\");\n const parsed = JSON.parse(data) as QueueEntry[];\n if (Array.isArray(parsed)) {\n this._queue = parsed.slice(0, QUEUE_MAX);\n if (this._queue.length > 0) {\n logInfo(TAG, `Loaded ${this._queue.length} queued message(s) for ${this.peerName} from disk`);\n }\n }\n }\n } catch { /* best effort \u2014 corrupt queue, start fresh */ }\n }\n\n private handleMessage(raw: string): void {\n try {\n const msg = JSON.parse(raw);\n if (msg.type === \"response\" && msg.id && this.pending.has(msg.id)) {\n const p = this.pending.get(msg.id)!;\n this.pending.delete(msg.id);\n clearTimeout(p.timer);\n p.resolve(msg.payload);\n } else if (msg.type === \"push\") {\n this.pushHandler?.(msg.method, msg.payload);\n }\n } catch { /* malformed \u2014 ignore */ }\n }\n\n private cleanup(): void {\n // Reject all pending requests\n for (const [, p] of this.pending) {\n clearTimeout(p.timer);\n p.reject(new Error(\"WS connection closed\"));\n }\n this.pending.clear();\n }\n\n private scheduleReconnect(): void {\n const jitter = this.backoff * (0.8 + Math.random() * 0.4); // \u00B120%\n logDebug(TAG, `Reconnecting to ${this.peerName} in ${Math.round(jitter)}ms`);\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, jitter);\n this.backoff = Math.min(this.backoff * 2, MAX_BACKOFF_MS);\n }\n\n /**\n * Dialer-side enrollment handshake over /v1/enroll-ws.\n * Called by `abtars tribe join`.\n */\n async enroll(tribeToken: string, selfSigningKey: string, selfVerifyKey: string, selfName: string): Promise<void> {\n const { randomBytes } = await import(\"node:crypto\");\n const {\n macTribe, signEnroll, verifyAck,\n } = await import(\"./peer-auth.js\");\n const { clearPeerConfigCache } = await import(\"../peer-config.js\");\n const { writeFileSync, existsSync: exSync, mkdirSync } = await import(\"node:fs\");\n\n const enrollUrl = `wss://${this.entry.host}:${this.entry.port}/v1/enroll-ws`;\n const nonceI = randomBytes(16).toString(\"hex\");\n const tsNow = Math.floor(Date.now() / 1000);\n\n return new Promise((resolve, reject) => {\n // No auth headers for enrollment path\n const enrollWs = new WebSocket(enrollUrl, {\n minVersion: \"TLSv1.3\",\n rejectUnauthorized: false, // Can't pin yet \u2014 cert is verified via MAC binding in step B\n } as any);\n\n let stage = 0;\n let nonceR = \"\";\n let pubKeyR = \"\";\n\n enrollWs.on(\"open\", () => {\n // Step A: knock\n enrollWs.send(JSON.stringify({\n pubKey_i: selfVerifyKey,\n nonce_i: nonceI,\n ts: tsNow,\n }));\n stage = 1;\n });\n\n enrollWs.on(\"message\", async (rawData) => {\n try {\n const msg = JSON.parse(rawData.toString());\n\n if (stage === 1) {\n // Step B: challenge\n const { pubKey_r, nonce_r, ts, mac_r } = msg as { pubKey_r: string; nonce_r: string; ts: number; mac_r: string };\n if (!pubKey_r || !nonce_r || !mac_r) { reject(new Error(\"Invalid challenge\")); enrollWs.close(); return; }\n\n // Verify mac_r: HMAC(tribeToken, pubKey_r + nonce_i)\n const expectedMacR = macTribe(tribeToken, pubKey_r + nonceI);\n if (mac_r !== expectedMacR) { reject(new Error(\"tribe token mismatch \u2014 not same tribe\")); enrollWs.close(); return; }\n\n nonceR = nonce_r;\n pubKeyR = pubKey_r;\n stage = 2;\n\n // Step C: enroll\n const macI = macTribe(tribeToken, selfVerifyKey + nonceR);\n const selfSig = signEnroll(selfSigningKey, selfVerifyKey, nonceR, selfName);\n enrollWs.send(JSON.stringify({\n mac_i: macI,\n name: selfName,\n nonce_r: nonceR,\n ts: Math.floor(Date.now() / 1000),\n selfSig,\n }));\n return;\n }\n\n if (stage === 2) {\n // Step D: ack\n const { name_r, pubKey_r: pubKeyRd, ackSig } = msg as { name_r: string; pubKey_r: string; ackSig: string };\n if (!ackSig || !name_r) { reject(new Error(\"Invalid ack\")); enrollWs.close(); return; }\n\n if (!verifyAck(ackSig, pubKeyRd, name_r, pubKeyRd, nonceR)) {\n reject(new Error(\"Invalid ack signature\")); enrollWs.close(); return;\n }\n\n // Persist responder to own peers.json\n const peersPath = join(abtarsHome(), \"config\", \"peers.json\");\n let raw: Record<string, unknown> = {};\n if (exSync(peersPath)) { try { raw = JSON.parse(require(\"fs\").readFileSync(peersPath, \"utf-8\")); } catch { raw = {}; } }\n if (!raw.peers || typeof raw.peers !== \"object\") raw.peers = {};\n (raw.peers as Record<string, unknown>)[name_r] = {\n host: this.entry.host,\n port: this.entry.port,\n verifyKey: pubKeyRd,\n trust: 1,\n transport: \"ws-outbound\",\n };\n writeFileSync(peersPath, JSON.stringify(raw, null, 2) + \"\\n\", { encoding: \"utf-8\" });\n clearPeerConfigCache();\n\n logInfo(TAG, `Enrolled with '${name_r}' at trust=1`);\n // Keep WS alive as steady-state peer connection\n this.ws = enrollWs;\n enrollWs.removeAllListeners(\"message\");\n enrollWs.on(\"message\", (data) => this.handleMessage(data.toString()));\n enrollWs.on(\"close\", () => { this.cleanup(); if (!this.destroyed) this.scheduleReconnect(); });\n enrollWs.on(\"error\", (err) => { logDebug(TAG, `WS error (${this.peerName}): ${err.message}`); this.ws?.close(); });\n resolve();\n }\n } catch (err) {\n reject(err);\n enrollWs.close();\n }\n });\n\n enrollWs.on(\"error\", (err) => reject(new Error(`Enrollment WS error: ${err.message}`)));\n enrollWs.on(\"close\", (code, reason) => {\n if (stage < 2) reject(new Error(`Enrollment WS closed early: ${code} ${reason}`));\n });\n\n setTimeout(() => { if (stage < 2) { reject(new Error(\"Enrollment timeout\")); enrollWs.close(); } }, 30_000);\n });\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["writeFileSync"]
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "abtars",
3
- "version": "0.3.4-alpha.8",
3
+ "version": "0.3.4",
4
4
  "description": "Agentic framework for connecting LLMs to messaging platforms, with persistent memory, skills, scheduled tasks, self-healing supervision, and distributed multi-agent collaboration",
5
5
  "type": "module",
6
6
  "main": "bundle/abtars.js",
@@ -5,7 +5,6 @@ AB="${ABTARS_HOME:-$HOME/.abtars}"
5
5
  LOCK="$AB/bridge.lock"
6
6
  STALE=300
7
7
  POLL=60
8
- LOG="$AB/logs/bridge.log"
9
8
  STATE="$AB/deploy.state"
10
9
 
11
10
  # Singleton: flock (Linux) / lockf (macOS)
@@ -59,15 +58,12 @@ while true; do
59
58
  exit 0 ;;
60
59
  esac
61
60
 
62
- # Pre-flight doctor
63
- command -v abtars &>/dev/null && abtars doctor --fix >> "$AB/logs/watchdog.log" 2>&1 || true
64
-
65
61
  # Start bridge
66
62
  BRIDGE_REASON="${REASON:-watchdog-respawn}"
67
63
  # #1261: exec replaces the subshell with the env->nohup->node chain so $! is the real node PID.
68
64
  # Without exec, bash forks a subshell for `cd && env=value cmd &` and $! returns the subshell,
69
65
  # leaving node as a grandchild that gets orphaned when the subshell dies.
70
- cd "$AB" && exec env ABTARS_WATCHDOG_PID=$$ NODE_PATH="$HOME/.local/lib/node_modules:${NODE_PATH:-}" ABTARS_START_REASON="$BRIDGE_REASON" nohup node --max-old-space-size=1024 app/bundle/abtars.js >> "$LOG" 2>&1 200>&- &
66
+ cd "$AB" && exec env ABTARS_WATCHDOG_PID=$$ NODE_PATH="$HOME/.local/lib/node_modules:${NODE_PATH:-}" ABTARS_START_REASON="$BRIDGE_REASON" nohup node --max-old-space-size=1024 app/bundle/abtars.js 200>&- &
71
67
  PID=$!
72
68
  disown $PID
73
69
  SPAWNED_AT=$(date +%s)
@@ -77,10 +77,10 @@ echo "Restarting..."
77
77
  if launchctl list 2>/dev/null | grep -q abtars; then
78
78
  echo "LaunchAgent manages watchdog — it will restart the bridge."
79
79
  elif [ -f "$HOME_DIR/scripts/abtars-watchdog.sh" ]; then
80
- nohup bash "$HOME_DIR/scripts/abtars-watchdog.sh" >> "$HOME_DIR/logs/watchdog.log" 2>&1 &
80
+ nohup bash "$HOME_DIR/scripts/abtars-watchdog.sh" &
81
81
  echo "Watchdog restarted (PID $!) — it will start the bridge."
82
82
  else
83
- nohup node "$HOME_DIR/app/bundle/abtars.js" >> "$HOME_DIR/logs/bridge.log" 2>&1 &
83
+ nohup node "$HOME_DIR/app/bundle/abtars.js" &
84
84
  echo $! > "$HOME_DIR/bridge.pid"
85
85
  echo "Bridge started (PID $!)."
86
86
  fi
@@ -1,20 +1,28 @@
1
1
  #!/usr/bin/env bash
2
2
  # emergency-update.sh — fully-manual deploy when the abtars CLI cannot update itself.
3
3
  #
4
- # Builds the fresh dev bundle with plain npm + esbuild (NO abtars/abmind CLI
4
+ # Builds the fresh dev bundle with plain npm + esbuild (NO abtars CLI
5
5
  # invocation), stages a release, repoints the symlinks, and restarts the
6
6
  # watchdog directly via launchctl/systemd. Result is identical to
7
7
  # `abtars update --dev` but needs no working deployed binary.
8
8
  #
9
- # This is a MANUAL MIRROR of src/cli/deploy-lib/deploy.ts (deployActivation).
10
- # If deploy.ts changes its stop/respawn sequence or path layout, UPDATE THIS.
9
+ # This is a MANUAL MIRROR of src/cli/deploy-lib/deploy.ts (deployActivation),
10
+ # EXCEPT for the stop/respawn sequence, which intentionally diverges (#1299):
11
+ # - deploy.ts `/update dev` runs INSIDE the abtars-watchdog.service cgroup, so
12
+ # it must NOT stop the service or kill the watchdog (cgroup suicide under
13
+ # KillMode=control-group). It kills only the bridge and lets L3 respawn it;
14
+ # it CANNOT refresh the watchdog.
15
+ # - THIS script runs OUTSIDE the cgroup (manual login shell), so it CAN and
16
+ # DOES fully refresh the watchdog via one atomic `systemctl restart`. This is
17
+ # the foolproof, dependency-free WD-refresh path for when the CLI is broken.
18
+ # If deploy.ts changes its release path layout, UPDATE THIS. Do NOT "re-sync" the
19
+ # stop/respawn sequences — the divergence is deliberate.
11
20
  #
12
21
  # Usage: bash ~/.abtars-releases/src/abtars/scripts/emergency-update.sh
13
22
 
14
23
  set -euo pipefail
15
24
 
16
25
  SRC_DIR="${ABTARS_SRC:-$HOME/.abtars-releases/src/abtars}"
17
- ABMIND_DIR="${ABMIND_SRC:-$HOME/.abtars-releases/src/abmind}"
18
26
  RELEASES_DIR="$HOME/.abtars-releases"
19
27
  ABTARS_HOME="${ABTARS_HOME:-$HOME/.abtars}"
20
28
  PLIST="$HOME/Library/LaunchAgents/com.abtars.watchdog.plist"
@@ -33,10 +41,6 @@ jget() { node -e 'const fs=require("fs");try{const v=JSON.parse(fs.readFileSync(
33
41
  step "bypassing dev branch fetch/reset..."
34
42
  # git -C "$SRC_DIR" fetch --depth 1 origin dev
35
43
  # git -C "$SRC_DIR" reset --hard origin/dev
36
- # if [ -d "$ABMIND_DIR/.git" ]; then
37
- # git -C "$ABMIND_DIR" fetch --depth 1 origin dev
38
- # git -C "$ABMIND_DIR" reset --hard origin/dev
39
- # fi
40
44
 
41
45
 
42
46
  COMMIT="$(git -C "$SRC_DIR" rev-parse --short HEAD)"
@@ -59,22 +63,6 @@ if [ -d "$SRC_DIR/agents" ]; then
59
63
  cp -r "$SRC_DIR/agents" "$SRC_DIR/bundle/agents"
60
64
  fi
61
65
 
62
- # ── 3. Build abmind + copy into bundle ─────────────────────────────────────
63
- if [ -f "$ABMIND_DIR/package.json" ]; then
64
- step "building abmind..."
65
- ( cd "$ABMIND_DIR" && npm install --ignore-scripts && npm run build )
66
- if [ -f "$ABMIND_DIR/dist/cli/abmind.js" ]; then
67
- ABMIND_DEST="$SRC_DIR/bundle/node_modules/abmind"
68
- rm -rf "$ABMIND_DEST"
69
- mkdir -p "$ABMIND_DEST"
70
- cp -r "$ABMIND_DIR/." "$ABMIND_DEST/"
71
- rm -rf "$ABMIND_DEST/node_modules" "$ABMIND_DEST/.git"
72
- chmod +x "$ABMIND_DEST/dist/cli/abmind.js" 2>/dev/null || true
73
- else
74
- echo "! abmind build produced no dist — bundle will fall back to global abmind"
75
- fi
76
- fi
77
-
78
66
  # ── 4. Stage release ───────────────────────────────────────────────────────
79
67
  step "staging release $VERSION -> $RELEASE_DIR ..."
80
68
  mkdir -p "$RELEASES_DIR"
@@ -112,24 +100,32 @@ node -e '
112
100
  fs.writeFileSync(path, JSON.stringify(m, null, 2) + "\n");
113
101
  ' "$ABTARS_HOME" "$VERSION" "$COMMIT"
114
102
 
115
- # ── 8. Stop daemon (FROZEN sequence — mirrors deploy.ts deployActivation) ──
103
+ # ── 8. Stop (mirrors deploy.ts, but see #1299 divergence) ──────────────────
116
104
  step "stopping daemon..."
117
105
  OLD_PID="$(jget "$BRIDGE_LOCK" pid)"
118
106
  WD_PID="$(jget "$BRIDGE_LOCK" watchdogPid)"
119
107
  if [ "$IS_MAC" = "1" ]; then
108
+ # macOS: bootout now, bootstrap in step 9. No cgroup teardown, so the detached
109
+ # deploy survives — the full stop/kill sequence is safe here.
120
110
  launchctl bootout "$UID_LABEL/com.abtars.watchdog" 2>/dev/null || true
121
- else
122
- systemctl --user stop abtars-watchdog 2>/dev/null || true
111
+ echo "update:$VERSION" > "$ABTARS_HOME/.start-reason"
112
+ [ -n "$OLD_PID" ] && kill "$OLD_PID" 2>/dev/null || true
113
+ [ -n "$WD_PID" ] && kill "$WD_PID" 2>/dev/null || true
114
+ for _ in 1 2 3 4 5 6 7 8 9 10; do # wait up to ~5s for bridge to exit
115
+ if [ -z "$OLD_PID" ] || ! kill -0 "$OLD_PID" 2>/dev/null; then break; fi
116
+ sleep 0.5
117
+ done
118
+ [ -n "$OLD_PID" ] && kill -9 "$OLD_PID" 2>/dev/null || true
119
+ [ -n "$WD_PID" ] && kill -9 "$WD_PID" 2>/dev/null || true
123
120
  fi
124
- echo "update:$VERSION" > "$ABTARS_HOME/.start-reason"
125
- [ -n "$OLD_PID" ] && kill "$OLD_PID" 2>/dev/null || true
126
- [ -n "$WD_PID" ] && kill "$WD_PID" 2>/dev/null || true
127
- for _ in 1 2 3 4 5 6 7 8 9 10; do # wait up to ~5s for bridge to exit
128
- if [ -z "$OLD_PID" ] || ! kill -0 "$OLD_PID" 2>/dev/null; then break; fi
129
- sleep 0.5
130
- done
131
- [ -n "$OLD_PID" ] && kill -9 "$OLD_PID" 2>/dev/null || true
132
- [ -n "$WD_PID" ] && kill -9 "$WD_PID" 2>/dev/null || true
121
+ # Linux (#1299): NO `systemctl stop` and NO manual kill here. An explicit stop
122
+ # opens a durable "stopped" window if the reconcile in 8b fails under set -e,
123
+ # the watchdog is left dead before the verify in 9b (the 2026-07-03 14.4h outage
124
+ # class). Instead we reconcile while the watchdog is still up, then do ONE atomic
125
+ # `systemctl restart` in step 9: it tears down the old watchdog cgroup (old WD +
126
+ # bridge) and starts a fresh watchdog with the new service def + new
127
+ # abtars-watchdog.sh. This script runs OUTSIDE the service cgroup (manual login
128
+ # shell), so the restart does not kill it this is the foolproof WD-refresh path.
133
129
  rm -f "$ABTARS_HOME/.stopped"
134
130
 
135
131
  # ── 8b. Reconcile watchdog service definition from repo template (#1284) ────
@@ -161,7 +157,10 @@ else
161
157
  systemctl --user daemon-reload 2>/dev/null || true
162
158
  systemctl --user unmask abtars-watchdog 2>/dev/null || true
163
159
  systemctl --user enable abtars-watchdog 2>/dev/null || true
164
- # #1278: atomic restart (no durable stopped window) NOT the old silent stop+start.
160
+ # #1278/#1299: single atomic restart is the ONLY teardown+respawn on Linux
161
+ # step 8 no longer does an explicit stop, so there is no durable stopped
162
+ # window. restart tears down the old watchdog cgroup and starts a fresh
163
+ # watchdog with the reconciled service def + new abtars-watchdog.sh.
165
164
  systemctl --user restart abtars-watchdog 2>/dev/null || systemctl --user start abtars-watchdog 2>/dev/null || true
166
165
  fi
167
166
 
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/capabilities/sleep/index.ts", "../src/capabilities/sleep/sleep-card.ts"],
4
- "sourcesContent": ["import { logAndSwallow } from \"../../components/log-and-swallow.js\";\nimport { getEnv } from \"../../components/env-schema.js\";\nimport type { CapabilityApi } from \"../capability.js\";\n/**\n * Sleep capability \u2014 spawn nightly sleep cycle via tick system.\n * One path: BED_TIME + quiet ticks \u2192 Dreamy \u2192 quiet ticks \u2192 hardware sleep.\n * Parses PROGRESS:<pct>:<label> from stdout for visibility.\n */\n\nimport { execSync } from \"node:child_process\";\nimport { writeSleepStatus, readAndClearForceSleep } from \"../../components/transport/bridge-lock-transport.js\";\nimport { join } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport type { Level } from \"abmind\";\nimport { abmind } from \"../../utils/abmind-lazy.js\";\nimport type { SleepRuntime } from \"abmind\";\nimport { logInfo, logWarn, logDebug } from \"../../components/logger.js\";\nimport { readEnv, readEnvWithDefault } from \"../../components/env.js\";\nimport { startSleepCard, type SleepCard } from \"./sleep-card.js\";\n\nexport interface SleepOpts {\n sleepHour: number;\n sleepAuditDir: string;\n memoryEnabled: boolean;\n memoryDir?: string;\n /** LLM runtime adapter \u2014 bridge wraps spin({ type: \"D\", ... }) (#1271). */\n runtime: SleepRuntime;\n onComplete: () => void;\n getLastMsgTs?: () => number;\n sendSystemMessage?: (prompt: string) => Promise<void>;\n killWakeInhibit?: () => void;\n /** Allocate a named Dreamy session upfront at sleep start (#1280).\n * Called before the first runtime.complete() so the session appears in /session\n * for the full duration of the cycle. Optional \u2014 sleep still works without it. */\n allocateSleepSession?: (name: string) => void;\n}\n\nexport interface SleepProgress {\n percent: number;\n step: string;\n}\n\nexport interface SleepHandle {\n /** True while a sleep cycle is running in-process. */\n readonly isActive: boolean;\n readonly progress: SleepProgress | null;\n readonly awaitingHwSleep: boolean;\n spawn(): void;\n /** Called by tick system to check if hardware sleep should fire. */\n checkHwSleep(): void;\n /** Force-clear isActive if no progress in 30min (#990). */\n checkStale(): void;\n}\n\nconst MAX_RETRIES = 3;\nconst RETRY_MS = 5 * 60 * 1000;\n\nexport function createSleepHandle(opts: SleepOpts): SleepHandle {\n let running = false;\n let attempts = 0;\n let progress: SleepProgress | null = null;\n let _awaitingHwSleep = false;\n // Post-Dreamy hw-sleep quiet-tick tracking (internal to this closure \u2014 decoupled from\n // daily-cycle.quietTickCount which freezes once hasSleepAuditToday returns true).\n // Both reset when _awaitingHwSleep flips to true (see the onComplete handler below).\n let postSleepQuietTicks = 0;\n let lastMsgTsSeenByHwCheck = 0;\n\n function buildDreamReport(): string {\n let dreamReport = \"Dreamy finished nightly maintenance.\";\n try {\n const sleepDir = join(opts.memoryDir ?? \"\", \"sleep\");\n const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, \"\");\n const lockPath = join(sleepDir, `sleep_${dateStr}.lock`);\n if (existsSync(lockPath)) {\n const lockData = JSON.parse(readFileSync(lockPath, \"utf-8\")) as { steps: Record<string, { status: string }>; llmCalls?: number };\n const ok = Object.entries(lockData.steps).filter(([, s]) => s.status === \"ok\").map(([k]) => k);\n const skipped = Object.entries(lockData.steps).filter(([, s]) => s.status === \"skipped\").map(([k]) => k);\n const failed = Object.entries(lockData.steps).filter(([, s]) => s.status === \"failed\" || s.status === \"timeout\").map(([k]) => k);\n dreamReport = `Dreamy finished nightly maintenance (${lockData.llmCalls ?? \"?\"} LLM calls). Completed: ${ok.join(\", \") || \"none\"}.`;\n if (skipped.length > 0) dreamReport += ` Skipped: ${skipped.join(\", \")}.`;\n if (failed.length > 0) dreamReport += ` \u26A0\uFE0F FAILED: ${failed.join(\", \")}. Please review.`;\n }\n } catch (err) { logAndSwallow(\"index\", \"op\", err); }\n return dreamReport;\n }\n\n function spawnSleep(): void {\n const forceSleep = readAndClearForceSleep();\n const forced = forceSleep !== null;\n if (forced) {\n logInfo(\"sleep\", `\u26A1 forceSleep=${forceSleep} \u2014 bypassing time-window + audit-today guards`);\n }\n\n if (!forced) {\n const hour = new Date().getHours();\n const WAKE_HOUR = parseInt(readEnvWithDefault(\"WAKE_TIME\", \"7\", \"wake hour\").split(\":\")[0] ?? \"7\", 10);\n if (opts.sleepHour <= WAKE_HOUR) {\n if (hour < opts.sleepHour || hour >= WAKE_HOUR) {\n logDebug(\"sleep\", `\uD83D\uDE34 Outside sleep window (${opts.sleepHour}:00-${WAKE_HOUR}:00) \u2014 skip`);\n return;\n }\n } else {\n if (hour < opts.sleepHour && hour >= WAKE_HOUR) {\n logDebug(\"sleep\", `\uD83D\uDE34 Outside sleep window (${opts.sleepHour}:00-${WAKE_HOUR}:00) \u2014 skip`);\n return;\n }\n }\n if (abmind()?.hasSleepAuditToday(opts.sleepAuditDir)) {\n logDebug(\"sleep\", \"\uD83D\uDE34 Sleep already done today \u2014 skip\");\n return;\n }\n }\n if (running) return;\n attempts++;\n progress = null;\n // Allocate the Dreamy session upfront so it appears in /session for the full cycle (#1280).\n if (opts.allocateSleepSession) {\n const dateStr = new Date().toISOString().slice(0, 10);\n opts.allocateSleepSession(`Sleep ${dateStr}`);\n }\n running = true;\n writeSleepStatus(\"sleeping\");\n logInfo(\"sleep\", `\uD83D\uDE34 Sleep started in-process (attempt ${attempts}, model=dreamy)`);\n\n const level = (() => {\n if (forced && forceSleep?.includes(\"fresh\")) return \"ultimate\" as Level;\n const raw = getEnv().sleepQuality;\n if (!raw) return abmind()!.DEFAULT_LEVEL;\n try { return abmind()!.parseLevel(raw); }\n catch (err) { logWarn(\"sleep\", `Invalid SLEEP_QUALITY='${raw}', using ${abmind()!.DEFAULT_LEVEL}: ${err instanceof Error ? err.message : String(err)}`); return abmind()!.DEFAULT_LEVEL; }\n })();\n\n let sleepCard: SleepCard | null = null;\n abmind()!.runSleepCycle({\n runtime: opts.runtime,\n level,\n fresh: forced && !!forceSleep?.includes(\"fresh\"),\n // #895: stepped card \u2014 created when the orchestrator commits to running steps,\n // ticked per step, completed once at cycle end (both success and failure paths).\n onCycleStart: () => { sleepCard = startSleepCard(); },\n onStep: (e) => sleepCard?.onStep(e),\n })\n .then(async (result: { ok: boolean; failCount: number }) => {\n running = false;\n progress = null;\n sleepCard?.complete();\n logInfo(\"sleep\", `\uD83D\uDE34 Sleep finished (ok=${result.ok}, failCount=${result.failCount}, attempt ${attempts})`);\n writeSleepStatus(\"awake\");\n if (!result.ok) {\n if (attempts < MAX_RETRIES) {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep had ${result.failCount} failures (attempt ${attempts}/${MAX_RETRIES}) \u2014 retry in 5min`);\n setTimeout(spawnSleep, RETRY_MS);\n } else {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep failures persist \u2014 exhausted ${MAX_RETRIES} attempts`);\n }\n return;\n }\n\n if (opts.memoryEnabled) opts.onComplete();\n\n // Force-sleep runs are explicit test/verify triggers \u2014 skip hw-sleep even if env enabled.\n const hwEnabled = !forced && readEnv(\"HARDWARE_SLEEP_AFTER_DREAMY\", \"hardware sleep after Dreamy disabled\") === \"true\";\n const quietTicks = Math.ceil(getEnv().bedQuietMin * 60 / parseInt(readEnvWithDefault(\"HEARTBEAT_INTERVAL_SEC\", \"60\", \"hb\"), 10));\n const hbInterval = parseInt(readEnvWithDefault(\"HEARTBEAT_INTERVAL_SEC\", \"60\", \"heartbeat tick interval\"), 10);\n const hwSleepMin = Math.round(quietTicks * hbInterval / 60);\n\n const dreamReport = buildDreamReport();\n const sleepNote = hwEnabled ? ` Hardware sleep in ~${hwSleepMin} minutes if no activity.` : \"\";\n\n // #844: buffer silently \u2014 don't trigger model response\n const { bufferSystemEvent } = await import(\"../../components/system-event-buffer.js\");\n bufferSystemEvent(`${dreamReport}${sleepNote}`);\n\n if (hwEnabled) {\n _awaitingHwSleep = true;\n // Reset hw-check counters \u2014 prevents stale state from a prior cycle (crash, force-sleep\n // re-run) from poisoning this one, and avoids burning the first tick on a spurious\n // reset when the very first checkHwSleep() sees currentMsgTs > 0.\n postSleepQuietTicks = 0;\n lastMsgTsSeenByHwCheck = opts.getLastMsgTs?.() ?? 0;\n logInfo(\"sleep\", `\uD83D\uDCA4 Awaiting hardware sleep \u2014 ${quietTicks} quiet ticks (${hwSleepMin} min) required`);\n }\n })\n .catch((err: unknown) => {\n running = false;\n progress = null;\n sleepCard?.complete();\n writeSleepStatus(\"awake\");\n const msg = err instanceof Error ? err.message : String(err);\n if (attempts < MAX_RETRIES) {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep threw (attempt ${attempts}/${MAX_RETRIES}): ${msg} \u2014 retry in 5min`);\n setTimeout(spawnSleep, RETRY_MS);\n } else {\n logWarn(\"sleep\", `\uD83D\uDE34 Sleep threw \u2014 exhausted ${MAX_RETRIES} attempts: ${msg}`);\n }\n });\n }\n\n function checkHwSleep(): void {\n if (!_awaitingHwSleep) return;\n\n // Sleep-window cutoff \u2014 give up if we've crossed out of the window. Next night retries.\n // Mirrors spawnSleep()'s window logic for consistency.\n const WAKE_HOUR = parseInt(readEnvWithDefault(\"WAKE_TIME\", \"7\", \"wake hour\").split(\":\")[0] ?? \"7\", 10);\n const BED_HOUR = opts.sleepHour;\n const hour = new Date().getHours();\n const inSleepWindow = (BED_HOUR < WAKE_HOUR)\n ? (hour >= BED_HOUR && hour < WAKE_HOUR) // normal: BED=00:30, WAKE=07:00 \u2192 sleep 00-06\n : (hour >= BED_HOUR || hour < WAKE_HOUR); // overnight: BED=23:00, WAKE=07:00 \u2192 sleep 23-06\n if (!inSleepWindow) {\n logInfo(\"sleep\", `\u23F0 Past sleep window (now ${hour}:00, window ${BED_HOUR}:00-${WAKE_HOUR}:00) \u2014 abandoning hw-sleep attempt`);\n _awaitingHwSleep = false;\n postSleepQuietTicks = 0;\n return;\n }\n\n // User messaged since last check \u2014 postpone and reset\n const currentMsgTs = opts.getLastMsgTs?.() ?? 0;\n if (currentMsgTs > lastMsgTsSeenByHwCheck) {\n lastMsgTsSeenByHwCheck = currentMsgTs;\n postSleepQuietTicks = 0;\n logInfo(\"sleep\", \"\uD83D\uDCA4 Hardware sleep postponed \u2014 user messaged (will retry after quiet period)\");\n return;\n }\n\n // Quiet tick \u2014 increment\n const requiredTicks = Math.ceil(getEnv().bedQuietMin * 60 / parseInt(process.env[\"HEARTBEAT_INTERVAL_SEC\"] ?? \"60\", 10));\n postSleepQuietTicks++;\n if (postSleepQuietTicks < requiredTicks) return;\n\n // Threshold reached \u2014 sleep\n _awaitingHwSleep = false;\n postSleepQuietTicks = 0;\n // Kill any wake inhibitor from /wakeup before sleeping\n opts.killWakeInhibit?.();\n const sleepCmd = process.platform === \"darwin\" ? \"pmset sleepnow\" : \"systemctl suspend\";\n logInfo(\"sleep\", `\uD83D\uDCA4 Putting hardware to sleep (${sleepCmd})...`);\n writeSleepStatus(\"hw_sleep\");\n try { execSync(sleepCmd, { timeout: 5000 }); }\n catch (err) {\n writeSleepStatus(\"awake\"); // recover \u2014 don't leave \"hw_sleep\" if pmset failed\n logWarn(\"sleep\", `\uD83D\uDCA4 Hardware sleep failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n function checkStale(): void {\n if (!running) return;\n const STALE_MS = 30 * 60_000;\n try {\n const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, \"\");\n const lockPath = join(opts.sleepAuditDir, `sleep_${dateStr}.lock`);\n if (!existsSync(lockPath)) { running = false; logWarn(\"sleep\", \"Sleep stuck \u2014 no lock file, force-clearing isActive\"); return; }\n const lock = JSON.parse(readFileSync(lockPath, \"utf-8\")) as { startedAt?: number; steps?: Record<string, { duration?: number }> };\n const stepTimes = Object.values(lock.steps ?? {}).map(s => (s as any).startedAt ?? (s as any).completedAt ?? 0).filter(Boolean);\n const lastActivity = Math.max(lock.startedAt ?? 0, ...stepTimes);\n if (lastActivity > 0 && Date.now() - lastActivity > STALE_MS) {\n running = false;\n logWarn(\"sleep\", `Sleep stuck \u2014 no progress in 30min (last activity ${Math.round((Date.now() - lastActivity) / 60_000)}min ago), force-clearing isActive`);\n }\n } catch { /* lock file unreadable \u2014 leave running as-is, next tick retries */ }\n }\n\n return {\n get isActive() { return running; },\n get progress() { return progress; },\n get awaitingHwSleep() { return _awaitingHwSleep; },\n spawn: spawnSleep,\n checkHwSleep,\n checkStale,\n };\n}\n\n/** Capability registration \u2014 called by discoverCapabilities(). */\nexport function register(_api: CapabilityApi): void {\n // Sleep registration is a no-op here \u2014 the actual SleepHandle is created\n // in phase-sleep.ts because it needs ctx.sendSystemMessage + memory deps\n // that aren't available at capability discovery time.\n // This manifest exists so sleep appears in discoverCapabilities() and\n // can be disabled via DISABLED_CAPABILITIES=sleep.\n}\n", "/**\n * sleep-card.ts \u2014 stepped kanban card for a nightly sleep cycle (#895).\n *\n * Display-only. One card per cycle whose notes render a checklist that ticks as\n * abmind fires onStep events. The card is created in \"running\" status (NOT\n * \"queued\") on purpose: a queued D-type card would be picked up by\n * spin.drainQueued() and dispatched as a spurious Dreamy worker. A parentless\n * \"running\" card is inert \u2014 drainQueued only scans \"queued\", and the reconciler\n * only touches children of running O-projects.\n *\n * All kanban writes are best-effort: a display failure must never break the\n * sleep cycle.\n */\n\nimport type { SleepStepEvent } from \"abmind\";\nimport { kanbanEnqueue, kanbanUpdate, kanbanComplete } from \"../../components/tasks/kanban-board.js\";\nimport { abmind } from \"../../utils/abmind-lazy.js\";\nimport { logAndSwallow } from \"../../components/log-and-swallow.js\";\n\ntype StepStatus = \"pending\" | \"running\" | \"done\" | \"skipped\" | \"failed\";\n\ninterface StepItem {\n name: string;\n filename: string;\n status: StepStatus;\n}\n\nconst MARK: Record<StepStatus, string> = {\n pending: \"[ ]\",\n running: \"[~]\",\n done: \"[x]\",\n skipped: \"[skip]\",\n failed: \"[fail]\",\n};\n\nconst TAG = \"sleep-card\";\n\nexport interface SleepCard {\n /** Flip the matching checklist item and re-render the card notes. */\n onStep(event: SleepStepEvent): void;\n /** Mark the card done once at cycle end (success or failure). Idempotent. */\n complete(): void;\n}\n\nfunction renderChecklist(items: readonly StepItem[]): string {\n return items.map(item => `${MARK[item.status]} ${item.name}`).join(\"\\n\");\n}\n\n/**\n * Create the stepped card for a cycle. Reads the step manifest from abmind so\n * the checklist mirrors loadSleepSteps() (name + order). Returns a no-op card if\n * abmind or the manifest is unavailable \u2014 sleep still runs.\n */\nexport function startSleepCard(): SleepCard {\n let cardId = 0;\n let items: StepItem[] = [];\n let completed = false;\n\n try {\n const steps = abmind()?.loadSleepSteps() ?? [];\n items = steps.map(step => ({ name: step.name, filename: step.filename, status: \"pending\" as StepStatus }));\n if (items.length > 0) {\n const dateStr = new Date().toISOString().slice(0, 10);\n cardId = kanbanEnqueue(`Sleep ${dateStr}`, \"scheduled\", undefined, {\n type: \"D\",\n deliveryMode: \"silent\",\n notes: renderChecklist(items),\n });\n // Move out of \"queued\" immediately so drainQueued() never dispatches it.\n if (cardId) kanbanUpdate(cardId, { status: \"running\" });\n }\n } catch (err) {\n logAndSwallow(TAG, \"start\", err);\n cardId = 0;\n }\n\n return {\n onStep(event: SleepStepEvent): void {\n if (!cardId) return;\n const item = items.find(i => i.name === event.name);\n if (!item) return;\n item.status = event.phase === \"start\" ? \"running\" : event.phase;\n try {\n kanbanUpdate(cardId, { notes: renderChecklist(items) });\n } catch (err) {\n logAndSwallow(TAG, \"tick\", err);\n }\n },\n\n complete(): void {\n if (!cardId || completed) return;\n completed = true;\n const done = items.filter(i => i.status === \"done\").length;\n const skipped = items.filter(i => i.status === \"skipped\").length;\n const failed = items.filter(i => i.status === \"failed\").length;\n const summary = `Sleep complete \u2014 ${done} done, ${skipped} skipped, ${failed} failed (of ${items.length})`;\n try {\n kanbanComplete(cardId, null, summary);\n } catch (err) {\n logAndSwallow(TAG, \"complete\", err);\n }\n },\n };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/cli/commands/doctor-probes.ts"],
4
- "sourcesContent": ["/**\n * doctor-probes.ts \u2014 structured health probes grouped by subsystem layer.\n * Replaces scripts/doctor.sh entirely.\n */\n\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { abtarsHome } from \"../../paths.js\";\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ProbeResult {\n name: string;\n status: \"ok\" | \"failed\" | \"skipped\";\n detail?: string;\n ms?: number;\n}\n\nexport interface FixResult {\n probe: string;\n action: string;\n success: boolean;\n}\n\nexport type LayerName = \"body\" | \"heart\" | \"brain\" | \"soul\" | \"tribe\";\n\nexport interface DoctorOutput {\n version: \"1.0\";\n totalMs: number;\n layers: Record<LayerName, ProbeResult[]>;\n fixes?: FixResult[];\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst home = abtarsHome();\nconst configDir = join(home, \"config\");\n\nfunction readJson(path: string): any | null {\n try { return JSON.parse(readFileSync(path, \"utf-8\")); } catch { return null; }\n}\n\nfunction readEnv(): Map<string, string> {\n const envPath = join(configDir, \".env\");\n const map = new Map<string, string>();\n if (!existsSync(envPath)) return map;\n for (const line of readFileSync(envPath, \"utf-8\").split(\"\\n\")) {\n const m = line.match(/^([A-Z_]+)=(.*)$/);\n if (m) map.set(m[1]!, m[2]!.replace(/^[\"']|[\"']$/g, \"\"));\n }\n return map;\n}\n\nfunction pidAlive(pid: number): boolean {\n try { process.kill(pid, 0); return true; } catch { return false; }\n}\n\nfunction ago(ms: number): string {\n const s = Math.round(ms / 1000);\n if (s < 60) return `${s}s ago`;\n return `${Math.round(s / 60)}m ago`;\n}\n\nasync function timedProbe(fn: () => Promise<ProbeResult>): Promise<ProbeResult> {\n const start = Date.now();\n try {\n const r = await fn();\n r.ms = r.ms ?? (Date.now() - start);\n return r;\n } catch (err) {\n return { name: \"unknown\", status: \"failed\", detail: String(err), ms: Date.now() - start };\n }\n}\n\n// \u2500\u2500 Body Probes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function probePlatforms(): Promise<ProbeResult> {\n const { readSecret, initSecretsKey } = await import(\"../../components/secrets.js\");\n initSecretsKey();\n\n const results: Array<{ name: string; status: \"ok\" | \"failed\" | \"skipped\"; detail: string }> = [];\n\n // Telegram: read token, call getMe\n const telegramToken = readSecret(\"TELEGRAM_BOT_TOKEN\") ?? readSecret(\"TELEGRAM_TOKEN\");\n if (telegramToken) {\n const r = await verifyTelegram(telegramToken);\n results.push({ name: \"telegram\", ...r });\n }\n\n // Discord: read token, call gateway\n const discordToken = readSecret(\"DISCORD_BOT_TOKEN\") ?? readSecret(\"DISCORD_TOKEN\");\n if (discordToken) {\n const r = await verifyDiscord(discordToken);\n results.push({ name: \"discord\", ...r });\n }\n\n // IRC: skip real verification (connection-based), just check if configured\n const ircServer = readSecret(\"IRC_SERVER\");\n if (ircServer) {\n results.push({ name: \"irc\", status: \"ok\", detail: \"server configured (connection not verified)\" });\n }\n\n if (results.length === 0) return { name: \"platforms\", status: \"skipped\", detail: \"no platform configured\" };\n\n const failed = results.filter(r => r.status === \"failed\");\n const skipped = results.filter(r => r.status === \"skipped\");\n const allOk = failed.length === 0 && skipped.length === 0;\n const status = allOk ? \"ok\" : failed.length > 0 ? \"failed\" : \"ok\";\n const detail = results.map(r => `${r.name}: ${r.status}${r.detail ? ` (${r.detail})` : \"\"}`).join(\", \");\n return { name: \"platforms\", status, detail };\n}\n\nasync function verifyTelegram(token: string): Promise<{ status: \"ok\" | \"failed\" | \"skipped\"; detail: string }> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`, { signal: controller.signal });\n clearTimeout(timeout);\n if (res.ok) return { status: \"ok\", detail: \"getMe ok\" };\n if (res.status === 401 || res.status === 403) return { status: \"failed\", detail: \"invalid token\" };\n return { status: \"skipped\", detail: `http ${res.status}` };\n } catch {\n return { status: \"skipped\", detail: \"unreachable\" };\n }\n}\n\nasync function verifyDiscord(token: string): Promise<{ status: \"ok\" | \"failed\" | \"skipped\"; detail: string }> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n const res = await fetch(\"https://discord.com/api/v10/users/@me\", {\n headers: { \"Authorization\": `Bot ${token}` },\n signal: controller.signal,\n });\n clearTimeout(timeout);\n if (res.ok) return { status: \"ok\", detail: \"gateway ok\" };\n if (res.status === 401 || res.status === 403) return { status: \"failed\", detail: \"invalid token\" };\n return { status: \"skipped\", detail: `http ${res.status}` };\n } catch {\n return { status: \"skipped\", detail: \"unreachable\" };\n }\n}\n\nasync function probeDashboard(): Promise<ProbeResult> {\n const env = readEnv();\n if (env.get(\"ENABLE_DASHBOARD\") !== \"true\") return { name: \"dashboard\", status: \"skipped\", detail: \"not enabled\" };\n const port = env.get(\"DASHBOARD_PORT\") || env.get(\"WEB_PORT\") || \"3000\";\n try {\n const res = await fetch(`http://127.0.0.1:${port}/`, { signal: AbortSignal.timeout(3000) });\n return { name: \"dashboard\", status: res.ok ? \"ok\" : \"failed\", detail: `:${port}` };\n } catch {\n return { name: \"dashboard\", status: \"failed\", detail: `:${port} unreachable` };\n }\n}\n\nasync function probeSecurity(): Promise<ProbeResult> {\n const env = readEnv();\n const mode = env.get(\"SECURITY_MODE\") || \"off\";\n const validModes = [\"off\", \"guardrails\", \"seatbelt\", \"docker\"];\n if (!validModes.includes(mode)) return { name: \"security\", status: \"failed\", detail: `invalid mode: ${mode}` };\n\n // Check secret file perms\n const secretDir = join(home, \"secret\");\n let permIssues = 0;\n if (existsSync(secretDir)) {\n for (const f of readdirSync(secretDir)) {\n const st = statSync(join(secretDir, f));\n if (st.isFile() && (st.mode & 0o777) !== 0o600) permIssues++;\n }\n }\n\n const parts = [mode];\n if (existsSync(join(home, \"auth\", \"rules.json\"))) parts.push(\"ActionGate\");\n if (permIssues > 0) return { name: \"security\", status: \"failed\", detail: `${mode}, ${permIssues} file(s) not 600` };\n return { name: \"security\", status: \"ok\", detail: parts.join(\", \") };\n}\n\nasync function probeWatchdog(): Promise<ProbeResult> {\n const lock = readJson(join(home, \"bridge.lock\"));\n if (!lock) return { name: \"watchdog\", status: \"failed\", detail: \"bridge.lock missing\" };\n\n const bridgePid = lock.pid ?? 0;\n const wdPid = lock.watchdogPid ?? 0;\n const bridgeAlive = bridgePid > 0 && pidAlive(bridgePid);\n const wdAlive = wdPid > 0 && pidAlive(wdPid);\n\n if (bridgeAlive && wdAlive) return { name: \"watchdog\", status: \"ok\", detail: `bridge:${bridgePid}, wd:${wdPid}` };\n if (!bridgeAlive && !wdAlive) return { name: \"watchdog\", status: \"failed\", detail: `bridge:${bridgePid} dead, wd:${wdPid} dead` };\n if (!wdAlive) return { name: \"watchdog\", status: \"failed\", detail: `bridge:${bridgePid} alive, wd:${wdPid} dead (unprotected)` };\n return { name: \"watchdog\", status: \"failed\", detail: `bridge:${bridgePid} dead, wd:${wdPid} alive (will restart)` };\n}\n\n// \u2500\u2500 Heart Probes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function probeHeartbeat(): Promise<ProbeResult> {\n const lock = readJson(join(home, \"bridge.lock\"));\n if (!lock?.lastHeartbeat) return { name: \"heartbeat\", status: \"skipped\", detail: \"no bridge.lock\" };\n const ageMs = Date.now() - lock.lastHeartbeat;\n if (ageMs > 120_000) return { name: \"heartbeat\", status: \"failed\", detail: `stale (${ago(ageMs)})` };\n return { name: \"heartbeat\", status: \"ok\", detail: ago(ageMs) };\n}\n\n// #1261: single-bridge invariant \u2014 catches duplicate-bridge regressions at runtime.\n// pgrep counts the bridge processes. >1 means a second bridge is running (likely orphaned).\nasync function probeSingleBridge(): Promise<ProbeResult> {\n const { spawnSync } = await import(\"node:child_process\");\n const pgrep = spawnSync(\"pgrep\", [\"-f\", \"app/bundle/abtars.js\"], { encoding: \"utf-8\" });\n const pids = pgrep.stdout ? pgrep.stdout.trim().split(\"\\n\").filter(Boolean) : [];\n if (pids.length === 0) return { name: \"single-bridge\", status: \"skipped\", detail: \"no bridge running\" };\n if (pids.length === 1) return { name: \"single-bridge\", status: \"ok\", detail: `pid:${pids[0]}` };\n return { name: \"single-bridge\", status: \"failed\", detail: `${pids.length} bridges running: ${pids.join(\",\")}` };\n}\n\n// \u2500\u2500 Brain Probes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function probeTransport(): Promise<ProbeResult> {\n const tPath = join(configDir, \"transport.json\");\n const t = readJson(tPath);\n if (!t) return { name: \"transport\", status: \"failed\", detail: \"transport.json missing or invalid\" };\n const agents = Object.keys(t.agents ?? {});\n if (agents.length === 0) return { name: \"transport\", status: \"failed\", detail: \"no agents configured\" };\n return { name: \"transport\", status: \"ok\", detail: `${agents.length} agent(s): ${agents.join(\", \")}` };\n}\n\nasync function probeSpin(): Promise<ProbeResult> {\n const lock = readJson(join(home, \"bridge.lock\"));\n if (!lock?.pid || !pidAlive(lock.pid)) return { name: \"spin\", status: \"failed\", detail: \"bridge not running\" };\n return { name: \"spin\", status: \"ok\", detail: \"bridge alive\" };\n}\n\nasync function probeKanban(): Promise<ProbeResult> {\n const dbPath = join(home, \"kanban\", \"kanban.db\");\n if (!existsSync(dbPath)) return { name: \"kanban\", status: \"skipped\", detail: \"kanban.db not found\" };\n const sharedNm = join(homedir(), \".local\", \"lib\", \"node_modules\", \"better-sqlite3\");\n if (!existsSync(sharedNm)) return { name: \"kanban\", status: \"skipped\", detail: \"better-sqlite3 not installed (run: abtars deps install)\" };\n let Db: any;\n try {\n const { createRequire } = await import(\"node:module\");\n const _require = createRequire(import.meta.url);\n Db = _require(sharedNm);\n } catch (err) {\n return { name: \"kanban\", status: \"skipped\", detail: `better-sqlite3 not loadable: ${err instanceof Error ? err.message : String(err)}` };\n }\n try {\n const db = new Db(dbPath, { readonly: true });\n const row = db.prepare(\"SELECT COUNT(*) as cnt FROM kanban_board\").get() as { cnt: number };\n const stuck = db.prepare(\"SELECT COUNT(*) as cnt FROM kanban_board WHERE status='running' AND updated_at < datetime('now', '-10 minutes')\").get() as { cnt: number };\n db.close();\n const detail = stuck.cnt > 0 ? `${row.cnt} cards, ${stuck.cnt} stuck` : `${row.cnt} cards`;\n return { name: \"kanban\", status: stuck.cnt > 0 ? \"failed\" : \"ok\", detail };\n } catch (err) {\n return { name: \"kanban\", status: \"skipped\", detail: `kanban.db query failed: ${err instanceof Error ? err.message : String(err)}` };\n }\n}\n\nasync function probeSkills(): Promise<ProbeResult> {\n const catalog = join(home, \"skills\", \"skills_catalog.md\");\n if (!existsSync(catalog)) return { name: \"skills\", status: \"failed\", detail: \"skills_catalog.md missing\" };\n const content = readFileSync(catalog, \"utf-8\");\n const count = (content.match(/^## /gm) || []).length;\n if (count === 0) return { name: \"skills\", status: \"failed\", detail: \"catalog empty\" };\n return { name: \"skills\", status: \"ok\", detail: `${count} loaded` };\n}\n\nasync function probeSha(): Promise<ProbeResult> {\n // Check if healer skill exists in catalog\n const catalog = join(home, \"skills\", \"skills_catalog.md\");\n if (!existsSync(catalog)) return { name: \"sha\", status: \"skipped\", detail: \"no catalog\" };\n const content = readFileSync(catalog, \"utf-8\");\n if (/self.heal|healer|auto.fix/i.test(content)) return { name: \"sha\", status: \"ok\", detail: \"rules loaded\" };\n // Check sha-policy.json\n if (existsSync(join(configDir, \"sha-policy.json\"))) return { name: \"sha\", status: \"ok\", detail: \"rules loaded\" };\n return { name: \"sha\", status: \"skipped\", detail: \"no healer rules configured\" };\n}\n\n// \u2500\u2500 Tribe Probes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function probeAgentApi(): Promise<ProbeResult> {\n const env = readEnv();\n if (env.get(\"ENABLE_AGENT_API\") !== \"true\") return { name: \"agent-api\", status: \"skipped\", detail: \"not enabled\" };\n const port = parseInt(env.get(\"AGENT_API_PORT\") || \"7100\", 10);\n try {\n const { createConnection } = await import(\"node:net\");\n await new Promise<void>((resolve, reject) => {\n const sock = createConnection({ port, host: \"127.0.0.1\" }, () => { sock.destroy(); resolve(); });\n sock.on(\"error\", reject);\n sock.setTimeout(2000, () => { sock.destroy(); reject(new Error(\"timeout\")); });\n });\n return { name: \"agent-api\", status: \"ok\", detail: `:${port}` };\n } catch {\n return { name: \"agent-api\", status: \"failed\", detail: `:${port} not listening` };\n }\n}\n\nasync function probePeers(): Promise<ProbeResult> {\n const peersPath = join(configDir, \"peers.json\");\n const peers = readJson(peersPath);\n if (!peers) return { name: \"peers\", status: \"skipped\", detail: \"peers.json missing\" };\n const peerCount = Object.keys(peers.peers ?? {}).length;\n if (peerCount === 0) return { name: \"peers\", status: \"ok\", detail: \"no peers configured\" };\n\n const lock = readJson(join(home, \"bridge.lock\"));\n const gossipAge = lock?.lastGossipBroadcast ? ago(Date.now() - lock.lastGossipBroadcast) : \"unknown\";\n return { name: \"peers\", status: \"ok\", detail: `${peerCount} configured, gossip: ${gossipAge}` };\n}\n\nasync function probeTls(): Promise<ProbeResult> {\n const env = readEnv();\n if (env.get(\"ENABLE_AGENT_API\") !== \"true\") return { name: \"tls\", status: \"skipped\", detail: \"agent-api disabled\" };\n const certExists = existsSync(join(configDir, \"identity.crt\"));\n const keyExists = existsSync(join(configDir, \"identity.tls.key\"));\n if (certExists && keyExists) return { name: \"tls\", status: \"ok\", detail: \"certs present\" };\n const missing = [!certExists && \"identity.crt\", !keyExists && \"identity.tls.key\"].filter(Boolean);\n return { name: \"tls\", status: \"failed\", detail: `missing: ${missing.join(\", \")}` };\n}\n\nasync function probeA2a(): Promise<ProbeResult> {\n const peersPath = join(configDir, \"peers.json\");\n const peers = readJson(peersPath) as { gossipSecret?: string; peers?: Record<string, { token?: string }>; self?: { udpPort?: number } } | null;\n if (!peers?.self?.udpPort) return { name: \"a2a\", status: \"skipped\", detail: \"no gossip port configured\" };\n\n const port = peers.self.udpPort;\n try {\n const dgram = await import(\"node:dgram\");\n const { createHmac } = await import(\"node:crypto\");\n const key = peers.gossipSecret ?? Object.values(peers.peers ?? {})[0]?.token ?? \"default\";\n const payload = JSON.stringify({ type: \"ping\", name: \"__doctor__\" });\n const sig = createHmac(\"sha256\", key).update(payload).digest(\"base64url\").slice(0, 16);\n const ping = Buffer.from(`${payload}|${sig}`);\n\n const alive = await new Promise<boolean>((resolve) => {\n const sock = dgram.createSocket(\"udp4\");\n const timer = setTimeout(() => { sock.close(); resolve(false); }, 500);\n sock.on(\"message\", () => { clearTimeout(timer); sock.close(); resolve(true); });\n sock.on(\"error\", () => { clearTimeout(timer); sock.close(); resolve(false); });\n sock.send(ping, port, \"127.0.0.1\");\n });\n return { name: \"a2a\", status: alive ? \"ok\" : \"failed\", detail: alive ? `UDP :${port} alive` : `UDP :${port} no response` };\n } catch {\n return { name: \"a2a\", status: \"failed\", detail: \"UDP probe error\" };\n }\n}\n\n// \u2500\u2500 Soul Probes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function probeMind(): Promise<ProbeResult> {\n try {\n const { loadAbmind } = await import(\"../../utils/abmind-lazy.js\");\n const mod = await loadAbmind();\n if (!mod) return { name: \"mind\", status: \"skipped\", detail: \"abmind not installed\" };\n return { name: \"mind\", status: \"ok\", detail: \"abmind loaded (in-process)\" };\n } catch {\n return { name: \"mind\", status: \"skipped\", detail: \"abmind load failed\" };\n }\n}\n\n// \u2500\u2500 Runner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function runAllProbes(): Promise<DoctorOutput> {\n const start = Date.now();\n\n const [body, heart, brain, soul, tribe] = await Promise.all([\n Promise.all([probePlatforms(), probeDashboard(), probeSecurity(), probeWatchdog(), probeSingleBridge()].map(p => timedProbe(() => p))),\n Promise.all([probeHeartbeat()].map(p => timedProbe(() => p))),\n Promise.all([probeTransport(), probeSpin(), probeKanban(), probeSkills(), probeSha()].map(p => timedProbe(() => p))),\n Promise.all([probeMind()].map(p => timedProbe(() => p))),\n Promise.all([probeAgentApi(), probePeers(), probeTls(), probeA2a()].map(p => timedProbe(() => p))),\n ]);\n\n return { version: \"1.0\", totalMs: Date.now() - start, layers: { body, heart, brain, soul, tribe } };\n}\n\n// \u2500\u2500 Fix Logic \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function runFixes(): Promise<FixResult[]> {\n const { chmodSync, unlinkSync, mkdirSync, existsSync: ex, readdirSync: rd, statSync: st, readFileSync: rf, writeFileSync: wf } = await import(\"node:fs\");\n const { spawnSync } = await import(\"node:child_process\");\n const fixes: FixResult[] = [];\n\n function fix(probe: string, action: string, fn: () => void): void {\n try { fn(); fixes.push({ probe, action, success: true }); }\n catch { fixes.push({ probe, action, success: false }); }\n }\n\n // 1. chmod 700 sensitive dirs\n for (const dir of [\"config\", \"secret\", \"auth\", \"hooks\"]) {\n const p = join(home, dir);\n if (ex(p) && (st(p).mode & 0o777) !== 0o700) {\n fix(\"security\", `${dir}/ \u2192 700`, () => chmodSync(p, 0o700));\n }\n }\n\n // 2. chmod 600 secret files\n const secretDir = join(home, \"secret\");\n if (ex(secretDir)) {\n for (const f of rd(secretDir)) {\n const fp = join(secretDir, f);\n if (st(fp).isFile() && (st(fp).mode & 0o777) !== 0o600) {\n fix(\"security\", `${f} \u2192 600`, () => chmodSync(fp, 0o600));\n }\n }\n }\n\n // 3. chmod 600 config files\n if (ex(configDir)) {\n for (const f of rd(configDir)) {\n const fp = join(configDir, f);\n if (st(fp).isFile() && (st(fp).mode & 0o777) !== 0o600) {\n fix(\"security\", `config/${f} \u2192 600`, () => chmodSync(fp, 0o600));\n }\n }\n }\n\n // 4. Stale deploy.lock\n const deployLock = join(home, \"deploy.lock\");\n if (ex(deployLock)) {\n const lock = readJson(deployLock);\n const lockAge = lock?.startedAt ? (Date.now() - new Date(lock.startedAt).getTime()) / 1000 : 9999;\n const lockPid = lock?.pid ?? 0;\n if (lockAge > 300 && (lockPid === 0 || !pidAlive(lockPid))) {\n fix(\"watchdog\", \"removed stale deploy.lock\", () => unlinkSync(deployLock));\n }\n }\n\n // 5. Stale .start-reason\n const startReason = join(home, \".start-reason\");\n if (ex(startReason)) {\n const age = (Date.now() - st(startReason).mtimeMs) / 1000;\n if (age > 300) fix(\"watchdog\", \"removed stale .start-reason\", () => unlinkSync(startReason));\n }\n\n // 6. Create missing dirs\n for (const dir of [\"logs\", \"workspace\", \"overflow\", \"received\"]) {\n const p = join(home, dir);\n if (!ex(p)) fix(\"watchdog\", `created ${dir}/`, () => mkdirSync(p, { recursive: true }));\n }\n\n // 7. Kill orphan CLI processes\n try {\n const lock = readJson(join(home, \"bridge.lock\"));\n const bridgePid = lock?.pid ?? 0;\n const wdPid = lock?.watchdogPid ?? 0;\n\n // Orphan kiro-cli\n const kiro = spawnSync(\"pgrep\", [\"-f\", \"kiro-cli.*acp\"], { encoding: \"utf-8\" });\n if (kiro.stdout) {\n for (const pid of kiro.stdout.trim().split(\"\\n\").filter(Boolean).map(Number)) {\n if (pid > 0 && pid !== bridgePid && pid !== wdPid && pid !== process.pid) {\n fix(\"brain\", `killed orphan kiro-cli ${pid}`, () => process.kill(pid, \"SIGTERM\"));\n }\n }\n }\n\n // Orphan abtars-sleep\n const sleep = spawnSync(\"pgrep\", [\"-f\", \"abtars-sleep\"], { encoding: \"utf-8\" });\n if (sleep.stdout) {\n for (const pid of sleep.stdout.trim().split(\"\\n\").filter(Boolean).map(Number)) {\n if (pid > 0 && pid !== bridgePid) {\n fix(\"brain\", `killed orphan abtars-sleep ${pid}`, () => process.kill(pid, \"SIGTERM\"));\n }\n }\n }\n } catch { /* pgrep not available or no orphans */ }\n\n // 8. Stale locks/sockets\n for (const f of [\"sleep.lock\", \"memory.sock\"]) {\n const p = join(home, f);\n if (ex(p)) {\n const age = (Date.now() - st(p).mtimeMs) / 1000;\n const lock = readJson(join(home, \"bridge.lock\"));\n if (age > 600 && (!lock?.pid || !pidAlive(lock.pid))) {\n fix(\"watchdog\", `removed stale ${f}`, () => unlinkSync(p));\n }\n }\n }\n\n // 9. Retention: delete old logs/overflow/media\n const LOGS_KEEP_DAYS = 7;\n const DATA_KEEP_DAYS = 30;\n try {\n const cutoffLogs = Date.now() - LOGS_KEEP_DAYS * 86400_000;\n const cutoffData = Date.now() - DATA_KEEP_DAYS * 86400_000;\n\n for (const [dir, cutoff] of [[join(home, \"logs\"), cutoffLogs], [join(home, \"overflow\"), cutoffData], [join(home, \"received\", \"media\"), cutoffLogs]] as const) {\n if (!ex(dir)) continue;\n let deleted = 0;\n for (const f of rd(dir)) {\n const fp = join(dir, f);\n if (st(fp).isFile() && st(fp).mtimeMs < cutoff) { unlinkSync(fp); deleted++; }\n }\n if (deleted > 0) fixes.push({ probe: \"retention\", action: `deleted ${deleted} stale file(s) from ${dir.split(\"/\").pop()}`, success: true });\n }\n\n // Truncate audit.jsonl if >10MB\n const auditPath = join(home, \"auth\", \"audit.jsonl\");\n if (ex(auditPath) && st(auditPath).size > 10_000_000) {\n const lines = rf(auditPath, \"utf-8\").split(\"\\n\");\n wf(auditPath, lines.slice(-1000).join(\"\\n\"));\n fixes.push({ probe: \"retention\", action: \"truncated audit.jsonl\", success: true });\n }\n } catch { /* retention errors non-fatal */ }\n\n // 10. Kill duplicate bridges\n try {\n const lock = readJson(join(home, \"bridge.lock\"));\n const expectedPid = lock?.pid ?? 0;\n const pgrep = spawnSync(\"pgrep\", [\"-f\", \"abtars.*main\"], { encoding: \"utf-8\" });\n if (pgrep.stdout) {\n for (const pid of pgrep.stdout.trim().split(\"\\n\").filter(Boolean).map(Number)) {\n if (pid > 0 && pid !== expectedPid && pid !== process.pid) {\n fix(\"watchdog\", `killed duplicate bridge ${pid}`, () => process.kill(pid, \"SIGTERM\"));\n }\n }\n }\n } catch { /* non-fatal */ }\n\n // 11. Hooks dir perms\n const hooksDir = join(home, \"hooks\");\n if (ex(hooksDir) && (st(hooksDir).mode & 0o777) !== 0o700) {\n fix(\"security\", \"hooks/ \u2192 700\", () => chmodSync(hooksDir, 0o700));\n }\n\n // 12. Install watchdog service if missing\n try {\n const manifest = readJson(join(home, \"manifest.json\"));\n if (manifest?.installMode === \"daemon\") {\n const { platform } = await import(\"node:os\");\n if (platform() === \"darwin\") {\n const plist = `${home}/com.abtars.watchdog.plist`;\n const dst = `${process.env[\"HOME\"]}/Library/LaunchAgents/com.abtars.watchdog.plist`;\n if (ex(plist) && !ex(dst)) {\n fix(\"watchdog\", \"installed LaunchAgent\", () => {\n const { copyFileSync } = require(\"node:fs\");\n copyFileSync(plist, dst);\n spawnSync(\"launchctl\", [\"load\", dst]);\n });\n }\n } else {\n const svc = `${home}/abtars-watchdog.service`;\n const dst = `${process.env[\"HOME\"]}/.config/systemd/user/abtars-watchdog.service`;\n if (ex(svc) && !ex(dst)) {\n fix(\"watchdog\", \"installed systemd unit\", () => {\n mkdirSync(join(process.env[\"HOME\"]!, \".config\", \"systemd\", \"user\"), { recursive: true });\n const { copyFileSync } = require(\"node:fs\");\n copyFileSync(svc, dst);\n spawnSync(\"systemctl\", [\"--user\", \"enable\", \"--now\", \"abtars-watchdog.service\"]);\n });\n }\n }\n }\n } catch { /* non-fatal */ }\n\n return fixes;\n}\n\n// \u2500\u2500 Renderer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst ICON = { ok: \"\u2713\", failed: \"\u2717\", skipped: \"~\" } as const;\n\nexport function renderHuman(output: DoctorOutput): string {\n const lines: string[] = [];\n for (const [layer, probes] of Object.entries(output.layers) as [string, ProbeResult[]][]) {\n lines.push(`${layer.charAt(0).toUpperCase() + layer.slice(1)}:`);\n for (const p of probes) {\n const ms = p.ms && p.ms > 500 ? ` (${p.ms}ms)` : \"\";\n const detail = p.detail ? ` \u2014 ${p.detail}` : \"\";\n lines.push(` ${ICON[p.status]} ${p.name}${ms}${detail}`);\n }\n }\n const total = Object.values(output.layers).flat();\n const okCount = total.filter(r => r.status === \"ok\").length;\n lines.push(`\\n${okCount}/${total.length} ok (${(output.totalMs / 1000).toFixed(1)}s)`);\n return lines.join(\"\\n\");\n}\n\nexport function renderJson(output: DoctorOutput): string {\n return JSON.stringify(output, null, 2);\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,105 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __bundleCreateRequire } from 'node:module'; import { fileURLToPath as __bundleFileURLToPath } from 'node:url'; import { dirname as __bundleDirname } from 'node:path'; const require = __bundleCreateRequire(import.meta.url); const __chunk_filename = __bundleFileURLToPath(import.meta.url); const __chunk_dirname = __bundleDirname(__chunk_filename);
3
- import {
4
- PEERS_SCHEMA,
5
- init_config_validator,
6
- validateShape
7
- } from "./chunk-LUNA6PM5.js";
8
- import {
9
- init_logger,
10
- logInfo,
11
- logWarn
12
- } from "./chunk-GWILHZPT.js";
13
- import {
14
- abtarsHome,
15
- init_paths
16
- } from "./chunk-GALQBVKO.js";
17
- import {
18
- __esm,
19
- __export
20
- } from "./chunk-7K2YZTLD.js";
21
-
22
- // src/components/peer-config.ts
23
- var peer_config_exports = {};
24
- __export(peer_config_exports, {
25
- clearPeerConfigCache: () => clearPeerConfigCache,
26
- loadPeerConfig: () => loadPeerConfig
27
- });
28
- import { existsSync, readFileSync } from "node:fs";
29
- import { join } from "node:path";
30
- function loadPeerConfig() {
31
- if (_config) return _config;
32
- const p = join(abtarsHome(), "config", "peers.json");
33
- if (!existsSync(p)) {
34
- _config = { self: { name: "default" }, peers: {}, ...DEFAULTS };
35
- return _config;
36
- }
37
- try {
38
- const raw = JSON.parse(readFileSync(p, "utf-8"));
39
- validateShape(raw, PEERS_SCHEMA, "peers.json");
40
- const peers = {};
41
- if (raw.peers && typeof raw.peers === "object") {
42
- for (const [name, entry] of Object.entries(raw.peers)) {
43
- const e = entry;
44
- if (typeof e.host === "string" && typeof e.port === "number" && typeof e.token === "string") {
45
- peers[name] = {
46
- host: e.host,
47
- port: e.port,
48
- token: e.token,
49
- ...typeof e.trust === "number" ? { trust: e.trust } : {},
50
- ...e.mode === "signed" ? { mode: "signed" } : {},
51
- ...typeof e.verifyKey === "string" ? { verifyKey: e.verifyKey } : {},
52
- ...typeof e.udpPort === "number" ? { udpPort: e.udpPort } : {},
53
- ...typeof e.certFingerprint === "string" ? { certFingerprint: e.certFingerprint } : {},
54
- ...typeof e.certPem === "string" ? { certPem: e.certPem } : {},
55
- ...Array.isArray(e.allowedTools) ? { allowedTools: e.allowedTools } : {},
56
- ...Array.isArray(e.allowedRead) ? { allowedRead: e.allowedRead } : {},
57
- ...Array.isArray(e.allowedWrite) ? { allowedWrite: e.allowedWrite } : {}
58
- };
59
- } else {
60
- logWarn(TAG, `Skipped peer '${name}' \u2014 missing host/port/token`);
61
- }
62
- }
63
- }
64
- _config = {
65
- self: {
66
- name: typeof raw.self?.name === "string" ? raw.self.name : "default",
67
- ...typeof raw.self?.signingKey === "string" ? { signingKey: raw.self.signingKey } : {},
68
- ...typeof raw.self?.udpPort === "number" ? { udpPort: raw.self.udpPort } : {}
69
- },
70
- peers,
71
- ...typeof raw.gossipSecret === "string" ? { gossipSecret: raw.gossipSecret } : {},
72
- maxHops: typeof raw.maxHops === "number" ? raw.maxHops : DEFAULTS.maxHops,
73
- timeoutMs: typeof raw.timeoutMs === "number" ? raw.timeoutMs : DEFAULTS.timeoutMs
74
- };
75
- const names = Object.keys(peers);
76
- if (names.length > 0) logInfo(TAG, `Loaded ${names.length} peer(s): ${names.join(", ")} (self: ${_config.self.name})`);
77
- return _config;
78
- } catch (err) {
79
- logWarn(TAG, `Failed to parse peers.json: ${err instanceof Error ? err.message : String(err)}`);
80
- _config = { self: { name: "default" }, peers: {}, ...DEFAULTS };
81
- return _config;
82
- }
83
- }
84
- function clearPeerConfigCache() {
85
- _config = null;
86
- }
87
- var TAG, DEFAULTS, _config;
88
- var init_peer_config = __esm({
89
- "src/components/peer-config.ts"() {
90
- init_paths();
91
- init_logger();
92
- init_config_validator();
93
- TAG = "peer-config";
94
- DEFAULTS = { maxHops: 12, timeoutMs: 6e4 };
95
- _config = null;
96
- }
97
- });
98
-
99
- export {
100
- loadPeerConfig,
101
- clearPeerConfigCache,
102
- peer_config_exports,
103
- init_peer_config
104
- };
105
- //# sourceMappingURL=chunk-4S554KLW.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/components/peer-config.ts"],
4
- "sourcesContent": ["/**\n * peer-config.ts \u2014 load and validate ~/.abtars/config/peers.json (#392).\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../paths.js\";\nimport { logInfo, logWarn } from \"./logger.js\";\nimport { validateShape, PEERS_SCHEMA } from \"./config-validator.js\";\n\nconst TAG = \"peer-config\";\n\nexport interface PeerEntry {\n host: string;\n port: number;\n token: string;\n trust?: number;\n mode?: \"plain\" | \"signed\";\n verifyKey?: string;\n udpPort?: number;\n certFingerprint?: string;\n certPem?: string;\n allowedTools?: string[];\n allowedRead?: string[];\n allowedWrite?: string[];\n transport?: \"http\" | \"ws-outbound\";\n}\n\nexport interface PeerConfig {\n self: { name: string; signingKey?: string; udpPort?: number };\n peers: Record<string, PeerEntry>;\n gossipSecret?: string;\n maxHops: number;\n timeoutMs: number;\n}\n\nconst DEFAULTS: Omit<PeerConfig, \"peers\" | \"self\"> = { maxHops: 12, timeoutMs: 60000 };\n\nlet _config: PeerConfig | null = null;\n\nexport function loadPeerConfig(): PeerConfig {\n if (_config) return _config;\n const p = join(abtarsHome(), \"config\", \"peers.json\");\n if (!existsSync(p)) {\n _config = { self: { name: \"default\" }, peers: {}, ...DEFAULTS };\n return _config;\n }\n try {\n const raw = JSON.parse(readFileSync(p, \"utf-8\"));\n validateShape(raw, PEERS_SCHEMA, \"peers.json\");\n const peers: Record<string, PeerEntry> = {};\n if (raw.peers && typeof raw.peers === \"object\") {\n for (const [name, entry] of Object.entries(raw.peers)) {\n const e = entry as Record<string, unknown>;\n if (typeof e.host === \"string\" && typeof e.port === \"number\" && typeof e.token === \"string\") {\n peers[name] = {\n host: e.host, port: e.port, token: e.token,\n ...(typeof e.trust === \"number\" ? { trust: e.trust } : {}),\n ...(e.mode === \"signed\" ? { mode: \"signed\" as const } : {}),\n ...(typeof e.verifyKey === \"string\" ? { verifyKey: e.verifyKey } : {}),\n ...(typeof e.udpPort === \"number\" ? { udpPort: e.udpPort } : {}),\n ...(typeof e.certFingerprint === \"string\" ? { certFingerprint: e.certFingerprint } : {}),\n ...(typeof e.certPem === \"string\" ? { certPem: e.certPem } : {}),\n ...(Array.isArray(e.allowedTools) ? { allowedTools: e.allowedTools as string[] } : {}),\n ...(Array.isArray(e.allowedRead) ? { allowedRead: e.allowedRead as string[] } : {}),\n ...(Array.isArray(e.allowedWrite) ? { allowedWrite: e.allowedWrite as string[] } : {}),\n };\n } else {\n logWarn(TAG, `Skipped peer '${name}' \u2014 missing host/port/token`);\n }\n }\n }\n _config = {\n self: {\n name: typeof raw.self?.name === \"string\" ? raw.self.name : \"default\",\n ...(typeof raw.self?.signingKey === \"string\" ? { signingKey: raw.self.signingKey } : {}),\n ...(typeof raw.self?.udpPort === \"number\" ? { udpPort: raw.self.udpPort } : {}),\n },\n peers,\n ...(typeof raw.gossipSecret === \"string\" ? { gossipSecret: raw.gossipSecret } : {}),\n maxHops: typeof raw.maxHops === \"number\" ? raw.maxHops : DEFAULTS.maxHops,\n timeoutMs: typeof raw.timeoutMs === \"number\" ? raw.timeoutMs : DEFAULTS.timeoutMs,\n };\n const names = Object.keys(peers);\n if (names.length > 0) logInfo(TAG, `Loaded ${names.length} peer(s): ${names.join(\", \")} (self: ${_config.self.name})`);\n return _config;\n } catch (err) {\n logWarn(TAG, `Failed to parse peers.json: ${err instanceof Error ? err.message : String(err)}`);\n _config = { self: { name: \"default\" }, peers: {}, ...DEFAULTS };\n return _config;\n }\n}\n\nexport function clearPeerConfigCache(): void { _config = null; }\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/components/spin-profiles.ts", "../src/components/spin-types.ts"],
4
- "sourcesContent": ["/**\n * spin-profiles.ts \u2014 Per-session-type behavior registry (#1271).\n *\n * Replaces the per-type `if (type === ...)` branches that used to live in\n * `execute()` and `executeOrc()`. Adding a new SessionType = adding a row to\n * SESSION_PROFILES; `spin()` itself contains no type-specific code.\n */\n\nimport type { AgentName } from \"./subagent-runtime.js\";\nimport type { ManagedSession, SessionType } from \"./spin-types.js\";\nimport { sessionType } from \"./spin-types.js\";\n\n/** A prompt decorator wraps/prepends context onto the outgoing prompt. */\nexport type PromptDecorator = (\n prompt: string,\n ctx: { session: ManagedSession; cardId?: number; parentCardId?: number },\n) => Promise<string> | string;\n\nexport interface SessionProfile {\n /** Agent to route the prompt to. */\n agent: AgentName;\n /** \"oneshot\" uses runtime.complete(); \"persistent\" uses session.transport.sendPrompt. */\n transportMode: \"oneshot\" | \"persistent\";\n /** How spin() resolves the ManagedSession \u2014 replaces per-type branches. */\n resolution: \"active\" | \"singleton\" | \"transient\";\n /** What happens to the session record after the call returns. */\n terminateAfter: \"call\" | \"response\" | \"external\";\n /** Ordered prompt transforms (decorator at index N prepends; last in list = outermost). */\n decorators: readonly PromptDecorator[];\n /** Side-effect hook fired before the prompt is sent. */\n beforePrompt?: (session: ManagedSession, cardId?: number) => Promise<void> | void;\n /** Side-effect hook fired after the prompt resolves (success OR failure). */\n afterPrompt?: (session: ManagedSession, cardId?: number) => Promise<void> | void;\n}\n\n// \u2500\u2500 Reusable decorators \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst soulBundle: PromptDecorator = async (prompt, { session }) => {\n const { buildSoulBundle } = await import(\"./soul-bundle.js\");\n const bundle = buildSoulBundle(sessionType(session));\n return bundle ? `${bundle}\\n\\n---\\n\\n${prompt}` : prompt;\n};\n\nconst channelMessages: PromptDecorator = async (prompt, { cardId, parentCardId }) => {\n if (cardId === undefined) return prompt;\n const { channelUnread } = await import(\"./tasks/kanban-channel.js\");\n const workerName = `Worker-${String(cardId).padStart(2, \"0\")}`;\n const msgs = channelUnread(parentCardId ?? cardId, workerName);\n if (msgs.length === 0) return prompt;\n const lines = msgs.map(m => `[${m.from_agent}\u2192${m.to_agent}]${m.directive ? \" \u26A1\" : \"\"} ${m.message}`);\n return `[CHANNEL \u2014 ${msgs.length} message(s) for ${workerName}]\\n${lines.join(\"\\n\")}\\n[/CHANNEL]\\n\\n${prompt}`;\n};\n\nconst orcContext: PromptDecorator = async (prompt, { cardId }) => {\n const { localDateTime } = await import(\"../utils/local-time.js\");\n return `[CONTEXT \u2014 do not respond to this section]\\n[PROJECT] card #${cardId}\\n[CURRENT TIME] ${localDateTime()}\\n[/CONTEXT]\\n\\n${prompt}`;\n};\n\nconst orcNotifications: PromptDecorator = async (prompt, { cardId }) => {\n if (cardId === undefined) return prompt;\n const { drainOrcNotifications } = await import(\"./spin-notifications.js\");\n const n = drainOrcNotifications(cardId);\n return n.length ? `${n.join(\"\\n\")}\\n\\n${prompt}` : prompt;\n};\n\nconst orcChannel: PromptDecorator = async (prompt, { cardId }) => {\n if (cardId === undefined) return prompt;\n const { channelUnread } = await import(\"./tasks/kanban-channel.js\");\n const msgs = channelUnread(cardId, \"Orc\");\n if (msgs.length === 0) return prompt;\n const lines = msgs.map(m => `[${m.from_agent}\u2192${m.to_agent}]${m.directive ? \" \u26A1\" : \"\"} ${m.message}`);\n return `[CHANNEL \u2014 ${msgs.length} message(s)]\\n${lines.join(\"\\n\")}\\n[/CHANNEL]\\n\\n${prompt}`;\n};\n\n// \u2500\u2500 The registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const SESSION_PROFILES: Record<SessionType, SessionProfile> = {\n A: { agent: \"professor\", transportMode: \"persistent\", resolution: \"active\", terminateAfter: \"response\", decorators: [] },\n B: { agent: \"browsie\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"response\", decorators: [soulBundle] },\n C: { agent: \"coding\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"response\", decorators: [soulBundle] },\n T: { agent: \"professor\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"response\", decorators: [soulBundle, channelMessages] },\n P: { agent: \"professor\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"response\", decorators: [soulBundle] },\n S: { agent: \"coding\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"call\", decorators: [] },\n W: { agent: \"browsie\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"response\", decorators: [soulBundle, channelMessages] },\n H: { agent: \"coding\", transportMode: \"oneshot\", resolution: \"transient\", terminateAfter: \"response\", decorators: [soulBundle] },\n D: { agent: \"dreamy\", transportMode: \"persistent\", resolution: \"transient\", terminateAfter: \"external\", decorators: [] },\n O: {\n agent: \"browsie\", // \u2190 preserves current Orc agent (NOT professor)\n transportMode: \"persistent\",\n resolution: \"singleton\", // \u2190 one Orc; reuse the visible O session\n terminateAfter: \"external\",\n decorators: [orcContext, soulBundle, orcNotifications, orcChannel],\n beforePrompt: async (_session, cardId) => {\n const { updateBridgeLockField } = await import(\"./transport/bridge-lock-transport.js\");\n const { setActiveOrcCard } = await import(\"./transport/orc-tools.js\");\n if (cardId !== undefined) { updateBridgeLockField(\"orc_active\", cardId); setActiveOrcCard(cardId); }\n },\n afterPrompt: async () => {\n const { updateBridgeLockField } = await import(\"./transport/bridge-lock-transport.js\");\n const { setActiveOrcCard } = await import(\"./transport/orc-tools.js\");\n updateBridgeLockField(\"orc_active\", null); setActiveOrcCard(null);\n },\n },\n};\n\nexport function profileFor(type: SessionType): SessionProfile {\n return SESSION_PROFILES[type];\n}\n", "/**\n * spin-types.ts \u2014 Types and helpers for the Spin session system (#943, #953).\n * Importable by any module that needs ManagedSession or SessionType without pulling in the full Spin class.\n */\n\nimport type { AgentName } from \"./subagent-runtime.js\";\nimport type { IKiroTransport } from \"./transport/kiro-transport.js\";\nimport type { SandboxPolicy } from \"./tool-sandbox.js\";\nimport { logError } from \"./logger.js\";\n\nexport type SessionType = \"A\" | \"B\" | \"C\" | \"T\" | \"P\" | \"S\" | \"O\" | \"W\" | \"D\" | \"H\";\n\nexport interface ManagedSession {\n id: string; // \"1749563282_A_01\"\n userId: string;\n platform: string;\n chatId: number;\n threadId?: number | string;\n\n // Transport\n transport?: IKiroTransport;\n delivery: \"streaming\" | \"simple\";\n model?: string;\n provider?: string;\n pid?: number;\n peer?: string; // remote host name (hollow session)\n remoteSessionId?: string; // session ID on the peer\n\n // Lifecycle\n active: boolean; // true = current session for this userId+platform\n status: \"creating\" | \"ready\" | \"paused\" | \"ended\";\n idleTimeoutMs: number;\n lastActiveAt: number;\n motherId?: string;\n name?: string;\n\n // Context\n workingDir?: string;\n contextPercent?: number;\n\n // Metrics\n messageCount: number;\n tokenCount: number;\n toolCallCount: number;\n\n // Session event log (last 5 events)\n log: string[];\n\n // Display\n shortIndex: number;\n\n // Pipeline state (#1040 \u2014 merged from SessionRegistry)\n busy: boolean;\n queue: Array<{ msg: import(\"../types/platform.js\").InboundMessage; adapter: import(\"../types/platform.js\").PlatformAdapter }>;\n fullMode: boolean;\n pendingStart: boolean;\n seen: boolean;\n compacting: boolean;\n ctxWarned: boolean;\n compactFailures: number;\n primingTerms: string[];\n pendingWait?: string;\n\n // Completion buffer (#1040 \u2014 merged from completion-buffer.ts)\n completions: Array<{ sessionId: string; goal: string; status: string; result: string; elapsedMs: number; inputTokens: number; outputTokens: number }>;\n\n // Session-scoped metadata (#1271). Set ONCE at session allocation from\n // `SpinSessionSpec.metadata`; never merged on `sessionId` reuse. Use\n // `onStepComplete`'s event for per-step data.\n metadata?: Record<string, unknown>;\n}\n\nexport interface SpinRequest {\n type: SessionType;\n agent?: import(\"./subagent-runtime.js\").AgentName; // override typeAgent() default\n goal: string;\n title?: string;\n source: \"task\" | \"user\" | \"agent\" | \"peer\";\n cardId?: number;\n parentCardId?: number;\n deliveryMode?: \"silent\" | \"deliver\" | \"announce\";\n priority?: string;\n tools?: SandboxPolicy;\n timeoutMs?: number;\n callbackPeer?: string; // #675: peer to notify on completion\n sourcePeer?: string; // #949: which peer delegated this task\n chatId?: string; // #1008: delivery target chat (fallback: masterChatId)\n maxToolRounds?: number; // #1283: per-task circuit breaker override\n}\n\n// \u2500\u2500 #1271: unified session API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface SpinSessionSpec {\n type: SessionType;\n\n // Identity\n userId?: string; // default: master user\n platform?: string; // default: \"background\"\n chatId?: number; // default: 0\n\n // Work\n goal?: string; // user-facing \u2192 creates kanban card\n prompt?: string; // background one-shot \u2192 no card\n\n // Reuse / continuation (multi-step sleep, pipeline main turn)\n sessionId?: string; // reuse an existing session (send next prompt to it)\n\n // Lifecycle overrides (default comes from the profile)\n active?: boolean;\n persistent?: boolean;\n terminateAfter?: \"call\" | \"response\" | \"external\";\n\n // Kanban tracking\n cardId?: number;\n parentCardId?: number;\n title?: string;\n priority?: \"CRITICAL\" | \"HIGH\" | \"MEDIUM\" | \"LOW\";\n source?: \"task\" | \"user\" | \"agent\" | \"peer\";\n\n // Execution\n agent?: import(\"./subagent-runtime.js\").AgentName; // override the profile's agent\n timeoutMs?: number;\n maxToolRounds?: number; // #1283: per-task circuit breaker override\n\n // Delivery (continuation / pipeline)\n deliveryMode?: \"deliver\" | \"silent\" | \"announce\";\n imageContent?: unknown; // \u2192 sendPrompt arg 3 (image passthrough)\n callbackPeer?: string;\n sourcePeer?: string;\n // NOTE: no `stream` field. Streaming is a transport property\n // (transport.onIntermediateResponse / onToolCallStart / onSegmentBreak) that the\n // PIPELINE sets before calling spin() and resets in its finally \u2014 Spin never touches it.\n // sendPrompt is (sessionKey, message, image?, userId?) \u2014 4 args, no stream.\n\n // Extension / future-proofing\n metadata?: Record<string, unknown>; // session-scoped initial data, set ONCE at allocation\n // (not merged on sessionId-reuse \u2014 see design \u00A72)\n\n // Result\n await?: boolean;\n\n // Progress hook (partial-result reporting \u2014 sleep, workers)\n onStepComplete?: (event: StepEvent) => void | Promise<void>;\n}\n\nexport interface StepEvent {\n sessionId: string;\n cardId?: number;\n stepIndex: number; // 1-based call count within this session\n result?: string; // undefined on failure\n error?: Error;\n durationMs: number;\n inputTokens?: number; // per-call absolute (usage.input), not a delta\n outputTokens?: number; // per-call absolute (usage.output)\n}\n\nexport interface SpinResult {\n sessionId: string;\n cardId?: number;\n result?: string; // present when await: true\n}\n\nexport interface DispatchBackgroundOptions {\n prompt: string;\n type?: SessionType; // default \"S\" (ephemeral one-shot)\n agent?: import(\"./subagent-runtime.js\").AgentName; // override the profile agent\n timeoutMs?: number;\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function sessionType(session: ManagedSession): SessionType {\n const type = session.id.split(\"_\")[1];\n if (!type) logError(\"spin-types\", `Malformed session ID \"${session.id}\" \u2014 no type segment, defaulting to A`);\n return (type ?? \"A\") as SessionType;\n}\n\nexport function sessionCreatedAt(session: ManagedSession): number {\n return parseInt(session.id.split(\"_\")[0] ?? \"0\", 10) * 1000;\n}\n\nconst TYPE_LABELS: Record<SessionType, string> = {\n A: \"Main\", B: \"Browse\", C: \"Code\", T: \"Task\", P: \"Peer\",\n S: \"System\", O: \"Orc\", W: \"Worker\", D: \"Dreamy\", H: \"Healer\",\n};\n\nconst TYPE_AGENT_MAP: Partial<Record<SessionType, AgentName>> = {\n A: \"professor\", C: \"coding\", B: \"browsie\", D: \"dreamy\",\n O: \"professor\", T: \"professor\", W: \"browsie\", H: \"coding\",\n};\n\nexport function typeLabel(t: SessionType): string { return TYPE_LABELS[t]; }\n\n/** #1271: single source of truth = SessionProfile. Kept as fallback for callers\n * that import spin-types without pulling in spin-profiles. */\nexport function typeAgent(t: SessionType): AgentName {\n try {\n // Lazy require to avoid circular import (spin-profiles \u2192 spin-types).\n // The static map is also kept for back-compat in the standalone abmind path.\n const { SESSION_PROFILES } = require(\"./spin-profiles.js\") as typeof import(\"./spin-profiles.js\");\n return SESSION_PROFILES[t].agent;\n } catch {\n return TYPE_AGENT_MAP[t] ?? \"professor\";\n }\n}\n\nexport function parseSessionType(input: string): SessionType | null {\n switch (input.toLowerCase()) {\n case \"browse\": return \"B\";\n case \"code\": return \"C\";\n case \"task\": return \"T\";\n default: return null;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["SESSION_PROFILES"]
7
- }