relaybot 1.0.4 → 1.0.6

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # RelayBot
2
2
 
3
- An AI assistant that lives in your Slack DMs — powered by Claude or Codex.
3
+ An AI assistant that lives in your Slack channels and DMs — powered by Claude or Codex.
4
4
 
5
5
  <img src="demo/demo.jpg" width="30%">
6
6
 
@@ -8,11 +8,11 @@ An AI assistant that lives in your Slack DMs — powered by Claude or Codex.
8
8
 
9
9
  ## What is RelayBot?
10
10
 
11
- RelayBot acts as a bridge between Slack and AI coding agents, allowing you to interact with Claude or Codex through simple Slack DMs. Instead of switching between tools, you can request code changes, ask questions, and manage development tasks without leaving Slack.
11
+ RelayBot acts as a bridge between Slack and AI coding agents, allowing you to interact with Claude or Codex by mentioning the bot in channels or sending a DM. Instead of switching between tools, you can request code changes, ask questions, and manage development tasks without leaving Slack.
12
12
 
13
13
  ### Key Features
14
14
 
15
- - **Conversational AI Access** — Chat with Claude or Codex directly from Slack DMs
15
+ - **Conversational AI Access** — Chat with Claude or Codex from Slack channels via mentions or via DM
16
16
  - **Code Execution** — AI can read, write, and modify code in your projects
17
17
  - **Task Automation** — Request file changes, refactoring, bug fixes, or new features
18
18
  - **Context-Aware Responses** — Maintains project directory context across conversations
@@ -37,7 +37,7 @@ RelayBot acts as a bridge between Slack and AI coding agents, allowing you to in
37
37
  │ SLACK │
38
38
  │ ┌──────────┐ ┌──────────────┐ │
39
39
  │ │ User │ ───── sends message ─────────────► │ Channel/ │ │
40
- │ │ │ ◄──── receives reply ───────────── │ DM │ │
40
+ │ │ │ ◄──── receives reply ───────────── │ Channel │ │
41
41
  │ └──────────┘ └──────────────┘ │
42
42
  └─────────────────────────────────────────────────────────────────────┘
43
43
  │ ▲
@@ -84,12 +84,12 @@ RelayBot acts as a bridge between Slack and AI coding agents, allowing you to in
84
84
 
85
85
  ## How It Works
86
86
 
87
- 1. **Slack Connection** — RelayBot connects to Slack via WebSocket (Socket Mode) and listens for DMs
87
+ 1. **Slack Connection** — RelayBot connects to Slack via WebSocket (Socket Mode) and listens for mentions and DMs
88
88
  2. **Message Reception** — When you send a message, Slack forwards it to RelayBot
89
89
  3. **AI Bridge** — RelayBot spawns a persistent Claude or Codex CLI session and forwards your message
90
90
  4. **AI Processing** — The AI processes your request with full access to your codebase
91
91
  5. **Response Summarization** — Long outputs are summarized into concise, actionable messages
92
- 6. **Slack Reply** — The summarized response is sent back to you via Slack DM
92
+ 6. **Slack Reply** — The summarized response is sent back to the same channel or DM
93
93
 
94
94
  ---
95
95
 
@@ -215,6 +215,7 @@ Socket Mode allows the bot to receive events via WebSocket instead of HTTP endpo
215
215
  2. Scroll to **Scopes** → **Bot Token Scopes**
216
216
  3. Add these scopes:
217
217
  - `chat:write` — Send messages
218
+ - `app_mentions:read` — Read mentions of your app
218
219
  - `im:history` — Read DM history
219
220
  - `im:read` — View DM metadata
220
221
  - `im:write` — Start DMs with users
@@ -226,6 +227,7 @@ Socket Mode allows the bot to receive events via WebSocket instead of HTTP endpo
226
227
  2. Toggle **Enable Events** to ON
227
228
  3. Expand **Subscribe to bot events**
228
229
  4. Add these events:
230
+ - `app_mention` — Receive mentions in channels
229
231
  - `message.im` — Receive DM messages
230
232
 
231
233
  #### 5. Install the App
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "display_information": {
3
3
  "name": "RelayBot",
4
- "description": "An AI assistant that lives in your Slack DMs — powered by Claude or Codex",
4
+ "description": "An AI assistant that lives in your Slack channels and DMs — powered by Claude or Codex",
5
5
  "background_color": "#4A154B"
6
6
  },
7
7
  "features": {
@@ -14,6 +14,7 @@
14
14
  "scopes": {
15
15
  "bot": [
16
16
  "chat:write",
17
+ "app_mentions:read",
17
18
  "im:history",
18
19
  "im:read",
19
20
  "im:write",
@@ -24,6 +25,7 @@
24
25
  "settings": {
25
26
  "event_subscriptions": {
26
27
  "bot_events": [
28
+ "app_mention",
27
29
  "message.im"
28
30
  ]
29
31
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relaybot",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "An AI assistant that lives in your Slack DMs — powered by Claude or Codex",
5
5
  "main": "main.js",
6
6
  "bin": {
@@ -24,13 +24,18 @@ function storeLastMessage(message) {
24
24
 
25
25
  function getPromptSuffix() {
26
26
  if (isProduction) {
27
- return `\nIMPORTANT: Use the relay-bot skill if it exists. Otherwise, read and follow the instructions in ${skillPath}`;
27
+ return `\nIMPORTANT: Read and follow the instructions in ${skillPath}`;
28
28
  }
29
29
  return '\nIMPORTANT: Use the relay-bot skill.';
30
30
  }
31
31
 
32
+ function stripMentions(text) {
33
+ if (!text) return text;
34
+ return text.replace(/<@[^>]+>/g, '').replace(/\s+/g, ' ').trim();
35
+ }
36
+
32
37
  function registerHandlers(app) {
33
- app.message(async ({ message, say }) => {
38
+ async function handleMessage({ message, say, text }) {
34
39
  // Only respond to messages from the configured user
35
40
  if (config.SLACK_USER_ID && message.user !== config.SLACK_USER_ID) {
36
41
  return;
@@ -39,11 +44,28 @@ function registerHandlers(app) {
39
44
  storeLastMessage(message);
40
45
 
41
46
  if (agent.isRunning()) {
42
- const fullPrompt = message.text + getPromptSuffix();
47
+ const fullPrompt = text + getPromptSuffix();
43
48
  agent.sendCommand(fullPrompt);
44
49
  } else {
45
50
  await say('Agent process is not running.');
46
51
  }
52
+ }
53
+
54
+ app.event('app_mention', async ({ event, say }) => {
55
+ if (event.channel_type === 'im' || event.channel_type === 'mpim') {
56
+ return;
57
+ }
58
+
59
+ const cleanedText = stripMentions(event.text);
60
+ await handleMessage({ message: event, say, text: cleanedText });
61
+ });
62
+
63
+ app.message(async ({ message, say }) => {
64
+ if (message.channel_type !== 'im') {
65
+ return;
66
+ }
67
+
68
+ await handleMessage({ message, say, text: message.text });
47
69
  });
48
70
  }
49
71