@chrisromp/copilot-bridge 0.7.0-dev.16 → 0.8.0
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/config.sample.json +8 -1
- package/dist/channels/slack/adapter.d.ts +62 -0
- package/dist/channels/slack/adapter.d.ts.map +1 -0
- package/dist/channels/slack/adapter.js +382 -0
- package/dist/channels/slack/adapter.js.map +1 -0
- package/dist/channels/slack/mrkdwn.d.ts +22 -0
- package/dist/channels/slack/mrkdwn.d.ts.map +1 -0
- package/dist/channels/slack/mrkdwn.js +120 -0
- package/dist/channels/slack/mrkdwn.js.map +1 -0
- package/dist/config.d.ts +5 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +55 -7
- package/dist/config.js.map +1 -1
- package/dist/core/access-control.d.ts +32 -0
- package/dist/core/access-control.d.ts.map +1 -0
- package/dist/core/access-control.js +59 -0
- package/dist/core/access-control.js.map +1 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +75 -1
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/inter-agent.d.ts +9 -2
- package/dist/core/inter-agent.d.ts.map +1 -1
- package/dist/core/inter-agent.js +87 -22
- package/dist/core/inter-agent.js.map +1 -1
- package/dist/core/model-fallback.js +1 -1
- package/dist/core/model-fallback.js.map +1 -1
- package/dist/index.js +182 -14
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +9 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/scripts/init.ts +322 -117
- package/scripts/lib/config-gen.ts +74 -10
- package/scripts/lib/prerequisites.ts +17 -5
- package/scripts/lib/prompts.ts +4 -0
- package/scripts/lib/slack.ts +190 -0
- package/templates/admin/AGENTS.md +5 -5
- package/templates/agents/AGENTS.md +1 -1
package/config.sample.json
CHANGED
|
@@ -2,8 +2,15 @@
|
|
|
2
2
|
"platforms": {
|
|
3
3
|
"mattermost": {
|
|
4
4
|
"url": "https://chat.example.com",
|
|
5
|
+
"access": {
|
|
6
|
+
"mode": "allowlist",
|
|
7
|
+
"users": ["your-username"]
|
|
8
|
+
},
|
|
5
9
|
"bots": {
|
|
6
|
-
"copilot": {
|
|
10
|
+
"copilot": {
|
|
11
|
+
"token": "YOUR_BOT_TOKEN",
|
|
12
|
+
"admin": true
|
|
13
|
+
}
|
|
7
14
|
}
|
|
8
15
|
}
|
|
9
16
|
},
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack channel adapter using @slack/bolt (Socket Mode).
|
|
3
|
+
*
|
|
4
|
+
* This adapter connects to Slack via Socket Mode (WebSocket) — no public URL required.
|
|
5
|
+
* It implements the full ChannelAdapter interface for bidirectional message flow.
|
|
6
|
+
*
|
|
7
|
+
* Required config:
|
|
8
|
+
* platforms.slack.bots.<name>.token — Bot User OAuth Token (xoxb-...)
|
|
9
|
+
* platforms.slack.bots.<name>.appToken — App-Level Token (xapp-...) for Socket Mode
|
|
10
|
+
*/
|
|
11
|
+
import type { ChannelAdapter, InboundMessage, InboundReaction, SendOpts } from '../../types.js';
|
|
12
|
+
/** Options for constructing a SlackAdapter. */
|
|
13
|
+
export interface SlackAdapterOptions {
|
|
14
|
+
platformName: string;
|
|
15
|
+
botToken: string;
|
|
16
|
+
appToken: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class SlackAdapter implements ChannelAdapter {
|
|
19
|
+
readonly platform: string;
|
|
20
|
+
private app;
|
|
21
|
+
private botUserId;
|
|
22
|
+
private botToken;
|
|
23
|
+
private appToken;
|
|
24
|
+
private messageHandlers;
|
|
25
|
+
private reactionHandlers;
|
|
26
|
+
private recentMessageTs;
|
|
27
|
+
private static readonly MAX_RECENT_MESSAGES;
|
|
28
|
+
constructor(opts: SlackAdapterOptions);
|
|
29
|
+
connect(): Promise<void>;
|
|
30
|
+
disconnect(): Promise<void>;
|
|
31
|
+
onMessage(handler: (msg: InboundMessage) => void): void;
|
|
32
|
+
onReaction(handler: (reaction: InboundReaction) => void): void;
|
|
33
|
+
sendMessage(channelId: string, content: string, opts?: SendOpts): Promise<string>;
|
|
34
|
+
updateMessage(channelId: string, messageId: string, content: string): Promise<void>;
|
|
35
|
+
deleteMessage(channelId: string, messageId: string): Promise<void>;
|
|
36
|
+
setTyping(_channelId: string): Promise<void>;
|
|
37
|
+
replyInThread(channelId: string, rootId: string, content: string): Promise<string>;
|
|
38
|
+
getBotUserId(): string;
|
|
39
|
+
addReaction(postId: string, emoji: string): Promise<void>;
|
|
40
|
+
downloadFile(fileId: string, destPath: string): Promise<string>;
|
|
41
|
+
sendFile(channelId: string, filePath: string, message?: string, opts?: SendOpts): Promise<string>;
|
|
42
|
+
discoverDMChannels(): Promise<{
|
|
43
|
+
channelId: string;
|
|
44
|
+
otherUserId: string;
|
|
45
|
+
}[]>;
|
|
46
|
+
private handleMessage;
|
|
47
|
+
private handleReaction;
|
|
48
|
+
private extractAttachments;
|
|
49
|
+
private trackMessage;
|
|
50
|
+
/**
|
|
51
|
+
* Parse a message reference into [channelId, ts].
|
|
52
|
+
* Inbound postIds are stored as "channelId:ts"; sendMessage returns bare "ts".
|
|
53
|
+
* Returns ['', ref] when no channel prefix is present.
|
|
54
|
+
*/
|
|
55
|
+
private parseMessageRef;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Split a message into chunks that fit within Slack's character limit.
|
|
59
|
+
* Tries to split on newlines first, then falls back to hard splits.
|
|
60
|
+
*/
|
|
61
|
+
export declare function chunkMessage(content: string, maxLength?: number): string[];
|
|
62
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EACf,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAOxB,+CAA+C;AAC/C,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,YAAa,YAAW,cAAc;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,eAAe,CAA4C;IACnE,OAAO,CAAC,gBAAgB,CAAkD;IAG1E,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;gBAEtC,IAAI,EAAE,mBAAmB;IAM/B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA0CxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAOjC,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,IAAI;IAIvD,UAAU,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,GAAG,IAAI;IAIxD,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBjF,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBnF,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBlE,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5C,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxF,YAAY,IAAI,MAAM;IAIhB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAezD,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwB/D,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBjG,kBAAkB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IA6BjF,OAAO,CAAC,aAAa;IAyDrB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,YAAY;IAYpB;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAKxB;AAID;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,SAA2B,GAAG,MAAM,EAAE,CA4B5F"}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack channel adapter using @slack/bolt (Socket Mode).
|
|
3
|
+
*
|
|
4
|
+
* This adapter connects to Slack via Socket Mode (WebSocket) — no public URL required.
|
|
5
|
+
* It implements the full ChannelAdapter interface for bidirectional message flow.
|
|
6
|
+
*
|
|
7
|
+
* Required config:
|
|
8
|
+
* platforms.slack.bots.<name>.token — Bot User OAuth Token (xoxb-...)
|
|
9
|
+
* platforms.slack.bots.<name>.appToken — App-Level Token (xapp-...) for Socket Mode
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { Readable } from 'node:stream';
|
|
14
|
+
import { createLogger } from '../../logger.js';
|
|
15
|
+
import { markdownToMrkdwn } from './mrkdwn.js';
|
|
16
|
+
const log = createLogger('slack');
|
|
17
|
+
// Slack message character limit — responses longer than this must be chunked
|
|
18
|
+
const SLACK_MAX_MESSAGE_LENGTH = 3_900; // leave room for formatting overhead under 4000 limit
|
|
19
|
+
export class SlackAdapter {
|
|
20
|
+
platform;
|
|
21
|
+
app; // Bolt App instance (typed as any to support optional dep)
|
|
22
|
+
botUserId = '';
|
|
23
|
+
botToken;
|
|
24
|
+
appToken;
|
|
25
|
+
messageHandlers = [];
|
|
26
|
+
reactionHandlers = [];
|
|
27
|
+
// Reconnect dedup state
|
|
28
|
+
recentMessageTs = new Set();
|
|
29
|
+
static MAX_RECENT_MESSAGES = 500;
|
|
30
|
+
constructor(opts) {
|
|
31
|
+
this.platform = opts.platformName;
|
|
32
|
+
this.botToken = opts.botToken;
|
|
33
|
+
this.appToken = opts.appToken;
|
|
34
|
+
}
|
|
35
|
+
async connect() {
|
|
36
|
+
// Dynamic import — @slack/bolt is an optional peer dependency
|
|
37
|
+
let App;
|
|
38
|
+
try {
|
|
39
|
+
const bolt = await import('@slack/bolt');
|
|
40
|
+
App = bolt.App;
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new Error('Slack adapter requires @slack/bolt. Install it with: npm install @slack/bolt');
|
|
44
|
+
}
|
|
45
|
+
this.app = new App({
|
|
46
|
+
token: this.botToken,
|
|
47
|
+
appToken: this.appToken,
|
|
48
|
+
socketMode: true,
|
|
49
|
+
// Disable built-in acknowledgment logging
|
|
50
|
+
logLevel: 'WARN',
|
|
51
|
+
});
|
|
52
|
+
// Fetch bot identity
|
|
53
|
+
const authResult = await this.app.client.auth.test({ token: this.botToken });
|
|
54
|
+
this.botUserId = authResult.user_id;
|
|
55
|
+
log.info(`Authenticated as <@${this.botUserId}> (${authResult.user})`);
|
|
56
|
+
// Wire up message events
|
|
57
|
+
this.app.message(async ({ message, context }) => {
|
|
58
|
+
this.handleMessage(message, context);
|
|
59
|
+
});
|
|
60
|
+
// Wire up reaction events
|
|
61
|
+
this.app.event('reaction_added', async ({ event }) => {
|
|
62
|
+
this.handleReaction(event, 'added');
|
|
63
|
+
});
|
|
64
|
+
this.app.event('reaction_removed', async ({ event }) => {
|
|
65
|
+
this.handleReaction(event, 'removed');
|
|
66
|
+
});
|
|
67
|
+
await this.app.start();
|
|
68
|
+
log.info('Slack adapter connected via Socket Mode');
|
|
69
|
+
}
|
|
70
|
+
async disconnect() {
|
|
71
|
+
if (this.app) {
|
|
72
|
+
await this.app.stop();
|
|
73
|
+
log.info('Slack adapter disconnected');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
onMessage(handler) {
|
|
77
|
+
this.messageHandlers.push(handler);
|
|
78
|
+
}
|
|
79
|
+
onReaction(handler) {
|
|
80
|
+
this.reactionHandlers.push(handler);
|
|
81
|
+
}
|
|
82
|
+
async sendMessage(channelId, content, opts) {
|
|
83
|
+
const formatted = markdownToMrkdwn(content);
|
|
84
|
+
const chunks = chunkMessage(formatted);
|
|
85
|
+
let firstTs = '';
|
|
86
|
+
for (const chunk of chunks) {
|
|
87
|
+
const result = await this.app.client.chat.postMessage({
|
|
88
|
+
token: this.botToken,
|
|
89
|
+
channel: channelId,
|
|
90
|
+
text: chunk,
|
|
91
|
+
thread_ts: opts?.threadRootId,
|
|
92
|
+
});
|
|
93
|
+
if (!firstTs)
|
|
94
|
+
firstTs = result.ts;
|
|
95
|
+
}
|
|
96
|
+
return firstTs;
|
|
97
|
+
}
|
|
98
|
+
async updateMessage(channelId, messageId, content) {
|
|
99
|
+
const formatted = markdownToMrkdwn(content);
|
|
100
|
+
// Truncate to Slack's limit — streaming updates can't be chunked across messages
|
|
101
|
+
const truncated = formatted.length > SLACK_MAX_MESSAGE_LENGTH
|
|
102
|
+
? formatted.slice(0, SLACK_MAX_MESSAGE_LENGTH - 20) + '\n\n_(truncated)_'
|
|
103
|
+
: formatted;
|
|
104
|
+
try {
|
|
105
|
+
await this.app.client.chat.update({
|
|
106
|
+
token: this.botToken,
|
|
107
|
+
channel: channelId,
|
|
108
|
+
ts: messageId,
|
|
109
|
+
text: truncated,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err?.data?.error === 'msg_too_old' || err?.data?.error === 'cant_update_message') {
|
|
114
|
+
log.warn(`Cannot update message ${messageId} (too old or restricted)`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async deleteMessage(channelId, messageId) {
|
|
122
|
+
try {
|
|
123
|
+
await this.app.client.chat.delete({
|
|
124
|
+
token: this.botToken,
|
|
125
|
+
channel: channelId,
|
|
126
|
+
ts: messageId,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
if (err?.data?.error === 'message_not_found') {
|
|
131
|
+
log.warn(`Message ${messageId} not found for deletion`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async setTyping(_channelId) {
|
|
139
|
+
// Slack doesn't have a reliable programmatic typing indicator API.
|
|
140
|
+
// The SDK-based typing indicator requires a user token, not a bot token.
|
|
141
|
+
// Best-effort no-op.
|
|
142
|
+
}
|
|
143
|
+
async replyInThread(channelId, rootId, content) {
|
|
144
|
+
return this.sendMessage(channelId, content, { threadRootId: rootId });
|
|
145
|
+
}
|
|
146
|
+
getBotUserId() {
|
|
147
|
+
return this.botUserId;
|
|
148
|
+
}
|
|
149
|
+
async addReaction(postId, emoji) {
|
|
150
|
+
try {
|
|
151
|
+
// postId is "channelId:ts" — we need both to add a reaction
|
|
152
|
+
const [channel, timestamp] = this.parseMessageRef(postId);
|
|
153
|
+
await this.app.client.reactions.add({
|
|
154
|
+
token: this.botToken,
|
|
155
|
+
channel,
|
|
156
|
+
timestamp,
|
|
157
|
+
name: emoji.replace(/:/g, ''), // Slack emoji names don't use colons
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Reactions are best-effort
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async downloadFile(fileId, destPath) {
|
|
165
|
+
// Slack file URLs require auth — use files.info to get the download URL
|
|
166
|
+
const fileInfo = await this.app.client.files.info({
|
|
167
|
+
token: this.botToken,
|
|
168
|
+
file: fileId,
|
|
169
|
+
});
|
|
170
|
+
const downloadUrl = fileInfo.file?.url_private_download ?? fileInfo.file?.url_private;
|
|
171
|
+
if (!downloadUrl)
|
|
172
|
+
throw new Error(`No download URL for file ${fileId}`);
|
|
173
|
+
const resp = await fetch(downloadUrl, {
|
|
174
|
+
headers: { 'Authorization': `Bearer ${this.botToken}` },
|
|
175
|
+
});
|
|
176
|
+
if (!resp.ok)
|
|
177
|
+
throw new Error(`Failed to download file ${fileId}: ${resp.status}`);
|
|
178
|
+
const dir = path.dirname(destPath);
|
|
179
|
+
if (!fs.existsSync(dir))
|
|
180
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
181
|
+
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
182
|
+
fs.writeFileSync(destPath, buffer);
|
|
183
|
+
log.info(`Downloaded file ${fileId} to ${destPath} (${buffer.length} bytes)`);
|
|
184
|
+
return destPath;
|
|
185
|
+
}
|
|
186
|
+
async sendFile(channelId, filePath, message, opts) {
|
|
187
|
+
const fileName = path.basename(filePath);
|
|
188
|
+
const fileBuffer = await fs.promises.readFile(filePath);
|
|
189
|
+
const result = await this.app.client.files.uploadV2({
|
|
190
|
+
token: this.botToken,
|
|
191
|
+
channel_id: channelId,
|
|
192
|
+
file: Readable.from(fileBuffer),
|
|
193
|
+
filename: fileName,
|
|
194
|
+
initial_comment: message ? markdownToMrkdwn(message) : '',
|
|
195
|
+
thread_ts: opts?.threadRootId,
|
|
196
|
+
});
|
|
197
|
+
// uploadV2 returns the file object; the associated message ts is in file.shares
|
|
198
|
+
const ts = result.file?.shares?.public?.[channelId]?.[0]?.ts
|
|
199
|
+
?? result.file?.shares?.private?.[channelId]?.[0]?.ts
|
|
200
|
+
?? '';
|
|
201
|
+
log.info(`Sent file "${fileName}" to channel ${channelId}`);
|
|
202
|
+
return ts;
|
|
203
|
+
}
|
|
204
|
+
async discoverDMChannels() {
|
|
205
|
+
try {
|
|
206
|
+
const dms = [];
|
|
207
|
+
let cursor;
|
|
208
|
+
do {
|
|
209
|
+
const result = await this.app.client.conversations.list({
|
|
210
|
+
token: this.botToken,
|
|
211
|
+
types: 'im',
|
|
212
|
+
limit: 200,
|
|
213
|
+
...(cursor ? { cursor } : {}),
|
|
214
|
+
});
|
|
215
|
+
for (const ch of result.channels ?? []) {
|
|
216
|
+
dms.push({ channelId: ch.id, otherUserId: ch.user });
|
|
217
|
+
}
|
|
218
|
+
cursor = result.response_metadata?.next_cursor || undefined;
|
|
219
|
+
} while (cursor);
|
|
220
|
+
return dms;
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
log.warn('Failed to discover DM channels:', err);
|
|
224
|
+
return [];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ── Private helpers ──────────────────────────────────────────
|
|
228
|
+
handleMessage(message, _context) {
|
|
229
|
+
try {
|
|
230
|
+
// Ignore bot messages (including our own)
|
|
231
|
+
if (message.bot_id || message.subtype === 'bot_message')
|
|
232
|
+
return;
|
|
233
|
+
// Ignore message edits, deletes, and other subtypes
|
|
234
|
+
if (message.subtype && message.subtype !== 'file_share')
|
|
235
|
+
return;
|
|
236
|
+
const channelId = message.channel;
|
|
237
|
+
const ts = message.ts;
|
|
238
|
+
// Dedup using composite key (ts is only unique within a channel)
|
|
239
|
+
const messageKey = `${channelId}:${ts}`;
|
|
240
|
+
if (this.recentMessageTs.has(messageKey))
|
|
241
|
+
return;
|
|
242
|
+
this.trackMessage(messageKey);
|
|
243
|
+
// Detect DM vs channel
|
|
244
|
+
// Slack channel IDs: C = public, G = group/private, D = DM
|
|
245
|
+
const isDM = channelId.startsWith('D');
|
|
246
|
+
const mentionsBot = isDM || (message.text ?? '').includes(`<@${this.botUserId}>`);
|
|
247
|
+
// Extract attachments from file_share messages
|
|
248
|
+
const attachments = this.extractAttachments(message);
|
|
249
|
+
// Strip bot mention from text for cleaner processing
|
|
250
|
+
let text = message.text ?? '';
|
|
251
|
+
text = text.replace(new RegExp(`<@${this.botUserId}>`, 'g'), '').trim();
|
|
252
|
+
const inbound = {
|
|
253
|
+
platform: this.platform,
|
|
254
|
+
channelId,
|
|
255
|
+
userId: message.user,
|
|
256
|
+
username: message.user, // Slack events don't include username; resolved later if needed
|
|
257
|
+
text,
|
|
258
|
+
postId: `${channelId}:${ts}`,
|
|
259
|
+
threadRootId: message.thread_ts !== ts ? message.thread_ts : undefined,
|
|
260
|
+
mentionsBot,
|
|
261
|
+
isDM,
|
|
262
|
+
attachments,
|
|
263
|
+
};
|
|
264
|
+
log.info(`Received: "${inbound.text.slice(0, 80)}" from ${inbound.userId} in ${channelId} (isDM=${isDM})`);
|
|
265
|
+
for (const handler of this.messageHandlers) {
|
|
266
|
+
try {
|
|
267
|
+
const result = handler(inbound);
|
|
268
|
+
if (result && typeof result.catch === 'function') {
|
|
269
|
+
result.catch((err) => log.error('Handler error:', err));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
log.error('Handler error:', err);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
log.error('Failed to handle Slack message:', err);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
handleReaction(event, action) {
|
|
282
|
+
try {
|
|
283
|
+
const inbound = {
|
|
284
|
+
platform: this.platform,
|
|
285
|
+
channelId: event.item?.channel ?? '',
|
|
286
|
+
userId: event.user,
|
|
287
|
+
postId: `${event.item?.channel ?? ''}:${event.item?.ts ?? ''}`,
|
|
288
|
+
emoji: event.reaction,
|
|
289
|
+
action,
|
|
290
|
+
};
|
|
291
|
+
for (const handler of this.reactionHandlers) {
|
|
292
|
+
try {
|
|
293
|
+
const result = handler(inbound);
|
|
294
|
+
if (result && typeof result.catch === 'function') {
|
|
295
|
+
result.catch((err) => log.error('Reaction handler error:', err));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
log.error('Reaction handler error:', err);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
log.error('Failed to handle Slack reaction:', err);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
extractAttachments(message) {
|
|
308
|
+
const files = message.files;
|
|
309
|
+
if (!files || files.length === 0)
|
|
310
|
+
return undefined;
|
|
311
|
+
return files.map((f) => {
|
|
312
|
+
let type = 'file';
|
|
313
|
+
if (f.mimetype?.startsWith('image/'))
|
|
314
|
+
type = 'image';
|
|
315
|
+
else if (f.mimetype?.startsWith('video/'))
|
|
316
|
+
type = 'video';
|
|
317
|
+
else if (f.mimetype?.startsWith('audio/'))
|
|
318
|
+
type = 'audio';
|
|
319
|
+
return {
|
|
320
|
+
id: f.id,
|
|
321
|
+
type,
|
|
322
|
+
url: f.url_private ?? '',
|
|
323
|
+
name: f.name ?? `file-${f.id}`,
|
|
324
|
+
mimeType: f.mimetype,
|
|
325
|
+
size: f.size,
|
|
326
|
+
};
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
trackMessage(key) {
|
|
330
|
+
this.recentMessageTs.add(key);
|
|
331
|
+
if (this.recentMessageTs.size > SlackAdapter.MAX_RECENT_MESSAGES) {
|
|
332
|
+
const iter = this.recentMessageTs.values();
|
|
333
|
+
for (let i = 0; i < 100; i++) {
|
|
334
|
+
const val = iter.next().value;
|
|
335
|
+
if (val != null)
|
|
336
|
+
this.recentMessageTs.delete(val);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Parse a message reference into [channelId, ts].
|
|
342
|
+
* Inbound postIds are stored as "channelId:ts"; sendMessage returns bare "ts".
|
|
343
|
+
* Returns ['', ref] when no channel prefix is present.
|
|
344
|
+
*/
|
|
345
|
+
parseMessageRef(ref) {
|
|
346
|
+
const idx = ref.indexOf(':');
|
|
347
|
+
if (idx > 0)
|
|
348
|
+
return [ref.slice(0, idx), ref.slice(idx + 1)];
|
|
349
|
+
return ['', ref];
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// ── Message chunking ──────────────────────────────────────────
|
|
353
|
+
/**
|
|
354
|
+
* Split a message into chunks that fit within Slack's character limit.
|
|
355
|
+
* Tries to split on newlines first, then falls back to hard splits.
|
|
356
|
+
*/
|
|
357
|
+
export function chunkMessage(content, maxLength = SLACK_MAX_MESSAGE_LENGTH) {
|
|
358
|
+
if (content.length <= maxLength)
|
|
359
|
+
return [content];
|
|
360
|
+
const chunks = [];
|
|
361
|
+
let remaining = content;
|
|
362
|
+
while (remaining.length > 0) {
|
|
363
|
+
if (remaining.length <= maxLength) {
|
|
364
|
+
chunks.push(remaining);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
// Try to find a good split point (newline, then space)
|
|
368
|
+
let splitAt = remaining.lastIndexOf('\n', maxLength);
|
|
369
|
+
if (splitAt <= maxLength * 0.3) {
|
|
370
|
+
// Newline too early — try space
|
|
371
|
+
splitAt = remaining.lastIndexOf(' ', maxLength);
|
|
372
|
+
}
|
|
373
|
+
if (splitAt <= maxLength * 0.3) {
|
|
374
|
+
// No good split point — hard split
|
|
375
|
+
splitAt = maxLength;
|
|
376
|
+
}
|
|
377
|
+
chunks.push(remaining.slice(0, splitAt));
|
|
378
|
+
remaining = remaining.slice(splitAt).replace(/^\n/, ''); // trim leading newline from next chunk
|
|
379
|
+
}
|
|
380
|
+
return chunks;
|
|
381
|
+
}
|
|
382
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/channels/slack/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert standard Markdown to Slack mrkdwn format.
|
|
3
|
+
*
|
|
4
|
+
* Key transformations:
|
|
5
|
+
* - **bold** → *bold*
|
|
6
|
+
* - [text](url) → <url|text>
|
|
7
|
+
* - Markdown tables → monospaced code blocks
|
|
8
|
+
* - Headers (## text) → *text* (bold)
|
|
9
|
+
*
|
|
10
|
+
* Things that are the same in both formats:
|
|
11
|
+
* - _italic_ / *italic* (Slack treats * as bold, so we leave _italic_ alone)
|
|
12
|
+
* - `inline code`
|
|
13
|
+
* - ```code blocks```
|
|
14
|
+
* - > blockquotes
|
|
15
|
+
* - • bullet lists
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Transform Markdown content to Slack mrkdwn.
|
|
19
|
+
* Preserves code blocks untouched, transforms everything else.
|
|
20
|
+
*/
|
|
21
|
+
export declare function markdownToMrkdwn(md: string): string;
|
|
22
|
+
//# sourceMappingURL=mrkdwn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mrkdwn.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/mrkdwn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CASnD"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert standard Markdown to Slack mrkdwn format.
|
|
3
|
+
*
|
|
4
|
+
* Key transformations:
|
|
5
|
+
* - **bold** → *bold*
|
|
6
|
+
* - [text](url) → <url|text>
|
|
7
|
+
* - Markdown tables → monospaced code blocks
|
|
8
|
+
* - Headers (## text) → *text* (bold)
|
|
9
|
+
*
|
|
10
|
+
* Things that are the same in both formats:
|
|
11
|
+
* - _italic_ / *italic* (Slack treats * as bold, so we leave _italic_ alone)
|
|
12
|
+
* - `inline code`
|
|
13
|
+
* - ```code blocks```
|
|
14
|
+
* - > blockquotes
|
|
15
|
+
* - • bullet lists
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Transform Markdown content to Slack mrkdwn.
|
|
19
|
+
* Preserves code blocks untouched, transforms everything else.
|
|
20
|
+
*/
|
|
21
|
+
export function markdownToMrkdwn(md) {
|
|
22
|
+
// Split on code blocks to avoid transforming code content
|
|
23
|
+
const parts = md.split(/(```[\s\S]*?```)/);
|
|
24
|
+
return parts.map((part, i) => {
|
|
25
|
+
// Odd indices are code blocks — leave them alone
|
|
26
|
+
if (i % 2 === 1)
|
|
27
|
+
return part;
|
|
28
|
+
return transformNonCode(part);
|
|
29
|
+
}).join('');
|
|
30
|
+
}
|
|
31
|
+
function transformNonCode(text) {
|
|
32
|
+
const lines = text.split('\n');
|
|
33
|
+
const result = [];
|
|
34
|
+
let i = 0;
|
|
35
|
+
while (i < lines.length) {
|
|
36
|
+
// Detect markdown table (line with pipes and a separator line following)
|
|
37
|
+
if (isTableRow(lines[i]) && i + 1 < lines.length && isTableSeparator(lines[i + 1])) {
|
|
38
|
+
const tableLines = [];
|
|
39
|
+
tableLines.push(lines[i]); // header
|
|
40
|
+
i++; // skip separator
|
|
41
|
+
i++; // move past separator
|
|
42
|
+
while (i < lines.length && isTableRow(lines[i])) {
|
|
43
|
+
tableLines.push(lines[i]);
|
|
44
|
+
i++;
|
|
45
|
+
}
|
|
46
|
+
result.push(renderTableAsCode(tableLines));
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
result.push(transformLine(lines[i]));
|
|
50
|
+
i++;
|
|
51
|
+
}
|
|
52
|
+
return result.join('\n');
|
|
53
|
+
}
|
|
54
|
+
function transformLine(line) {
|
|
55
|
+
// Preserve inline code spans — split on them
|
|
56
|
+
const parts = line.split(/(`[^`]+`)/);
|
|
57
|
+
const transformed = parts.map((part, i) => {
|
|
58
|
+
if (i % 2 === 1)
|
|
59
|
+
return part; // inline code — leave alone
|
|
60
|
+
return transformInline(part);
|
|
61
|
+
}).join('');
|
|
62
|
+
return transformed;
|
|
63
|
+
}
|
|
64
|
+
function transformInline(text) {
|
|
65
|
+
// Headers → bold (## Header → *Header*)
|
|
66
|
+
text = text.replace(/^(#{1,6})\s+(.+)$/, (_, _hashes, content) => `*${content.trim()}*`);
|
|
67
|
+
// Bold: **text** or __text__ → *text*
|
|
68
|
+
text = text.replace(/\*\*(.+?)\*\*/g, '*$1*');
|
|
69
|
+
text = text.replace(/__(.+?)__/g, '*$1*');
|
|
70
|
+
// Images:  → <url|alt> (must come before links)
|
|
71
|
+
text = text.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<$2|$1>');
|
|
72
|
+
// Links: [text](url) → <url|text>
|
|
73
|
+
text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<$2|$1>');
|
|
74
|
+
// Strikethrough: ~~text~~ → ~text~
|
|
75
|
+
text = text.replace(/~~(.+?)~~/g, '~$1~');
|
|
76
|
+
return text;
|
|
77
|
+
}
|
|
78
|
+
// ── Table rendering ──────────────────────────────────────────
|
|
79
|
+
function isTableRow(line) {
|
|
80
|
+
if (!line)
|
|
81
|
+
return false;
|
|
82
|
+
const trimmed = line.trim();
|
|
83
|
+
return trimmed.includes('|') && !isTableSeparator(line);
|
|
84
|
+
}
|
|
85
|
+
function isTableSeparator(line) {
|
|
86
|
+
if (!line)
|
|
87
|
+
return false;
|
|
88
|
+
// Matches lines like |---|---|---| or | --- | --- |
|
|
89
|
+
return /^\|?\s*[-:]+[-|\s:]*$/.test(line.trim());
|
|
90
|
+
}
|
|
91
|
+
function renderTableAsCode(rows) {
|
|
92
|
+
// Parse cells from each row
|
|
93
|
+
const parsed = rows.map(row => row.split('|')
|
|
94
|
+
.map(cell => cell.trim())
|
|
95
|
+
.filter((_, i, arr) => {
|
|
96
|
+
// Remove empty first/last from leading/trailing pipes
|
|
97
|
+
if (i === 0 && arr[i] === '')
|
|
98
|
+
return false;
|
|
99
|
+
if (i === arr.length - 1 && arr[i] === '')
|
|
100
|
+
return false;
|
|
101
|
+
return true;
|
|
102
|
+
}));
|
|
103
|
+
if (parsed.length === 0)
|
|
104
|
+
return '';
|
|
105
|
+
// Calculate column widths
|
|
106
|
+
const colCount = Math.max(...parsed.map(r => r.length));
|
|
107
|
+
const widths = Array(colCount).fill(0);
|
|
108
|
+
for (const row of parsed) {
|
|
109
|
+
for (let c = 0; c < colCount; c++) {
|
|
110
|
+
widths[c] = Math.max(widths[c], (row[c] ?? '').length);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Render as aligned monospace
|
|
114
|
+
const lines = parsed.map(row => row.map((cell, c) => cell.padEnd(widths[c])).join(' '));
|
|
115
|
+
// Add separator after header
|
|
116
|
+
const separator = widths.map(w => '─'.repeat(w)).join('──');
|
|
117
|
+
lines.splice(1, 0, separator);
|
|
118
|
+
return '```\n' + lines.join('\n') + '\n```';
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=mrkdwn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mrkdwn.js","sourceRoot":"","sources":["../../../src/channels/slack/mrkdwn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAU;IACzC,0DAA0D;IAC1D,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAE3C,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QAC3B,iDAAiD;QACjD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7B,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,yEAAyE;QACzE,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACnF,MAAM,UAAU,GAAa,EAAE,CAAC;YAChC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;YACpC,CAAC,EAAE,CAAC,CAAC,iBAAiB;YACtB,CAAC,EAAE,CAAC,CAAC,sBAAsB;YAC3B,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChD,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1B,CAAC,EAAE,CAAC;YACN,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;YAC3C,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC,EAAE,CAAC;IACN,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,6CAA6C;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACxC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,4BAA4B;QAC1D,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,eAAe,CAAC,IAAY;IACnC,wCAAwC;IACxC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAEzF,sCAAsC;IACtC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAE1C,2DAA2D;IAC3D,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,2BAA2B,EAAE,SAAS,CAAC,CAAC;IAE5D,kCAAkC;IAClC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,SAAS,CAAC,CAAC;IAE3D,mCAAmC;IACnC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAE1C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gEAAgE;AAEhE,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,oDAAoD;IACpD,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAc;IACvC,4BAA4B;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAC5B,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;SACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;QACpB,sDAAsD;QACtD,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;YAAE,OAAO,KAAK,CAAC;QACxD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CACL,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEnC,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACxD,MAAM,MAAM,GAAa,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjD,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAC7B,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACxD,CAAC;IAEF,6BAA6B;IAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IAE9B,OAAO,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;AAC9C,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AppConfig, ChannelConfig, BotConfig, InterAgentConfig } from './types.js';
|
|
1
|
+
import type { AppConfig, ChannelConfig, BotConfig, InterAgentConfig, AccessConfig } from './types.js';
|
|
2
2
|
export declare function loadConfig(configPath?: string): AppConfig;
|
|
3
3
|
/** The resolved config file path (available after loadConfig). */
|
|
4
4
|
export declare function getConfigPath(): string | null;
|
|
@@ -43,8 +43,12 @@ export declare function getChannelBotConfig(channelId: string): BotConfig | null
|
|
|
43
43
|
*/
|
|
44
44
|
export declare function getPlatformBots(platformName: string): Map<string, {
|
|
45
45
|
token: string;
|
|
46
|
+
appToken?: string;
|
|
46
47
|
agent?: string | null;
|
|
48
|
+
access?: AccessConfig;
|
|
47
49
|
}>;
|
|
50
|
+
/** Get platform-level access config (if any). */
|
|
51
|
+
export declare function getPlatformAccess(platformName: string): AccessConfig | undefined;
|
|
48
52
|
/** Check if a bot is an admin. */
|
|
49
53
|
export declare function isBotAdmin(platformName: string, botName: string): boolean;
|
|
50
54
|
/** Check if a bot name is admin on any platform. */
|