@openacp/cli 0.6.10 → 2026.326.3

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 (256) hide show
  1. package/dist/{action-detect-P7ZE4NEM.js → action-detect-QPA775HB.js} +2 -2
  2. package/dist/adapter-6ANPBSVU.js +16 -0
  3. package/dist/{discord-OMC52Y54.js → adapter-77ZCVABT.js} +520 -365
  4. package/dist/adapter-77ZCVABT.js.map +1 -0
  5. package/dist/{adapter-ZOANORGM.js → adapter-PQGHVG4K.js} +300 -93
  6. package/dist/adapter-PQGHVG4K.js.map +1 -0
  7. package/dist/{admin-6SYB6XCZ.js → admin-GBPZFFAU.js} +3 -3
  8. package/dist/agent-catalog-YHBFERYO.js +11 -0
  9. package/dist/{agent-dependencies-4OWBMZWZ.js → agent-dependencies-WS7Z2DFW.js} +2 -2
  10. package/dist/agent-registry-5LZT7CUB.js +9 -0
  11. package/dist/agent-store-VSHNY5GT.js +9 -0
  12. package/dist/{agents-QO7DKARJ.js → agents-BWU4MRRD.js} +3 -3
  13. package/dist/{api-client-CFQT5U7D.js → api-client-AQPNKXI2.js} +2 -2
  14. package/dist/api-server-3PYLRBCN.js +8 -0
  15. package/dist/api-server-CHVSUDBX.js +11 -0
  16. package/dist/{autostart-X33OGMX6.js → autostart-6JS565RY.js} +3 -3
  17. package/dist/chunk-2CX4IEEC.js +124 -0
  18. package/dist/chunk-2CX4IEEC.js.map +1 -0
  19. package/dist/{chunk-O7CPGUAI.js → chunk-4KGLKKQK.js} +4 -4
  20. package/dist/chunk-4KGLKKQK.js.map +1 -0
  21. package/dist/{chunk-W3EYKZNQ.js → chunk-4WXALZA3.js} +2 -2
  22. package/dist/chunk-4WXALZA3.js.map +1 -0
  23. package/dist/chunk-5OCGO27U.js +125 -0
  24. package/dist/chunk-5OCGO27U.js.map +1 -0
  25. package/dist/{chunk-OWP7RZ62.js → chunk-5ZOFBTOR.js} +118 -262
  26. package/dist/chunk-5ZOFBTOR.js.map +1 -0
  27. package/dist/chunk-6RXVEXF3.js +23 -0
  28. package/dist/chunk-6RXVEXF3.js.map +1 -0
  29. package/dist/{chunk-34M4OS5P.js → chunk-A6Y4GZM3.js} +3 -3
  30. package/dist/chunk-A6Y4GZM3.js.map +1 -0
  31. package/dist/chunk-AD3X6DGK.js +166 -0
  32. package/dist/chunk-AD3X6DGK.js.map +1 -0
  33. package/dist/{chunk-7QJS2XBD.js → chunk-AFKX424Q.js} +2 -2
  34. package/dist/chunk-AFKX424Q.js.map +1 -0
  35. package/dist/chunk-APS6UEFU.js +259 -0
  36. package/dist/chunk-APS6UEFU.js.map +1 -0
  37. package/dist/chunk-BLQUXO7S.js +113 -0
  38. package/dist/chunk-BLQUXO7S.js.map +1 -0
  39. package/dist/{chunk-WTZDAYZX.js → chunk-BQ6FR32N.js} +3 -3
  40. package/dist/chunk-BQ6FR32N.js.map +1 -0
  41. package/dist/chunk-FNRSWA2K.js +1 -0
  42. package/dist/chunk-FQEBWOZR.js +3557 -0
  43. package/dist/chunk-FQEBWOZR.js.map +1 -0
  44. package/dist/{chunk-4CTX774K.js → chunk-GJOY37U7.js} +4 -4
  45. package/dist/chunk-GJOY37U7.js.map +1 -0
  46. package/dist/{chunk-I7WC6E5S.js → chunk-HVBNCPAY.js} +2 -2
  47. package/dist/chunk-HVBNCPAY.js.map +1 -0
  48. package/dist/{chunk-2HMQOC7N.js → chunk-I3CGU5W7.js} +4 -4
  49. package/dist/chunk-I3CGU5W7.js.map +1 -0
  50. package/dist/{chunk-NVPG6JCL.js → chunk-L7YNNBI5.js} +3 -3
  51. package/dist/chunk-L7YNNBI5.js.map +1 -0
  52. package/dist/chunk-LGFWH3AE.js +26 -0
  53. package/dist/chunk-LGFWH3AE.js.map +1 -0
  54. package/dist/chunk-MLF4W5R6.js +101 -0
  55. package/dist/chunk-MLF4W5R6.js.map +1 -0
  56. package/dist/{chunk-KIRH7TUJ.js → chunk-MTSDOSXS.js} +3 -3
  57. package/dist/chunk-MTSDOSXS.js.map +1 -0
  58. package/dist/{chunk-J4SJTKIK.js → chunk-NAM4ERUW.js} +3 -3
  59. package/dist/chunk-NAM4ERUW.js.map +1 -0
  60. package/dist/{chunk-MKHUZLII.js → chunk-NBFIBGAT.js} +39 -25
  61. package/dist/chunk-NBFIBGAT.js.map +1 -0
  62. package/dist/{chunk-BNLGTZ34.js → chunk-O5RG4YZY.js} +3 -3
  63. package/dist/chunk-O5RG4YZY.js.map +1 -0
  64. package/dist/{chunk-JHYXKVV2.js → chunk-ODUM3D6X.js} +2 -2
  65. package/dist/chunk-ODUM3D6X.js.map +1 -0
  66. package/dist/chunk-OYSAN7UX.js +15 -0
  67. package/dist/chunk-OYSAN7UX.js.map +1 -0
  68. package/dist/chunk-P4SNGQNI.js +158 -0
  69. package/dist/chunk-P4SNGQNI.js.map +1 -0
  70. package/dist/{chunk-2CJ46J3C.js → chunk-PPSMUECX.js} +3 -3
  71. package/dist/chunk-PPSMUECX.js.map +1 -0
  72. package/dist/chunk-Q6ZXJTZB.js +56 -0
  73. package/dist/chunk-Q6ZXJTZB.js.map +1 -0
  74. package/dist/{chunk-XANPHG7W.js → chunk-QSDZDHNS.js} +7 -7
  75. package/dist/chunk-QSDZDHNS.js.map +1 -0
  76. package/dist/{chunk-33RP6K2O.js → chunk-QVMEF6FB.js} +6 -6
  77. package/dist/chunk-QVMEF6FB.js.map +1 -0
  78. package/dist/chunk-QWP76EBW.js +536 -0
  79. package/dist/chunk-QWP76EBW.js.map +1 -0
  80. package/dist/{chunk-V5GZQEIY.js → chunk-RBYBSSGO.js} +4 -4
  81. package/dist/chunk-RBYBSSGO.js.map +1 -0
  82. package/dist/{chunk-CS3KCJ5D.js → chunk-RKB2ZK6S.js} +555 -383
  83. package/dist/chunk-RKB2ZK6S.js.map +1 -0
  84. package/dist/{chunk-UKT3G5IA.js → chunk-SHTGQGAU.js} +7 -7
  85. package/dist/chunk-SHTGQGAU.js.map +1 -0
  86. package/dist/chunk-SNPYTMPR.js +51 -0
  87. package/dist/chunk-SNPYTMPR.js.map +1 -0
  88. package/dist/chunk-UB2QB6DE.js +124 -0
  89. package/dist/chunk-UB2QB6DE.js.map +1 -0
  90. package/dist/chunk-UNJUWWQO.js +1108 -0
  91. package/dist/chunk-UNJUWWQO.js.map +1 -0
  92. package/dist/chunk-V2M243KZ.js +445 -0
  93. package/dist/chunk-V2M243KZ.js.map +1 -0
  94. package/dist/chunk-V5JT5TPD.js +97 -0
  95. package/dist/chunk-V5JT5TPD.js.map +1 -0
  96. package/dist/chunk-W26AUH5B.js +61 -0
  97. package/dist/chunk-W26AUH5B.js.map +1 -0
  98. package/dist/chunk-WAAD23KY.js +222 -0
  99. package/dist/chunk-WAAD23KY.js.map +1 -0
  100. package/dist/chunk-WIIZNPCR.js +150 -0
  101. package/dist/chunk-WIIZNPCR.js.map +1 -0
  102. package/dist/chunk-WQCJTU2C.js +84 -0
  103. package/dist/chunk-WQCJTU2C.js.map +1 -0
  104. package/dist/chunk-WVLDNYOJ.js +150 -0
  105. package/dist/chunk-WVLDNYOJ.js.map +1 -0
  106. package/dist/chunk-WXVT3AOY.js +22 -0
  107. package/dist/chunk-WXVT3AOY.js.map +1 -0
  108. package/dist/{chunk-GAK6PIBW.js → chunk-XMMAGAT4.js} +2 -2
  109. package/dist/chunk-XMMAGAT4.js.map +1 -0
  110. package/dist/chunk-Y64XWMJ4.js +212 -0
  111. package/dist/chunk-Y64XWMJ4.js.map +1 -0
  112. package/dist/chunk-YEULD3SG.js +62 -0
  113. package/dist/chunk-YEULD3SG.js.map +1 -0
  114. package/dist/chunk-ZHGPZBS4.js +49 -0
  115. package/dist/chunk-ZHGPZBS4.js.map +1 -0
  116. package/dist/{chunk-JKBFUAJK.js → chunk-ZSLHHQPQ.js} +2 -2
  117. package/dist/chunk-ZSLHHQPQ.js.map +1 -0
  118. package/dist/cli.js +496 -150
  119. package/dist/cli.js.map +1 -1
  120. package/dist/{config-6S355X75.js → config-I4FMCJGZ.js} +3 -3
  121. package/dist/config-editor-HNEKXRLQ.js +11 -0
  122. package/dist/{config-registry-AHYI4MYL.js → config-registry-CUMNXFGK.js} +2 -2
  123. package/dist/context-XM6E22LM.js +10 -0
  124. package/dist/core-plugins-VEUNFTMB.js +27 -0
  125. package/dist/{daemon-4CS6HMB5.js → daemon-PXO5QPCR.js} +4 -4
  126. package/dist/dev-loader-RDC5E2CW.js +50 -0
  127. package/dist/dev-loader-RDC5E2CW.js.map +1 -0
  128. package/dist/discord-NOJQ5PZO.js +8 -0
  129. package/dist/doctor-H72BZOPA.js +10 -0
  130. package/dist/{doctor-OLYBO3V3.js → doctor-RF6BHMCC.js} +5 -5
  131. package/dist/file-service-EUODJAIT.js +9 -0
  132. package/dist/file-service-EUODJAIT.js.map +1 -0
  133. package/dist/index.d.ts +1293 -188
  134. package/dist/index.js +387 -48
  135. package/dist/index.js.map +1 -1
  136. package/dist/{install-cloudflared-Z7VCGOVG.js → install-cloudflared-AN24L4DP.js} +5 -5
  137. package/dist/install-cloudflared-AN24L4DP.js.map +1 -0
  138. package/dist/install-context-XPWTFT3J.js +78 -0
  139. package/dist/install-context-XPWTFT3J.js.map +1 -0
  140. package/dist/{install-jq-HUYSQWKR.js → install-jq-CRVDJGF3.js} +5 -5
  141. package/dist/install-jq-CRVDJGF3.js.map +1 -0
  142. package/dist/{integrate-PNEHRY2I.js → integrate-5C6KSU6D.js} +2 -2
  143. package/dist/integrate-5C6KSU6D.js.map +1 -0
  144. package/dist/{log-NXABYJTT.js → log-LZ7FTRKG.js} +2 -2
  145. package/dist/log-LZ7FTRKG.js.map +1 -0
  146. package/dist/main-T5WVCCFN.js +715 -0
  147. package/dist/main-T5WVCCFN.js.map +1 -0
  148. package/dist/{menu-YY5MKHEK.js → menu-YDQ2LWAR.js} +2 -2
  149. package/dist/menu-YDQ2LWAR.js.map +1 -0
  150. package/dist/{new-session-FEO4J4VU.js → new-session-AVQCNXRG.js} +5 -5
  151. package/dist/new-session-AVQCNXRG.js.map +1 -0
  152. package/dist/notifications-D5BRDNSU.js +9 -0
  153. package/dist/notifications-D5BRDNSU.js.map +1 -0
  154. package/dist/plugin-create-LYF5PP5W.js +327 -0
  155. package/dist/plugin-create-LYF5PP5W.js.map +1 -0
  156. package/dist/plugin-registry-WB3DR67H.js +8 -0
  157. package/dist/plugin-registry-WB3DR67H.js.map +1 -0
  158. package/dist/{post-upgrade-CJG5I7M2.js → post-upgrade-XLHZ6ZB7.js} +8 -8
  159. package/dist/post-upgrade-XLHZ6ZB7.js.map +1 -0
  160. package/dist/read-text-file-IRZM3QLM.js +8 -0
  161. package/dist/read-text-file-IRZM3QLM.js.map +1 -0
  162. package/dist/security-YNRBW6S7.js +9 -0
  163. package/dist/security-YNRBW6S7.js.map +1 -0
  164. package/dist/{session-IUSI7P5S.js → session-KZFA6Z26.js} +4 -4
  165. package/dist/session-KZFA6Z26.js.map +1 -0
  166. package/dist/{settings-RQPAM4KC.js → settings-MFYM7CZO.js} +4 -4
  167. package/dist/settings-MFYM7CZO.js.map +1 -0
  168. package/dist/settings-manager-MD2U4ZV2.js +8 -0
  169. package/dist/settings-manager-MD2U4ZV2.js.map +1 -0
  170. package/dist/{chunk-LCRLAV4G.js → setup-BAI2F24H.js} +154 -492
  171. package/dist/setup-BAI2F24H.js.map +1 -0
  172. package/dist/slack-KH7E3VBS.js +8 -0
  173. package/dist/slack-KH7E3VBS.js.map +1 -0
  174. package/dist/speech-2GHQNRIO.js +9 -0
  175. package/dist/speech-2GHQNRIO.js.map +1 -0
  176. package/dist/telegram-ZDC3JQF2.js +8 -0
  177. package/dist/telegram-ZDC3JQF2.js.map +1 -0
  178. package/dist/tunnel-M47I7H4B.js +8 -0
  179. package/dist/tunnel-M47I7H4B.js.map +1 -0
  180. package/dist/{tunnel-service-CJLUH6SZ.js → tunnel-service-WADYHREX.js} +17 -17
  181. package/dist/tunnel-service-WADYHREX.js.map +1 -0
  182. package/dist/usage-WYNK6ZC5.js +10 -0
  183. package/dist/usage-WYNK6ZC5.js.map +1 -0
  184. package/dist/validators-6CLEZUBD.js +8 -0
  185. package/dist/validators-6CLEZUBD.js.map +1 -0
  186. package/dist/validators-WSTBNKRW.js +12 -0
  187. package/dist/validators-WSTBNKRW.js.map +1 -0
  188. package/package.json +1 -1
  189. package/dist/adapter-ZOANORGM.js.map +0 -1
  190. package/dist/agent-catalog-FC3HGDEQ.js +0 -11
  191. package/dist/agent-registry-WT4NXPYG.js +0 -9
  192. package/dist/agent-store-VZLFPTZU.js +0 -9
  193. package/dist/chunk-2CJ46J3C.js.map +0 -1
  194. package/dist/chunk-2HMQOC7N.js.map +0 -1
  195. package/dist/chunk-33RP6K2O.js.map +0 -1
  196. package/dist/chunk-34M4OS5P.js.map +0 -1
  197. package/dist/chunk-4CTX774K.js.map +0 -1
  198. package/dist/chunk-7QJS2XBD.js.map +0 -1
  199. package/dist/chunk-BNLGTZ34.js.map +0 -1
  200. package/dist/chunk-CS3KCJ5D.js.map +0 -1
  201. package/dist/chunk-GAK6PIBW.js.map +0 -1
  202. package/dist/chunk-I7WC6E5S.js.map +0 -1
  203. package/dist/chunk-J4SJTKIK.js.map +0 -1
  204. package/dist/chunk-JHYXKVV2.js.map +0 -1
  205. package/dist/chunk-JKBFUAJK.js.map +0 -1
  206. package/dist/chunk-KIRH7TUJ.js.map +0 -1
  207. package/dist/chunk-LBIKITQT.js +0 -22
  208. package/dist/chunk-LBIKITQT.js.map +0 -1
  209. package/dist/chunk-LCRLAV4G.js.map +0 -1
  210. package/dist/chunk-LGP2YGRL.js +0 -4880
  211. package/dist/chunk-LGP2YGRL.js.map +0 -1
  212. package/dist/chunk-MKHUZLII.js.map +0 -1
  213. package/dist/chunk-NAMYZIS5.js +0 -1
  214. package/dist/chunk-NVPG6JCL.js.map +0 -1
  215. package/dist/chunk-O7CPGUAI.js.map +0 -1
  216. package/dist/chunk-OWP7RZ62.js.map +0 -1
  217. package/dist/chunk-UKT3G5IA.js.map +0 -1
  218. package/dist/chunk-V5GZQEIY.js.map +0 -1
  219. package/dist/chunk-VOIJ6OY4.js +0 -63
  220. package/dist/chunk-VOIJ6OY4.js.map +0 -1
  221. package/dist/chunk-W3EYKZNQ.js.map +0 -1
  222. package/dist/chunk-WTZDAYZX.js.map +0 -1
  223. package/dist/chunk-XANPHG7W.js.map +0 -1
  224. package/dist/config-editor-QQTZMWGD.js +0 -13
  225. package/dist/discord-OMC52Y54.js.map +0 -1
  226. package/dist/doctor-HZZ5BSHB.js +0 -10
  227. package/dist/install-cloudflared-Z7VCGOVG.js.map +0 -1
  228. package/dist/install-jq-HUYSQWKR.js.map +0 -1
  229. package/dist/integrate-PNEHRY2I.js.map +0 -1
  230. package/dist/main-XOZCLFUK.js +0 -238
  231. package/dist/main-XOZCLFUK.js.map +0 -1
  232. package/dist/post-upgrade-CJG5I7M2.js.map +0 -1
  233. package/dist/setup-XHS4OMPM.js +0 -37
  234. package/dist/tunnel-service-CJLUH6SZ.js.map +0 -1
  235. /package/dist/{action-detect-P7ZE4NEM.js.map → action-detect-QPA775HB.js.map} +0 -0
  236. /package/dist/{admin-6SYB6XCZ.js.map → adapter-6ANPBSVU.js.map} +0 -0
  237. /package/dist/{agent-catalog-FC3HGDEQ.js.map → admin-GBPZFFAU.js.map} +0 -0
  238. /package/dist/{agent-dependencies-4OWBMZWZ.js.map → agent-catalog-YHBFERYO.js.map} +0 -0
  239. /package/dist/{agent-registry-WT4NXPYG.js.map → agent-dependencies-WS7Z2DFW.js.map} +0 -0
  240. /package/dist/{agent-store-VZLFPTZU.js.map → agent-registry-5LZT7CUB.js.map} +0 -0
  241. /package/dist/{agents-QO7DKARJ.js.map → agent-store-VSHNY5GT.js.map} +0 -0
  242. /package/dist/{api-client-CFQT5U7D.js.map → agents-BWU4MRRD.js.map} +0 -0
  243. /package/dist/{autostart-X33OGMX6.js.map → api-client-AQPNKXI2.js.map} +0 -0
  244. /package/dist/{chunk-NAMYZIS5.js.map → api-server-3PYLRBCN.js.map} +0 -0
  245. /package/dist/{config-6S355X75.js.map → api-server-CHVSUDBX.js.map} +0 -0
  246. /package/dist/{config-editor-QQTZMWGD.js.map → autostart-6JS565RY.js.map} +0 -0
  247. /package/dist/{config-registry-AHYI4MYL.js.map → chunk-FNRSWA2K.js.map} +0 -0
  248. /package/dist/{daemon-4CS6HMB5.js.map → config-I4FMCJGZ.js.map} +0 -0
  249. /package/dist/{doctor-HZZ5BSHB.js.map → config-editor-HNEKXRLQ.js.map} +0 -0
  250. /package/dist/{doctor-OLYBO3V3.js.map → config-registry-CUMNXFGK.js.map} +0 -0
  251. /package/dist/{log-NXABYJTT.js.map → context-XM6E22LM.js.map} +0 -0
  252. /package/dist/{menu-YY5MKHEK.js.map → core-plugins-VEUNFTMB.js.map} +0 -0
  253. /package/dist/{new-session-FEO4J4VU.js.map → daemon-PXO5QPCR.js.map} +0 -0
  254. /package/dist/{session-IUSI7P5S.js.map → discord-NOJQ5PZO.js.map} +0 -0
  255. /package/dist/{settings-RQPAM4KC.js.map → doctor-H72BZOPA.js.map} +0 -0
  256. /package/dist/{setup-XHS4OMPM.js.map → doctor-RF6BHMCC.js.map} +0 -0
@@ -0,0 +1,150 @@
1
+ // src/plugins/speech/speech-service.ts
2
+ var SpeechService = class {
3
+ constructor(config) {
4
+ this.config = config;
5
+ }
6
+ sttProviders = /* @__PURE__ */ new Map();
7
+ ttsProviders = /* @__PURE__ */ new Map();
8
+ providerFactory;
9
+ /** Set a factory function that can recreate providers from config (for hot-reload) */
10
+ setProviderFactory(factory) {
11
+ this.providerFactory = factory;
12
+ }
13
+ registerSTTProvider(name, provider) {
14
+ this.sttProviders.set(name, provider);
15
+ }
16
+ registerTTSProvider(name, provider) {
17
+ this.ttsProviders.set(name, provider);
18
+ }
19
+ isSTTAvailable() {
20
+ const { provider, providers } = this.config.stt;
21
+ return provider !== null && providers[provider]?.apiKey !== void 0;
22
+ }
23
+ isTTSAvailable() {
24
+ const provider = this.config.tts.provider;
25
+ return provider !== null && this.ttsProviders.has(provider);
26
+ }
27
+ async transcribe(audioBuffer, mimeType, options) {
28
+ const providerName = this.config.stt.provider;
29
+ if (!providerName || !this.config.stt.providers[providerName]?.apiKey) {
30
+ throw new Error("STT not configured. Set speech.stt.provider and API key in config.");
31
+ }
32
+ const provider = this.sttProviders.get(providerName);
33
+ if (!provider) {
34
+ throw new Error(`STT provider "${providerName}" not registered. Available: ${[...this.sttProviders.keys()].join(", ") || "none"}`);
35
+ }
36
+ return provider.transcribe(audioBuffer, mimeType, options);
37
+ }
38
+ async synthesize(text, options) {
39
+ const providerName = this.config.tts.provider;
40
+ if (!providerName) {
41
+ throw new Error("TTS not configured. Set speech.tts.provider in config.");
42
+ }
43
+ const provider = this.ttsProviders.get(providerName);
44
+ if (!provider) {
45
+ throw new Error(`TTS provider "${providerName}" not registered. Available: ${[...this.ttsProviders.keys()].join(", ") || "none"}`);
46
+ }
47
+ return provider.synthesize(text, options);
48
+ }
49
+ updateConfig(config) {
50
+ this.config = config;
51
+ }
52
+ /** Re-create all providers from current config using the registered factory */
53
+ refreshProviders(newConfig) {
54
+ this.config = newConfig;
55
+ if (this.providerFactory) {
56
+ const { stt, tts } = this.providerFactory(newConfig);
57
+ this.sttProviders = stt;
58
+ this.ttsProviders = tts;
59
+ }
60
+ }
61
+ };
62
+
63
+ // src/plugins/speech/providers/groq.ts
64
+ var GROQ_API_URL = "https://api.groq.com/openai/v1/audio/transcriptions";
65
+ var GroqSTT = class {
66
+ constructor(apiKey, defaultModel = "whisper-large-v3-turbo") {
67
+ this.apiKey = apiKey;
68
+ this.defaultModel = defaultModel;
69
+ }
70
+ name = "groq";
71
+ async transcribe(audioBuffer, mimeType, options) {
72
+ const ext = mimeToExt(mimeType);
73
+ const form = new FormData();
74
+ form.append("file", new Blob([new Uint8Array(audioBuffer)], { type: mimeType }), `audio${ext}`);
75
+ form.append("model", options?.model || this.defaultModel);
76
+ form.append("response_format", "verbose_json");
77
+ if (options?.language) {
78
+ form.append("language", options.language);
79
+ }
80
+ const resp = await fetch(GROQ_API_URL, {
81
+ method: "POST",
82
+ headers: { Authorization: `Bearer ${this.apiKey}` },
83
+ body: form
84
+ });
85
+ if (!resp.ok) {
86
+ const body = await resp.text();
87
+ if (resp.status === 401) {
88
+ throw new Error("Invalid Groq API key. Check your key at console.groq.com.");
89
+ }
90
+ if (resp.status === 413) {
91
+ throw new Error("Audio file too large for Groq API (max 25MB).");
92
+ }
93
+ if (resp.status === 429) {
94
+ throw new Error("Groq rate limit exceeded. Free tier: 28,800 seconds/day. Try again later.");
95
+ }
96
+ throw new Error(`Groq STT error (${resp.status}): ${body}`);
97
+ }
98
+ const data = await resp.json();
99
+ return {
100
+ text: data.text,
101
+ language: data.language,
102
+ duration: data.duration
103
+ };
104
+ }
105
+ };
106
+ function mimeToExt(mimeType) {
107
+ const map = {
108
+ "audio/ogg": ".ogg",
109
+ "audio/wav": ".wav",
110
+ "audio/mpeg": ".mp3",
111
+ "audio/mp4": ".m4a",
112
+ "audio/webm": ".webm",
113
+ "audio/flac": ".flac"
114
+ };
115
+ return map[mimeType] || ".bin";
116
+ }
117
+
118
+ // src/plugins/speech/providers/edge-tts.ts
119
+ var DEFAULT_VOICE = "en-US-AriaNeural";
120
+ var EdgeTTS = class {
121
+ name = "edge-tts";
122
+ voice;
123
+ constructor(voice) {
124
+ this.voice = voice || DEFAULT_VOICE;
125
+ }
126
+ async synthesize(text, options) {
127
+ const { MsEdgeTTS, OUTPUT_FORMAT } = await import("./dist-UHQK5CXN.js");
128
+ const tts = new MsEdgeTTS();
129
+ const voice = options?.voice || this.voice;
130
+ const format = OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3;
131
+ await tts.setMetadata(voice, format);
132
+ const { audioStream } = tts.toStream(text);
133
+ const chunks = [];
134
+ for await (const chunk of audioStream) {
135
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
136
+ }
137
+ tts.close();
138
+ return {
139
+ audioBuffer: Buffer.concat(chunks),
140
+ mimeType: "audio/mpeg"
141
+ };
142
+ }
143
+ };
144
+
145
+ export {
146
+ SpeechService,
147
+ GroqSTT,
148
+ EdgeTTS
149
+ };
150
+ //# sourceMappingURL=chunk-WIIZNPCR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/speech/speech-service.ts","../../src/plugins/speech/providers/groq.ts","../../src/plugins/speech/providers/edge-tts.ts"],"sourcesContent":["import type { STTProvider, TTSProvider, STTOptions, STTResult, TTSOptions, TTSResult, SpeechServiceConfig } from './speech-types.js';\n\nexport type ProviderFactory = (config: SpeechServiceConfig) => { stt: Map<string, STTProvider>; tts: Map<string, TTSProvider> };\n\nexport class SpeechService {\n private sttProviders = new Map<string, STTProvider>();\n private ttsProviders = new Map<string, TTSProvider>();\n private providerFactory?: ProviderFactory;\n\n constructor(private config: SpeechServiceConfig) {}\n\n /** Set a factory function that can recreate providers from config (for hot-reload) */\n setProviderFactory(factory: ProviderFactory): void {\n this.providerFactory = factory;\n }\n\n registerSTTProvider(name: string, provider: STTProvider): void {\n this.sttProviders.set(name, provider);\n }\n\n registerTTSProvider(name: string, provider: TTSProvider): void {\n this.ttsProviders.set(name, provider);\n }\n\n isSTTAvailable(): boolean {\n const { provider, providers } = this.config.stt;\n return provider !== null && providers[provider]?.apiKey !== undefined;\n }\n\n isTTSAvailable(): boolean {\n const provider = this.config.tts.provider;\n return provider !== null && this.ttsProviders.has(provider);\n }\n\n async transcribe(audioBuffer: Buffer, mimeType: string, options?: STTOptions): Promise<STTResult> {\n const providerName = this.config.stt.provider;\n if (!providerName || !this.config.stt.providers[providerName]?.apiKey) {\n throw new Error(\"STT not configured. Set speech.stt.provider and API key in config.\");\n }\n const provider = this.sttProviders.get(providerName);\n if (!provider) {\n throw new Error(`STT provider \"${providerName}\" not registered. Available: ${[...this.sttProviders.keys()].join(\", \") || \"none\"}`);\n }\n return provider.transcribe(audioBuffer, mimeType, options);\n }\n\n async synthesize(text: string, options?: TTSOptions): Promise<TTSResult> {\n const providerName = this.config.tts.provider;\n if (!providerName) {\n throw new Error(\"TTS not configured. Set speech.tts.provider in config.\");\n }\n const provider = this.ttsProviders.get(providerName);\n if (!provider) {\n throw new Error(`TTS provider \"${providerName}\" not registered. Available: ${[...this.ttsProviders.keys()].join(\", \") || \"none\"}`);\n }\n return provider.synthesize(text, options);\n }\n\n updateConfig(config: SpeechServiceConfig): void {\n this.config = config;\n }\n\n /** Re-create all providers from current config using the registered factory */\n refreshProviders(newConfig: SpeechServiceConfig): void {\n this.config = newConfig;\n if (this.providerFactory) {\n const { stt, tts } = this.providerFactory(newConfig);\n this.sttProviders = stt;\n this.ttsProviders = tts;\n }\n }\n}\n","import type { STTProvider, STTOptions, STTResult } from '../speech-types.js';\n\nconst GROQ_API_URL = \"https://api.groq.com/openai/v1/audio/transcriptions\";\n\nexport class GroqSTT implements STTProvider {\n readonly name = \"groq\";\n\n constructor(\n private apiKey: string,\n private defaultModel: string = \"whisper-large-v3-turbo\",\n ) {}\n\n async transcribe(audioBuffer: Buffer, mimeType: string, options?: STTOptions): Promise<STTResult> {\n const ext = mimeToExt(mimeType);\n const form = new FormData();\n form.append(\"file\", new Blob([new Uint8Array(audioBuffer)], { type: mimeType }), `audio${ext}`);\n form.append(\"model\", options?.model || this.defaultModel);\n form.append(\"response_format\", \"verbose_json\");\n if (options?.language) {\n form.append(\"language\", options.language);\n }\n\n const resp = await fetch(GROQ_API_URL, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${this.apiKey}` },\n body: form,\n });\n\n if (!resp.ok) {\n const body = await resp.text();\n if (resp.status === 401) {\n throw new Error(\"Invalid Groq API key. Check your key at console.groq.com.\");\n }\n if (resp.status === 413) {\n throw new Error(\"Audio file too large for Groq API (max 25MB).\");\n }\n if (resp.status === 429) {\n throw new Error(\"Groq rate limit exceeded. Free tier: 28,800 seconds/day. Try again later.\");\n }\n throw new Error(`Groq STT error (${resp.status}): ${body}`);\n }\n\n const data = await resp.json() as { text: string; language?: string; duration?: number };\n return {\n text: data.text,\n language: data.language,\n duration: data.duration,\n };\n }\n}\n\nfunction mimeToExt(mimeType: string): string {\n const map: Record<string, string> = {\n \"audio/ogg\": \".ogg\",\n \"audio/wav\": \".wav\",\n \"audio/mpeg\": \".mp3\",\n \"audio/mp4\": \".m4a\",\n \"audio/webm\": \".webm\",\n \"audio/flac\": \".flac\",\n };\n return map[mimeType] || \".bin\";\n}\n","import type { TTSProvider, TTSOptions, TTSResult } from '../speech-types.js';\n\nconst DEFAULT_VOICE = \"en-US-AriaNeural\";\n\nexport class EdgeTTS implements TTSProvider {\n readonly name = \"edge-tts\";\n private voice: string;\n\n constructor(voice?: string) {\n this.voice = voice || DEFAULT_VOICE;\n }\n\n async synthesize(text: string, options?: TTSOptions): Promise<TTSResult> {\n const { MsEdgeTTS, OUTPUT_FORMAT } = await import(\"msedge-tts\");\n const tts = new MsEdgeTTS();\n\n const voice = options?.voice || this.voice;\n const format = OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3;\n\n await tts.setMetadata(voice, format);\n const { audioStream } = tts.toStream(text);\n\n const chunks: Buffer[] = [];\n for await (const chunk of audioStream) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n\n tts.close();\n\n return {\n audioBuffer: Buffer.concat(chunks),\n mimeType: \"audio/mpeg\",\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,84 @@
1
+ // src/plugins/telegram/validators.ts
2
+ async function validateBotToken(token) {
3
+ try {
4
+ const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);
5
+ const data = await res.json();
6
+ if (data.ok && data.result) {
7
+ return {
8
+ ok: true,
9
+ botName: data.result.first_name,
10
+ botUsername: data.result.username
11
+ };
12
+ }
13
+ return { ok: false, error: data.description || "Invalid token" };
14
+ } catch (err) {
15
+ return { ok: false, error: err.message };
16
+ }
17
+ }
18
+ async function validateChatId(token, chatId) {
19
+ try {
20
+ const res = await fetch(`https://api.telegram.org/bot${token}/getChat`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ chat_id: chatId })
24
+ });
25
+ const data = await res.json();
26
+ if (!data.ok || !data.result) {
27
+ return { ok: false, error: data.description || "Invalid chat ID" };
28
+ }
29
+ if (data.result.type !== "supergroup") {
30
+ return {
31
+ ok: false,
32
+ error: `Chat is "${data.result.type}", must be a supergroup`
33
+ };
34
+ }
35
+ return {
36
+ ok: true,
37
+ title: data.result.title,
38
+ isForum: data.result.is_forum === true
39
+ };
40
+ } catch (err) {
41
+ return { ok: false, error: err.message };
42
+ }
43
+ }
44
+ async function validateBotAdmin(token, chatId) {
45
+ try {
46
+ const meRes = await fetch(`https://api.telegram.org/bot${token}/getMe`);
47
+ const meData = await meRes.json();
48
+ if (!meData.ok || !meData.result) {
49
+ return { ok: false, error: "Could not retrieve bot info" };
50
+ }
51
+ const res = await fetch(
52
+ `https://api.telegram.org/bot${token}/getChatMember`,
53
+ {
54
+ method: "POST",
55
+ headers: { "Content-Type": "application/json" },
56
+ body: JSON.stringify({ chat_id: chatId, user_id: meData.result.id })
57
+ }
58
+ );
59
+ const data = await res.json();
60
+ if (!data.ok || !data.result) {
61
+ return {
62
+ ok: false,
63
+ error: data.description || "Could not check bot membership"
64
+ };
65
+ }
66
+ const { status } = data.result;
67
+ if (status === "administrator" || status === "creator") {
68
+ return { ok: true };
69
+ }
70
+ return {
71
+ ok: false,
72
+ error: `Bot is "${status}" in this group. It must be an admin. Please promote the bot to admin in group settings.`
73
+ };
74
+ } catch (err) {
75
+ return { ok: false, error: err.message };
76
+ }
77
+ }
78
+
79
+ export {
80
+ validateBotToken,
81
+ validateChatId,
82
+ validateBotAdmin
83
+ };
84
+ //# sourceMappingURL=chunk-WQCJTU2C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/telegram/validators.ts"],"sourcesContent":["export async function validateBotToken(\n token: string,\n): Promise<\n | { ok: true; botName: string; botUsername: string }\n | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);\n const data = (await res.json()) as {\n ok: boolean;\n result?: { first_name: string; username: string };\n description?: string;\n };\n if (data.ok && data.result) {\n return {\n ok: true,\n botName: data.result.first_name,\n botUsername: data.result.username,\n };\n }\n return { ok: false, error: data.description || \"Invalid token\" };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\nexport async function validateChatId(\n token: string,\n chatId: number,\n): Promise<\n { ok: true; title: string; isForum: boolean } | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getChat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n result?: { title: string; type: string; is_forum?: boolean };\n description?: string;\n };\n if (!data.ok || !data.result) {\n return { ok: false, error: data.description || \"Invalid chat ID\" };\n }\n if (data.result.type !== \"supergroup\") {\n return {\n ok: false,\n error: `Chat is \"${data.result.type}\", must be a supergroup`,\n };\n }\n return {\n ok: true,\n title: data.result.title,\n isForum: data.result.is_forum === true,\n };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\nexport async function validateBotAdmin(\n token: string,\n chatId: number,\n): Promise<{ ok: true } | { ok: false; error: string }> {\n try {\n // Get bot's own user ID\n const meRes = await fetch(`https://api.telegram.org/bot${token}/getMe`);\n const meData = (await meRes.json()) as {\n ok: boolean;\n result?: { id: number };\n };\n if (!meData.ok || !meData.result) {\n return { ok: false, error: \"Could not retrieve bot info\" };\n }\n\n const res = await fetch(\n `https://api.telegram.org/bot${token}/getChatMember`,\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId, user_id: meData.result.id }),\n },\n );\n const data = (await res.json()) as {\n ok: boolean;\n result?: { status: string };\n description?: string;\n };\n if (!data.ok || !data.result) {\n return {\n ok: false,\n error: data.description || \"Could not check bot membership\",\n };\n }\n\n const { status } = data.result;\n if (status === \"administrator\" || status === \"creator\") {\n return { ok: true };\n }\n return {\n ok: false,\n error: `Bot is \"${status}\" in this group. It must be an admin. Please promote the bot to admin in group settings.`,\n };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n"],"mappings":";AAAA,eAAsB,iBACpB,OAIA;AACA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,+BAA+B,KAAK,QAAQ;AACpE,UAAM,OAAQ,MAAM,IAAI,KAAK;AAK7B,QAAI,KAAK,MAAM,KAAK,QAAQ;AAC1B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS,KAAK,OAAO;AAAA,QACrB,aAAa,KAAK,OAAO;AAAA,MAC3B;AAAA,IACF;AACA,WAAO,EAAE,IAAI,OAAO,OAAO,KAAK,eAAe,gBAAgB;AAAA,EACjE,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,OAAQ,IAAc,QAAQ;AAAA,EACpD;AACF;AAEA,eAAsB,eACpB,OACA,QAGA;AACA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,+BAA+B,KAAK,YAAY;AAAA,MACtE,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,OAAO,CAAC;AAAA,IAC1C,CAAC;AACD,UAAM,OAAQ,MAAM,IAAI,KAAK;AAK7B,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,aAAO,EAAE,IAAI,OAAO,OAAO,KAAK,eAAe,kBAAkB;AAAA,IACnE;AACA,QAAI,KAAK,OAAO,SAAS,cAAc;AACrC,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,YAAY,KAAK,OAAO,IAAI;AAAA,MACrC;AAAA,IACF;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,KAAK,OAAO;AAAA,MACnB,SAAS,KAAK,OAAO,aAAa;AAAA,IACpC;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,OAAQ,IAAc,QAAQ;AAAA,EACpD;AACF;AAEA,eAAsB,iBACpB,OACA,QACsD;AACtD,MAAI;AAEF,UAAM,QAAQ,MAAM,MAAM,+BAA+B,KAAK,QAAQ;AACtE,UAAM,SAAU,MAAM,MAAM,KAAK;AAIjC,QAAI,CAAC,OAAO,MAAM,CAAC,OAAO,QAAQ;AAChC,aAAO,EAAE,IAAI,OAAO,OAAO,8BAA8B;AAAA,IAC3D;AAEA,UAAM,MAAM,MAAM;AAAA,MAChB,+BAA+B,KAAK;AAAA,MACpC;AAAA,QACE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,QAAQ,SAAS,OAAO,OAAO,GAAG,CAAC;AAAA,MACrE;AAAA,IACF;AACA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAK7B,QAAI,CAAC,KAAK,MAAM,CAAC,KAAK,QAAQ;AAC5B,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,OAAO,KAAK,eAAe;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,EAAE,OAAO,IAAI,KAAK;AACxB,QAAI,WAAW,mBAAmB,WAAW,WAAW;AACtD,aAAO,EAAE,IAAI,KAAK;AAAA,IACpB;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,WAAW,MAAM;AAAA,IAC1B;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,EAAE,IAAI,OAAO,OAAQ,IAAc,QAAQ;AAAA,EACpD;AACF;","names":[]}
@@ -0,0 +1,150 @@
1
+ // src/plugins/discord/index.ts
2
+ function createDiscordPlugin() {
3
+ let adapter = null;
4
+ return {
5
+ name: "@openacp/discord",
6
+ version: "1.0.0",
7
+ description: "Discord adapter with forum threads",
8
+ essential: true,
9
+ pluginDependencies: {
10
+ "@openacp/security": "^1.0.0",
11
+ "@openacp/notifications": "^1.0.0"
12
+ },
13
+ optionalPluginDependencies: {
14
+ "@openacp/speech": "^1.0.0"
15
+ },
16
+ permissions: ["services:register", "kernel:access", "events:read"],
17
+ async install(ctx) {
18
+ const { terminal, settings, legacyConfig } = ctx;
19
+ if (legacyConfig) {
20
+ const ch = legacyConfig.channels;
21
+ const discordCfg = ch?.discord;
22
+ if (discordCfg?.botToken) {
23
+ await settings.setAll({
24
+ botToken: discordCfg.botToken,
25
+ guildId: discordCfg.guildId,
26
+ forumChannelId: discordCfg.forumChannelId ?? null,
27
+ notificationChannelId: discordCfg.notificationChannelId ?? null,
28
+ assistantThreadId: discordCfg.assistantThreadId ?? null
29
+ });
30
+ terminal.log.success("Discord settings migrated from legacy config");
31
+ return;
32
+ }
33
+ }
34
+ const { validateDiscordToken } = await import("./validators-6CLEZUBD.js");
35
+ terminal.note(
36
+ "1. Create app at https://discord.com/developers/applications\n2. Go to Bot > Reset Token > copy it\n3. Enable Message Content Intent (Bot > Privileged Intents)\n4. OAuth2 > URL Generator > scopes: bot + applications.commands\n5. Bot Permissions: Manage Channels, Send Messages, Manage Threads, Attach Files\n6. Open generated URL > invite bot to your server",
37
+ "Discord Setup"
38
+ );
39
+ let botToken = "";
40
+ while (true) {
41
+ botToken = await terminal.text({
42
+ message: "Bot token (from Discord Developer Portal):",
43
+ validate: (val) => {
44
+ if (!val.trim()) return "Token cannot be empty";
45
+ return void 0;
46
+ }
47
+ });
48
+ botToken = botToken.trim();
49
+ const spin = terminal.spinner();
50
+ spin.start("Validating token...");
51
+ const result = await validateDiscordToken(botToken);
52
+ if (result.ok) {
53
+ spin.stop(`Connected as @${result.username} (id: ${result.id})`);
54
+ break;
55
+ }
56
+ spin.fail(result.error);
57
+ const action = await terminal.select({
58
+ message: "What to do?",
59
+ options: [
60
+ { label: "Re-enter token", value: "retry" },
61
+ { label: "Use as-is (skip validation)", value: "skip" }
62
+ ]
63
+ });
64
+ if (action === "skip") break;
65
+ }
66
+ const guildId = await terminal.text({
67
+ message: "Guild (server) ID:",
68
+ validate: (val) => {
69
+ const trimmed = val.trim();
70
+ if (!trimmed) return "Guild ID cannot be empty";
71
+ if (!/^\d{17,20}$/.test(trimmed)) return "Guild ID must be a numeric Discord snowflake (17-20 digits)";
72
+ return void 0;
73
+ }
74
+ });
75
+ await settings.setAll({
76
+ botToken,
77
+ guildId: guildId.trim(),
78
+ forumChannelId: null,
79
+ notificationChannelId: null,
80
+ assistantThreadId: null
81
+ });
82
+ terminal.log.success("Discord settings saved");
83
+ },
84
+ async configure(ctx) {
85
+ const { terminal, settings } = ctx;
86
+ const current = await settings.getAll();
87
+ const choice = await terminal.select({
88
+ message: "What to configure?",
89
+ options: [
90
+ { value: "token", label: "Change bot token" },
91
+ { value: "guildId", label: "Change guild ID" },
92
+ { value: "done", label: "Done" }
93
+ ]
94
+ });
95
+ if (choice === "token") {
96
+ const token = await terminal.text({
97
+ message: "New bot token:",
98
+ validate: (v) => !v.trim() ? "Token cannot be empty" : void 0
99
+ });
100
+ await settings.set("botToken", token.trim());
101
+ terminal.log.success("Bot token updated");
102
+ } else if (choice === "guildId") {
103
+ const val = await terminal.text({
104
+ message: "New guild ID:",
105
+ defaultValue: current.guildId ?? "",
106
+ validate: (v) => {
107
+ const trimmed = v.trim();
108
+ if (!trimmed) return "Guild ID cannot be empty";
109
+ if (!/^\d{17,20}$/.test(trimmed)) return "Guild ID must be a numeric Discord snowflake (17-20 digits)";
110
+ return void 0;
111
+ }
112
+ });
113
+ await settings.set("guildId", val.trim());
114
+ terminal.log.success("Guild ID updated");
115
+ }
116
+ },
117
+ async uninstall(ctx, opts) {
118
+ if (opts.purge) {
119
+ await ctx.settings.clear();
120
+ ctx.terminal.log.success("Discord settings cleared");
121
+ }
122
+ },
123
+ async setup(ctx) {
124
+ const config = ctx.pluginConfig;
125
+ if (!config.botToken || !config.guildId) {
126
+ ctx.log.info("Discord disabled (missing botToken or guildId)");
127
+ return;
128
+ }
129
+ const { DiscordAdapter } = await import("./adapter-77ZCVABT.js");
130
+ adapter = new DiscordAdapter(ctx.core, {
131
+ ...config,
132
+ enabled: true,
133
+ maxMessageLength: 2e3
134
+ });
135
+ ctx.registerService("adapter:discord", adapter);
136
+ ctx.log.info("Discord adapter registered");
137
+ },
138
+ async teardown() {
139
+ if (adapter) {
140
+ await adapter.stop();
141
+ }
142
+ }
143
+ };
144
+ }
145
+ var discord_default = createDiscordPlugin();
146
+
147
+ export {
148
+ discord_default
149
+ };
150
+ //# sourceMappingURL=chunk-WVLDNYOJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/discord/index.ts"],"sourcesContent":["import type { OpenACPPlugin, InstallContext } from '../../core/plugin/types.js'\nimport type { OpenACPCore } from '../../core/core.js'\nimport type { DiscordChannelConfig } from './types.js'\n\nfunction createDiscordPlugin(): OpenACPPlugin {\n let adapter: { stop(): Promise<void> } | null = null\n\n return {\n name: '@openacp/discord',\n version: '1.0.0',\n description: 'Discord adapter with forum threads',\n essential: true,\n pluginDependencies: {\n '@openacp/security': '^1.0.0',\n '@openacp/notifications': '^1.0.0',\n },\n optionalPluginDependencies: {\n '@openacp/speech': '^1.0.0',\n },\n permissions: ['services:register', 'kernel:access', 'events:read'],\n\n async install(ctx: InstallContext) {\n const { terminal, settings, legacyConfig } = ctx\n\n // Migrate from legacy config if present\n if (legacyConfig) {\n const ch = legacyConfig.channels as Record<string, unknown> | undefined\n const discordCfg = ch?.discord as Record<string, unknown> | undefined\n if (discordCfg?.botToken) {\n await settings.setAll({\n botToken: discordCfg.botToken,\n guildId: discordCfg.guildId,\n forumChannelId: discordCfg.forumChannelId ?? null,\n notificationChannelId: discordCfg.notificationChannelId ?? null,\n assistantThreadId: discordCfg.assistantThreadId ?? null,\n })\n terminal.log.success('Discord settings migrated from legacy config')\n return\n }\n }\n\n // Interactive setup via terminal\n const { validateDiscordToken } = await import('./validators.js')\n\n terminal.note(\n '1. Create app at https://discord.com/developers/applications\\n' +\n '2. Go to Bot > Reset Token > copy it\\n' +\n '3. Enable Message Content Intent (Bot > Privileged Intents)\\n' +\n '4. OAuth2 > URL Generator > scopes: bot + applications.commands\\n' +\n '5. Bot Permissions: Manage Channels, Send Messages, Manage Threads, Attach Files\\n' +\n '6. Open generated URL > invite bot to your server',\n 'Discord Setup',\n )\n\n let botToken = ''\n while (true) {\n botToken = await terminal.text({\n message: 'Bot token (from Discord Developer Portal):',\n validate: (val) => {\n if (!val.trim()) return 'Token cannot be empty'\n return undefined\n },\n })\n botToken = botToken.trim()\n\n const spin = terminal.spinner()\n spin.start('Validating token...')\n const result = await validateDiscordToken(botToken)\n if (result.ok) {\n spin.stop(`Connected as @${result.username} (id: ${result.id})`)\n break\n }\n spin.fail(result.error)\n const action = await terminal.select({\n message: 'What to do?',\n options: [\n { label: 'Re-enter token', value: 'retry' },\n { label: 'Use as-is (skip validation)', value: 'skip' },\n ],\n })\n if (action === 'skip') break\n }\n\n const guildId = await terminal.text({\n message: 'Guild (server) ID:',\n validate: (val) => {\n const trimmed = val.trim()\n if (!trimmed) return 'Guild ID cannot be empty'\n if (!/^\\d{17,20}$/.test(trimmed)) return 'Guild ID must be a numeric Discord snowflake (17-20 digits)'\n return undefined\n },\n })\n\n await settings.setAll({\n botToken,\n guildId: guildId.trim(),\n forumChannelId: null,\n notificationChannelId: null,\n assistantThreadId: null,\n })\n terminal.log.success('Discord settings saved')\n },\n\n async configure(ctx: InstallContext) {\n const { terminal, settings } = ctx\n const current = await settings.getAll()\n\n const choice = await terminal.select({\n message: 'What to configure?',\n options: [\n { value: 'token', label: 'Change bot token' },\n { value: 'guildId', label: 'Change guild ID' },\n { value: 'done', label: 'Done' },\n ],\n })\n\n if (choice === 'token') {\n const token = await terminal.text({\n message: 'New bot token:',\n validate: (v) => (!v.trim() ? 'Token cannot be empty' : undefined),\n })\n await settings.set('botToken', token.trim())\n terminal.log.success('Bot token updated')\n } else if (choice === 'guildId') {\n const val = await terminal.text({\n message: 'New guild ID:',\n defaultValue: (current.guildId as string) ?? '',\n validate: (v) => {\n const trimmed = v.trim()\n if (!trimmed) return 'Guild ID cannot be empty'\n if (!/^\\d{17,20}$/.test(trimmed)) return 'Guild ID must be a numeric Discord snowflake (17-20 digits)'\n return undefined\n },\n })\n await settings.set('guildId', val.trim())\n terminal.log.success('Guild ID updated')\n }\n },\n\n async uninstall(ctx: InstallContext, opts: { purge: boolean }) {\n if (opts.purge) {\n await ctx.settings.clear()\n ctx.terminal.log.success('Discord settings cleared')\n }\n },\n\n async setup(ctx) {\n const config = ctx.pluginConfig as Record<string, unknown>\n if (!config.botToken || !config.guildId) {\n ctx.log.info('Discord disabled (missing botToken or guildId)')\n return\n }\n\n const { DiscordAdapter } = await import('./adapter.js')\n // config is a Record<string, unknown> from pluginConfig; at runtime it\n // contains all DiscordChannelConfig fields populated from the migrated config.\n adapter = new DiscordAdapter(ctx.core as OpenACPCore, {\n ...config,\n enabled: true,\n maxMessageLength: 2000,\n } as unknown as DiscordChannelConfig)\n\n ctx.registerService('adapter:discord', adapter)\n ctx.log.info('Discord adapter registered')\n },\n\n async teardown() {\n if (adapter) {\n await adapter.stop()\n }\n },\n }\n}\n\nexport default createDiscordPlugin()\n"],"mappings":"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","names":[]}
@@ -0,0 +1,22 @@
1
+ // src/plugins/notifications/notification.ts
2
+ var NotificationManager = class {
3
+ constructor(adapters) {
4
+ this.adapters = adapters;
5
+ }
6
+ async notify(channelId, notification) {
7
+ const adapter = this.adapters.get(channelId);
8
+ if (adapter) {
9
+ await adapter.sendNotification(notification);
10
+ }
11
+ }
12
+ async notifyAll(notification) {
13
+ for (const adapter of this.adapters.values()) {
14
+ await adapter.sendNotification(notification);
15
+ }
16
+ }
17
+ };
18
+
19
+ export {
20
+ NotificationManager
21
+ };
22
+ //# sourceMappingURL=chunk-WXVT3AOY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/notifications/notification.ts"],"sourcesContent":["import type { IChannelAdapter } from '../../core/channel.js'\nimport type { NotificationMessage } from '../../core/types.js'\n\nexport class NotificationManager {\n constructor(private adapters: Map<string, IChannelAdapter>) {}\n\n async notify(channelId: string, notification: NotificationMessage): Promise<void> {\n const adapter = this.adapters.get(channelId)\n if (adapter) {\n await adapter.sendNotification(notification)\n }\n }\n\n async notifyAll(notification: NotificationMessage): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.sendNotification(notification)\n }\n }\n}\n"],"mappings":";AAGO,IAAM,sBAAN,MAA0B;AAAA,EAC/B,YAAoB,UAAwC;AAAxC;AAAA,EAAyC;AAAA,EAE7D,MAAM,OAAO,WAAmB,cAAkD;AAChF,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS;AAC3C,QAAI,SAAS;AACX,YAAM,QAAQ,iBAAiB,YAAY;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,cAAkD;AAChE,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,YAAM,QAAQ,iBAAiB,YAAY;AAAA,IAC7C;AAAA,EACF;AACF;","names":[]}
@@ -1,4 +1,4 @@
1
- // src/core/log.ts
1
+ // src/core/utils/log.ts
2
2
  import pino from "pino";
3
3
  import fs from "fs";
4
4
  import path from "path";
@@ -221,4 +221,4 @@ export {
221
221
  shutdownLogger,
222
222
  cleanupOldSessionLogs
223
223
  };
224
- //# sourceMappingURL=chunk-GAK6PIBW.js.map
224
+ //# sourceMappingURL=chunk-XMMAGAT4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/utils/log.ts"],"sourcesContent":["import pino from 'pino'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport type { LoggingConfig } from '../config/config.js'\n\nexport type Logger = pino.Logger\n\n// --- Default console-only logger (pre-init) ---\nlet rootLogger: pino.Logger = pino({\n level: 'debug',\n transport: { target: 'pino-pretty', options: { colorize: true, translateTime: 'SYS:standard' } },\n})\nlet initialized = false\nlet logDir: string | undefined\nlet currentTransport: ReturnType<typeof pino.transport> | undefined\n\nfunction expandHome(p: string): string {\n return p.startsWith('~') ? path.join(os.homedir(), p.slice(1)) : p\n}\n\n// --- Variadic wrapper for backward compatibility ---\nfunction wrapVariadic(logger: pino.Logger) {\n return {\n info: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.info(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.info(args.map(String).join(' '))\n }\n },\n warn: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.warn(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.warn(args.map(String).join(' '))\n }\n },\n error: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.error(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.error(args.map(String).join(' '))\n }\n },\n debug: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.debug(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.debug(args.map(String).join(' '))\n }\n },\n fatal: (...args: unknown[]) => {\n if (args.length === 0) return\n if (typeof args[0] === 'object' && args[0] !== null && !(args[0] instanceof Error)) {\n logger.fatal(args[0] as object, args.slice(1).join(' '))\n } else {\n logger.fatal(args.map(String).join(' '))\n }\n },\n child: (bindings: pino.Bindings) => logger.child(bindings),\n }\n}\n\nexport const log = wrapVariadic(rootLogger)\n\n// --- Mute/unmute (suppress pino output during interactive prompts) ---\n\nlet muteCount = 0\nlet savedLevel = 'info'\n\nexport function muteLogger(): void {\n if (muteCount === 0) {\n savedLevel = rootLogger.level\n rootLogger.level = 'silent'\n }\n muteCount++\n}\n\nexport function unmuteLogger(): void {\n muteCount--\n if (muteCount <= 0) {\n muteCount = 0\n rootLogger.level = savedLevel\n }\n}\n\n// --- Public API ---\n\nexport function initLogger(config: LoggingConfig): Logger {\n if (initialized) return rootLogger\n\n const resolvedLogDir = expandHome(config.logDir)\n logDir = resolvedLogDir\n\n try {\n fs.mkdirSync(resolvedLogDir, { recursive: true })\n fs.mkdirSync(path.join(resolvedLogDir, 'sessions'), { recursive: true })\n } catch (err) {\n console.error(`[WARN] Failed to create log directory ${resolvedLogDir}, falling back to console-only:`, err)\n return rootLogger\n }\n\n const transports = pino.transport({\n targets: [\n {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'HH:mm:ss',\n ignore: 'pid,hostname',\n singleLine: true,\n },\n level: config.level,\n },\n {\n target: 'pino-roll',\n options: {\n file: path.join(resolvedLogDir, 'openacp.log'),\n size: config.maxFileSize,\n limit: { count: config.maxFiles },\n },\n level: config.level,\n },\n ],\n })\n\n currentTransport = transports\n rootLogger = pino({ level: config.level }, transports)\n initialized = true\n\n // Update the default log wrapper to use the new root logger\n Object.assign(log, wrapVariadic(rootLogger))\n\n return rootLogger\n}\n\n/** Change log level at runtime. Pino transport targets respect parent level changes automatically. */\nexport function setLogLevel(level: string): void {\n rootLogger.level = level\n}\n\nexport function createChildLogger(context: { module: string; [key: string]: unknown }): Logger {\n // Return a proxy that always delegates to the current rootLogger.\n // This ensures child loggers created at module-level (before initLogger)\n // pick up the initialized logger with pino-pretty transport.\n return new Proxy({} as Logger, {\n get(_target, prop, receiver) {\n const child = rootLogger.child(context)\n const value = Reflect.get(child, prop, receiver)\n return typeof value === 'function' ? value.bind(child) : value\n },\n })\n}\n\nexport function createSessionLogger(sessionId: string, parentLogger: Logger): Logger {\n const sessionLogDir = logDir ? path.join(logDir, 'sessions') : undefined\n if (!sessionLogDir) {\n return parentLogger.child({ sessionId })\n }\n\n try {\n const sessionLogPath = path.join(sessionLogDir, `${sessionId}.log`)\n const dest = pino.destination(sessionLogPath)\n const sessionFileLogger = pino({ level: parentLogger.level }, dest).child({ sessionId })\n\n // Create a logger that writes to both parent (combined) and session file\n const combinedChild = parentLogger.child({ sessionId })\n const originalInfo = combinedChild.info.bind(combinedChild)\n const originalWarn = combinedChild.warn.bind(combinedChild)\n const originalError = combinedChild.error.bind(combinedChild)\n const originalDebug = combinedChild.debug.bind(combinedChild)\n const originalFatal = combinedChild.fatal.bind(combinedChild)\n\n // Proxy log methods to write to both destinations\n combinedChild.info = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.info(objOrMsg, ...rest)\n return originalInfo(objOrMsg, ...rest)\n }) as any\n combinedChild.warn = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.warn(objOrMsg, ...rest)\n return originalWarn(objOrMsg, ...rest)\n }) as any\n combinedChild.error = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.error(objOrMsg, ...rest)\n return originalError(objOrMsg, ...rest)\n }) as any\n combinedChild.debug = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.debug(objOrMsg, ...rest)\n return originalDebug(objOrMsg, ...rest)\n }) as any\n combinedChild.fatal = ((objOrMsg: any, ...rest: any[]) => {\n sessionFileLogger.fatal(objOrMsg, ...rest)\n return originalFatal(objOrMsg, ...rest)\n }) as any\n\n // Store dest for cleanup\n ;(combinedChild as any).__sessionDest = dest\n\n return combinedChild\n } catch (err) {\n // Graceful degradation: session file failed, just use combined log\n parentLogger.warn({ sessionId, err }, 'Failed to create session log file, using combined log only')\n return parentLogger.child({ sessionId })\n }\n}\n\nexport async function shutdownLogger(): Promise<void> {\n if (!initialized) return\n\n const transport = currentTransport\n\n // Reset state immediately so re-init is possible\n rootLogger = pino({ level: 'debug' })\n Object.assign(log, wrapVariadic(rootLogger))\n currentTransport = undefined\n logDir = undefined\n initialized = false\n\n if (transport) {\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(resolve, 3000)\n transport.on('close', () => {\n clearTimeout(timeout)\n resolve()\n })\n transport.end()\n })\n }\n}\n\nexport async function cleanupOldSessionLogs(retentionDays: number): Promise<void> {\n if (!logDir) return\n\n const sessionsDir = path.join(logDir, 'sessions')\n try {\n const files = await fs.promises.readdir(sessionsDir)\n const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1000\n\n for (const file of files) {\n try {\n const filePath = path.join(sessionsDir, file)\n const stat = await fs.promises.stat(filePath)\n if (stat.mtimeMs < cutoff) {\n await fs.promises.unlink(filePath)\n rootLogger.debug({ file }, 'Deleted old session log')\n }\n } catch (err) {\n rootLogger.warn({ file, err }, 'Failed to delete old session log')\n }\n }\n } catch {\n // Sessions directory doesn't exist — no-op\n }\n}\n"],"mappings":"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","names":[]}