abtars 0.1.0-alpha.1

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 (312) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +84 -0
  3. package/bundle/_registry.generated-M4WY2MMI.js +35 -0
  4. package/bundle/_registry.generated-M4WY2MMI.js.map +7 -0
  5. package/bundle/abtars-browser.js +162 -0
  6. package/bundle/abtars-browser.js.map +7 -0
  7. package/bundle/abtars-cli.js +1438 -0
  8. package/bundle/abtars-cli.js.map +7 -0
  9. package/bundle/abtars-restart.js +12 -0
  10. package/bundle/abtars-restart.js.map +7 -0
  11. package/bundle/abtars-rss.js +165 -0
  12. package/bundle/abtars-rss.js.map +7 -0
  13. package/bundle/abtars-task.js +258 -0
  14. package/bundle/abtars-task.js.map +7 -0
  15. package/bundle/abtars.js +4072 -0
  16. package/bundle/abtars.js.map +7 -0
  17. package/bundle/agent-api-rate-limit-OQNFMXTZ.js +38 -0
  18. package/bundle/agent-api-rate-limit-OQNFMXTZ.js.map +7 -0
  19. package/bundle/agent-registry-LT4JNQH6.js +18 -0
  20. package/bundle/agent-registry-LT4JNQH6.js.map +7 -0
  21. package/bundle/agents/default.md +29 -0
  22. package/bundle/anthropic-adapter-2APTH3LA.js +40 -0
  23. package/bundle/anthropic-adapter-2APTH3LA.js.map +7 -0
  24. package/bundle/bridge-lock-transport-4AC2G5G6.js +39 -0
  25. package/bundle/bridge-lock-transport-4AC2G5G6.js.map +7 -0
  26. package/bundle/browse-delivery-JXBY36GK.js +17 -0
  27. package/bundle/browse-delivery-JXBY36GK.js.map +7 -0
  28. package/bundle/browser-ELNDVPLC.js +18 -0
  29. package/bundle/browser-ELNDVPLC.js.map +7 -0
  30. package/bundle/capability-CIL3G4FI.js +17 -0
  31. package/bundle/capability-CIL3G4FI.js.map +7 -0
  32. package/bundle/chunk-265TPOPC.js +289 -0
  33. package/bundle/chunk-265TPOPC.js.map +7 -0
  34. package/bundle/chunk-2UENBO6M.js +223 -0
  35. package/bundle/chunk-2UENBO6M.js.map +7 -0
  36. package/bundle/chunk-2UPU3OW6.js +67 -0
  37. package/bundle/chunk-2UPU3OW6.js.map +7 -0
  38. package/bundle/chunk-2XU2X4OI.js +125 -0
  39. package/bundle/chunk-2XU2X4OI.js.map +7 -0
  40. package/bundle/chunk-3B7BBE4F.js +758 -0
  41. package/bundle/chunk-3B7BBE4F.js.map +7 -0
  42. package/bundle/chunk-3E545J66.js +69 -0
  43. package/bundle/chunk-3E545J66.js.map +7 -0
  44. package/bundle/chunk-5R2ANXQ7.js +510 -0
  45. package/bundle/chunk-5R2ANXQ7.js.map +7 -0
  46. package/bundle/chunk-6CPN4IGS.js +507 -0
  47. package/bundle/chunk-6CPN4IGS.js.map +7 -0
  48. package/bundle/chunk-6NR3OHEW.js +88 -0
  49. package/bundle/chunk-6NR3OHEW.js.map +7 -0
  50. package/bundle/chunk-6SETMHNN.js +206 -0
  51. package/bundle/chunk-6SETMHNN.js.map +7 -0
  52. package/bundle/chunk-6UCRKRWR.js +644 -0
  53. package/bundle/chunk-6UCRKRWR.js.map +7 -0
  54. package/bundle/chunk-AR6GO6YC.js +83 -0
  55. package/bundle/chunk-AR6GO6YC.js.map +7 -0
  56. package/bundle/chunk-AZJIODTQ.js +54 -0
  57. package/bundle/chunk-AZJIODTQ.js.map +7 -0
  58. package/bundle/chunk-BHMZ4RCC.js +3706 -0
  59. package/bundle/chunk-BHMZ4RCC.js.map +7 -0
  60. package/bundle/chunk-BQ2L4GMG.js +9175 -0
  61. package/bundle/chunk-BQ2L4GMG.js.map +7 -0
  62. package/bundle/chunk-BSSBCSCL.js +159 -0
  63. package/bundle/chunk-BSSBCSCL.js.map +7 -0
  64. package/bundle/chunk-BUUVFUPO.js +157 -0
  65. package/bundle/chunk-BUUVFUPO.js.map +7 -0
  66. package/bundle/chunk-CEVRHKJY.js +131 -0
  67. package/bundle/chunk-CEVRHKJY.js.map +7 -0
  68. package/bundle/chunk-CWOHNFUV.js +39 -0
  69. package/bundle/chunk-CWOHNFUV.js.map +7 -0
  70. package/bundle/chunk-D2DCBO6M.js +228 -0
  71. package/bundle/chunk-D2DCBO6M.js.map +7 -0
  72. package/bundle/chunk-FMWKEPM7.js +31 -0
  73. package/bundle/chunk-FMWKEPM7.js.map +7 -0
  74. package/bundle/chunk-GRNENTPA.js +145 -0
  75. package/bundle/chunk-GRNENTPA.js.map +7 -0
  76. package/bundle/chunk-GST5T3WZ.js +93 -0
  77. package/bundle/chunk-GST5T3WZ.js.map +7 -0
  78. package/bundle/chunk-GUQVJC3U.js +299 -0
  79. package/bundle/chunk-GUQVJC3U.js.map +7 -0
  80. package/bundle/chunk-HX7Y7EYP.js +3659 -0
  81. package/bundle/chunk-HX7Y7EYP.js.map +7 -0
  82. package/bundle/chunk-JCJS4ZIB.js +296 -0
  83. package/bundle/chunk-JCJS4ZIB.js.map +7 -0
  84. package/bundle/chunk-JW6RU47G.js +184 -0
  85. package/bundle/chunk-JW6RU47G.js.map +7 -0
  86. package/bundle/chunk-LSPKJQCI.js +24 -0
  87. package/bundle/chunk-LSPKJQCI.js.map +7 -0
  88. package/bundle/chunk-M6VBAPNT.js +16 -0
  89. package/bundle/chunk-M6VBAPNT.js.map +7 -0
  90. package/bundle/chunk-MPX525QO.js +129 -0
  91. package/bundle/chunk-MPX525QO.js.map +7 -0
  92. package/bundle/chunk-MW6WDLU7.js +130 -0
  93. package/bundle/chunk-MW6WDLU7.js.map +7 -0
  94. package/bundle/chunk-NT3OBORC.js +215 -0
  95. package/bundle/chunk-NT3OBORC.js.map +7 -0
  96. package/bundle/chunk-NWDBD4PA.js +50 -0
  97. package/bundle/chunk-NWDBD4PA.js.map +7 -0
  98. package/bundle/chunk-OP7BTAWY.js +29 -0
  99. package/bundle/chunk-OP7BTAWY.js.map +7 -0
  100. package/bundle/chunk-PLCY3GFH.js +77 -0
  101. package/bundle/chunk-PLCY3GFH.js.map +7 -0
  102. package/bundle/chunk-PNEDC45Y.js +97 -0
  103. package/bundle/chunk-PNEDC45Y.js.map +7 -0
  104. package/bundle/chunk-QBGBT5QS.js +81 -0
  105. package/bundle/chunk-QBGBT5QS.js.map +7 -0
  106. package/bundle/chunk-RVE2N7FA.js +70 -0
  107. package/bundle/chunk-RVE2N7FA.js.map +7 -0
  108. package/bundle/chunk-TZHIDLDS.js +71910 -0
  109. package/bundle/chunk-TZHIDLDS.js.map +7 -0
  110. package/bundle/chunk-UCQ2WC3B.js +126 -0
  111. package/bundle/chunk-UCQ2WC3B.js.map +7 -0
  112. package/bundle/chunk-UHRP745J.js +214 -0
  113. package/bundle/chunk-UHRP745J.js.map +7 -0
  114. package/bundle/chunk-V76TVMCM.js +58 -0
  115. package/bundle/chunk-V76TVMCM.js.map +7 -0
  116. package/bundle/chunk-VVEDVGCR.js +981 -0
  117. package/bundle/chunk-VVEDVGCR.js.map +7 -0
  118. package/bundle/chunk-W6FAL35D.js +102 -0
  119. package/bundle/chunk-W6FAL35D.js.map +7 -0
  120. package/bundle/chunk-X6TERNVJ.js +15902 -0
  121. package/bundle/chunk-X6TERNVJ.js.map +7 -0
  122. package/bundle/chunk-X76UX47U.js +47 -0
  123. package/bundle/chunk-X76UX47U.js.map +7 -0
  124. package/bundle/chunk-XREWVCUO.js +518 -0
  125. package/bundle/chunk-XREWVCUO.js.map +7 -0
  126. package/bundle/chunk-Y6XAEX2Q.js +408 -0
  127. package/bundle/chunk-Y6XAEX2Q.js.map +7 -0
  128. package/bundle/chunk-YOCTDKKL.js +28 -0
  129. package/bundle/chunk-YOCTDKKL.js.map +7 -0
  130. package/bundle/chunk-ZXPXCDA6.js +160 -0
  131. package/bundle/chunk-ZXPXCDA6.js.map +7 -0
  132. package/bundle/commands-BHVUOU3V.js +31 -0
  133. package/bundle/commands-BHVUOU3V.js.map +7 -0
  134. package/bundle/completion-buffer-P253ONKF.js +13 -0
  135. package/bundle/completion-buffer-P253ONKF.js.map +7 -0
  136. package/bundle/config-RGSDAPZN.js +19 -0
  137. package/bundle/config-RGSDAPZN.js.map +7 -0
  138. package/bundle/config-show-ERTATR6E.js +40 -0
  139. package/bundle/config-show-ERTATR6E.js.map +7 -0
  140. package/bundle/context-HCEGZNDC.js +72 -0
  141. package/bundle/context-HCEGZNDC.js.map +7 -0
  142. package/bundle/delegation-tools-GYTS2D6A.js +27 -0
  143. package/bundle/delegation-tools-GYTS2D6A.js.map +7 -0
  144. package/bundle/deploy-lib-import-32ZFKHWP.js +49 -0
  145. package/bundle/deploy-lib-import-32ZFKHWP.js.map +7 -0
  146. package/bundle/digital-signature-OFCGSHWO.js +13 -0
  147. package/bundle/digital-signature-OFCGSHWO.js.map +7 -0
  148. package/bundle/direct-api-transport-YR7SXXNN.js +860 -0
  149. package/bundle/direct-api-transport-YR7SXXNN.js.map +7 -0
  150. package/bundle/discord-adapter-YYWVMPPU.js +584 -0
  151. package/bundle/discord-adapter-YYWVMPPU.js.map +7 -0
  152. package/bundle/dist-MTMKARCP.js +1969 -0
  153. package/bundle/dist-MTMKARCP.js.map +7 -0
  154. package/bundle/dns-wakeup-27M7D2MR.js +107 -0
  155. package/bundle/dns-wakeup-27M7D2MR.js.map +7 -0
  156. package/bundle/doctor-QNUSDY73.js +248 -0
  157. package/bundle/doctor-QNUSDY73.js.map +7 -0
  158. package/bundle/ensure-invariants-NMXNS476.js +49 -0
  159. package/bundle/ensure-invariants-NMXNS476.js.map +7 -0
  160. package/bundle/env-schema-2KBHBDGN.js +19 -0
  161. package/bundle/env-schema-2KBHBDGN.js.map +7 -0
  162. package/bundle/esm-DDP6NCZG.js +100663 -0
  163. package/bundle/esm-DDP6NCZG.js.map +7 -0
  164. package/bundle/fallback-policy-L4QV2PEJ.js +46 -0
  165. package/bundle/fallback-policy-L4QV2PEJ.js.map +7 -0
  166. package/bundle/health-check-SPA7NT6N.js +56 -0
  167. package/bundle/health-check-SPA7NT6N.js.map +7 -0
  168. package/bundle/hook-system-6Q5YTR53.js +17 -0
  169. package/bundle/hook-system-6Q5YTR53.js.map +7 -0
  170. package/bundle/hotskills-K7BM4YLB.js +12 -0
  171. package/bundle/hotskills-K7BM4YLB.js.map +7 -0
  172. package/bundle/install-6HRZVKUM.js +15 -0
  173. package/bundle/install-6HRZVKUM.js.map +7 -0
  174. package/bundle/install-log-IAPHYKD4.js +28 -0
  175. package/bundle/install-log-IAPHYKD4.js.map +7 -0
  176. package/bundle/install-manifest-SPQRUNXL.js +102 -0
  177. package/bundle/install-manifest-SPQRUNXL.js.map +7 -0
  178. package/bundle/install-validate-PVLZXYLQ.js +53 -0
  179. package/bundle/install-validate-PVLZXYLQ.js.map +7 -0
  180. package/bundle/irc-adapter-OI5UZSQF.js +293 -0
  181. package/bundle/irc-adapter-OI5UZSQF.js.map +7 -0
  182. package/bundle/irc-config-55YO6EGB.js +88 -0
  183. package/bundle/irc-config-55YO6EGB.js.map +7 -0
  184. package/bundle/logs-ZNYXX5PA.js +19 -0
  185. package/bundle/logs-ZNYXX5PA.js.map +7 -0
  186. package/bundle/media-utils-XNNDTYFI.js +4662 -0
  187. package/bundle/media-utils-XNNDTYFI.js.map +7 -0
  188. package/bundle/message-pipeline-LLH5SYMO.js +33 -0
  189. package/bundle/message-pipeline-LLH5SYMO.js.map +7 -0
  190. package/bundle/meta.json +41304 -0
  191. package/bundle/model-health-registry-35LQNVQR.js +11 -0
  192. package/bundle/model-health-registry-35LQNVQR.js.map +7 -0
  193. package/bundle/notification-Y5S5MMLV.js +13 -0
  194. package/bundle/notification-Y5S5MMLV.js.map +7 -0
  195. package/bundle/openrouter-credits-EDY7ETAU.js +32 -0
  196. package/bundle/openrouter-credits-EDY7ETAU.js.map +7 -0
  197. package/bundle/passwd-RRFV4CC5.js +133 -0
  198. package/bundle/passwd-RRFV4CC5.js.map +7 -0
  199. package/bundle/paths-G33RZWZ7.js +17 -0
  200. package/bundle/paths-G33RZWZ7.js.map +7 -0
  201. package/bundle/peer-client-52XYMNI7.js +156 -0
  202. package/bundle/peer-client-52XYMNI7.js.map +7 -0
  203. package/bundle/peer-config-VK6EDLN5.js +16 -0
  204. package/bundle/peer-config-VK6EDLN5.js.map +7 -0
  205. package/bundle/peer-sessions-EAXTNQ36.js +49 -0
  206. package/bundle/peer-sessions-EAXTNQ36.js.map +7 -0
  207. package/bundle/pending-callback-RIMQZ7FJ.js +40 -0
  208. package/bundle/pending-callback-RIMQZ7FJ.js.map +7 -0
  209. package/bundle/phase-transport-KYERDL2O.js +22 -0
  210. package/bundle/phase-transport-KYERDL2O.js.map +7 -0
  211. package/bundle/public/css/dashboard.css +542 -0
  212. package/bundle/public/index.html +180 -0
  213. package/bundle/public/js/app.js +437 -0
  214. package/bundle/public/memory-universe.js +384 -0
  215. package/bundle/responses-adapter-AAQTY3K4.js +30 -0
  216. package/bundle/responses-adapter-AAQTY3K4.js.map +7 -0
  217. package/bundle/restore-ZE3SEPSS.js +46 -0
  218. package/bundle/restore-ZE3SEPSS.js.map +7 -0
  219. package/bundle/self-healer-utils-DMUUXC47.js +43 -0
  220. package/bundle/self-healer-utils-DMUUXC47.js.map +7 -0
  221. package/bundle/skill-stats-LLEXEXLR.js +22 -0
  222. package/bundle/skill-stats-LLEXEXLR.js.map +7 -0
  223. package/bundle/sleep-OYIUOVQD.js +19 -0
  224. package/bundle/sleep-OYIUOVQD.js.map +7 -0
  225. package/bundle/soul-loader-54WCVNLJ.js +16 -0
  226. package/bundle/soul-loader-54WCVNLJ.js.map +7 -0
  227. package/bundle/src-JL4PVO23.js +8 -0
  228. package/bundle/src-JL4PVO23.js.map +7 -0
  229. package/bundle/sse-parser-anthropic-P7CE2MH2.js +72 -0
  230. package/bundle/sse-parser-anthropic-P7CE2MH2.js.map +7 -0
  231. package/bundle/sse-parser-responses-EQQA5FWN.js +63 -0
  232. package/bundle/sse-parser-responses-EQQA5FWN.js.map +7 -0
  233. package/bundle/ssrf-guard-FZCBYIVW.js +64 -0
  234. package/bundle/ssrf-guard-FZCBYIVW.js.map +7 -0
  235. package/bundle/start-FH3GRMJ4.js +35 -0
  236. package/bundle/start-FH3GRMJ4.js.map +7 -0
  237. package/bundle/stream-single-WSG4D53C.js +33 -0
  238. package/bundle/stream-single-WSG4D53C.js.map +7 -0
  239. package/bundle/stt-2UH3RITX.js +14 -0
  240. package/bundle/stt-2UH3RITX.js.map +7 -0
  241. package/bundle/subagent-runtime-LE2ZXH3G.js +12 -0
  242. package/bundle/subagent-runtime-LE2ZXH3G.js.map +7 -0
  243. package/bundle/system-message-T5R3EYYN.js +30 -0
  244. package/bundle/system-message-T5R3EYYN.js.map +7 -0
  245. package/bundle/system-status-KQ6KHFJ6.js +189 -0
  246. package/bundle/system-status-KQ6KHFJ6.js.map +7 -0
  247. package/bundle/task-store-K7CQDEPI.js +22 -0
  248. package/bundle/task-store-K7CQDEPI.js.map +7 -0
  249. package/bundle/telegram-adapter-2V3XUMT5.js +1060 -0
  250. package/bundle/telegram-adapter-2V3XUMT5.js.map +7 -0
  251. package/bundle/tool-registry-MU3OX4UI.js +38 -0
  252. package/bundle/tool-registry-MU3OX4UI.js.map +7 -0
  253. package/bundle/tool-sandbox-VYOK4ZOA.js +20 -0
  254. package/bundle/tool-sandbox-VYOK4ZOA.js.map +7 -0
  255. package/bundle/transport-config-YLXU33RO.js +57 -0
  256. package/bundle/transport-config-YLXU33RO.js.map +7 -0
  257. package/bundle/update-QCW5LXRN.js +13 -0
  258. package/bundle/update-QCW5LXRN.js.map +7 -0
  259. package/bundle/update-check-27KZSAP6.js +12 -0
  260. package/bundle/update-check-27KZSAP6.js.map +7 -0
  261. package/bundle/usage-tracker-OVVEVMOY.js +17 -0
  262. package/bundle/usage-tracker-OVVEVMOY.js.map +7 -0
  263. package/bundle/user-registry-D4SD73UV.js +16 -0
  264. package/bundle/user-registry-D4SD73UV.js.map +7 -0
  265. package/core/professor.json +14 -0
  266. package/core/prompts/browsing_prompt.md +39 -0
  267. package/core/prompts/compaction.md +32 -0
  268. package/core/skills/memory/classification/SKILL.md +37 -0
  269. package/core/skills/memory/memory-anomalies/SKILL.md +39 -0
  270. package/core/skills/memory/memory-search/SKILL.md +48 -0
  271. package/core/skills/memory/topic-save/SKILL.md +44 -0
  272. package/core/skills/ops/cron/SKILL.md +51 -0
  273. package/core/skills/ops/gdrive-backup/SKILL.md +15 -0
  274. package/core/skills/ops/session-start/SKILL.md +11 -0
  275. package/core/skills/ops/skill-authoring/SKILL.md +54 -0
  276. package/core/skills/ops/system-health/SKILL.md +104 -0
  277. package/core/skills/ops/troubleshooting/SKILL.md +48 -0
  278. package/core/skills/ops/trust-gating/SKILL.md +30 -0
  279. package/core/skills/tools/a2a-communication/SKILL.md +68 -0
  280. package/core/skills/tools/browse-delegate/SKILL.md +27 -0
  281. package/core/skills/tools/browser/SKILL.md +36 -0
  282. package/core/skills/tools/clawhub/SKILL.md +44 -0
  283. package/core/skills/tools/delegation/SKILL.md +48 -0
  284. package/core/skills/tools/fxtwitter/SKILL.md +52 -0
  285. package/core/skills/tools/gmail/SKILL.md +44 -0
  286. package/core/skills/tools/irc-chat/SKILL.md +84 -0
  287. package/core/skills/tools/linear/SKILL.md +90 -0
  288. package/core/skills/tools/mcporter/SKILL.md +46 -0
  289. package/core/skills/tools/model-scout/SKILL.md +132 -0
  290. package/core/skills/tools/model-scout/scout-add-model.py +67 -0
  291. package/core/skills/tools/model-scout/scout-ollama.py +116 -0
  292. package/core/skills/tools/model-scout/scout-openrouter.py +85 -0
  293. package/core/skills/tools/nlm/SKILL.md +40 -0
  294. package/core/skills/tools/todo/SKILL.md +30 -0
  295. package/core/skills/tools/twitterX/SKILL.md +52 -0
  296. package/core/skills/tools/twitterX/scripts/abtars-tweet.js +532 -0
  297. package/core/skills/tools/twitterX/scripts/package.json +1 -0
  298. package/core/skills/tools/web-fetch/SKILL.md +29 -0
  299. package/package.json +59 -0
  300. package/scripts/abtars-daemon.service +23 -0
  301. package/scripts/abtars-fetch.sh +42 -0
  302. package/scripts/abtars-watchdog.service +13 -0
  303. package/scripts/abtars.sh +14 -0
  304. package/scripts/abtars@.service +21 -0
  305. package/scripts/browser-patchright.sh +79 -0
  306. package/scripts/com.abtars.daemon.plist +24 -0
  307. package/scripts/com.abtars.watchdog.plist +27 -0
  308. package/scripts/daily-backup.sh +62 -0
  309. package/scripts/doctor.sh +553 -0
  310. package/scripts/hooks/audit-logger.sh +22 -0
  311. package/scripts/upgrade-deps.sh +64 -0
  312. package/scripts/watchdog.sh +309 -0
@@ -0,0 +1,228 @@
1
+ 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);
2
+
3
+ // src/components/command-registry.ts
4
+ var BOT_COMMANDS = [
5
+ { name: "reset", description: "Fresh session + exit coding" },
6
+ { name: "session", description: "Session management" },
7
+ { name: "compact", description: "Compact context window" },
8
+ { name: "status", description: "Bridge status" },
9
+ { name: "doctor", description: "Deep healthcheck (probes all subsystems)" },
10
+ { name: "mcp", description: "MCP server status" },
11
+ { name: "hooks", description: "List configured hooks" },
12
+ { name: "stop", description: "Stop current response" },
13
+ { name: "wait", description: "Inject message mid-run (non-interrupting)" },
14
+ { name: "models", description: "Model, transport & agents" },
15
+ { name: "change", description: "Switch model/provider" },
16
+ { name: "emergency", description: "Activate paid hailMary model" },
17
+ { name: "heartbeat", description: "Heartbeat diagnostics" },
18
+ { name: "memory", description: "Memory stats" },
19
+ { name: "skills", description: "List skills" },
20
+ { name: "skill", description: "Reload skills catalog" },
21
+ { name: "tasks", description: "Scheduled tasks" },
22
+ { name: "facts", description: "Core knowledge" },
23
+ { name: "nlm", description: "Knowledge base" },
24
+ { name: "restart", description: "Restart bridge" },
25
+ { name: "wakeup", description: "Wake Mac from sleep" },
26
+ { name: "sleep", description: "Sleep status / resume / now" },
27
+ { name: "help", description: "Show all commands" }
28
+ ];
29
+
30
+ // src/components/security-gate.ts
31
+ var SecurityGate = class {
32
+ registry;
33
+ constructor(registry) {
34
+ if (registry.users.length === 0) {
35
+ throw new Error("SecurityGate requires at least one user in registry");
36
+ }
37
+ this.registry = registry;
38
+ }
39
+ /** Authorize a platform user. Checks allowedChats if set. */
40
+ authorize(platformUserId, platform, channelId) {
41
+ const key = `${platform}:${platformUserId}`;
42
+ const user = this.registry.byPlatformId.get(key);
43
+ if (!user) return { authorized: false };
44
+ if (!this.chatAllowed(user, channelId)) return { authorized: false };
45
+ return { authorized: true, user };
46
+ }
47
+ /** Authorize by platform user ID string (tries both platforms). */
48
+ authorizeById(userId, channelId) {
49
+ const tg = this.registry.byPlatformId.get(`telegram:${userId}`);
50
+ const dc = this.registry.byPlatformId.get(`discord:${userId}`);
51
+ const user = tg ?? dc;
52
+ if (!user) return false;
53
+ return this.chatAllowed(user, channelId);
54
+ }
55
+ chatAllowed(user, channelId) {
56
+ if (!user.allowedChats || user.allowedChats.length === 0) return true;
57
+ if (!channelId) return true;
58
+ return user.allowedChats.includes(channelId);
59
+ }
60
+ };
61
+
62
+ // src/components/response-formatter.ts
63
+ var TELEGRAM_MAX_LENGTH = 4096;
64
+ var DISCORD_MAX_LENGTH = 2e3;
65
+ var MARKDOWN_V2_ESCAPE = /([_*\[\]()~`>#+\-=|{}.!\\])/g;
66
+ var ResponseFormatter = class {
67
+ buffers = /* @__PURE__ */ new Map();
68
+ /** Accumulate a chunk for a session. */
69
+ collectChunk(sessionId, chunk) {
70
+ const existing = this.buffers.get(sessionId);
71
+ if (existing) {
72
+ existing.push(chunk);
73
+ } else {
74
+ this.buffers.set(sessionId, [chunk]);
75
+ }
76
+ }
77
+ /** Flush accumulated chunks for a session, returning Telegram-ready messages. */
78
+ flush(sessionId) {
79
+ const chunks = this.buffers.get(sessionId);
80
+ this.buffers.delete(sessionId);
81
+ if (!chunks || chunks.length === 0) return [];
82
+ const full = chunks.join("");
83
+ return this.chunkText(full);
84
+ }
85
+ /** Split text into chunks that fit Telegram's 4096-char limit. */
86
+ chunkText(text) {
87
+ if (text.length <= TELEGRAM_MAX_LENGTH) {
88
+ return [text];
89
+ }
90
+ const result = [];
91
+ let remaining = text;
92
+ while (remaining.length > 0) {
93
+ if (remaining.length <= TELEGRAM_MAX_LENGTH) {
94
+ result.push(remaining);
95
+ break;
96
+ }
97
+ let splitAt = remaining.lastIndexOf("\n\n", TELEGRAM_MAX_LENGTH);
98
+ if (splitAt <= 0) {
99
+ splitAt = remaining.lastIndexOf("\n", TELEGRAM_MAX_LENGTH);
100
+ }
101
+ if (splitAt <= 0) {
102
+ splitAt = remaining.lastIndexOf(" ", TELEGRAM_MAX_LENGTH);
103
+ }
104
+ if (splitAt <= 0) {
105
+ splitAt = TELEGRAM_MAX_LENGTH;
106
+ }
107
+ result.push(remaining.slice(0, splitAt));
108
+ remaining = remaining.slice(splitAt).trimStart();
109
+ }
110
+ return result;
111
+ }
112
+ /** Escape text for Telegram MarkdownV2 parse mode. */
113
+ toTelegramMarkdown(markdown) {
114
+ const parts = markdown.split(/(```[\s\S]*?```|`[^`]+`)/);
115
+ return parts.map((part, i) => {
116
+ if (i % 2 === 1) return part;
117
+ return part.replace(MARKDOWN_V2_ESCAPE, "\\$1");
118
+ }).join("");
119
+ }
120
+ /** Split text into chunks for Discord's 2000-char limit.
121
+ * Respects paragraph and code block boundaries — never splits inside a fenced code block. */
122
+ chunkTextForDiscord(text) {
123
+ if (text.length <= DISCORD_MAX_LENGTH) {
124
+ return [text];
125
+ }
126
+ const result = [];
127
+ let remaining = text;
128
+ while (remaining.length > 0) {
129
+ if (remaining.length <= DISCORD_MAX_LENGTH) {
130
+ result.push(remaining);
131
+ break;
132
+ }
133
+ const window = remaining.slice(0, DISCORD_MAX_LENGTH);
134
+ const fenceMatches = window.match(/```/g);
135
+ const hasOpenCodeBlock = fenceMatches != null && fenceMatches.length % 2 !== 0;
136
+ if (hasOpenCodeBlock) {
137
+ const lastFenceIdx = window.lastIndexOf("```");
138
+ let splitAt2 = remaining.lastIndexOf("\n\n", lastFenceIdx);
139
+ if (splitAt2 <= 0) {
140
+ splitAt2 = remaining.lastIndexOf("\n", lastFenceIdx);
141
+ }
142
+ if (splitAt2 <= 0) {
143
+ splitAt2 = remaining.lastIndexOf("\n", DISCORD_MAX_LENGTH - 4);
144
+ if (splitAt2 <= 0) {
145
+ splitAt2 = DISCORD_MAX_LENGTH - 4;
146
+ }
147
+ const fenceStart = remaining.lastIndexOf("```", splitAt2);
148
+ const fenceLine = remaining.slice(fenceStart, remaining.indexOf("\n", fenceStart));
149
+ result.push(remaining.slice(0, splitAt2) + "\n```");
150
+ remaining = fenceLine + "\n" + remaining.slice(splitAt2).trimStart();
151
+ continue;
152
+ }
153
+ result.push(remaining.slice(0, splitAt2));
154
+ remaining = remaining.slice(splitAt2).trimStart();
155
+ continue;
156
+ }
157
+ let splitAt = remaining.lastIndexOf("\n\n", DISCORD_MAX_LENGTH);
158
+ if (splitAt <= 0) {
159
+ splitAt = remaining.lastIndexOf("\n", DISCORD_MAX_LENGTH);
160
+ }
161
+ if (splitAt <= 0) {
162
+ splitAt = remaining.lastIndexOf(" ", DISCORD_MAX_LENGTH);
163
+ }
164
+ if (splitAt <= 0) {
165
+ splitAt = DISCORD_MAX_LENGTH;
166
+ }
167
+ result.push(remaining.slice(0, splitAt));
168
+ remaining = remaining.slice(splitAt).trimStart();
169
+ }
170
+ return result;
171
+ }
172
+ /** Split text for the appropriate platform. */
173
+ chunkForPlatform(text, platform) {
174
+ if (platform === "discord") {
175
+ return this.chunkTextForDiscord(text);
176
+ }
177
+ return this.chunkText(text);
178
+ }
179
+ /** Convert standard Markdown to Discord-compatible Markdown (mostly passthrough). */
180
+ toDiscordMarkdown(text) {
181
+ return text;
182
+ }
183
+ /** Format a tool status update for the user. */
184
+ formatToolStatus(toolName, status) {
185
+ switch (status) {
186
+ case "start":
187
+ return `\u{1F527} ${toolName}...`;
188
+ case "done":
189
+ return `\u2705 ${toolName}`;
190
+ case "error":
191
+ return `\u274C ${toolName} failed`;
192
+ }
193
+ }
194
+ };
195
+
196
+ // src/utils/emoji-score.ts
197
+ var EMOJI_SCORES = {
198
+ "\u2764\uFE0F": 4,
199
+ "\u{1F525}": 4,
200
+ "\u{1F389}": 3,
201
+ "\u{1F44F}": 4,
202
+ "\u2764": 4,
203
+ "\u{1F44D}": 3,
204
+ "\u{1F602}": 3,
205
+ "\u{1F929}": 4,
206
+ "\u{1F4AF}": 3,
207
+ "\u26A1": 3,
208
+ "\u{1F60A}": 2,
209
+ "\u{1F64F}": 2,
210
+ "\u{1F914}": 1,
211
+ "\u{1F62E}": 1,
212
+ "\u{1F44E}": -3,
213
+ "\u{1F622}": -3,
214
+ "\u{1F621}": -4,
215
+ "\u{1F92E}": -4,
216
+ "\u{1F4A9}": -5
217
+ };
218
+ function emojiToScore(emoji) {
219
+ return EMOJI_SCORES[emoji] ?? 1;
220
+ }
221
+
222
+ export {
223
+ BOT_COMMANDS,
224
+ SecurityGate,
225
+ ResponseFormatter,
226
+ emojiToScore
227
+ };
228
+ //# sourceMappingURL=chunk-D2DCBO6M.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/command-registry.ts", "../src/components/security-gate.ts", "../src/components/response-formatter.ts", "../src/utils/emoji-score.ts"],
4
+ "sourcesContent": ["/**\n * command-registry.ts \u2014 Shared bot command definitions for all platforms.\n * Both Telegram (setMyCommands) and Discord (application commands) import from here.\n */\n\nexport interface BotCommand {\n readonly name: string;\n readonly description: string;\n}\n\n/** All registered bot commands. Discord requires: name \u226432 chars lowercase, description \u2264100 chars. */\nexport const BOT_COMMANDS: readonly BotCommand[] = [\n { name: \"reset\", description: \"Fresh session + exit coding\" },\n { name: \"session\", description: \"Session management\" },\n { name: \"compact\", description: \"Compact context window\" },\n { name: \"status\", description: \"Bridge status\" },\n { name: \"doctor\", description: \"Deep healthcheck (probes all subsystems)\" },\n { name: \"mcp\", description: \"MCP server status\" },\n { name: \"hooks\", description: \"List configured hooks\" },\n { name: \"stop\", description: \"Stop current response\" },\n { name: \"wait\", description: \"Inject message mid-run (non-interrupting)\" },\n { name: \"models\", description: \"Model, transport & agents\" },\n { name: \"change\", description: \"Switch model/provider\" },\n { name: \"emergency\", description: \"Activate paid hailMary model\" },\n { name: \"heartbeat\", description: \"Heartbeat diagnostics\" },\n { name: \"memory\", description: \"Memory stats\" },\n { name: \"skills\", description: \"List skills\" },\n { name: \"skill\", description: \"Reload skills catalog\" },\n { name: \"tasks\", description: \"Scheduled tasks\" },\n { name: \"facts\", description: \"Core knowledge\" },\n { name: \"nlm\", description: \"Knowledge base\" },\n { name: \"restart\", description: \"Restart bridge\" },\n { name: \"wakeup\", description: \"Wake Mac from sleep\" },\n { name: \"sleep\", description: \"Sleep status / resume / now\" },\n { name: \"help\", description: \"Show all commands\" },\n];\n", "/**\n * Fail-closed security gate that authorizes messages against the user registry.\n * Unauthorized messages are silently dropped \u2014 no response, no side effects.\n * Per-user channel gating via UserEntry.allowedChats.\n */\nimport type { UserEntry, UserRegistry } from \"./user-registry.js\";\n\nexport interface AuthResult {\n authorized: boolean;\n user?: UserEntry;\n}\n\nexport class SecurityGate {\n private readonly registry: UserRegistry;\n\n constructor(registry: UserRegistry) {\n if (registry.users.length === 0) {\n throw new Error(\"SecurityGate requires at least one user in registry\");\n }\n this.registry = registry;\n }\n\n /** Authorize a platform user. Checks allowedChats if set. */\n authorize(platformUserId: string, platform: string, channelId?: string): AuthResult {\n const key = `${platform}:${platformUserId}`;\n const user = this.registry.byPlatformId.get(key);\n if (!user) return { authorized: false };\n if (!this.chatAllowed(user, channelId)) return { authorized: false };\n return { authorized: true, user };\n }\n\n /** Authorize by platform user ID string (tries both platforms). */\n authorizeById(userId: string, channelId?: string): boolean {\n const tg = this.registry.byPlatformId.get(`telegram:${userId}`);\n const dc = this.registry.byPlatformId.get(`discord:${userId}`);\n const user = tg ?? dc;\n if (!user) return false;\n return this.chatAllowed(user, channelId);\n }\n\n private chatAllowed(user: UserEntry, channelId?: string): boolean {\n if (!user.allowedChats || user.allowedChats.length === 0) return true;\n if (!channelId) return true;\n return user.allowedChats.includes(channelId);\n }\n}\n", "import type { Platform } from \"../types/index.js\";\n\nconst TELEGRAM_MAX_LENGTH = 4096;\nconst DISCORD_MAX_LENGTH = 2000;\n\n/** Characters that must be escaped in Telegram MarkdownV2. */\nconst MARKDOWN_V2_ESCAPE = /([_*\\[\\]()~`>#+\\-=|{}.!\\\\])/g;\n\n/**\n * Collects streaming ACP response chunks and formats them\n * for Telegram delivery (chunking, Markdown conversion).\n */\nexport class ResponseFormatter {\n private buffers = new Map<string, string[]>();\n\n /** Accumulate a chunk for a session. */\n collectChunk(sessionId: string, chunk: string): void {\n const existing = this.buffers.get(sessionId);\n if (existing) {\n existing.push(chunk);\n } else {\n this.buffers.set(sessionId, [chunk]);\n }\n }\n\n /** Flush accumulated chunks for a session, returning Telegram-ready messages. */\n flush(sessionId: string): string[] {\n const chunks = this.buffers.get(sessionId);\n this.buffers.delete(sessionId);\n if (!chunks || chunks.length === 0) return [];\n const full = chunks.join(\"\");\n return this.chunkText(full);\n }\n\n /** Split text into chunks that fit Telegram's 4096-char limit. */\n chunkText(text: string): string[] {\n if (text.length <= TELEGRAM_MAX_LENGTH) {\n return [text];\n }\n\n const result: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= TELEGRAM_MAX_LENGTH) {\n result.push(remaining);\n break;\n }\n\n // Try to split at paragraph boundary\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", TELEGRAM_MAX_LENGTH);\n if (splitAt <= 0) {\n // Try single newline\n splitAt = remaining.lastIndexOf(\"\\n\", TELEGRAM_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n // Try space\n splitAt = remaining.lastIndexOf(\" \", TELEGRAM_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n // Hard split\n splitAt = TELEGRAM_MAX_LENGTH;\n }\n\n result.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return result;\n }\n\n /** Escape text for Telegram MarkdownV2 parse mode. */\n toTelegramMarkdown(markdown: string): string {\n // Preserve code blocks \u2014 don't escape inside them\n const parts = markdown.split(/(```[\\s\\S]*?```|`[^`]+`)/);\n return parts\n .map((part, i) => {\n // Odd indices are code blocks/inline code \u2014 leave as-is\n if (i % 2 === 1) return part;\n return part.replace(MARKDOWN_V2_ESCAPE, \"\\\\$1\");\n })\n .join(\"\");\n }\n\n /** Split text into chunks for Discord's 2000-char limit.\n * Respects paragraph and code block boundaries \u2014 never splits inside a fenced code block. */\n chunkTextForDiscord(text: string): string[] {\n if (text.length <= DISCORD_MAX_LENGTH) {\n return [text];\n }\n\n const result: string[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n if (remaining.length <= DISCORD_MAX_LENGTH) {\n result.push(remaining);\n break;\n }\n\n // Check if there's an open code block in the window we're about to cut\n const window = remaining.slice(0, DISCORD_MAX_LENGTH);\n const fenceMatches = window.match(/```/g);\n const hasOpenCodeBlock = fenceMatches != null && fenceMatches.length % 2 !== 0;\n\n if (hasOpenCodeBlock) {\n // Find the start of the open code block (last unmatched ```)\n const lastFenceIdx = window.lastIndexOf(\"```\");\n // Try to split before the code block at a paragraph boundary\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", lastFenceIdx);\n if (splitAt <= 0) {\n splitAt = remaining.lastIndexOf(\"\\n\", lastFenceIdx);\n }\n if (splitAt <= 0) {\n // Can't avoid splitting inside the code block \u2014 close and reopen\n splitAt = remaining.lastIndexOf(\"\\n\", DISCORD_MAX_LENGTH - 4); // leave room for closing ```\n if (splitAt <= 0) {\n splitAt = DISCORD_MAX_LENGTH - 4;\n }\n // Find the code fence language specifier for reopening\n const fenceStart = remaining.lastIndexOf(\"```\", splitAt);\n const fenceLine = remaining.slice(fenceStart, remaining.indexOf(\"\\n\", fenceStart));\n result.push(remaining.slice(0, splitAt) + \"\\n```\");\n remaining = fenceLine + \"\\n\" + remaining.slice(splitAt).trimStart();\n continue;\n }\n result.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n continue;\n }\n\n // No open code block \u2014 split normally at paragraph/line boundaries\n let splitAt = remaining.lastIndexOf(\"\\n\\n\", DISCORD_MAX_LENGTH);\n if (splitAt <= 0) {\n splitAt = remaining.lastIndexOf(\"\\n\", DISCORD_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n splitAt = remaining.lastIndexOf(\" \", DISCORD_MAX_LENGTH);\n }\n if (splitAt <= 0) {\n splitAt = DISCORD_MAX_LENGTH;\n }\n\n result.push(remaining.slice(0, splitAt));\n remaining = remaining.slice(splitAt).trimStart();\n }\n\n return result;\n }\n\n /** Split text for the appropriate platform. */\n chunkForPlatform(text: string, platform: Platform): string[] {\n if (platform === \"discord\") {\n return this.chunkTextForDiscord(text);\n }\n return this.chunkText(text);\n }\n\n /** Convert standard Markdown to Discord-compatible Markdown (mostly passthrough). */\n toDiscordMarkdown(text: string): string {\n return text;\n }\n\n /** Format a tool status update for the user. */\n formatToolStatus(toolName: string, status: \"start\" | \"done\" | \"error\"): string {\n switch (status) {\n case \"start\":\n return `\uD83D\uDD27 ${toolName}...`;\n case \"done\":\n return `\u2705 ${toolName}`;\n case \"error\":\n return `\u274C ${toolName} failed`;\n }\n }\n}\n", "/** Inline emoji-to-score map (avoids hard dep on abmind for adapters). */\nconst EMOJI_SCORES: Record<string, number> = {\n \"\u2764\uFE0F\": 4, \"\uD83D\uDD25\": 4, \"\uD83C\uDF89\": 3, \"\uD83D\uDC4F\": 4, \"\u2764\": 4,\n \"\uD83D\uDC4D\": 3, \"\uD83D\uDE02\": 3, \"\uD83E\uDD29\": 4, \"\uD83D\uDCAF\": 3, \"\u26A1\": 3,\n \"\uD83D\uDE0A\": 2, \"\uD83D\uDE4F\": 2, \"\uD83E\uDD14\": 1, \"\uD83D\uDE2E\": 1,\n \"\uD83D\uDC4E\": -3, \"\uD83D\uDE22\": -3, \"\uD83D\uDE21\": -4, \"\uD83E\uDD2E\": -4, \"\uD83D\uDCA9\": -5,\n};\n\nexport function emojiToScore(emoji: string): number {\n return EMOJI_SCORES[emoji] ?? 1;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["splitAt"]
7
+ }
@@ -0,0 +1,31 @@
1
+ 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);
2
+ import {
3
+ init_logger,
4
+ logError,
5
+ logTrace,
6
+ logWarn
7
+ } from "./chunk-BUUVFUPO.js";
8
+ import {
9
+ __esm
10
+ } from "./chunk-NWDBD4PA.js";
11
+
12
+ // src/components/log-and-swallow.ts
13
+ function logAndSwallow(tag, context, err, level = "trace") {
14
+ const msg = `[swallowed] ${context}${err ? `: ${err instanceof Error ? err.message : String(err)}` : ""}`;
15
+ if (level === "error") logError(tag, msg);
16
+ else if (level === "warn") logWarn(tag, msg);
17
+ else logTrace(tag, msg);
18
+ return void 0;
19
+ }
20
+ var init_log_and_swallow = __esm({
21
+ "src/components/log-and-swallow.ts"() {
22
+ "use strict";
23
+ init_logger();
24
+ }
25
+ });
26
+
27
+ export {
28
+ logAndSwallow,
29
+ init_log_and_swallow
30
+ };
31
+ //# sourceMappingURL=chunk-FMWKEPM7.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/log-and-swallow.ts"],
4
+ "sourcesContent": ["/**\n * log-and-swallow.ts \u2014 Visible error swallowing.\n * Replaces silent `} catch { }` blocks with a trace-level log.\n */\n\nimport { logTrace, logWarn, logError } from \"./logger.js\";\n\ntype SwallowLevel = \"trace\" | \"warn\" | \"error\";\n\n/** Log a swallowed error and return undefined. Default level: trace. */\nexport function logAndSwallow(tag: string, context: string, err?: unknown, level: SwallowLevel = \"trace\"): undefined {\n const msg = `[swallowed] ${context}${err ? `: ${err instanceof Error ? err.message : String(err)}` : \"\"}`;\n if (level === \"error\") logError(tag, msg);\n else if (level === \"warn\") logWarn(tag, msg);\n else logTrace(tag, msg);\n return undefined;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;AAUO,SAAS,cAAc,KAAa,SAAiB,KAAe,QAAsB,SAAoB;AACnH,QAAM,MAAM,eAAe,OAAO,GAAG,MAAM,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,KAAK,EAAE;AACvG,MAAI,UAAU,QAAS,UAAS,KAAK,GAAG;AAAA,WAC/B,UAAU,OAAQ,SAAQ,KAAK,GAAG;AAAA,MACtC,UAAS,KAAK,GAAG;AACtB,SAAO;AACT;AAhBA;AAAA;AAAA;AAKA;AAAA;AAAA;",
6
+ "names": []
7
+ }
@@ -0,0 +1,145 @@
1
+ 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);
2
+ import {
3
+ init_logger,
4
+ logDebug,
5
+ logInfo,
6
+ logWarn
7
+ } from "./chunk-BUUVFUPO.js";
8
+
9
+ // src/components/hooks/hook-system.ts
10
+ init_logger();
11
+ import { spawn } from "node:child_process";
12
+ import { readFileSync, statSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { homedir } from "node:os";
15
+ var TAG = "hooks";
16
+ var DEFAULT_TIMEOUT = 5e3;
17
+ var config = null;
18
+ function loadHookConfig() {
19
+ const configPath = join(homedir(), ".abtars", "config", "hooks.json");
20
+ try {
21
+ const raw = readFileSync(configPath, "utf-8");
22
+ const parsed = JSON.parse(raw);
23
+ if (!parsed.enabled) {
24
+ config = null;
25
+ logDebug(TAG, "Hooks disabled in config");
26
+ return;
27
+ }
28
+ const hooksDir = join(homedir(), ".abtars", "hooks");
29
+ try {
30
+ const st = statSync(hooksDir);
31
+ const mode = st.mode & 511;
32
+ if (mode !== 448) {
33
+ logWarn(TAG, `Hooks dir ${hooksDir} has mode ${mode.toString(8)}, expected 700 \u2014 hooks disabled`);
34
+ config = null;
35
+ return;
36
+ }
37
+ } catch {
38
+ }
39
+ config = parsed;
40
+ const count = Object.values(parsed.hooks).reduce((n, arr) => n + (arr?.length ?? 0), 0);
41
+ logInfo(TAG, `Loaded ${count} hook(s) from ${configPath}`);
42
+ } catch {
43
+ config = null;
44
+ logDebug(TAG, "No hooks.json found \u2014 hooks disabled");
45
+ }
46
+ }
47
+ function hasHooks(event) {
48
+ return (config?.hooks[event]?.length ?? 0) > 0;
49
+ }
50
+ function getHookSummary() {
51
+ const events = ["BridgeStart", "BeforeMessage", "AfterMessage", "SessionStart", "SessionEnd", "AfterPrompt"];
52
+ return events.map((event) => ({ event, hooks: config?.hooks[event] ?? [] }));
53
+ }
54
+ async function fire(event, input) {
55
+ const hooks = config?.hooks[event];
56
+ if (!hooks?.length) return null;
57
+ for (const hook of hooks) {
58
+ try {
59
+ const result = await runOne(hook, input);
60
+ if (result?.decision === "block" && event === "BeforeMessage") {
61
+ logInfo(TAG, `${event}/${hook.name}: BLOCKED \u2014 ${result.reason ?? "no reason"}`);
62
+ return result;
63
+ }
64
+ } catch (err) {
65
+ logWarn(TAG, `${event}/${hook.name} failed: ${err instanceof Error ? err.message : String(err)} \u2014 skipping`);
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+ function runOne(hook, input) {
71
+ const timeout = hook.timeout ?? DEFAULT_TIMEOUT;
72
+ return new Promise((resolve) => {
73
+ const child = spawn(hook.command, [], {
74
+ stdio: ["pipe", "pipe", "pipe"],
75
+ timeout,
76
+ env: {
77
+ ABTARS_HOME: join(homedir(), ".abtars"),
78
+ ABMIND_HOME: join(homedir(), ".abmind"),
79
+ PATH: process.env["PATH"] ?? ""
80
+ }
81
+ });
82
+ let stdout = "";
83
+ let stderr = "";
84
+ let stdoutBytes = 0;
85
+ let stderrBytes = 0;
86
+ const MAX_STDOUT = 1048576;
87
+ const MAX_STDERR = 65536;
88
+ child.stdout?.on("data", (d) => {
89
+ stdoutBytes += d.length;
90
+ if (stdoutBytes > MAX_STDOUT) {
91
+ child.kill("SIGTERM");
92
+ logWarn(TAG, `${hook.name} stdout exceeded 1MB \u2014 killed`);
93
+ return;
94
+ }
95
+ stdout += d.toString();
96
+ });
97
+ child.stderr?.on("data", (d) => {
98
+ if (stderrBytes > MAX_STDERR) return;
99
+ stderrBytes += d.length;
100
+ stderr += d.toString();
101
+ });
102
+ let killTimer = null;
103
+ const timer = setTimeout(() => {
104
+ child.kill("SIGTERM");
105
+ killTimer = setTimeout(() => {
106
+ if (!child.killed) child.kill("SIGKILL");
107
+ }, 1e3);
108
+ }, timeout);
109
+ child.on("close", (code) => {
110
+ clearTimeout(timer);
111
+ if (killTimer) clearTimeout(killTimer);
112
+ if (stderr.trim()) logDebug(TAG, `${hook.name} stderr: ${stderr.trim().slice(0, 200)}`);
113
+ if (code !== 0) {
114
+ logDebug(TAG, `${hook.name} exited ${code}`);
115
+ resolve(null);
116
+ return;
117
+ }
118
+ if (!stdout.trim()) {
119
+ resolve(null);
120
+ return;
121
+ }
122
+ try {
123
+ resolve(JSON.parse(stdout.trim()));
124
+ } catch {
125
+ logDebug(TAG, `${hook.name} non-JSON output: ${stdout.trim().slice(0, 100)}`);
126
+ resolve(null);
127
+ }
128
+ });
129
+ child.on("error", (err) => {
130
+ clearTimeout(timer);
131
+ logWarn(TAG, `${hook.name} spawn error: ${err.message}`);
132
+ resolve(null);
133
+ });
134
+ child.stdin?.write(JSON.stringify(input));
135
+ child.stdin?.end();
136
+ });
137
+ }
138
+
139
+ export {
140
+ loadHookConfig,
141
+ hasHooks,
142
+ getHookSummary,
143
+ fire
144
+ };
145
+ //# sourceMappingURL=chunk-GRNENTPA.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/hooks/hook-system.ts"],
4
+ "sourcesContent": ["/**\n * Hook system \u2014 loads config, fires events to shell-script hooks.\n * Sequential execution, first-block-wins on BeforeMessage, log-and-skip on failure.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { logInfo, logWarn, logDebug } from \"../logger.js\";\nimport type { HookConfig, HookEntry, HookEvent, HookInput, HookOutput } from \"./types.js\";\n\nconst TAG = \"hooks\";\nconst DEFAULT_TIMEOUT = 5000;\n\nlet config: HookConfig | null = null;\n\nexport function loadHookConfig(): void {\n const configPath = join(homedir(), \".abtars\", \"config\", \"hooks.json\");\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw) as HookConfig;\n if (!parsed.enabled) {\n config = null;\n logDebug(TAG, \"Hooks disabled in config\");\n return;\n }\n // Permission check on hooks dir\n const hooksDir = join(homedir(), \".abtars\", \"hooks\");\n try {\n const st = statSync(hooksDir);\n const mode = st.mode & 0o777;\n if (mode !== 0o700) {\n logWarn(TAG, `Hooks dir ${hooksDir} has mode ${mode.toString(8)}, expected 700 \u2014 hooks disabled`);\n config = null;\n return;\n }\n } catch {\n // Dir doesn't exist \u2014 that's fine, hooks just won't find scripts there\n }\n config = parsed;\n const count = Object.values(parsed.hooks).reduce((n, arr) => n + (arr?.length ?? 0), 0);\n logInfo(TAG, `Loaded ${count} hook(s) from ${configPath}`);\n } catch {\n config = null;\n logDebug(TAG, \"No hooks.json found \u2014 hooks disabled\");\n }\n}\n\nexport function hasHooks(event: HookEvent): boolean {\n return (config?.hooks[event]?.length ?? 0) > 0;\n}\n\nexport function getHookSummary(): Array<{ event: HookEvent; hooks: HookEntry[] }> {\n const events: HookEvent[] = [\"BridgeStart\", \"BeforeMessage\", \"AfterMessage\", \"SessionStart\", \"SessionEnd\", \"AfterPrompt\"];\n return events.map(event => ({ event, hooks: config?.hooks[event] ?? [] }));\n}\n\nexport async function fire(event: HookEvent, input: HookInput): Promise<HookOutput | null> {\n const hooks = config?.hooks[event];\n if (!hooks?.length) return null;\n\n for (const hook of hooks) {\n try {\n const result = await runOne(hook, input);\n if (result?.decision === \"block\" && event === \"BeforeMessage\") {\n logInfo(TAG, `${event}/${hook.name}: BLOCKED \u2014 ${result.reason ?? \"no reason\"}`);\n return result;\n }\n } catch (err) {\n logWarn(TAG, `${event}/${hook.name} failed: ${err instanceof Error ? err.message : String(err)} \u2014 skipping`);\n }\n }\n return null;\n}\n\nfunction runOne(hook: HookEntry, input: HookInput): Promise<HookOutput | null> {\n const timeout = hook.timeout ?? DEFAULT_TIMEOUT;\n return new Promise((resolve) => {\n const child = spawn(hook.command, [], {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout,\n env: {\n ABTARS_HOME: join(homedir(), \".abtars\"),\n ABMIND_HOME: join(homedir(), \".abmind\"),\n PATH: process.env[\"PATH\"] ?? \"\",\n },\n });\n\n let stdout = \"\";\n let stderr = \"\";\n let stdoutBytes = 0;\n let stderrBytes = 0;\n const MAX_STDOUT = 1_048_576;\n const MAX_STDERR = 65_536;\n child.stdout?.on(\"data\", (d: Buffer) => {\n stdoutBytes += d.length;\n if (stdoutBytes > MAX_STDOUT) { child.kill(\"SIGTERM\"); logWarn(TAG, `${hook.name} stdout exceeded 1MB \u2014 killed`); return; }\n stdout += d.toString();\n });\n child.stderr?.on(\"data\", (d: Buffer) => {\n if (stderrBytes > MAX_STDERR) return;\n stderrBytes += d.length;\n stderr += d.toString();\n });\n\n let killTimer: ReturnType<typeof setTimeout> | null = null;\n const timer = setTimeout(() => {\n child.kill(\"SIGTERM\");\n killTimer = setTimeout(() => { if (!child.killed) child.kill(\"SIGKILL\"); }, 1000);\n }, timeout);\n\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n if (killTimer) clearTimeout(killTimer);\n if (stderr.trim()) logDebug(TAG, `${hook.name} stderr: ${stderr.trim().slice(0, 200)}`);\n if (code !== 0) {\n logDebug(TAG, `${hook.name} exited ${code}`);\n resolve(null);\n return;\n }\n if (!stdout.trim()) { resolve(null); return; }\n try {\n resolve(JSON.parse(stdout.trim()) as HookOutput);\n } catch {\n logDebug(TAG, `${hook.name} non-JSON output: ${stdout.trim().slice(0, 100)}`);\n resolve(null);\n }\n });\n\n child.on(\"error\", (err) => {\n clearTimeout(timer);\n logWarn(TAG, `${hook.name} spawn error: ${err.message}`);\n resolve(null);\n });\n\n child.stdin?.write(JSON.stringify(input));\n child.stdin?.end();\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,93 @@
1
+ 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);
2
+ import {
3
+ getEnv,
4
+ init_env_schema
5
+ } from "./chunk-JCJS4ZIB.js";
6
+ import {
7
+ init_logger,
8
+ logInfo,
9
+ logWarn
10
+ } from "./chunk-BUUVFUPO.js";
11
+ import {
12
+ abtarsHome,
13
+ init_paths
14
+ } from "./chunk-X76UX47U.js";
15
+
16
+ // src/components/user-registry.ts
17
+ init_env_schema();
18
+ init_paths();
19
+ init_logger();
20
+ import { readFileSync, existsSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ var TAG = "user-registry";
23
+ var _override = null;
24
+ var _cached = null;
25
+ function setUserRegistryOverride(registry) {
26
+ _override = registry;
27
+ _cached = null;
28
+ }
29
+ function loadUsers() {
30
+ if (_override) return _override;
31
+ if (_cached) return _cached;
32
+ _cached = loadFromDisk();
33
+ return _cached;
34
+ }
35
+ function loadFromDisk() {
36
+ const configPath = join(abtarsHome(), "config", "users.json");
37
+ const registry = { users: [], byPlatformId: /* @__PURE__ */ new Map(), byUserId: /* @__PURE__ */ new Map() };
38
+ if (existsSync(configPath)) {
39
+ try {
40
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
41
+ const entries = Array.isArray(raw.users) ? raw.users : [];
42
+ for (const u of entries) {
43
+ if (!u.userId || !u.role) continue;
44
+ const entry = {
45
+ userId: u.userId,
46
+ displayName: u.displayName ?? u.userId,
47
+ role: u.role,
48
+ maxClass: typeof u.maxClass === "number" ? u.maxClass : u.role === "master" ? 3 : 0,
49
+ tools: Array.isArray(u.tools) ? u.tools : u.role === "master" ? ["all"] : [],
50
+ languages: Array.isArray(u.languages) ? u.languages : void 0,
51
+ platforms: u.platforms ?? {}
52
+ };
53
+ registry.users.push(entry);
54
+ registry.byUserId.set(entry.userId, entry);
55
+ if (entry.platforms.telegram) registry.byPlatformId.set(`telegram:${entry.platforms.telegram}`, entry);
56
+ if (entry.platforms.discord) registry.byPlatformId.set(`discord:${entry.platforms.discord}`, entry);
57
+ }
58
+ logInfo(TAG, `Loaded ${registry.users.length} users from users.json`);
59
+ } catch (err) {
60
+ logWarn(TAG, `Failed to parse users.json: ${err instanceof Error ? err.message : String(err)}`);
61
+ }
62
+ }
63
+ if (registry.users.length === 0) {
64
+ const mainChatId = getEnv().mainChatId;
65
+ if (mainChatId) {
66
+ const entry = {
67
+ userId: "master",
68
+ role: "master",
69
+ maxClass: 3,
70
+ tools: ["all"],
71
+ platforms: { telegram: parseInt(mainChatId, 10) || void 0 }
72
+ };
73
+ registry.users.push(entry);
74
+ registry.byUserId.set("master", entry);
75
+ registry.byPlatformId.set(`telegram:${mainChatId}`, entry);
76
+ logInfo(TAG, `Fallback: single master from MAIN_CHAT_ID`);
77
+ }
78
+ }
79
+ return registry;
80
+ }
81
+ function buildUsersBlock(registry) {
82
+ const CLASS_NAMES = ["UNCLASSIFIED", "RESTRICTED", "CONFIDENTIAL", "SECRET"];
83
+ const lines = registry.users.filter((u) => u.role !== "guest").map((u) => `- ${u.userId} (${u.role}, ${CLASS_NAMES[u.maxClass] ?? `class ${u.maxClass}`} clearance)`);
84
+ return `[USERS]
85
+ ${lines.join("\n")}`;
86
+ }
87
+
88
+ export {
89
+ setUserRegistryOverride,
90
+ loadUsers,
91
+ buildUsersBlock
92
+ };
93
+ //# sourceMappingURL=chunk-GST5T3WZ.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/components/user-registry.ts"],
4
+ "sourcesContent": ["import { getEnv } from \"./env-schema.js\";\n/**\n * User registry \u2014 loads users from config/users.json.\n * Falls back to MAIN_CHAT_ID.\n */\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { abtarsHome } from \"../paths.js\";\nimport { logInfo, logWarn } from \"./logger.js\";\n\nconst TAG = \"user-registry\";\n\nexport interface UserEntry {\n userId: string;\n displayName?: string;\n role: \"master\" | \"user\" | \"guest\";\n maxClass: number;\n tools: string[];\n languages?: string[];\n platforms: { telegram?: number; discord?: string };\n allowedChats?: string[];\n}\n\nexport interface UserRegistry {\n users: UserEntry[];\n byPlatformId: Map<string, UserEntry>;\n byUserId: Map<string, UserEntry>;\n}\n\nlet _override: UserRegistry | null = null;\nlet _cached: UserRegistry | null = null;\n\n/** Override registry for testing. Pass null to clear (also clears cache). */\nexport function setUserRegistryOverride(registry: UserRegistry | null): void { _override = registry; _cached = null; }\n\n/** Load users from config/users.json, fallback to MAIN_CHAT_ID. Cached after first call. */\nexport function loadUsers(): UserRegistry {\n if (_override) return _override;\n if (_cached) return _cached;\n _cached = loadFromDisk();\n return _cached;\n}\n\nfunction loadFromDisk(): UserRegistry {\n const configPath = join(abtarsHome(), \"config\", \"users.json\");\n const registry: UserRegistry = { users: [], byPlatformId: new Map(), byUserId: new Map() };\n\n if (existsSync(configPath)) {\n try {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const entries = Array.isArray(raw.users) ? raw.users as UserEntry[] : [];\n for (const u of entries) {\n if (!u.userId || !u.role) continue;\n const entry: UserEntry = {\n userId: u.userId,\n displayName: u.displayName ?? u.userId,\n role: u.role,\n maxClass: typeof u.maxClass === \"number\" ? u.maxClass : (u.role === \"master\" ? 3 : 0),\n tools: Array.isArray(u.tools) ? u.tools : (u.role === \"master\" ? [\"all\"] : []),\n languages: Array.isArray(u.languages) ? u.languages : undefined,\n platforms: u.platforms ?? {},\n };\n registry.users.push(entry);\n registry.byUserId.set(entry.userId, entry);\n if (entry.platforms.telegram) registry.byPlatformId.set(`telegram:${entry.platforms.telegram}`, entry);\n if (entry.platforms.discord) registry.byPlatformId.set(`discord:${entry.platforms.discord}`, entry);\n }\n logInfo(TAG, `Loaded ${registry.users.length} users from users.json`);\n } catch (err) {\n logWarn(TAG, `Failed to parse users.json: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n // Fallback: MAIN_CHAT_ID \u2192 single master\n if (registry.users.length === 0) {\n const mainChatId = getEnv().mainChatId;\n if (mainChatId) {\n const entry: UserEntry = {\n userId: \"master\",\n role: \"master\",\n maxClass: 3,\n tools: [\"all\"],\n platforms: { telegram: parseInt(mainChatId, 10) || undefined },\n };\n registry.users.push(entry);\n registry.byUserId.set(\"master\", entry);\n registry.byPlatformId.set(`telegram:${mainChatId}`, entry);\n logInfo(TAG, `Fallback: single master from MAIN_CHAT_ID`);\n }\n }\n\n return registry;\n}\n\n/** Build [USERS] block for soul bundle injection. */\nexport function buildUsersBlock(registry: UserRegistry): string {\n const CLASS_NAMES = [\"UNCLASSIFIED\", \"RESTRICTED\", \"CONFIDENTIAL\", \"SECRET\"];\n const lines = registry.users\n .filter(u => u.role !== \"guest\")\n .map(u => `- ${u.userId} (${u.role}, ${CLASS_NAMES[u.maxClass] ?? `class ${u.maxClass}`} clearance)`);\n return `[USERS]\\n${lines.join(\"\\n\")}`;\n}\n\n\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;AAAA;AAOA;AACA;AAHA,SAAS,cAAc,kBAAkB;AACzC,SAAS,YAAY;AAIrB,IAAM,MAAM;AAmBZ,IAAI,YAAiC;AACrC,IAAI,UAA+B;AAG5B,SAAS,wBAAwB,UAAqC;AAAE,cAAY;AAAU,YAAU;AAAM;AAG9G,SAAS,YAA0B;AACxC,MAAI,UAAW,QAAO;AACtB,MAAI,QAAS,QAAO;AACpB,YAAU,aAAa;AACvB,SAAO;AACT;AAEA,SAAS,eAA6B;AACpC,QAAM,aAAa,KAAK,WAAW,GAAG,UAAU,YAAY;AAC5D,QAAM,WAAyB,EAAE,OAAO,CAAC,GAAG,cAAc,oBAAI,IAAI,GAAG,UAAU,oBAAI,IAAI,EAAE;AAEzF,MAAI,WAAW,UAAU,GAAG;AAC1B,QAAI;AACF,YAAM,MAAM,KAAK,MAAM,aAAa,YAAY,OAAO,CAAC;AACxD,YAAM,UAAU,MAAM,QAAQ,IAAI,KAAK,IAAI,IAAI,QAAuB,CAAC;AACvE,iBAAW,KAAK,SAAS;AACvB,YAAI,CAAC,EAAE,UAAU,CAAC,EAAE,KAAM;AAC1B,cAAM,QAAmB;AAAA,UACvB,QAAQ,EAAE;AAAA,UACV,aAAa,EAAE,eAAe,EAAE;AAAA,UAChC,MAAM,EAAE;AAAA,UACR,UAAU,OAAO,EAAE,aAAa,WAAW,EAAE,WAAY,EAAE,SAAS,WAAW,IAAI;AAAA,UACnF,OAAO,MAAM,QAAQ,EAAE,KAAK,IAAI,EAAE,QAAS,EAAE,SAAS,WAAW,CAAC,KAAK,IAAI,CAAC;AAAA,UAC5E,WAAW,MAAM,QAAQ,EAAE,SAAS,IAAI,EAAE,YAAY;AAAA,UACtD,WAAW,EAAE,aAAa,CAAC;AAAA,QAC7B;AACA,iBAAS,MAAM,KAAK,KAAK;AACzB,iBAAS,SAAS,IAAI,MAAM,QAAQ,KAAK;AACzC,YAAI,MAAM,UAAU,SAAU,UAAS,aAAa,IAAI,YAAY,MAAM,UAAU,QAAQ,IAAI,KAAK;AACrG,YAAI,MAAM,UAAU,QAAS,UAAS,aAAa,IAAI,WAAW,MAAM,UAAU,OAAO,IAAI,KAAK;AAAA,MACpG;AACA,cAAQ,KAAK,UAAU,SAAS,MAAM,MAAM,wBAAwB;AAAA,IACtE,SAAS,KAAK;AACZ,cAAQ,KAAK,+BAA+B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IAChG;AAAA,EACF;AAGA,MAAI,SAAS,MAAM,WAAW,GAAG;AAC/B,UAAM,aAAa,OAAO,EAAE;AAC5B,QAAI,YAAY;AACd,YAAM,QAAmB;AAAA,QACvB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,UAAU;AAAA,QACV,OAAO,CAAC,KAAK;AAAA,QACb,WAAW,EAAE,UAAU,SAAS,YAAY,EAAE,KAAK,OAAU;AAAA,MAC/D;AACA,eAAS,MAAM,KAAK,KAAK;AACzB,eAAS,SAAS,IAAI,UAAU,KAAK;AACrC,eAAS,aAAa,IAAI,YAAY,UAAU,IAAI,KAAK;AACzD,cAAQ,KAAK,2CAA2C;AAAA,IAC1D;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,gBAAgB,UAAgC;AAC9D,QAAM,cAAc,CAAC,gBAAgB,cAAc,gBAAgB,QAAQ;AAC3E,QAAM,QAAQ,SAAS,MACpB,OAAO,OAAK,EAAE,SAAS,OAAO,EAC9B,IAAI,OAAK,KAAK,EAAE,MAAM,KAAK,EAAE,IAAI,KAAK,YAAY,EAAE,QAAQ,KAAK,SAAS,EAAE,QAAQ,EAAE,aAAa;AACtG,SAAO;AAAA,EAAY,MAAM,KAAK,IAAI,CAAC;AACrC;",
6
+ "names": []
7
+ }