@openacp/cli 0.6.10 → 2026.326.2
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.
- package/dist/{action-detect-P7ZE4NEM.js → action-detect-QPA775HB.js} +2 -2
- package/dist/adapter-6ANPBSVU.js +16 -0
- package/dist/{discord-OMC52Y54.js → adapter-77ZCVABT.js} +520 -365
- package/dist/adapter-77ZCVABT.js.map +1 -0
- package/dist/{adapter-ZOANORGM.js → adapter-PQGHVG4K.js} +300 -93
- package/dist/adapter-PQGHVG4K.js.map +1 -0
- package/dist/{admin-6SYB6XCZ.js → admin-GBPZFFAU.js} +3 -3
- package/dist/agent-catalog-YHBFERYO.js +11 -0
- package/dist/{agent-dependencies-4OWBMZWZ.js → agent-dependencies-WS7Z2DFW.js} +2 -2
- package/dist/agent-registry-5LZT7CUB.js +9 -0
- package/dist/agent-store-VSHNY5GT.js +9 -0
- package/dist/{agents-QO7DKARJ.js → agents-BWU4MRRD.js} +3 -3
- package/dist/{api-client-CFQT5U7D.js → api-client-AQPNKXI2.js} +2 -2
- package/dist/api-server-3PYLRBCN.js +8 -0
- package/dist/api-server-CHVSUDBX.js +11 -0
- package/dist/{autostart-X33OGMX6.js → autostart-6JS565RY.js} +3 -3
- package/dist/chunk-2CX4IEEC.js +124 -0
- package/dist/chunk-2CX4IEEC.js.map +1 -0
- package/dist/{chunk-O7CPGUAI.js → chunk-4KGLKKQK.js} +4 -4
- package/dist/chunk-4KGLKKQK.js.map +1 -0
- package/dist/{chunk-W3EYKZNQ.js → chunk-4WXALZA3.js} +2 -2
- package/dist/chunk-4WXALZA3.js.map +1 -0
- package/dist/chunk-5OCGO27U.js +125 -0
- package/dist/chunk-5OCGO27U.js.map +1 -0
- package/dist/{chunk-OWP7RZ62.js → chunk-5ZOFBTOR.js} +118 -262
- package/dist/chunk-5ZOFBTOR.js.map +1 -0
- package/dist/chunk-6RXVEXF3.js +23 -0
- package/dist/chunk-6RXVEXF3.js.map +1 -0
- package/dist/{chunk-34M4OS5P.js → chunk-A6Y4GZM3.js} +3 -3
- package/dist/chunk-A6Y4GZM3.js.map +1 -0
- package/dist/chunk-AD3X6DGK.js +166 -0
- package/dist/chunk-AD3X6DGK.js.map +1 -0
- package/dist/{chunk-7QJS2XBD.js → chunk-AFKX424Q.js} +2 -2
- package/dist/chunk-AFKX424Q.js.map +1 -0
- package/dist/chunk-APS6UEFU.js +259 -0
- package/dist/chunk-APS6UEFU.js.map +1 -0
- package/dist/chunk-BLQUXO7S.js +113 -0
- package/dist/chunk-BLQUXO7S.js.map +1 -0
- package/dist/{chunk-WTZDAYZX.js → chunk-BQ6FR32N.js} +3 -3
- package/dist/chunk-BQ6FR32N.js.map +1 -0
- package/dist/chunk-FNRSWA2K.js +1 -0
- package/dist/chunk-FQEBWOZR.js +3557 -0
- package/dist/chunk-FQEBWOZR.js.map +1 -0
- package/dist/{chunk-4CTX774K.js → chunk-GJOY37U7.js} +4 -4
- package/dist/chunk-GJOY37U7.js.map +1 -0
- package/dist/{chunk-I7WC6E5S.js → chunk-HVBNCPAY.js} +2 -2
- package/dist/chunk-HVBNCPAY.js.map +1 -0
- package/dist/{chunk-2HMQOC7N.js → chunk-I3CGU5W7.js} +4 -4
- package/dist/chunk-I3CGU5W7.js.map +1 -0
- package/dist/{chunk-NVPG6JCL.js → chunk-L7YNNBI5.js} +3 -3
- package/dist/chunk-L7YNNBI5.js.map +1 -0
- package/dist/chunk-LGFWH3AE.js +26 -0
- package/dist/chunk-LGFWH3AE.js.map +1 -0
- package/dist/chunk-MLF4W5R6.js +101 -0
- package/dist/chunk-MLF4W5R6.js.map +1 -0
- package/dist/{chunk-KIRH7TUJ.js → chunk-MTSDOSXS.js} +3 -3
- package/dist/chunk-MTSDOSXS.js.map +1 -0
- package/dist/{chunk-J4SJTKIK.js → chunk-NAM4ERUW.js} +3 -3
- package/dist/chunk-NAM4ERUW.js.map +1 -0
- package/dist/{chunk-MKHUZLII.js → chunk-NBFIBGAT.js} +39 -25
- package/dist/chunk-NBFIBGAT.js.map +1 -0
- package/dist/{chunk-BNLGTZ34.js → chunk-O5RG4YZY.js} +3 -3
- package/dist/chunk-O5RG4YZY.js.map +1 -0
- package/dist/{chunk-JHYXKVV2.js → chunk-ODUM3D6X.js} +2 -2
- package/dist/chunk-ODUM3D6X.js.map +1 -0
- package/dist/chunk-OYSAN7UX.js +15 -0
- package/dist/chunk-OYSAN7UX.js.map +1 -0
- package/dist/chunk-P4SNGQNI.js +158 -0
- package/dist/chunk-P4SNGQNI.js.map +1 -0
- package/dist/{chunk-2CJ46J3C.js → chunk-PPSMUECX.js} +3 -3
- package/dist/chunk-PPSMUECX.js.map +1 -0
- package/dist/chunk-Q6ZXJTZB.js +56 -0
- package/dist/chunk-Q6ZXJTZB.js.map +1 -0
- package/dist/{chunk-XANPHG7W.js → chunk-QSDZDHNS.js} +7 -7
- package/dist/chunk-QSDZDHNS.js.map +1 -0
- package/dist/{chunk-33RP6K2O.js → chunk-QVMEF6FB.js} +6 -6
- package/dist/chunk-QVMEF6FB.js.map +1 -0
- package/dist/chunk-QWP76EBW.js +536 -0
- package/dist/chunk-QWP76EBW.js.map +1 -0
- package/dist/{chunk-V5GZQEIY.js → chunk-RBYBSSGO.js} +4 -4
- package/dist/chunk-RBYBSSGO.js.map +1 -0
- package/dist/{chunk-CS3KCJ5D.js → chunk-RKB2ZK6S.js} +555 -383
- package/dist/chunk-RKB2ZK6S.js.map +1 -0
- package/dist/{chunk-UKT3G5IA.js → chunk-SHTGQGAU.js} +7 -7
- package/dist/chunk-SHTGQGAU.js.map +1 -0
- package/dist/chunk-SNPYTMPR.js +51 -0
- package/dist/chunk-SNPYTMPR.js.map +1 -0
- package/dist/chunk-UB2QB6DE.js +124 -0
- package/dist/chunk-UB2QB6DE.js.map +1 -0
- package/dist/chunk-UNJUWWQO.js +1108 -0
- package/dist/chunk-UNJUWWQO.js.map +1 -0
- package/dist/chunk-V2M243KZ.js +445 -0
- package/dist/chunk-V2M243KZ.js.map +1 -0
- package/dist/chunk-V5JT5TPD.js +97 -0
- package/dist/chunk-V5JT5TPD.js.map +1 -0
- package/dist/chunk-W26AUH5B.js +61 -0
- package/dist/chunk-W26AUH5B.js.map +1 -0
- package/dist/chunk-WAAD23KY.js +222 -0
- package/dist/chunk-WAAD23KY.js.map +1 -0
- package/dist/chunk-WIIZNPCR.js +150 -0
- package/dist/chunk-WIIZNPCR.js.map +1 -0
- package/dist/chunk-WQCJTU2C.js +84 -0
- package/dist/chunk-WQCJTU2C.js.map +1 -0
- package/dist/chunk-WVLDNYOJ.js +150 -0
- package/dist/chunk-WVLDNYOJ.js.map +1 -0
- package/dist/chunk-WXVT3AOY.js +22 -0
- package/dist/chunk-WXVT3AOY.js.map +1 -0
- package/dist/{chunk-GAK6PIBW.js → chunk-XMMAGAT4.js} +2 -2
- package/dist/chunk-XMMAGAT4.js.map +1 -0
- package/dist/chunk-Y64XWMJ4.js +212 -0
- package/dist/chunk-Y64XWMJ4.js.map +1 -0
- package/dist/chunk-YEULD3SG.js +62 -0
- package/dist/chunk-YEULD3SG.js.map +1 -0
- package/dist/chunk-ZHGPZBS4.js +49 -0
- package/dist/chunk-ZHGPZBS4.js.map +1 -0
- package/dist/{chunk-JKBFUAJK.js → chunk-ZSLHHQPQ.js} +2 -2
- package/dist/chunk-ZSLHHQPQ.js.map +1 -0
- package/dist/cli.js +496 -150
- package/dist/cli.js.map +1 -1
- package/dist/{config-6S355X75.js → config-I4FMCJGZ.js} +3 -3
- package/dist/config-editor-HNEKXRLQ.js +11 -0
- package/dist/{config-registry-AHYI4MYL.js → config-registry-CUMNXFGK.js} +2 -2
- package/dist/context-XM6E22LM.js +10 -0
- package/dist/core-plugins-VEUNFTMB.js +27 -0
- package/dist/{daemon-4CS6HMB5.js → daemon-PXO5QPCR.js} +4 -4
- package/dist/dev-loader-RDC5E2CW.js +50 -0
- package/dist/dev-loader-RDC5E2CW.js.map +1 -0
- package/dist/discord-NOJQ5PZO.js +8 -0
- package/dist/doctor-H72BZOPA.js +10 -0
- package/dist/{doctor-OLYBO3V3.js → doctor-RF6BHMCC.js} +5 -5
- package/dist/file-service-EUODJAIT.js +9 -0
- package/dist/file-service-EUODJAIT.js.map +1 -0
- package/dist/index.d.ts +1293 -188
- package/dist/index.js +387 -48
- package/dist/index.js.map +1 -1
- package/dist/{install-cloudflared-Z7VCGOVG.js → install-cloudflared-AN24L4DP.js} +5 -5
- package/dist/install-cloudflared-AN24L4DP.js.map +1 -0
- package/dist/install-context-XPWTFT3J.js +78 -0
- package/dist/install-context-XPWTFT3J.js.map +1 -0
- package/dist/{install-jq-HUYSQWKR.js → install-jq-CRVDJGF3.js} +5 -5
- package/dist/install-jq-CRVDJGF3.js.map +1 -0
- package/dist/{integrate-PNEHRY2I.js → integrate-5C6KSU6D.js} +2 -2
- package/dist/integrate-5C6KSU6D.js.map +1 -0
- package/dist/{log-NXABYJTT.js → log-LZ7FTRKG.js} +2 -2
- package/dist/log-LZ7FTRKG.js.map +1 -0
- package/dist/main-T5WVCCFN.js +715 -0
- package/dist/main-T5WVCCFN.js.map +1 -0
- package/dist/{menu-YY5MKHEK.js → menu-YDQ2LWAR.js} +2 -2
- package/dist/menu-YDQ2LWAR.js.map +1 -0
- package/dist/{new-session-FEO4J4VU.js → new-session-AVQCNXRG.js} +5 -5
- package/dist/new-session-AVQCNXRG.js.map +1 -0
- package/dist/notifications-D5BRDNSU.js +9 -0
- package/dist/notifications-D5BRDNSU.js.map +1 -0
- package/dist/plugin-create-JVCVUG6V.js +331 -0
- package/dist/plugin-create-JVCVUG6V.js.map +1 -0
- package/dist/plugin-registry-WB3DR67H.js +8 -0
- package/dist/plugin-registry-WB3DR67H.js.map +1 -0
- package/dist/{post-upgrade-CJG5I7M2.js → post-upgrade-XLHZ6ZB7.js} +8 -8
- package/dist/post-upgrade-XLHZ6ZB7.js.map +1 -0
- package/dist/read-text-file-IRZM3QLM.js +8 -0
- package/dist/read-text-file-IRZM3QLM.js.map +1 -0
- package/dist/security-YNRBW6S7.js +9 -0
- package/dist/security-YNRBW6S7.js.map +1 -0
- package/dist/{session-IUSI7P5S.js → session-KZFA6Z26.js} +4 -4
- package/dist/session-KZFA6Z26.js.map +1 -0
- package/dist/{settings-RQPAM4KC.js → settings-MFYM7CZO.js} +4 -4
- package/dist/settings-MFYM7CZO.js.map +1 -0
- package/dist/settings-manager-MD2U4ZV2.js +8 -0
- package/dist/settings-manager-MD2U4ZV2.js.map +1 -0
- package/dist/{chunk-LCRLAV4G.js → setup-BAI2F24H.js} +154 -492
- package/dist/setup-BAI2F24H.js.map +1 -0
- package/dist/slack-KH7E3VBS.js +8 -0
- package/dist/slack-KH7E3VBS.js.map +1 -0
- package/dist/speech-2GHQNRIO.js +9 -0
- package/dist/speech-2GHQNRIO.js.map +1 -0
- package/dist/telegram-ZDC3JQF2.js +8 -0
- package/dist/telegram-ZDC3JQF2.js.map +1 -0
- package/dist/tunnel-M47I7H4B.js +8 -0
- package/dist/tunnel-M47I7H4B.js.map +1 -0
- package/dist/{tunnel-service-CJLUH6SZ.js → tunnel-service-WADYHREX.js} +17 -17
- package/dist/tunnel-service-WADYHREX.js.map +1 -0
- package/dist/usage-WYNK6ZC5.js +10 -0
- package/dist/usage-WYNK6ZC5.js.map +1 -0
- package/dist/validators-6CLEZUBD.js +8 -0
- package/dist/validators-6CLEZUBD.js.map +1 -0
- package/dist/validators-WSTBNKRW.js +12 -0
- package/dist/validators-WSTBNKRW.js.map +1 -0
- package/package.json +1 -1
- package/dist/adapter-ZOANORGM.js.map +0 -1
- package/dist/agent-catalog-FC3HGDEQ.js +0 -11
- package/dist/agent-registry-WT4NXPYG.js +0 -9
- package/dist/agent-store-VZLFPTZU.js +0 -9
- package/dist/chunk-2CJ46J3C.js.map +0 -1
- package/dist/chunk-2HMQOC7N.js.map +0 -1
- package/dist/chunk-33RP6K2O.js.map +0 -1
- package/dist/chunk-34M4OS5P.js.map +0 -1
- package/dist/chunk-4CTX774K.js.map +0 -1
- package/dist/chunk-7QJS2XBD.js.map +0 -1
- package/dist/chunk-BNLGTZ34.js.map +0 -1
- package/dist/chunk-CS3KCJ5D.js.map +0 -1
- package/dist/chunk-GAK6PIBW.js.map +0 -1
- package/dist/chunk-I7WC6E5S.js.map +0 -1
- package/dist/chunk-J4SJTKIK.js.map +0 -1
- package/dist/chunk-JHYXKVV2.js.map +0 -1
- package/dist/chunk-JKBFUAJK.js.map +0 -1
- package/dist/chunk-KIRH7TUJ.js.map +0 -1
- package/dist/chunk-LBIKITQT.js +0 -22
- package/dist/chunk-LBIKITQT.js.map +0 -1
- package/dist/chunk-LCRLAV4G.js.map +0 -1
- package/dist/chunk-LGP2YGRL.js +0 -4880
- package/dist/chunk-LGP2YGRL.js.map +0 -1
- package/dist/chunk-MKHUZLII.js.map +0 -1
- package/dist/chunk-NAMYZIS5.js +0 -1
- package/dist/chunk-NVPG6JCL.js.map +0 -1
- package/dist/chunk-O7CPGUAI.js.map +0 -1
- package/dist/chunk-OWP7RZ62.js.map +0 -1
- package/dist/chunk-UKT3G5IA.js.map +0 -1
- package/dist/chunk-V5GZQEIY.js.map +0 -1
- package/dist/chunk-VOIJ6OY4.js +0 -63
- package/dist/chunk-VOIJ6OY4.js.map +0 -1
- package/dist/chunk-W3EYKZNQ.js.map +0 -1
- package/dist/chunk-WTZDAYZX.js.map +0 -1
- package/dist/chunk-XANPHG7W.js.map +0 -1
- package/dist/config-editor-QQTZMWGD.js +0 -13
- package/dist/discord-OMC52Y54.js.map +0 -1
- package/dist/doctor-HZZ5BSHB.js +0 -10
- package/dist/install-cloudflared-Z7VCGOVG.js.map +0 -1
- package/dist/install-jq-HUYSQWKR.js.map +0 -1
- package/dist/integrate-PNEHRY2I.js.map +0 -1
- package/dist/main-XOZCLFUK.js +0 -238
- package/dist/main-XOZCLFUK.js.map +0 -1
- package/dist/post-upgrade-CJG5I7M2.js.map +0 -1
- package/dist/setup-XHS4OMPM.js +0 -37
- package/dist/tunnel-service-CJLUH6SZ.js.map +0 -1
- /package/dist/{action-detect-P7ZE4NEM.js.map → action-detect-QPA775HB.js.map} +0 -0
- /package/dist/{admin-6SYB6XCZ.js.map → adapter-6ANPBSVU.js.map} +0 -0
- /package/dist/{agent-catalog-FC3HGDEQ.js.map → admin-GBPZFFAU.js.map} +0 -0
- /package/dist/{agent-dependencies-4OWBMZWZ.js.map → agent-catalog-YHBFERYO.js.map} +0 -0
- /package/dist/{agent-registry-WT4NXPYG.js.map → agent-dependencies-WS7Z2DFW.js.map} +0 -0
- /package/dist/{agent-store-VZLFPTZU.js.map → agent-registry-5LZT7CUB.js.map} +0 -0
- /package/dist/{agents-QO7DKARJ.js.map → agent-store-VSHNY5GT.js.map} +0 -0
- /package/dist/{api-client-CFQT5U7D.js.map → agents-BWU4MRRD.js.map} +0 -0
- /package/dist/{autostart-X33OGMX6.js.map → api-client-AQPNKXI2.js.map} +0 -0
- /package/dist/{chunk-NAMYZIS5.js.map → api-server-3PYLRBCN.js.map} +0 -0
- /package/dist/{config-6S355X75.js.map → api-server-CHVSUDBX.js.map} +0 -0
- /package/dist/{config-editor-QQTZMWGD.js.map → autostart-6JS565RY.js.map} +0 -0
- /package/dist/{config-registry-AHYI4MYL.js.map → chunk-FNRSWA2K.js.map} +0 -0
- /package/dist/{daemon-4CS6HMB5.js.map → config-I4FMCJGZ.js.map} +0 -0
- /package/dist/{doctor-HZZ5BSHB.js.map → config-editor-HNEKXRLQ.js.map} +0 -0
- /package/dist/{doctor-OLYBO3V3.js.map → config-registry-CUMNXFGK.js.map} +0 -0
- /package/dist/{log-NXABYJTT.js.map → context-XM6E22LM.js.map} +0 -0
- /package/dist/{menu-YY5MKHEK.js.map → core-plugins-VEUNFTMB.js.map} +0 -0
- /package/dist/{new-session-FEO4J4VU.js.map → daemon-PXO5QPCR.js.map} +0 -0
- /package/dist/{session-IUSI7P5S.js.map → discord-NOJQ5PZO.js.map} +0 -0
- /package/dist/{settings-RQPAM4KC.js.map → doctor-H72BZOPA.js.map} +0 -0
- /package/dist/{setup-XHS4OMPM.js.map → doctor-RF6BHMCC.js.map} +0 -0
|
@@ -1,70 +1,18 @@
|
|
|
1
|
-
import "./chunk-LGP2YGRL.js";
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import "./chunk-WTZDAYZX.js";
|
|
7
|
-
import "./chunk-UKT3G5IA.js";
|
|
8
|
-
import "./chunk-34M4OS5P.js";
|
|
9
|
-
import "./chunk-MKHUZLII.js";
|
|
10
|
-
import "./chunk-2CJ46J3C.js";
|
|
11
|
-
import "./chunk-LCRLAV4G.js";
|
|
12
|
-
import "./chunk-JKBFUAJK.js";
|
|
13
|
-
import "./chunk-VOIJ6OY4.js";
|
|
14
|
-
import "./chunk-JHYXKVV2.js";
|
|
15
|
-
import "./chunk-33RP6K2O.js";
|
|
2
|
+
BaseRenderer,
|
|
3
|
+
MessagingAdapter
|
|
4
|
+
} from "./chunk-V2M243KZ.js";
|
|
16
5
|
import {
|
|
17
6
|
createChildLogger
|
|
18
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XMMAGAT4.js";
|
|
19
8
|
import "./chunk-VUNV25KB.js";
|
|
20
9
|
|
|
21
|
-
// src/
|
|
10
|
+
// src/plugins/slack/adapter.ts
|
|
22
11
|
import fs from "fs";
|
|
23
12
|
import { App } from "@slack/bolt";
|
|
24
13
|
import { WebClient } from "@slack/web-api";
|
|
25
14
|
|
|
26
|
-
// src/
|
|
27
|
-
import PQueue from "p-queue";
|
|
28
|
-
var METHOD_RPM = {
|
|
29
|
-
"chat.postMessage": 50,
|
|
30
|
-
// Tier 3
|
|
31
|
-
"chat.update": 50,
|
|
32
|
-
// Tier 3
|
|
33
|
-
"conversations.create": 20,
|
|
34
|
-
// Tier 2
|
|
35
|
-
"conversations.rename": 20,
|
|
36
|
-
// Tier 2
|
|
37
|
-
"conversations.archive": 20,
|
|
38
|
-
// Tier 2
|
|
39
|
-
"conversations.invite": 20,
|
|
40
|
-
// Tier 2
|
|
41
|
-
"conversations.join": 20,
|
|
42
|
-
// Tier 2
|
|
43
|
-
"conversations.unarchive": 20,
|
|
44
|
-
// Tier 2
|
|
45
|
-
"conversations.info": 50
|
|
46
|
-
// Tier 3
|
|
47
|
-
};
|
|
48
|
-
var SlackSendQueue = class {
|
|
49
|
-
constructor(client) {
|
|
50
|
-
this.client = client;
|
|
51
|
-
for (const [method, rpm] of Object.entries(METHOD_RPM)) {
|
|
52
|
-
this.queues.set(method, new PQueue({
|
|
53
|
-
interval: Math.ceil(6e4 / rpm),
|
|
54
|
-
intervalCap: 1,
|
|
55
|
-
carryoverConcurrencyCount: true
|
|
56
|
-
}));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
queues = /* @__PURE__ */ new Map();
|
|
60
|
-
async enqueue(method, params) {
|
|
61
|
-
const queue = this.queues.get(method);
|
|
62
|
-
if (!queue) throw new Error(`Unknown Slack method: ${method}`);
|
|
63
|
-
return queue.add(() => this.client.apiCall(method, params));
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// src/adapters/slack/utils.ts
|
|
15
|
+
// src/plugins/slack/utils.ts
|
|
68
16
|
function isAudioClip(file) {
|
|
69
17
|
return file.mimetype === "video/mp4" && file.name?.startsWith("audio_message") || file.mimetype?.startsWith("audio/");
|
|
70
18
|
}
|
|
@@ -86,7 +34,7 @@ function splitSafe(text, limit = SECTION_LIMIT) {
|
|
|
86
34
|
return chunks;
|
|
87
35
|
}
|
|
88
36
|
|
|
89
|
-
// src/
|
|
37
|
+
// src/plugins/slack/formatter.ts
|
|
90
38
|
function markdownToMrkdwn(text) {
|
|
91
39
|
return text.replace(/^#{1,6}\s+(.+)$/gm, "\0BOLD\0$1\0BOLD\0").replace(/\*\*(.+?)\*\*/g, "\0BOLD\0$1\0BOLD\0").replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "_$1_").replace(/\x00BOLD\x00(.+?)\x00BOLD\x00/g, "*$1*").replace(/~~(.+?)~~/g, "~$1~").replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g, "<$2|$1>").replace(/^[ \t]*[-*]\s+/gm, "\u2022 ").trim();
|
|
92
40
|
}
|
|
@@ -174,7 +122,182 @@ ${req.description}`),
|
|
|
174
122
|
}
|
|
175
123
|
};
|
|
176
124
|
|
|
177
|
-
// src/
|
|
125
|
+
// src/plugins/slack/renderer.ts
|
|
126
|
+
var SlackRenderer = class extends BaseRenderer {
|
|
127
|
+
formatter;
|
|
128
|
+
constructor(formatter) {
|
|
129
|
+
super();
|
|
130
|
+
this.formatter = formatter ?? new SlackFormatter();
|
|
131
|
+
}
|
|
132
|
+
renderText(content) {
|
|
133
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
134
|
+
return {
|
|
135
|
+
body: content.text ?? "",
|
|
136
|
+
format: "structured",
|
|
137
|
+
components: blocks
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
renderThought(content, _verbosity) {
|
|
141
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
142
|
+
return {
|
|
143
|
+
body: content.text ?? "",
|
|
144
|
+
format: "structured",
|
|
145
|
+
components: blocks
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
renderToolCall(content, _verbosity) {
|
|
149
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
150
|
+
return {
|
|
151
|
+
body: content.text ?? "",
|
|
152
|
+
format: "structured",
|
|
153
|
+
components: blocks
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
renderToolUpdate(content, _verbosity) {
|
|
157
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
158
|
+
return {
|
|
159
|
+
body: content.text ?? "",
|
|
160
|
+
format: "structured",
|
|
161
|
+
components: blocks
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
renderPlan(content, _verbosity) {
|
|
165
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
166
|
+
return {
|
|
167
|
+
body: content.text ?? "",
|
|
168
|
+
format: "structured",
|
|
169
|
+
components: blocks
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
renderUsage(content, _verbosity) {
|
|
173
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
174
|
+
return {
|
|
175
|
+
body: content.text ?? "",
|
|
176
|
+
format: "structured",
|
|
177
|
+
components: blocks
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
renderError(content) {
|
|
181
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
182
|
+
return {
|
|
183
|
+
body: content.text ?? "",
|
|
184
|
+
format: "structured",
|
|
185
|
+
components: blocks
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
renderSessionEnd(content) {
|
|
189
|
+
const blocks = this.formatter.formatSessionEnd(content.text);
|
|
190
|
+
return {
|
|
191
|
+
body: content.text ?? "Session ended",
|
|
192
|
+
format: "structured",
|
|
193
|
+
components: blocks
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
renderPermission(request) {
|
|
197
|
+
const blocks = this.formatter.formatPermissionRequest(request);
|
|
198
|
+
return {
|
|
199
|
+
body: request.description,
|
|
200
|
+
format: "structured",
|
|
201
|
+
components: blocks,
|
|
202
|
+
actions: request.options.map((o) => ({ id: o.id, label: o.label, isAllow: o.isAllow }))
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
renderNotification(notification) {
|
|
206
|
+
const emoji = {
|
|
207
|
+
completed: "\u2705",
|
|
208
|
+
error: "\u274C",
|
|
209
|
+
permission: "\u{1F510}",
|
|
210
|
+
input_required: "\u{1F4AC}",
|
|
211
|
+
budget_warning: "\u26A0\uFE0F"
|
|
212
|
+
};
|
|
213
|
+
const icon = emoji[notification.type] || "\u2139\uFE0F";
|
|
214
|
+
const text = `${icon} *${notification.sessionName ?? "Session"}*
|
|
215
|
+
${notification.summary}`;
|
|
216
|
+
const blocks = this.formatter.formatNotification(text);
|
|
217
|
+
return {
|
|
218
|
+
body: text,
|
|
219
|
+
format: "structured",
|
|
220
|
+
components: blocks
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
renderSystemMessage(content) {
|
|
224
|
+
const mrkdwn = markdownToMrkdwn(content.text ?? "");
|
|
225
|
+
return {
|
|
226
|
+
body: mrkdwn,
|
|
227
|
+
format: "structured",
|
|
228
|
+
components: [{ type: "section", text: { type: "mrkdwn", text: mrkdwn } }]
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
renderModeChange(content) {
|
|
232
|
+
const modeId = content.metadata?.modeId ?? "";
|
|
233
|
+
const text = `\u{1F504} *Mode:* ${modeId}`;
|
|
234
|
+
return {
|
|
235
|
+
body: text,
|
|
236
|
+
format: "structured",
|
|
237
|
+
components: [{ type: "context", elements: [{ type: "mrkdwn", text }] }]
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
renderConfigUpdate() {
|
|
241
|
+
const text = "\u2699\uFE0F *Config updated*";
|
|
242
|
+
return {
|
|
243
|
+
body: text,
|
|
244
|
+
format: "structured",
|
|
245
|
+
components: [{ type: "context", elements: [{ type: "mrkdwn", text }] }]
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
renderModelUpdate(content) {
|
|
249
|
+
const modelId = content.metadata?.modelId ?? "";
|
|
250
|
+
const text = `\u{1F916} *Model:* ${modelId}`;
|
|
251
|
+
return {
|
|
252
|
+
body: text,
|
|
253
|
+
format: "structured",
|
|
254
|
+
components: [{ type: "context", elements: [{ type: "mrkdwn", text }] }]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// src/plugins/slack/send-queue.ts
|
|
260
|
+
import PQueue from "p-queue";
|
|
261
|
+
var METHOD_RPM = {
|
|
262
|
+
"chat.postMessage": 50,
|
|
263
|
+
// Tier 3
|
|
264
|
+
"chat.update": 50,
|
|
265
|
+
// Tier 3
|
|
266
|
+
"conversations.create": 20,
|
|
267
|
+
// Tier 2
|
|
268
|
+
"conversations.rename": 20,
|
|
269
|
+
// Tier 2
|
|
270
|
+
"conversations.archive": 20,
|
|
271
|
+
// Tier 2
|
|
272
|
+
"conversations.invite": 20,
|
|
273
|
+
// Tier 2
|
|
274
|
+
"conversations.join": 20,
|
|
275
|
+
// Tier 2
|
|
276
|
+
"conversations.unarchive": 20,
|
|
277
|
+
// Tier 2
|
|
278
|
+
"conversations.info": 50
|
|
279
|
+
// Tier 3
|
|
280
|
+
};
|
|
281
|
+
var SlackSendQueue = class {
|
|
282
|
+
constructor(client) {
|
|
283
|
+
this.client = client;
|
|
284
|
+
for (const [method, rpm] of Object.entries(METHOD_RPM)) {
|
|
285
|
+
this.queues.set(method, new PQueue({
|
|
286
|
+
interval: Math.ceil(6e4 / rpm),
|
|
287
|
+
intervalCap: 1,
|
|
288
|
+
carryoverConcurrencyCount: true
|
|
289
|
+
}));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
queues = /* @__PURE__ */ new Map();
|
|
293
|
+
async enqueue(method, params) {
|
|
294
|
+
const queue = this.queues.get(method);
|
|
295
|
+
if (!queue) throw new Error(`Unknown Slack method: ${method}`);
|
|
296
|
+
return queue.add(() => this.client.apiCall(method, params));
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// src/plugins/slack/slug.ts
|
|
178
301
|
import { customAlphabet } from "nanoid";
|
|
179
302
|
var nanoidAlpha = customAlphabet("abcdefghijklmnopqrstuvwxyz0123456789", 4);
|
|
180
303
|
function toSlug(name, prefix = "openacp") {
|
|
@@ -183,7 +306,7 @@ function toSlug(name, prefix = "openacp") {
|
|
|
183
306
|
return `${prefix}-${base}-${suffix}`.replace(/-+/g, "-");
|
|
184
307
|
}
|
|
185
308
|
|
|
186
|
-
// src/
|
|
309
|
+
// src/plugins/slack/channel-manager.ts
|
|
187
310
|
var SlackChannelManager = class {
|
|
188
311
|
constructor(queue, config) {
|
|
189
312
|
this.queue = queue;
|
|
@@ -230,7 +353,7 @@ var SlackChannelManager = class {
|
|
|
230
353
|
}
|
|
231
354
|
};
|
|
232
355
|
|
|
233
|
-
// src/
|
|
356
|
+
// src/plugins/slack/permission-handler.ts
|
|
234
357
|
var SlackPermissionHandler = class {
|
|
235
358
|
constructor(queue, onResponse) {
|
|
236
359
|
this.queue = queue;
|
|
@@ -277,7 +400,7 @@ var SlackPermissionHandler = class {
|
|
|
277
400
|
}
|
|
278
401
|
};
|
|
279
402
|
|
|
280
|
-
// src/
|
|
403
|
+
// src/plugins/slack/event-router.ts
|
|
281
404
|
var log = createChildLogger({ module: "slack-event-router" });
|
|
282
405
|
var SlackEventRouter = class {
|
|
283
406
|
constructor(sessionLookup, onIncoming, botUserId, notificationChannelId, onNewSession, config, globalAllowedUserIds = []) {
|
|
@@ -333,7 +456,7 @@ var SlackEventRouter = class {
|
|
|
333
456
|
}
|
|
334
457
|
};
|
|
335
458
|
|
|
336
|
-
// src/
|
|
459
|
+
// src/plugins/slack/text-buffer.ts
|
|
337
460
|
var log2 = createChildLogger({ module: "slack-text-buffer" });
|
|
338
461
|
var FLUSH_IDLE_MS = 2e3;
|
|
339
462
|
var SlackTextBuffer = class {
|
|
@@ -419,9 +542,20 @@ var SlackTextBuffer = class {
|
|
|
419
542
|
}
|
|
420
543
|
};
|
|
421
544
|
|
|
422
|
-
// src/
|
|
545
|
+
// src/plugins/slack/adapter.ts
|
|
423
546
|
var log3 = createChildLogger({ module: "slack" });
|
|
424
|
-
var SlackAdapter = class extends
|
|
547
|
+
var SlackAdapter = class extends MessagingAdapter {
|
|
548
|
+
name = "slack";
|
|
549
|
+
renderer;
|
|
550
|
+
capabilities = {
|
|
551
|
+
streaming: true,
|
|
552
|
+
richFormatting: true,
|
|
553
|
+
threads: true,
|
|
554
|
+
reactions: false,
|
|
555
|
+
fileUpload: true,
|
|
556
|
+
voice: true
|
|
557
|
+
};
|
|
558
|
+
core;
|
|
425
559
|
app;
|
|
426
560
|
webClient;
|
|
427
561
|
queue;
|
|
@@ -435,9 +569,14 @@ var SlackAdapter = class extends ChannelAdapter {
|
|
|
435
569
|
slackConfig;
|
|
436
570
|
fileService;
|
|
437
571
|
constructor(core, config) {
|
|
438
|
-
super(
|
|
572
|
+
super(
|
|
573
|
+
{ configManager: core.configManager },
|
|
574
|
+
{ ...config, maxMessageLength: 3e3, enabled: config.enabled ?? true }
|
|
575
|
+
);
|
|
576
|
+
this.core = core;
|
|
439
577
|
this.slackConfig = config;
|
|
440
578
|
this.formatter = new SlackFormatter();
|
|
579
|
+
this.renderer = new SlackRenderer(this.formatter);
|
|
441
580
|
}
|
|
442
581
|
async start() {
|
|
443
582
|
const { botToken, appToken, signingSecret } = this.slackConfig;
|
|
@@ -639,7 +778,7 @@ var SlackAdapter = class extends ChannelAdapter {
|
|
|
639
778
|
await this.app.stop();
|
|
640
779
|
log3.info("Slack adapter stopped");
|
|
641
780
|
}
|
|
642
|
-
// ---
|
|
781
|
+
// --- MessagingAdapter implementations ---
|
|
643
782
|
async createSessionThread(sessionId, name) {
|
|
644
783
|
const meta = await this.channelManager.createChannel(sessionId, name);
|
|
645
784
|
this.sessions.set(sessionId, meta);
|
|
@@ -689,6 +828,10 @@ var SlackAdapter = class extends ChannelAdapter {
|
|
|
689
828
|
this.textBuffers.delete(sessionId);
|
|
690
829
|
}
|
|
691
830
|
}
|
|
831
|
+
_sessionMetas = /* @__PURE__ */ new Map();
|
|
832
|
+
getSessionMeta(sessionId) {
|
|
833
|
+
return this._sessionMetas.get(sessionId);
|
|
834
|
+
}
|
|
692
835
|
getTextBuffer(sessionId, channelId) {
|
|
693
836
|
let buf = this.textBuffers.get(sessionId);
|
|
694
837
|
if (!buf) {
|
|
@@ -703,35 +846,99 @@ var SlackAdapter = class extends ChannelAdapter {
|
|
|
703
846
|
log3.warn({ sessionId }, "No Slack channel for session, skipping message");
|
|
704
847
|
return;
|
|
705
848
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
849
|
+
this._sessionMetas.set(sessionId, meta);
|
|
850
|
+
try {
|
|
851
|
+
await super.sendMessage(sessionId, content);
|
|
852
|
+
} finally {
|
|
853
|
+
this._sessionMetas.delete(sessionId);
|
|
710
854
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
855
|
+
}
|
|
856
|
+
// --- Handler overrides (dispatched by base class) ---
|
|
857
|
+
async handleText(sessionId, content) {
|
|
858
|
+
const meta = this.getSessionMeta(sessionId);
|
|
859
|
+
if (!meta) return;
|
|
860
|
+
const buf = this.getTextBuffer(sessionId, meta.channelId);
|
|
861
|
+
buf.append(content.text ?? "");
|
|
862
|
+
}
|
|
863
|
+
async handleSessionEnd(sessionId, content) {
|
|
864
|
+
const meta = this.getSessionMeta(sessionId);
|
|
865
|
+
if (!meta) return;
|
|
866
|
+
await this.flushTextBuffer(sessionId);
|
|
867
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
868
|
+
if (blocks.length === 0) return;
|
|
869
|
+
try {
|
|
870
|
+
await this.queue.enqueue("chat.postMessage", {
|
|
871
|
+
channel: meta.channelId,
|
|
872
|
+
text: content.text ?? content.type,
|
|
873
|
+
blocks
|
|
874
|
+
});
|
|
875
|
+
} catch (err) {
|
|
876
|
+
log3.error({ err, sessionId, type: content.type }, "Failed to post Slack message");
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
async handleError(sessionId, content) {
|
|
880
|
+
const meta = this.getSessionMeta(sessionId);
|
|
881
|
+
if (!meta) return;
|
|
882
|
+
await this.flushTextBuffer(sessionId);
|
|
883
|
+
const blocks = this.formatter.formatOutgoing(content);
|
|
884
|
+
if (blocks.length === 0) return;
|
|
885
|
+
try {
|
|
886
|
+
await this.queue.enqueue("chat.postMessage", {
|
|
887
|
+
channel: meta.channelId,
|
|
888
|
+
text: content.text ?? content.type,
|
|
889
|
+
blocks
|
|
890
|
+
});
|
|
891
|
+
} catch (err) {
|
|
892
|
+
log3.error({ err, sessionId, type: content.type }, "Failed to post Slack message");
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
async handleAttachment(sessionId, content) {
|
|
896
|
+
const meta = this.getSessionMeta(sessionId);
|
|
897
|
+
if (!meta || !content.attachment) return;
|
|
898
|
+
if (content.attachment.type === "audio") {
|
|
899
|
+
try {
|
|
900
|
+
await this.uploadAudioFile(meta.channelId, content.attachment);
|
|
901
|
+
const buf = this.textBuffers.get(sessionId);
|
|
902
|
+
if (buf) await buf.stripTtsBlock();
|
|
903
|
+
} catch (err) {
|
|
904
|
+
log3.error({ err, sessionId }, "Failed to upload audio to Slack");
|
|
721
905
|
}
|
|
722
906
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
907
|
+
}
|
|
908
|
+
async handleThought(sessionId, content, _verbosity) {
|
|
909
|
+
await this.postFormattedMessage(sessionId, content);
|
|
910
|
+
}
|
|
911
|
+
async handleToolCall(sessionId, content, _verbosity) {
|
|
912
|
+
await this.postFormattedMessage(sessionId, content);
|
|
913
|
+
}
|
|
914
|
+
async handleToolUpdate(sessionId, content, _verbosity) {
|
|
915
|
+
await this.postFormattedMessage(sessionId, content);
|
|
916
|
+
}
|
|
917
|
+
async handlePlan(sessionId, content, _verbosity) {
|
|
918
|
+
await this.postFormattedMessage(sessionId, content);
|
|
919
|
+
}
|
|
920
|
+
async handleUsage(sessionId, content, _verbosity) {
|
|
921
|
+
await this.postFormattedMessage(sessionId, content);
|
|
922
|
+
}
|
|
923
|
+
async handleSystem(sessionId, content) {
|
|
924
|
+
await this.postFormattedMessage(sessionId, content);
|
|
925
|
+
}
|
|
926
|
+
// --- Private helpers ---
|
|
927
|
+
async flushTextBuffer(sessionId) {
|
|
928
|
+
const buf = this.textBuffers.get(sessionId);
|
|
929
|
+
if (buf) {
|
|
930
|
+
try {
|
|
931
|
+
await buf.flush();
|
|
932
|
+
} catch (err) {
|
|
933
|
+
log3.warn({ err, sessionId }, "Flush failed on session_end");
|
|
732
934
|
}
|
|
733
|
-
|
|
935
|
+
buf.destroy();
|
|
936
|
+
this.textBuffers.delete(sessionId);
|
|
734
937
|
}
|
|
938
|
+
}
|
|
939
|
+
async postFormattedMessage(sessionId, content) {
|
|
940
|
+
const meta = this.getSessionMeta(sessionId);
|
|
941
|
+
if (!meta) return;
|
|
735
942
|
const blocks = this.formatter.formatOutgoing(content);
|
|
736
943
|
if (blocks.length === 0) return;
|
|
737
944
|
try {
|
|
@@ -796,4 +1003,4 @@ ${notification.summary}`;
|
|
|
796
1003
|
export {
|
|
797
1004
|
SlackAdapter
|
|
798
1005
|
};
|
|
799
|
-
//# sourceMappingURL=adapter-
|
|
1006
|
+
//# sourceMappingURL=adapter-PQGHVG4K.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/slack/adapter.ts","../../src/plugins/slack/utils.ts","../../src/plugins/slack/formatter.ts","../../src/plugins/slack/renderer.ts","../../src/plugins/slack/send-queue.ts","../../src/plugins/slack/slug.ts","../../src/plugins/slack/channel-manager.ts","../../src/plugins/slack/permission-handler.ts","../../src/plugins/slack/event-router.ts","../../src/plugins/slack/text-buffer.ts"],"sourcesContent":["// src/adapters/slack/adapter.ts\nimport fs from \"node:fs\";\nimport { App } from \"@slack/bolt\";\nimport { WebClient } from \"@slack/web-api\";\nimport type { OpenACPCore } from \"../../core/core.js\";\nimport type {\n OutgoingMessage,\n PermissionRequest,\n NotificationMessage,\n Attachment,\n} from \"../../core/types.js\";\nimport type { AdapterCapabilities } from \"../../core/channel.js\";\nimport type { FileServiceInterface } from \"../../core/plugin/types.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\nimport { MessagingAdapter, type MessagingAdapterConfig } from \"../../core/adapter-primitives/messaging-adapter.js\";\nimport type { DisplayVerbosity } from \"../../core/adapter-primitives/format-types.js\";\nimport type { IRenderer } from \"../../core/adapter-primitives/rendering/renderer.js\";\nimport { SlackRenderer } from \"./renderer.js\";\nconst log = createChildLogger({ module: \"slack\" });\n\nimport type { SlackChannelConfig } from \"./types.js\";\nimport type { SlackSessionMeta, SlackFileInfo } from \"./types.js\";\nimport { SlackSendQueue } from \"./send-queue.js\";\nimport { SlackFormatter } from \"./formatter.js\";\nimport { SlackChannelManager } from \"./channel-manager.js\";\nimport { SlackPermissionHandler } from \"./permission-handler.js\";\nimport { SlackEventRouter } from \"./event-router.js\";\nimport { SlackTextBuffer } from \"./text-buffer.js\";\nimport { toSlug } from \"./slug.js\";\nimport { isAudioClip } from \"./utils.js\";\n\nexport class SlackAdapter extends MessagingAdapter {\n readonly name = 'slack';\n readonly renderer!: IRenderer;\n readonly capabilities: AdapterCapabilities = {\n streaming: true, richFormatting: true, threads: true,\n reactions: false, fileUpload: true, voice: true,\n };\n\n private core: OpenACPCore;\n private app!: App;\n private webClient!: WebClient;\n private queue!: SlackSendQueue;\n private formatter: SlackFormatter;\n private channelManager!: SlackChannelManager;\n private permissionHandler!: SlackPermissionHandler;\n private eventRouter!: SlackEventRouter;\n private sessions = new Map<string, SlackSessionMeta>();\n private textBuffers = new Map<string, SlackTextBuffer>();\n private botUserId = \"\";\n private slackConfig: SlackChannelConfig;\n private fileService!: FileServiceInterface;\n\n constructor(core: OpenACPCore, config: SlackChannelConfig) {\n super(\n { configManager: core.configManager },\n { ...config as Record<string, unknown>, maxMessageLength: 3000, enabled: config.enabled ?? true } as MessagingAdapterConfig,\n );\n this.core = core;\n this.slackConfig = config;\n this.formatter = new SlackFormatter();\n (this as { renderer: IRenderer }).renderer = new SlackRenderer(this.formatter);\n }\n\n async start(): Promise<void> {\n const { botToken, appToken, signingSecret } = this.slackConfig;\n\n if (!botToken || !appToken || !signingSecret) {\n throw new Error(\"Slack adapter requires botToken, appToken, and signingSecret\");\n }\n\n this.app = new App({\n token: botToken,\n appToken,\n signingSecret,\n socketMode: true,\n });\n\n this.webClient = new WebClient(botToken);\n this.queue = new SlackSendQueue(this.webClient);\n this.fileService = this.core.fileService;\n\n // Resolve bot user ID — required to filter bot's own messages (prevent infinite loop)\n const authResult = await this.webClient.auth.test();\n if (!authResult.user_id) {\n throw new Error(\"Slack auth.test() did not return user_id — verify botToken is valid\");\n }\n this.botUserId = authResult.user_id as string;\n log.info({ botUserId: this.botUserId }, \"Slack bot authenticated\");\n\n this.channelManager = new SlackChannelManager(this.queue, this.slackConfig);\n\n // Permission handler — resolve permission gate when user clicks a button\n this.permissionHandler = new SlackPermissionHandler(\n this.queue,\n (requestId, optionId) => {\n for (const [sessionId, _meta] of this.sessions) {\n const session = this.core.sessionManager.getSession(sessionId);\n if (session && session.permissionGate.requestId === requestId) {\n session.permissionGate.resolve(optionId);\n log.info({ sessionId, requestId, optionId }, \"Permission resolved\");\n return;\n }\n }\n log.warn({ requestId, optionId }, \"No matching session found for permission response\");\n },\n );\n this.permissionHandler.register(this.app);\n\n // Event router — dispatch incoming messages from session channels to core\n this.eventRouter = new SlackEventRouter(\n (slackChannelId) => {\n for (const meta of this.sessions.values()) {\n if (meta.channelId === slackChannelId) return meta;\n }\n return undefined;\n },\n (sessionChannelSlug, text, userId, files) => {\n const processFiles = async (): Promise<Attachment[] | undefined> => {\n if (!files?.length) return undefined;\n const audioFiles = files.filter((f) => isAudioClip(f));\n if (!audioFiles.length) return undefined;\n\n const attachments: Attachment[] = [];\n for (const file of audioFiles) {\n const buffer = await this.downloadSlackFile(file.url_private);\n if (!buffer) continue;\n const mimeType = file.mimetype === \"video/mp4\" ? \"audio/mp4\" : file.mimetype;\n const sessionId = this.core.sessionManager.getSessionByThread(\"slack\", sessionChannelSlug)?.id;\n if (!sessionId) continue;\n const att = await this.fileService.saveFile(sessionId, file.name, buffer, mimeType);\n attachments.push(att);\n }\n return attachments.length > 0 ? attachments : undefined;\n };\n\n processFiles()\n .then((attachments) => {\n this.core\n .handleMessage({\n channelId: \"slack\",\n threadId: sessionChannelSlug,\n userId,\n text,\n attachments,\n })\n .catch((err) => log.error({ err }, \"handleMessage error\"));\n })\n .catch((err) => log.error({ err }, \"Failed to process audio files\"));\n },\n this.botUserId,\n this.slackConfig.notificationChannelId,\n // onNewSession: reply with guidance when user messages the notification channel\n async (_text, _userId) => {\n if (this.slackConfig.notificationChannelId) {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.slackConfig.notificationChannelId,\n text: \"💬 To start a new session, use the `/openacp-new` slash command in any channel.\",\n }).catch((err: unknown) => log.warn({ err }, \"Failed to send onNewSession reply\"));\n }\n },\n this.slackConfig,\n this.core.configManager.get().security.allowedUserIds,\n );\n this.eventRouter.register(this.app);\n\n // Start Bolt (Socket Mode)\n await this.app.start();\n log.info(\"Slack adapter started (Socket Mode)\");\n\n // Create startup session + channel (configurable — set autoCreateSession: false to skip)\n if (this.slackConfig.autoCreateSession !== false) {\n await this._createStartupSession();\n }\n }\n\n private async downloadSlackFile(url: string): Promise<Buffer | null> {\n try {\n const resp = await fetch(url, {\n headers: { Authorization: `Bearer ${this.slackConfig.botToken}` },\n });\n if (!resp.ok) {\n log.warn({ status: resp.status }, \"Failed to download Slack file\");\n return null;\n }\n // Slack returns 200 with HTML login page if bot lacks files:read scope\n const contentType = resp.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"text/html\")) {\n log.warn(\"Slack file download returned HTML instead of binary — bot likely missing files:read scope. Reinstall the Slack app with files:read scope.\");\n return null;\n }\n return Buffer.from(await resp.arrayBuffer());\n } catch (err) {\n log.error({ err }, \"Error downloading Slack file\");\n return null;\n }\n }\n\n private async uploadAudioFile(channelId: string, att: Attachment): Promise<void> {\n const fileBuffer = await fs.promises.readFile(att.filePath);\n await this.webClient.files.uploadV2({\n channel_id: channelId,\n file: fileBuffer,\n filename: att.fileName,\n });\n }\n\n private async _createStartupSession(): Promise<void> {\n try {\n let reuseChannelId = this.slackConfig.startupChannelId;\n\n // Try to reuse existing startup channel (Telegram ensureTopics pattern)\n if (reuseChannelId) {\n try {\n const info = await this.queue.enqueue<Record<string, unknown>>(\n \"conversations.info\", { channel: reuseChannelId },\n );\n const channel = (info as Record<string, unknown>)?.channel as Record<string, unknown> | undefined;\n if (!channel || typeof channel.is_archived !== \"boolean\") {\n log.warn({ reuseChannelId }, \"Unexpected conversations.info response shape, creating new channel\");\n reuseChannelId = undefined;\n } else if (channel.is_archived) {\n await this.queue.enqueue(\"conversations.unarchive\", { channel: reuseChannelId });\n log.info({ channelId: reuseChannelId }, \"Unarchived startup channel for reuse\");\n }\n } catch {\n // Channel deleted or inaccessible — will create new\n reuseChannelId = undefined;\n }\n }\n\n if (reuseChannelId) {\n // Reuse existing channel — create session pointing to it\n let hasSession = false;\n for (const m of this.sessions.values()) {\n if (m.channelId === reuseChannelId) { hasSession = true; break; }\n }\n if (!hasSession) {\n const session = await this.core.handleNewSession(\"slack\", undefined, undefined, { createThread: false });\n const slug = `startup-${session.id.slice(0, 8)}`;\n this.sessions.set(session.id, { channelId: reuseChannelId, channelSlug: slug });\n session.threadId = slug;\n // Persist slug to session store so session resume after restart can find it\n await this.core.sessionManager.patchRecord(session.id, {\n platform: { topicId: slug },\n });\n log.info({ sessionId: session.id, channelId: reuseChannelId }, \"Reused startup channel\");\n }\n } else {\n // Create new channel + session\n const session = await this.core.handleNewSession(\"slack\", undefined, undefined, { createThread: true });\n if (!session.threadId) {\n log.error({ sessionId: session.id }, \"Startup session created without threadId\");\n return;\n }\n\n // Persist channel ID to config for reuse on next restart\n const meta = this.sessions.get(session.id);\n if (meta) {\n await this.core.configManager.save(\n { channels: { slack: { startupChannelId: meta.channelId } } },\n );\n log.info({ sessionId: session.id, channelId: meta.channelId }, \"Saved startup channel to config\");\n }\n }\n\n // Notify\n if (this.slackConfig.notificationChannelId) {\n const startupMeta = [...this.sessions.values()].find(m =>\n m.channelId === (reuseChannelId ?? this.slackConfig.startupChannelId)\n );\n if (startupMeta) {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.slackConfig.notificationChannelId,\n text: `✅ OpenACP ready — chat with the agent in <#${startupMeta.channelId}>`,\n });\n }\n }\n } catch (err) {\n log.error({ err }, \"Failed to create/reuse Slack startup session\");\n }\n }\n\n async stop(): Promise<void> {\n // Flush all active text buffers before stopping to prevent data loss\n for (const [sessionId, buf] of this.textBuffers) {\n try {\n await buf.flush();\n } catch (err) {\n log.warn({ err, sessionId }, \"Flush failed during stop\");\n }\n buf.destroy();\n }\n this.textBuffers.clear();\n await this.app.stop();\n log.info(\"Slack adapter stopped\");\n }\n\n // --- MessagingAdapter implementations ---\n\n async createSessionThread(sessionId: string, name: string): Promise<string> {\n const meta = await this.channelManager.createChannel(sessionId, name);\n this.sessions.set(sessionId, meta);\n log.info({ sessionId, channelId: meta.channelId, slug: meta.channelSlug }, \"Session channel created\");\n // Return the slug as the threadId so that lookups via getSessionByThread work\n return meta.channelSlug;\n }\n\n async renameSessionThread(sessionId: string, newName: string): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) return;\n\n const newSlug = toSlug(newName, this.slackConfig.channelPrefix ?? \"openacp\");\n\n try {\n await this.queue.enqueue(\"conversations.rename\", {\n channel: meta.channelId,\n name: newSlug,\n });\n meta.channelSlug = newSlug;\n // Update session.threadId so getSessionByThread() keeps working after rename\n const session = this.core.sessionManager.getSession(sessionId);\n if (session) session.threadId = newSlug;\n const existingRecord = this.core.sessionManager.getSessionRecord(sessionId);\n await this.core.sessionManager.patchRecord(sessionId, {\n name: newName,\n platform: { ...(existingRecord?.platform ?? {}), topicId: newSlug },\n });\n log.info({ sessionId, newSlug }, \"Session channel renamed\");\n } catch (err) {\n log.warn({ err, sessionId }, \"Failed to rename Slack channel\");\n }\n }\n\n async deleteSessionThread(sessionId: string): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) return;\n\n try {\n await this.permissionHandler.cleanupSession(meta.channelId);\n } catch (err) {\n log.warn({ err, sessionId }, \"Failed to clean up permission buttons\");\n }\n\n try {\n await this.channelManager.archiveChannel(meta.channelId);\n log.info({ sessionId, channelId: meta.channelId }, \"Session channel archived\");\n } catch (err) {\n log.warn({ err, sessionId }, \"Failed to archive Slack channel\");\n }\n this.sessions.delete(sessionId);\n const buf = this.textBuffers.get(sessionId);\n if (buf) { buf.destroy(); this.textBuffers.delete(sessionId); }\n }\n\n private _sessionMetas = new Map<string, SlackSessionMeta>();\n\n private getSessionMeta(sessionId: string): SlackSessionMeta | undefined {\n return this._sessionMetas.get(sessionId);\n }\n\n private getTextBuffer(sessionId: string, channelId: string): SlackTextBuffer {\n let buf = this.textBuffers.get(sessionId);\n if (!buf) {\n buf = new SlackTextBuffer(channelId, sessionId, this.queue);\n this.textBuffers.set(sessionId, buf);\n }\n return buf;\n }\n\n async sendMessage(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) {\n log.warn({ sessionId }, \"No Slack channel for session, skipping message\");\n return;\n }\n\n // Store meta per-session so concurrent calls for different sessions don't overwrite each other\n this._sessionMetas.set(sessionId, meta);\n try {\n await super.sendMessage(sessionId, content);\n } finally {\n this._sessionMetas.delete(sessionId);\n }\n }\n\n // --- Handler overrides (dispatched by base class) ---\n\n protected async handleText(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n // Text chunks are buffered and flushed as a single message after idle timeout\n const buf = this.getTextBuffer(sessionId, meta.channelId);\n buf.append(content.text ?? \"\");\n }\n\n protected async handleSessionEnd(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n // Flush any pending text first\n await this.flushTextBuffer(sessionId);\n\n const blocks = this.formatter.formatOutgoing(content);\n if (blocks.length === 0) return;\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: content.text ?? content.type,\n blocks,\n });\n } catch (err) {\n log.error({ err, sessionId, type: content.type }, \"Failed to post Slack message\");\n }\n }\n\n protected async handleError(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n // Flush any pending text first\n await this.flushTextBuffer(sessionId);\n\n const blocks = this.formatter.formatOutgoing(content);\n if (blocks.length === 0) return;\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: content.text ?? content.type,\n blocks,\n });\n } catch (err) {\n log.error({ err, sessionId, type: content.type }, \"Failed to post Slack message\");\n }\n }\n\n protected async handleAttachment(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta || !content.attachment) return;\n if (content.attachment.type === \"audio\") {\n try {\n await this.uploadAudioFile(meta.channelId, content.attachment);\n const buf = this.textBuffers.get(sessionId);\n if (buf) await buf.stripTtsBlock();\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to upload audio to Slack\");\n }\n }\n }\n\n protected async handleThought(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleToolCall(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleToolUpdate(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handlePlan(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleUsage(sessionId: string, content: OutgoingMessage, _verbosity: DisplayVerbosity): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n protected async handleSystem(sessionId: string, content: OutgoingMessage): Promise<void> {\n await this.postFormattedMessage(sessionId, content);\n }\n\n // --- Private helpers ---\n\n private async flushTextBuffer(sessionId: string): Promise<void> {\n const buf = this.textBuffers.get(sessionId);\n if (buf) {\n try {\n await buf.flush();\n } catch (err) {\n log.warn({ err, sessionId }, \"Flush failed on session_end\");\n }\n buf.destroy();\n this.textBuffers.delete(sessionId);\n }\n }\n\n private async postFormattedMessage(sessionId: string, content: OutgoingMessage): Promise<void> {\n const meta = this.getSessionMeta(sessionId);\n if (!meta) return;\n const blocks = this.formatter.formatOutgoing(content);\n if (blocks.length === 0) return;\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: content.text ?? content.type,\n blocks,\n });\n } catch (err) {\n log.error({ err, sessionId, type: content.type }, \"Failed to post Slack message\");\n }\n }\n\n // NOTE: Async flow — different from Telegram adapter.\n // Telegram: sendPermissionRequest awaits user response inline.\n // Slack: posts interactive buttons and returns immediately.\n // Resolution happens asynchronously via the Bolt action handler in\n // SlackPermissionHandler, which calls the PermissionResponseCallback\n // passed during construction. The callback iterates sessions to find\n // the matching permissionGate and resolves it.\n async sendPermissionRequest(\n sessionId: string,\n request: PermissionRequest,\n ): Promise<void> {\n const meta = this.sessions.get(sessionId);\n if (!meta) return;\n\n log.info({ sessionId, requestId: request.id }, \"Sending Slack permission request\");\n const blocks = this.formatter.formatPermissionRequest(request);\n\n try {\n const result = await this.queue.enqueue(\"chat.postMessage\", {\n channel: meta.channelId,\n text: `Permission request: ${request.description}`,\n blocks,\n });\n const ts = (result as { ts?: string })?.ts;\n if (ts) {\n this.permissionHandler.trackPendingMessage(request.id, meta.channelId, ts);\n }\n } catch (err) {\n log.error({ err, sessionId }, \"Failed to post Slack permission request\");\n }\n }\n\n async sendNotification(notification: NotificationMessage): Promise<void> {\n if (!this.slackConfig.notificationChannelId) return;\n\n const emoji: Record<string, string> = {\n completed: \"✅\",\n error: \"❌\",\n permission: \"🔐\",\n input_required: \"💬\",\n };\n const icon = emoji[notification.type] ?? \"ℹ️\";\n const text = `${icon} *${notification.sessionName ?? \"Session\"}*\\n${notification.summary}`;\n const blocks = this.formatter.formatNotification(text);\n\n try {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.slackConfig.notificationChannelId,\n text,\n blocks,\n });\n } catch (err) {\n log.warn({ err, sessionId: notification.sessionId }, \"Failed to send Slack notification\");\n }\n }\n}\n\nexport type { SlackChannelConfig } from \"./types.js\";\n","// src/adapters/slack/utils.ts\n// Shared utilities for Slack adapter modules.\n\nimport type { SlackFileInfo } from \"./types.js\";\n\n/** Detect Slack audio clips — MIME type or filename pattern */\nexport function isAudioClip(file: SlackFileInfo): boolean {\n return (file.mimetype === \"video/mp4\" && file.name?.startsWith(\"audio_message\")) ||\n file.mimetype?.startsWith(\"audio/\");\n}\n\nconst SECTION_LIMIT = 3000;\n\n/**\n * Split text at nearest newline boundary before `limit`.\n * Does NOT track code fence state — a triple-backtick block straddling\n * the boundary will be split mid-block.\n * Used by SlackFormatter and SlackTextBuffer to avoid exceeding Slack's\n * 3000-char section limit.\n */\nexport function splitSafe(text: string, limit = SECTION_LIMIT): string[] {\n if (text.length <= limit) return [text];\n const chunks: string[] = [];\n let remaining = text;\n while (remaining.length > 0) {\n if (remaining.length <= limit) { chunks.push(remaining); break; }\n let cut = remaining.lastIndexOf(\"\\n\", limit);\n if (cut <= 0) cut = limit;\n chunks.push(remaining.slice(0, cut));\n remaining = remaining.slice(cut).trimStart();\n }\n return chunks;\n}\n","// src/adapters/slack/formatter.ts\nimport type { types } from \"@slack/bolt\";\nimport type { OutgoingMessage, PermissionRequest } from \"../../core/types.js\";\nimport { splitSafe } from \"./utils.js\";\n\ntype KnownBlock = types.KnownBlock;\n\nexport interface ISlackFormatter {\n formatOutgoing(message: OutgoingMessage): KnownBlock[];\n formatPermissionRequest(req: PermissionRequest): KnownBlock[];\n formatNotification(text: string): KnownBlock[];\n formatSessionEnd(reason?: string): KnownBlock[];\n}\n\n/**\n * Convert a markdown string to Slack mrkdwn format.\n * Handles the most common patterns from AI responses.\n */\nexport function markdownToMrkdwn(text: string): string {\n return text\n // Fenced code blocks — preserve as-is (Slack supports ``` natively)\n // Headers: # H1 → placeholder (protected from italic regex)\n .replace(/^#{1,6}\\s+(.+)$/gm, \"\\x00BOLD\\x00$1\\x00BOLD\\x00\")\n // Bold: **text** → placeholder\n .replace(/\\*\\*(.+?)\\*\\*/g, \"\\x00BOLD\\x00$1\\x00BOLD\\x00\")\n // Italic: *text* → _text_ (won't match placeholder tokens)\n .replace(/(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)/g, \"_$1_\")\n // Restore bold/header placeholders → *text*\n .replace(/\\x00BOLD\\x00(.+?)\\x00BOLD\\x00/g, \"*$1*\")\n // Inline code: `code` — kept as-is (Slack supports backtick)\n // Strikethrough: ~~text~~ → ~text~\n .replace(/~~(.+?)~~/g, \"~$1~\")\n // Links: [text](url) → <url|text>\n .replace(/\\[([^\\]]+)\\]\\((https?:\\/\\/[^)]+)\\)/g, \"<$2|$1>\")\n // Unordered lists: \"- item\" or \"* item\" → \"• item\"\n .replace(/^[ \\t]*[-*]\\s+/gm, \"• \")\n // Ordered lists: \"1. item\" → \"1. item\" (already fine in mrkdwn)\n .trim();\n}\n\n// Slack mrkdwn text block, max 3000 chars per section\nconst SECTION_LIMIT = 3000;\n\nfunction section(text: string): KnownBlock {\n return { type: \"section\", text: { type: \"mrkdwn\", text: text.slice(0, SECTION_LIMIT) } };\n}\n\nfunction context(text: string): KnownBlock {\n return { type: \"context\", elements: [{ type: \"mrkdwn\", text }] };\n}\n\nexport class SlackFormatter implements ISlackFormatter {\n formatOutgoing(message: OutgoingMessage): KnownBlock[] {\n switch (message.type) {\n case \"text\": {\n const text = message.text ?? \"\";\n if (!text.trim()) return [];\n const converted = markdownToMrkdwn(text);\n return splitSafe(converted).map(chunk => section(chunk));\n }\n\n case \"thought\":\n return [context(`💭 _${(message.text ?? \"\").slice(0, 500)}_`)];\n\n case \"tool_call\": {\n const name = (message as OutgoingMessage & { metadata?: { name?: string; input?: unknown } }).metadata?.name ?? \"tool\";\n const input = (message as OutgoingMessage & { metadata?: { input?: unknown } }).metadata?.input;\n const inputStr = input ? `\\n\\`\\`\\`\\n${JSON.stringify(input, null, 2).slice(0, 500)}\\n\\`\\`\\`` : \"\";\n return [context(`🔧 \\`${name}\\`${inputStr}`)];\n }\n\n case \"tool_update\": {\n const name = (message as OutgoingMessage & { metadata?: { name?: string; status?: string } }).metadata?.name ?? \"tool\";\n const status = (message as OutgoingMessage & { metadata?: { status?: string } }).metadata?.status ?? \"done\";\n const icon = status === \"error\" ? \"❌\" : \"✅\";\n return [context(`${icon} \\`${name}\\` — ${status}`)];\n }\n\n case \"plan\":\n return [\n { type: \"divider\" },\n section(`📋 *Plan*\\n${message.text ?? \"\"}`),\n ];\n\n case \"usage\": {\n const meta = (message as OutgoingMessage & { metadata?: { input_tokens?: number; output_tokens?: number; cost_usd?: number } }).metadata ?? {};\n const parts = [\n meta.input_tokens != null ? `in: ${meta.input_tokens}` : null,\n meta.output_tokens != null ? `out: ${meta.output_tokens}` : null,\n meta.cost_usd != null ? `$${Number(meta.cost_usd).toFixed(4)}` : null,\n ].filter((p): p is string => p !== null);\n return parts.length ? [context(`📊 ${parts.join(\" · \")}`)] : [];\n }\n\n case \"session_end\":\n return this.formatSessionEnd(message.text);\n\n case \"error\":\n return [section(`⚠️ *Error:* ${message.text ?? \"Unknown error\"}`)];\n\n default:\n return [];\n }\n }\n\n formatPermissionRequest(req: PermissionRequest): KnownBlock[] {\n return [\n section(`🔐 *Permission Request*\\n${req.description}`),\n {\n type: \"actions\",\n block_id: `perm_${req.id}`,\n elements: req.options.map(opt => ({\n type: \"button\" as const,\n text: { type: \"plain_text\" as const, text: opt.label, emoji: true },\n value: `${req.id}:${opt.id}`,\n action_id: `perm_action_${opt.id}_${req.id}`,\n style: (opt.isAllow ? \"primary\" : \"danger\") as \"primary\" | \"danger\",\n })),\n } as KnownBlock,\n ];\n }\n\n formatNotification(text: string): KnownBlock[] {\n return [section(text)];\n }\n\n formatSessionEnd(reason?: string): KnownBlock[] {\n return [\n { type: \"divider\" },\n context(`✅ Session ended${reason ? ` — ${reason}` : \"\"}`),\n ];\n }\n}\n","import { BaseRenderer } from '../../core/adapter-primitives/rendering/renderer.js'\nimport type { RenderedMessage, RenderedPermission } from '../../core/adapter-primitives/rendering/renderer.js'\nimport type { OutgoingMessage, PermissionRequest, NotificationMessage } from '../../core/types.js'\nimport type { DisplayVerbosity } from '../../core/adapter-primitives/format-types.js'\nimport { SlackFormatter, markdownToMrkdwn } from './formatter.js'\n\n/**\n * SlackRenderer — renders messages as Slack Block Kit structures.\n * Delegates to the existing SlackFormatter for block generation,\n * wrapping results into RenderedMessage with format: 'structured'.\n */\nexport class SlackRenderer extends BaseRenderer {\n private formatter: SlackFormatter\n\n constructor(formatter?: SlackFormatter) {\n super()\n this.formatter = formatter ?? new SlackFormatter()\n }\n\n renderText(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderThought(content: OutgoingMessage, _verbosity: DisplayVerbosity): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderToolCall(content: OutgoingMessage, _verbosity: DisplayVerbosity): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderToolUpdate(content: OutgoingMessage, _verbosity: DisplayVerbosity): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderPlan(content: OutgoingMessage, _verbosity: DisplayVerbosity): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderUsage(content: OutgoingMessage, _verbosity: DisplayVerbosity): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderError(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatOutgoing(content)\n return {\n body: content.text ?? '',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderSessionEnd(content: OutgoingMessage): RenderedMessage {\n const blocks = this.formatter.formatSessionEnd(content.text)\n return {\n body: content.text ?? 'Session ended',\n format: 'structured',\n components: blocks,\n }\n }\n\n renderPermission(request: PermissionRequest): RenderedPermission {\n const blocks = this.formatter.formatPermissionRequest(request)\n return {\n body: request.description,\n format: 'structured',\n components: blocks,\n actions: request.options.map(o => ({ id: o.id, label: o.label, isAllow: o.isAllow })),\n }\n }\n\n renderNotification(notification: NotificationMessage): RenderedMessage {\n const emoji: Record<string, string> = {\n completed: '✅', error: '❌', permission: '🔐', input_required: '💬', budget_warning: '⚠️',\n }\n const icon = emoji[notification.type] || 'ℹ️'\n const text = `${icon} *${notification.sessionName ?? 'Session'}*\\n${notification.summary}`\n const blocks = this.formatter.formatNotification(text)\n return {\n body: text,\n format: 'structured',\n components: blocks,\n }\n }\n\n renderSystemMessage(content: OutgoingMessage): RenderedMessage {\n const mrkdwn = markdownToMrkdwn(content.text ?? '')\n return {\n body: mrkdwn,\n format: 'structured',\n components: [{ type: 'section' as const, text: { type: 'mrkdwn' as const, text: mrkdwn } }],\n }\n }\n\n renderModeChange(content: OutgoingMessage): RenderedMessage {\n const modeId = (content.metadata as Record<string, unknown>)?.modeId ?? ''\n const text = `🔄 *Mode:* ${modeId}`\n return {\n body: text,\n format: 'structured',\n components: [{ type: 'context' as const, elements: [{ type: 'mrkdwn' as const, text }] }],\n }\n }\n\n renderConfigUpdate(): RenderedMessage {\n const text = '⚙️ *Config updated*'\n return {\n body: text,\n format: 'structured',\n components: [{ type: 'context' as const, elements: [{ type: 'mrkdwn' as const, text }] }],\n }\n }\n\n renderModelUpdate(content: OutgoingMessage): RenderedMessage {\n const modelId = (content.metadata as Record<string, unknown>)?.modelId ?? ''\n const text = `🤖 *Model:* ${modelId}`\n return {\n body: text,\n format: 'structured',\n components: [{ type: 'context' as const, elements: [{ type: 'mrkdwn' as const, text }] }],\n }\n }\n}\n","import PQueue from \"p-queue\";\nimport type { WebClient } from \"@slack/web-api\";\n\nexport type SlackMethod =\n | \"chat.postMessage\"\n | \"chat.update\"\n | \"conversations.create\"\n | \"conversations.rename\"\n | \"conversations.archive\"\n | \"conversations.invite\"\n | \"conversations.join\"\n | \"conversations.unarchive\"\n | \"conversations.info\";\n\n// Requests per minute per method (Slack Tier definitions)\nconst METHOD_RPM: Record<SlackMethod, number> = {\n \"chat.postMessage\": 50, // Tier 3\n \"chat.update\": 50, // Tier 3\n \"conversations.create\": 20, // Tier 2\n \"conversations.rename\": 20, // Tier 2\n \"conversations.archive\": 20, // Tier 2\n \"conversations.invite\": 20, // Tier 2\n \"conversations.join\": 20, // Tier 2\n \"conversations.unarchive\": 20, // Tier 2\n \"conversations.info\": 50, // Tier 3\n};\n\nexport interface ISlackSendQueue {\n enqueue<T = unknown>(method: SlackMethod, params: Record<string, unknown>): Promise<T>;\n}\n\nexport class SlackSendQueue implements ISlackSendQueue {\n private queues = new Map<SlackMethod, PQueue>();\n\n constructor(private client: WebClient) {\n for (const [method, rpm] of Object.entries(METHOD_RPM) as [SlackMethod, number][]) {\n // Spread requests evenly across the minute\n this.queues.set(method, new PQueue({\n interval: Math.ceil(60_000 / rpm),\n intervalCap: 1,\n carryoverConcurrencyCount: true,\n }));\n }\n }\n\n async enqueue<T = unknown>(method: SlackMethod, params: Record<string, unknown>): Promise<T> {\n const queue = this.queues.get(method);\n if (!queue) throw new Error(`Unknown Slack method: ${method}`);\n return queue.add(() => this.client.apiCall(method, params) as Promise<T>);\n }\n}\n","// src/adapters/slack/slug.ts\nimport { customAlphabet } from \"nanoid\";\n\nconst nanoidAlpha = customAlphabet(\"abcdefghijklmnopqrstuvwxyz0123456789\", 4);\n\n/**\n * Convert a human-readable session name to a valid Slack channel name.\n * Rules: lowercase, ≤80 chars, only [a-z0-9-], unique suffix appended.\n *\n * Examples:\n * \"Fix authentication bug\" → \"openacp-fix-authentication-bug-a3k9\"\n * \"New Session\" → \"openacp-new-session-x7p2\"\n * \"Implement OAuth 2.0 & JWT refresh\" → \"openacp-implement-oauth-20-jwt-refresh-b8qr\"\n */\nexport function toSlug(name: string, prefix = \"openacp\"): string {\n const base = name\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, \"\") // strip special chars\n .trim()\n .replace(/\\s+/g, \"-\") // spaces → dashes\n .replace(/-+/g, \"-\") // collapse consecutive dashes\n .slice(0, 60); // leave room for prefix and suffix\n\n const suffix = nanoidAlpha();\n return `${prefix}-${base}-${suffix}`.replace(/-+/g, \"-\");\n}\n","// src/adapters/slack/channel-manager.ts\nimport type { ISlackSendQueue } from \"./send-queue.js\";\nimport { toSlug } from \"./slug.js\";\nimport type { SlackSessionMeta } from \"./types.js\";\nimport type { SlackChannelConfig } from \"./types.js\";\n\nexport interface ISlackChannelManager {\n createChannel(sessionId: string, sessionName: string): Promise<SlackSessionMeta>;\n archiveChannel(channelId: string): Promise<void>;\n notifyChannel(text: string): Promise<void>;\n}\n\nexport class SlackChannelManager implements ISlackChannelManager {\n constructor(\n private queue: ISlackSendQueue,\n private config: SlackChannelConfig,\n ) {}\n\n async createChannel(sessionId: string, sessionName: string): Promise<SlackSessionMeta> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const finalSlug = toSlug(sessionName, this.config.channelPrefix ?? \"openacp\");\n\n try {\n const res = await this.queue.enqueue<{ channel: { id: string } }>(\n \"conversations.create\",\n { name: finalSlug, is_private: true },\n );\n const channelId = res.channel.id;\n\n // Bot is automatically a member of private channels it creates — no join/invite needed.\n // Invite configured users so they can access the channel.\n const userIds = this.config.allowedUserIds ?? [];\n if (userIds.length > 0) {\n await this.queue.enqueue(\"conversations.invite\", {\n channel: channelId,\n users: userIds.join(\",\"),\n });\n }\n\n return { channelId, channelSlug: finalSlug };\n } catch (err: any) {\n if (err?.data?.error === \"name_taken\" && attempt < 2) {\n lastError = err;\n continue;\n }\n throw err;\n }\n }\n\n throw lastError;\n }\n\n async archiveChannel(channelId: string): Promise<void> {\n await this.queue.enqueue(\"conversations.archive\", { channel: channelId });\n }\n\n async notifyChannel(text: string): Promise<void> {\n if (this.config.notificationChannelId) {\n await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.config.notificationChannelId,\n text,\n });\n }\n }\n}\n","import type { App, BlockAction, ButtonAction } from \"@slack/bolt\";\nimport type { ISlackSendQueue } from \"./send-queue.js\";\n\nexport type PermissionResponseCallback = (requestId: string, optionId: string) => void;\n\nexport interface ISlackPermissionHandler {\n register(app: App): void;\n trackPendingMessage(requestId: string, channelId: string, messageTs: string): void;\n cleanupSession(channelId: string): Promise<void>;\n}\n\nexport class SlackPermissionHandler implements ISlackPermissionHandler {\n private pendingMessages = new Map<string, { channelId: string; messageTs: string }>();\n\n constructor(\n private queue: ISlackSendQueue,\n private onResponse: PermissionResponseCallback,\n ) {}\n\n trackPendingMessage(requestId: string, channelId: string, messageTs: string): void {\n this.pendingMessages.set(requestId, { channelId, messageTs });\n }\n\n async cleanupSession(channelId: string): Promise<void> {\n for (const [requestId, info] of this.pendingMessages) {\n if (info.channelId !== channelId) continue;\n await this.queue.enqueue(\"chat.update\", {\n channel: info.channelId,\n ts: info.messageTs,\n blocks: [],\n });\n this.pendingMessages.delete(requestId);\n }\n }\n\n register(app: App): void {\n // Match any action starting with \"perm_action_\"\n app.action<BlockAction<ButtonAction>>(\n /^perm_action_/,\n async ({ ack, body, action }) => {\n await ack();\n\n const value: string = action.value ?? \"\";\n const colonIdx = value.indexOf(\":\");\n if (colonIdx === -1) return;\n\n const requestId = value.slice(0, colonIdx);\n const optionId = value.slice(colonIdx + 1);\n\n this.onResponse(requestId, optionId);\n\n // Remove from pending tracking since the user has responded\n this.pendingMessages.delete(requestId);\n\n // Update message to remove action buttons and show confirmation\n const message = body.message;\n if (message) {\n await this.queue.enqueue(\"chat.update\", {\n channel: body.channel?.id ?? \"\",\n ts: message.ts,\n text: `✅ Permission response: *${optionId}*`,\n blocks: [],\n });\n }\n }\n );\n }\n}\n","// src/adapters/slack/event-router.ts\nimport type { App } from \"@slack/bolt\";\nimport type { SlackSessionMeta, SlackFileInfo } from \"./types.js\";\nimport type { SlackChannelConfig } from \"./types.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\nconst log = createChildLogger({ module: \"slack-event-router\" });\n\n/** Subset of Bolt's message event fields used by the router */\ninterface SlackMessageEvent {\n bot_id?: string;\n subtype?: string;\n channel: string;\n text?: string;\n user?: string;\n files?: Array<{\n id: string;\n name: string;\n mimetype: string;\n size: number;\n url_private: string;\n }>;\n}\n\n// Callback to look up which session (if any) owns a Slack channelId\nexport type SessionLookup = (channelId: string) => SlackSessionMeta | undefined;\n\n// Callback to dispatch an incoming message to core\nexport type IncomingMessageCallback = (sessionId: string, text: string, userId: string, files?: SlackFileInfo[]) => void;\n\n// Callback to create a new session when user messages the notification channel\nexport type NewSessionCallback = (text: string, userId: string) => void;\n\nexport interface ISlackEventRouter {\n register(app: App): void;\n}\n\nexport class SlackEventRouter implements ISlackEventRouter {\n constructor(\n private sessionLookup: SessionLookup,\n private onIncoming: IncomingMessageCallback,\n private botUserId: string,\n private notificationChannelId: string | undefined,\n private onNewSession: NewSessionCallback,\n private config: SlackChannelConfig,\n private globalAllowedUserIds: string[] = [],\n ) {}\n\n private isAllowedUser(userId: string): boolean {\n const slackAllowed = this.config.allowedUserIds ?? [];\n const allowed = slackAllowed.length > 0 ? slackAllowed : this.globalAllowedUserIds;\n if (allowed.length === 0) return true;\n return allowed.includes(userId);\n }\n\n register(app: App): void {\n app.message(async ({ message }) => {\n log.debug({ message }, \"Slack raw message event\");\n\n const msg = message as unknown as SlackMessageEvent;\n\n if (msg.bot_id) return;\n const subtype = msg.subtype;\n if (subtype && subtype !== \"file_share\") return; // edited, deleted, etc.\n\n const channelId = msg.channel;\n const text: string = msg.text ?? \"\";\n const userId: string = msg.user ?? \"\";\n\n const files: SlackFileInfo[] | undefined = msg.files?.map((f) => ({\n id: f.id,\n name: f.name,\n mimetype: f.mimetype,\n size: f.size,\n url_private: f.url_private,\n }));\n\n log.debug({ channelId, userId, text }, \"Slack message received\");\n\n // Ignore messages from the bot itself\n if (userId === this.botUserId) return;\n\n // Enforce allowedUserIds\n if (!this.isAllowedUser(userId)) {\n log.warn({ userId }, \"slack: message from non-allowed user rejected\");\n return;\n }\n\n const session = this.sessionLookup(channelId);\n if (session) {\n // Message to an existing session channel\n log.debug({ channelId, sessionSlug: session.channelSlug }, \"Routing to session\");\n this.onIncoming(session.channelSlug, text, userId, files);\n return;\n }\n\n log.debug({ channelId, notificationChannelId: this.notificationChannelId }, \"No session found for channel\");\n\n // Message to the notification channel → create new session\n if (this.notificationChannelId && channelId === this.notificationChannelId) {\n this.onNewSession(text, userId);\n return;\n }\n });\n }\n}\n","// src/adapters/slack/text-buffer.ts\n// Buffers streamed text chunks per session and flushes as a single Slack message.\n// This prevents the \"many tiny messages\" problem from streaming AI responses.\n\nimport type { ISlackSendQueue } from \"./send-queue.js\";\nimport { markdownToMrkdwn } from \"./formatter.js\";\nimport { splitSafe } from \"./utils.js\";\nimport { createChildLogger } from \"../../core/utils/log.js\";\n\nconst log = createChildLogger({ module: \"slack-text-buffer\" });\n\nconst FLUSH_IDLE_MS = 2000; // flush after 2s of no new chunks\n\nexport class SlackTextBuffer {\n private buffer = \"\";\n private timer: ReturnType<typeof setTimeout> | undefined;\n private flushPromise: Promise<void> | undefined;\n private lastMessageTs: string | undefined;\n private lastPostedText: string | undefined;\n\n constructor(\n private channelId: string,\n private sessionId: string,\n private queue: ISlackSendQueue,\n ) {}\n\n append(text: string): void {\n if (!text) return;\n this.buffer += text;\n this.resetTimer();\n }\n\n private resetTimer(): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = setTimeout(() => {\n this.timer = undefined;\n this.flush().catch((err) => log.error({ err, sessionId: this.sessionId }, \"Text buffer flush error\"));\n }, FLUSH_IDLE_MS);\n }\n\n async flush(): Promise<void> {\n if (this.flushPromise) return this.flushPromise;\n const text = this.buffer.trim();\n if (!text) return;\n this.buffer = \"\";\n if (this.timer) { clearTimeout(this.timer); this.timer = undefined; }\n\n this.flushPromise = (async () => {\n try {\n const converted = markdownToMrkdwn(text);\n const chunks = splitSafe(converted);\n for (const chunk of chunks) {\n if (!chunk.trim()) continue;\n const result = await this.queue.enqueue(\"chat.postMessage\", {\n channel: this.channelId,\n text: chunk,\n blocks: [{ type: \"section\", text: { type: \"mrkdwn\", text: chunk } }],\n });\n // Track last posted message for potential TTS block editing\n this.lastMessageTs = (result as { ts?: string } | undefined)?.ts;\n this.lastPostedText = chunk;\n }\n } finally {\n this.flushPromise = undefined;\n // Re-flush if content arrived while we were flushing\n if (this.buffer.trim()) {\n await this.flush();\n }\n }\n })();\n\n return this.flushPromise;\n }\n\n destroy(): void {\n if (this.timer) { clearTimeout(this.timer); this.timer = undefined; }\n this.buffer = \"\";\n }\n\n /** Remove [TTS]...[/TTS] blocks — from buffer if unflushed, or edit posted message */\n async stripTtsBlock(): Promise<void> {\n // Case 1: TTS block still in unflushed buffer\n if (/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/.test(this.buffer)) {\n this.buffer = this.buffer.replace(/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/g, \"\").replace(/\\s{2,}/g, \" \").trim();\n return;\n }\n\n // Case 2: Already flushed — edit the posted message via chat.update\n if (this.lastMessageTs && this.lastPostedText && /\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/.test(this.lastPostedText)) {\n const cleaned = this.lastPostedText.replace(/\\[TTS\\][\\s\\S]*?\\[\\/TTS\\]/g, \"\").replace(/\\s{2,}/g, \" \").trim();\n if (cleaned) {\n await this.queue.enqueue(\"chat.update\", {\n channel: this.channelId,\n ts: this.lastMessageTs,\n text: cleaned,\n blocks: [{ type: \"section\", text: { type: \"mrkdwn\", text: cleaned } }],\n });\n }\n this.lastPostedText = cleaned;\n }\n }\n}\n"],"mappings":"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","names":["SECTION_LIMIT","log","log"]}
|