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,532 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ function abtarsHome() {
5
+ return process.env.ABTARS_HOME ?? join(homedir(), ".abtars");
6
+ }
7
+ function reportsDir(cat) {
8
+ return join(abtarsHome(), "reports", cat);
9
+ }
10
+ function localDate() {
11
+ const d = /* @__PURE__ */ new Date();
12
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
13
+ }
14
+ function logAndSwallow(_tag, _ctx, _err) {
15
+ return void 0;
16
+ }
17
+ import { join, basename } from "node:path";
18
+ const AB_HOME = abtarsHome();
19
+ const TWITTER_DIR = join(AB_HOME, "workspace", "twitterX");
20
+ const COOKIE_PATH = join(AB_HOME, "secret", "cookies", "x-cookies.json");
21
+ const BASE_FOLLOWS = join(TWITTER_DIR, process.env["TWEET_BASE_FOLLOWS_FILE"] ?? "base.follows.json");
22
+ const AGENT_FOLLOWS = join(TWITTER_DIR, process.env["TWEET_FOLLOWS_FILE"] ?? "agent.follows.json");
23
+ const REPORTS_DIR = reportsDir("x");
24
+ const OUTPUT_DIR = join(TWITTER_DIR, "output");
25
+ async function sendReportToTelegram(filePath, caption) {
26
+ const token = process.env["TELEGRAM_BOT_TOKEN"];
27
+ const chatId = process.env["AGENTBRIDGE_MAIN_CHAT_ID"];
28
+ if (!token || !chatId) return;
29
+ if (!existsSync(filePath)) return;
30
+ const buf = readFileSync(filePath);
31
+ const form = new FormData();
32
+ form.append("chat_id", chatId);
33
+ const blob = new Blob([buf], { type: "text/markdown" });
34
+ form.append("document", blob, basename(filePath));
35
+ form.append("caption", caption.slice(0, 1024));
36
+ const res = await fetch(`https://api.telegram.org/bot${token}/sendDocument`, { method: "POST", body: form });
37
+ if (!res.ok) {
38
+ const text = await res.text().catch(() => "");
39
+ throw new Error(`Telegram sendDocument failed (${res.status}): ${text}`);
40
+ }
41
+ }
42
+ const AI_BIO_KEYWORDS = /\b(ai|ml|llm|machine.?learning|deep.?learning|neural|nlp|computer.?vision|reinforcement|transformer|diffusion|robotics|research|phd|professor|scientist)\b/i;
43
+ function loadApiKey() {
44
+ if (!existsSync(COOKIE_PATH)) return void 0;
45
+ try {
46
+ const raw = readFileSync(COOKIE_PATH, "utf8");
47
+ const parsed = JSON.parse(raw);
48
+ const cookieStr = Object.entries(parsed).map(([k, v]) => `${k}=${v}`).join("; ") + ";";
49
+ return Buffer.from(cookieStr).toString("base64");
50
+ } catch {
51
+ return void 0;
52
+ }
53
+ }
54
+ function loadFollows() {
55
+ const handles = /* @__PURE__ */ new Set();
56
+ for (const path of [BASE_FOLLOWS, AGENT_FOLLOWS]) {
57
+ if (!existsSync(path)) continue;
58
+ try {
59
+ const raw = JSON.parse(readFileSync(path, "utf8"));
60
+ if (Array.isArray(raw)) {
61
+ raw.forEach((e) => handles.add(e.handle.replace(/^@/, "").toLowerCase()));
62
+ } else {
63
+ raw.handles?.forEach((h) => handles.add(h.replace(/^@/, "").toLowerCase()));
64
+ raw.entries?.forEach((e) => handles.add(e.handle.replace(/^@/, "").toLowerCase()));
65
+ }
66
+ } catch (err) {
67
+ logAndSwallow("abtars_tweet", "op", err);
68
+ }
69
+ }
70
+ return [...handles];
71
+ }
72
+ async function fetchTweet(url) {
73
+ const match = url.match(/(?:twitter\.com|x\.com)\/(\w+)\/status\/(\d+)/);
74
+ if (!match) {
75
+ console.error("Invalid tweet URL. Expected: https://x.com/user/status/123");
76
+ process.exit(1);
77
+ }
78
+ const [, user, id] = match;
79
+ const res = await fetch(`https://api.fxtwitter.com/${user}/status/${id}`);
80
+ const data = await res.json();
81
+ if (data.code !== 200) {
82
+ console.error(`FxTwitter error: ${data.message}`);
83
+ process.exit(1);
84
+ }
85
+ const t = data.tweet;
86
+ console.log(JSON.stringify({
87
+ id: t.id,
88
+ author: t.author?.name,
89
+ handle: t.author?.screen_name,
90
+ text: t.text,
91
+ likes: t.likes,
92
+ retweets: t.retweets,
93
+ replies: t.replies,
94
+ views: t.views,
95
+ created_at: t.created_at,
96
+ media: t.media
97
+ }, null, 2));
98
+ }
99
+ async function loadRettiwt() {
100
+ try {
101
+ return await import("rettiwt-api");
102
+ } catch {
103
+ console.error("rettiwt-api not installed. Run: npm install rettiwt-api");
104
+ process.exit(1);
105
+ }
106
+ }
107
+ async function fetchUser(handle) {
108
+ const { Rettiwt } = await loadRettiwt();
109
+ const r = new Rettiwt();
110
+ const d = await r.user.details(handle.replace(/^@/, ""));
111
+ if (!d) {
112
+ console.error("User not found");
113
+ process.exit(1);
114
+ }
115
+ console.log(JSON.stringify(d.toJSON(), null, 2));
116
+ }
117
+ const GQL_USER_TWEETS = "https://x.com/i/api/graphql/E3opETHurmVJflFsUBVuUQ/UserTweets";
118
+ async function fetchTimeline(handle, count) {
119
+ const { Rettiwt } = await loadRettiwt();
120
+ const r = new Rettiwt();
121
+ const clean = handle.replace(/^@/, "");
122
+ const user = await r.user.details(clean);
123
+ if (!user) throw new Error(`User @${clean} not found`);
124
+ const auth = loadCookieHeader();
125
+ if (auth) {
126
+ try {
127
+ return await fetchTimelineGql(user.id, user.fullName ?? clean, clean, count);
128
+ } catch (err) {
129
+ logAndSwallow("abtars_tweet", "op", err);
130
+ }
131
+ }
132
+ const data = await r.user.timeline(user.id, count);
133
+ return data.list.map((t) => {
134
+ const j = t.toJSON();
135
+ const likes = j.likeCount ?? 0;
136
+ const retweets = j.retweetCount ?? 0;
137
+ const views = j.viewCount ?? 0;
138
+ return {
139
+ id: j.id,
140
+ text: j.fullText ?? "",
141
+ author: user.fullName ?? clean,
142
+ handle: clean,
143
+ likes,
144
+ retweets,
145
+ views,
146
+ createdAt: j.createdAt,
147
+ score: likes + retweets * 3 + (views ? views / 1e3 : 0)
148
+ };
149
+ });
150
+ }
151
+ async function fetchTimelineGql(userId, authorName, handle, count) {
152
+ const data = await twitterGql(GQL_USER_TWEETS, {
153
+ userId,
154
+ count,
155
+ includePromotedContent: false,
156
+ withQuickPromoteEligibilityTweetFields: true,
157
+ withVoice: true,
158
+ withV2Timeline: true
159
+ });
160
+ const instructions = data?.data?.user?.result?.timeline_v2?.timeline?.instructions ?? [];
161
+ const entries = instructions.find((i) => i.type === "TimelineAddEntries")?.entries ?? [];
162
+ const tweets = [];
163
+ for (const e of entries) {
164
+ const tw = e.content?.itemContent?.tweet_results?.result;
165
+ if (!tw?.legacy) continue;
166
+ const p = parseTweetResult(tw);
167
+ const likes = p.likes, retweets = p.retweets, views = p.views;
168
+ tweets.push({
169
+ id: p.id,
170
+ text: p.text,
171
+ author: p.name || authorName,
172
+ handle: p.handle || handle,
173
+ likes,
174
+ retweets,
175
+ views,
176
+ createdAt: p.createdAt,
177
+ score: likes + retweets * 3 + (views ? views / 1e3 : 0)
178
+ });
179
+ }
180
+ return tweets;
181
+ }
182
+ async function runFeed(format, count, topN, discover, outputPath) {
183
+ const handles = loadFollows();
184
+ if (handles.length === 0) {
185
+ console.error("No follows found. Create ~/.abtars/workspace/twitterX/base.follows.json or agent.follows.json");
186
+ process.exit(1);
187
+ }
188
+ console.error(`Fetching timelines for ${handles.length} handles...`);
189
+ const allTweets = [];
190
+ for (const h of handles) {
191
+ try {
192
+ console.error(` @${h}...`);
193
+ const tweets = await fetchTimeline(h, count);
194
+ const cutoff = Date.now() - 24 * 60 * 60 * 1e3;
195
+ const recent = tweets.filter((t) => new Date(t.createdAt).getTime() > cutoff);
196
+ allTweets.push(...recent);
197
+ } catch (e) {
198
+ console.error(` \u26A0 @${h} failed: ${e.message}`);
199
+ }
200
+ }
201
+ allTweets.sort((a, b) => b.score - a.score);
202
+ const top = allTweets.slice(0, topN);
203
+ let candidates = [];
204
+ if (discover && top.length > 0) {
205
+ candidates = await runDiscover(top.slice(0, 5), handles);
206
+ }
207
+ const date = localDate();
208
+ const outFile = outputPath ?? join(OUTPUT_DIR, `tweets-${date}.json`);
209
+ mkdirSync(join(outFile, ".."), { recursive: true });
210
+ const payload = { date, source: "abtars-tweet", totalCollected: allTweets.length, tweets: top, discover: candidates };
211
+ writeFileSync(outFile, JSON.stringify(payload, null, 2), "utf8");
212
+ console.error(`\u{1F4C4} ${top.length} tweets written to ${outFile}`);
213
+ if (format === "md") {
214
+ const md = renderNewsletter(top, candidates, date);
215
+ mkdirSync(REPORTS_DIR, { recursive: true });
216
+ const reportPath = join(REPORTS_DIR, `AI-Daily-${date}.md`);
217
+ writeFileSync(reportPath, md, "utf8");
218
+ console.error(`\u{1F4F0} Newsletter written to ${reportPath}`);
219
+ await sendReportToTelegram(reportPath, `AI Daily ${date}`).catch((err) => {
220
+ console.error(`\u26A0 Telegram send failed: ${err instanceof Error ? err.message : String(err)}`);
221
+ });
222
+ }
223
+ }
224
+ const BEARER = "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
225
+ const GQL_TWEET_DETAIL = "https://x.com/i/api/graphql/97JF30KziU00483E_8elBA/TweetDetail";
226
+ const UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
227
+ const GQL_FEATURES = {
228
+ rweb_tipjar_consumption_enabled: true,
229
+ responsive_web_graphql_exclude_directive_enabled: true,
230
+ verified_phone_label_enabled: false,
231
+ creator_subscriptions_tweet_preview_api_enabled: true,
232
+ responsive_web_graphql_timeline_navigation_enabled: true,
233
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
234
+ communities_web_enable_tweet_community_results_fetch: true,
235
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
236
+ articles_preview_enabled: true,
237
+ responsive_web_edit_tweet_api_enabled: true,
238
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
239
+ view_counts_everywhere_api_enabled: true,
240
+ longform_notetweets_consumption_enabled: true,
241
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
242
+ tweet_awards_web_tipping_enabled: false,
243
+ creator_subscriptions_quote_tweet_preview_enabled: false,
244
+ freedom_of_speech_not_reach_fetch_enabled: true,
245
+ standardized_nudges_misinfo: true,
246
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
247
+ rweb_video_timestamps_enabled: true,
248
+ longform_notetweets_rich_text_read_enabled: true,
249
+ longform_notetweets_inline_media_enabled: true,
250
+ responsive_web_enhance_cards_enabled: false
251
+ };
252
+ function loadCookieHeader() {
253
+ if (!existsSync(COOKIE_PATH)) return void 0;
254
+ try {
255
+ const parsed = JSON.parse(readFileSync(COOKIE_PATH, "utf8"));
256
+ const cookie = Object.entries(parsed).map(([k, v]) => `${k}=${v}`).join("; ");
257
+ return { cookie, csrf: parsed.ct0 };
258
+ } catch {
259
+ return void 0;
260
+ }
261
+ }
262
+ async function twitterGql(url, variables) {
263
+ const auth = loadCookieHeader();
264
+ if (!auth) throw new Error("User auth required. Refresh cookies in ~/.abtars/secret/cookies/x-cookies.json");
265
+ const params = new URLSearchParams({
266
+ variables: JSON.stringify(variables),
267
+ features: JSON.stringify(GQL_FEATURES)
268
+ });
269
+ const res = await fetch(`${url}?${params}`, {
270
+ headers: {
271
+ authorization: `Bearer ${BEARER}`,
272
+ "x-csrf-token": auth.csrf,
273
+ cookie: auth.cookie,
274
+ "user-agent": UA
275
+ }
276
+ });
277
+ if (!res.ok) {
278
+ if (res.status === 403) throw new Error("403 \u2014 cookies may be expired. Refresh in ~/.abtars/secret/cookies/x-cookies.json");
279
+ throw new Error(`Twitter API ${res.status}: ${await res.text().catch(() => "")}`);
280
+ }
281
+ return res.json();
282
+ }
283
+ function extractTweetsFromTimeline(data) {
284
+ const entries = [];
285
+ const instructions = data?.data?.tweetResult?.result?.timeline?.instructions ?? data?.data?.threaded_conversation_with_injections_v2?.instructions ?? data?.data?.search_by_raw_query?.search_timeline?.timeline?.instructions ?? [];
286
+ for (const inst of instructions) {
287
+ for (const entry of inst.entries ?? []) {
288
+ const tweet = entry.content?.itemContent?.tweet_results?.result ?? entry.content?.items?.[0]?.item?.itemContent?.tweet_results?.result;
289
+ if (tweet?.legacy) entries.push(tweet);
290
+ for (const item of entry.content?.items ?? []) {
291
+ const t = item.item?.itemContent?.tweet_results?.result;
292
+ if (t?.legacy) entries.push(t);
293
+ }
294
+ }
295
+ }
296
+ return entries;
297
+ }
298
+ function parseTweetResult(t) {
299
+ const legacy = t.legacy ?? {};
300
+ const userResult = t.core?.user_results?.result ?? {};
301
+ const userCore = userResult.core ?? {};
302
+ const userLegacy = userResult.legacy ?? {};
303
+ return {
304
+ id: legacy.id_str ?? t.rest_id ?? "",
305
+ handle: userCore.screen_name ?? userLegacy.screen_name ?? "",
306
+ name: userCore.name ?? userLegacy.name ?? "",
307
+ text: legacy.full_text ?? "",
308
+ likes: legacy.favorite_count ?? 0,
309
+ retweets: legacy.retweet_count ?? 0,
310
+ views: parseInt(t.views?.count ?? "0", 10),
311
+ createdAt: legacy.created_at ?? ""
312
+ };
313
+ }
314
+ async function fetchReplies(tweetId, minLikes) {
315
+ const data = await twitterGql(GQL_TWEET_DETAIL, {
316
+ focalTweetId: tweetId,
317
+ with_rux_injections: false,
318
+ rankingMode: "Relevance",
319
+ includePromotedContent: false,
320
+ withCommunity: true,
321
+ withQuickPromoteEligibilityTweetFields: true,
322
+ withBirdwatchNotes: true,
323
+ withVoice: true
324
+ });
325
+ const all = extractTweetsFromTimeline(data);
326
+ const seen = /* @__PURE__ */ new Set();
327
+ const replies = all.map(parseTweetResult).filter((t) => {
328
+ if (t.id === tweetId || seen.has(t.id) || t.likes < minLikes) return false;
329
+ seen.add(t.id);
330
+ return true;
331
+ }).sort((a, b) => b.likes - a.likes);
332
+ console.log(JSON.stringify(replies, null, 2));
333
+ }
334
+ async function searchTweets(_query, _count) {
335
+ console.error("\u26A0 Direct X search is restricted. Use --timeline per handle or web search for discovery.");
336
+ console.error(" Tip: abtars-tweet --replies <tweet-id> works for finding interesting commenters.");
337
+ process.exit(1);
338
+ }
339
+ async function runDiscover(topTweets, knownHandles) {
340
+ const auth = loadCookieHeader();
341
+ if (!auth) {
342
+ console.error(" \u26A0 Skipping discovery \u2014 user auth required. Refresh cookies.");
343
+ return [];
344
+ }
345
+ const { Rettiwt } = await loadRettiwt();
346
+ const guestRettiwt = new Rettiwt();
347
+ const known = new Set(knownHandles.map((h) => h.toLowerCase()));
348
+ const candidates = [];
349
+ const seen = /* @__PURE__ */ new Set();
350
+ console.error(`
351
+ \u{1F50D} Discovering new follows from top ${topTweets.length} tweets...`);
352
+ for (const tweet of topTweets) {
353
+ try {
354
+ console.error(` Checking replies on @${tweet.handle}/${tweet.id}...`);
355
+ const data = await twitterGql(GQL_TWEET_DETAIL, {
356
+ focalTweetId: tweet.id,
357
+ with_rux_injections: false,
358
+ rankingMode: "Relevance",
359
+ includePromotedContent: false,
360
+ withCommunity: true,
361
+ withQuickPromoteEligibilityTweetFields: true,
362
+ withBirdwatchNotes: true,
363
+ withVoice: true
364
+ });
365
+ const all = extractTweetsFromTimeline(data);
366
+ const goodReplies = all.map(parseTweetResult).filter((t) => t.id !== tweet.id && t.likes >= 50).sort((a, b) => b.likes - a.likes).slice(0, 5);
367
+ for (const reply of goodReplies) {
368
+ const rHandle = reply.handle.toLowerCase();
369
+ if (!rHandle || known.has(rHandle) || seen.has(rHandle)) continue;
370
+ seen.add(rHandle);
371
+ try {
372
+ const profile = await guestRettiwt.user.details(rHandle);
373
+ if (!profile) continue;
374
+ const pj = profile.toJSON();
375
+ const bio = pj.description ?? "";
376
+ if (!AI_BIO_KEYWORDS.test(bio)) continue;
377
+ candidates.push({
378
+ handle: rHandle,
379
+ name: pj.fullName ?? rHandle,
380
+ bio,
381
+ followers: pj.followersCount ?? 0,
382
+ foundVia: `reply on @${tweet.handle}'s tweet`,
383
+ replyLikes: reply.likes,
384
+ replyText: reply.text.slice(0, 200)
385
+ });
386
+ } catch (err) {
387
+ logAndSwallow("abtars_tweet", "op", err);
388
+ }
389
+ }
390
+ } catch (e) {
391
+ console.error(` \u26A0 Replies failed for ${tweet.id}: ${e.message}`);
392
+ }
393
+ }
394
+ console.error(` Found ${candidates.length} candidates`);
395
+ return candidates.sort((a, b) => b.replyLikes - a.replyLikes);
396
+ }
397
+ function renderNewsletter(tweets, candidates, date) {
398
+ const lines = [`# AI Daily Brief \u2014 ${date}
399
+ `];
400
+ if (tweets.length === 0) {
401
+ lines.push("No tweets found in the last 24 hours from followed accounts.\n");
402
+ return lines.join("\n");
403
+ }
404
+ lines.push("## \u{1F525} Top Tweets (by engagement)\n");
405
+ tweets.forEach((t, i) => {
406
+ const text = t.text.length > 280 ? t.text.slice(0, 277) + "..." : t.text;
407
+ lines.push(`### ${i + 1}. @${t.handle} \u2014 ${t.author}`);
408
+ lines.push(`- **Likes:** ${t.likes} | **Retweets:** ${t.retweets} | **Views:** ${t.views ?? "N/A"}`);
409
+ lines.push(`- ${text.replace(/\n/g, " ")}`);
410
+ lines.push(`- \u{1F517} https://x.com/${t.handle}/status/${t.id}
411
+ `);
412
+ });
413
+ if (candidates.length > 0) {
414
+ lines.push("## \u{1F464} Discover \u2014 New Follows\n");
415
+ candidates.forEach((c) => {
416
+ lines.push(`### @${c.handle} \u2014 ${c.name}`);
417
+ lines.push(`- **Bio:** ${c.bio.slice(0, 200)}`);
418
+ lines.push(`- **Followers:** ${c.followers.toLocaleString()}`);
419
+ lines.push(`- **Found via:** ${c.foundVia}`);
420
+ lines.push(`- **Their reply** (${c.replyLikes} likes): ${c.replyText.replace(/\n/g, " ")}
421
+ `);
422
+ });
423
+ }
424
+ lines.push("## \u{1F4CA} Signals & Trends\n");
425
+ lines.push("_(To be filled by sleep cycle analysis)_\n");
426
+ lines.push(`---
427
+ *Auto-generated via abtars-tweet. Sources: X (via rettiwt-api).*
428
+ `);
429
+ return lines.join("\n");
430
+ }
431
+ function parseArgs() {
432
+ const args = process.argv.slice(2);
433
+ let command = "feed";
434
+ let target = "";
435
+ let count = 20;
436
+ let topN = 12;
437
+ let format = "md";
438
+ let discover = false;
439
+ let minLikes = 50;
440
+ let output;
441
+ for (let i = 0; i < args.length; i++) {
442
+ switch (args[i]) {
443
+ case "--fetch":
444
+ command = "fetch";
445
+ target = args[++i] ?? "";
446
+ break;
447
+ case "--timeline":
448
+ command = "timeline";
449
+ target = args[++i] ?? "";
450
+ break;
451
+ case "--user":
452
+ command = "user";
453
+ target = args[++i] ?? "";
454
+ break;
455
+ case "--feed":
456
+ command = "feed";
457
+ break;
458
+ case "--replies":
459
+ command = "replies";
460
+ target = args[++i] ?? "";
461
+ break;
462
+ case "--search":
463
+ command = "search";
464
+ target = args[++i] ?? "";
465
+ break;
466
+ case "--discover":
467
+ discover = true;
468
+ break;
469
+ case "--count":
470
+ count = parseInt(args[++i] ?? "20", 10);
471
+ break;
472
+ case "--top":
473
+ topN = parseInt(args[++i] ?? "12", 10);
474
+ break;
475
+ case "--min-likes":
476
+ minLikes = parseInt(args[++i] ?? "50", 10);
477
+ break;
478
+ case "--format":
479
+ format = args[++i] ?? "md";
480
+ break;
481
+ case "--output":
482
+ output = args[++i] ?? "";
483
+ break;
484
+ }
485
+ }
486
+ return { command, target, count, topN, format, discover, minLikes, output };
487
+ }
488
+ async function main() {
489
+ if (process.argv.includes("--help")) {
490
+ console.log(`abtars-tweet \u2014 fetch tweets via rettiwt-api + FxTwitter.
491
+
492
+ Usage:
493
+ abtars-tweet --fetch <tweet-url> # single tweet via FxTwitter
494
+ abtars-tweet --timeline <handle> [--count N] # user timeline
495
+ abtars-tweet --feed [--format md] # all followed handles \u2192 ranked output
496
+ abtars-tweet --feed --discover # feed + reply analysis for new follows
497
+ abtars-tweet --replies <tweet-id> # replies on a tweet
498
+ abtars-tweet --search "query" # search X
499
+ abtars-tweet --user <handle> # user profile info`);
500
+ process.exit(0);
501
+ }
502
+ const { command, target, count, topN, format, discover, minLikes, output } = parseArgs();
503
+ switch (command) {
504
+ case "fetch":
505
+ await fetchTweet(target);
506
+ break;
507
+ case "user":
508
+ await fetchUser(target);
509
+ break;
510
+ case "timeline": {
511
+ const tweets = await fetchTimeline(target, count);
512
+ console.log(JSON.stringify(tweets, null, 2));
513
+ break;
514
+ }
515
+ case "replies":
516
+ await fetchReplies(target, minLikes);
517
+ break;
518
+ case "search":
519
+ await searchTweets(target, count);
520
+ break;
521
+ case "feed":
522
+ await runFeed(format, count, topN, discover, output);
523
+ break;
524
+ }
525
+ }
526
+ main().catch((e) => {
527
+ console.error(`Fatal: ${e.message}`);
528
+ process.exit(1);
529
+ });
530
+ export {
531
+ loadApiKey
532
+ };
@@ -0,0 +1 @@
1
+ { "type": "module" }
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: web-fetch
3
+ description: Fetch web page content as markdown using lightpanda (Level 1 browsing)
4
+ user-invocable: false
5
+ ---
6
+
7
+ # Web Fetch (Level 1)
8
+
9
+ Fast, lightweight page fetching. Returns clean markdown. No browser session, no login.
10
+
11
+ ```bash
12
+ abtars-fetch "<url>"
13
+ ```
14
+
15
+ Returns markdown to stdout. Truncated at 50K chars.
16
+
17
+ ## When to use
18
+ - Reading documentation, articles, news
19
+ - Checking public data (stock prices, weather, APIs)
20
+ - Any page that works without JavaScript or login
21
+
22
+ ## When NOT to use — escalate to Level 2
23
+ - Output is empty or says "enable JavaScript"
24
+ - Page requires login or authentication
25
+ - Multi-page navigation needed (click through, fill forms)
26
+ - Anti-bot protection (Cloudflare, captcha)
27
+ - Screenshots needed
28
+
29
+ For Level 2: use `abtars-browse --task "description" --chat-id <CHAT_ID>`
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "abtars",
3
+ "version": "0.1.0-alpha.1",
4
+ "description": "Standalone agent bridging Telegram to Kiro CLI via tmux/ACP",
5
+ "type": "module",
6
+ "main": "bundle/abtars.js",
7
+ "scripts": {
8
+ "build": "tsc && rm -rf dist/components/dashboard/public && cp -r src/components/dashboard/public dist/components/dashboard/public && git log -1 --format='{\"hash\":\"%h\",\"date\":\"%ci\"}' > dist/build-info.json",
9
+ "bundle": "rm -rf bundle && cd ../abmind && npm run build && cd ../abtars && node esbuild.config.js && rm -rf bundle/public && cp -r src/components/dashboard/public bundle/public && cp -r agents bundle/agents",
10
+ "dev": "node --import tsx src/main.ts",
11
+ "start": "node dist/main.js",
12
+ "typecheck": "tsc --noEmit",
13
+ "check-imports": "bash -c '! grep -rE \"from \\\"abmind/|from '\\''abmind/\" src --include=*.ts | grep -vE \"abmind/deploy-lib\\\"|abmind/deploy-lib'\\''\"'",
14
+ "test": "vitest --run",
15
+ "test:watch": "vitest"
16
+ },
17
+ "engines": {
18
+ "node": ">=22.0.0"
19
+ },
20
+ "dependencies": {
21
+ "@agentclientprotocol/sdk": "^0.14.1",
22
+ "@andresaya/edge-tts": "^1.8.0",
23
+ "@clack/prompts": "^1.2.0",
24
+ "abmind": "file:../abmind",
25
+ "cron-parser": "^5.5.0",
26
+ "discord.js": "^14.26.3",
27
+ "dotenv": "^16.6.1",
28
+ "file-type": "^22.0.1",
29
+ "jimp": "1.6.0",
30
+ "patchright": "^1.59.4",
31
+ "pdf-parse": "^2.4.5",
32
+ "ws": "^8.20.0",
33
+ "youtube-transcript": "^1.3.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^22.19.17",
37
+ "@types/pdf-parse": "^1.1.5",
38
+ "@types/ws": "^8.18.1",
39
+ "esbuild": "0.25.4",
40
+ "fast-check": "^4.7.0",
41
+ "tsx": "^4.21.0",
42
+ "typescript": "^5.9.3",
43
+ "vitest": "^4.1.5"
44
+ },
45
+ "bin": {
46
+ "abtars": "bundle/abtars-cli.js",
47
+ "abtars-browser": "bundle/abtars-browser.js",
48
+ "abtars-restart": "bundle/abtars-restart.js"
49
+ },
50
+ "license": "Apache-2.0",
51
+ "files": [
52
+ "bundle/",
53
+ "core/",
54
+ "scripts/",
55
+ "README.md",
56
+ "LICENSE",
57
+ "CHANGELOG.md"
58
+ ]
59
+ }
@@ -0,0 +1,23 @@
1
+ [Unit]
2
+ Description=Abtars (supervised-daemon)
3
+ After=network-online.target
4
+ Wants=network-online.target
5
+
6
+ [Service]
7
+ Type=simple
8
+ User={{USER}}
9
+ Group={{USER}}
10
+ WorkingDirectory=/home/{{USER}}/.abtars
11
+ ExecStart=/home/{{USER}}/.abtars/watchdog.sh
12
+ Restart=always
13
+ RestartSec=5
14
+ Environment=NODE_ENV=production
15
+ Environment=ABTARS_HOME=/home/{{USER}}/.abtars
16
+ Environment=ABMIND_HOME=/home/{{USER}}/.abmind
17
+ Environment=SUPERVISION=systemd
18
+ StandardOutput=journal
19
+ StandardError=journal
20
+ SyslogIdentifier=abtars
21
+
22
+ [Install]
23
+ WantedBy=multi-user.target
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+ # abtars-fetch — fetch a URL and return clean markdown.
3
+ # Usage: abtars-fetch <url>
4
+ # Returns truncated markdown to stdout. Exits 1 on error.
5
+ set -euo pipefail
6
+
7
+ MAX_CHARS=50000
8
+
9
+ if [[ $# -lt 1 ]]; then
10
+ echo "Usage: abtars-fetch <url>" >&2
11
+ exit 1
12
+ fi
13
+
14
+ URL="$1"
15
+
16
+ if ! command -v lightpanda &>/dev/null; then
17
+ echo "ERROR: lightpanda not installed. Use Level 2 browse (abtars-browse) instead." >&2
18
+ exit 1
19
+ fi
20
+
21
+ OUTPUT=$(lightpanda fetch \
22
+ --dump markdown \
23
+ --strip-mode full \
24
+ --http-connect-timeout 10000 \
25
+ --http-timeout 15000 \
26
+ --wait-ms 10000 \
27
+ --block-private-networks \
28
+ "$URL" 2>/dev/null)
29
+
30
+ if [[ -z "$OUTPUT" ]]; then
31
+ echo "ERROR: Empty response. Page may require JavaScript or login. Use Level 2 browse (abtars-browse) instead." >&2
32
+ exit 1
33
+ fi
34
+
35
+ # Truncate to prevent context window blowout
36
+ if [[ ${#OUTPUT} -gt $MAX_CHARS ]]; then
37
+ echo "${OUTPUT:0:$MAX_CHARS}"
38
+ echo ""
39
+ echo "[Content truncated at ${MAX_CHARS} characters]"
40
+ else
41
+ echo "$OUTPUT"
42
+ fi