@oh-my-pi/pi-mom 0.1.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/CHANGELOG.md +338 -0
- package/README.md +517 -0
- package/dev.sh +30 -0
- package/docker.sh +95 -0
- package/docs/artifacts-server.md +475 -0
- package/docs/events.md +307 -0
- package/docs/new.md +977 -0
- package/docs/sandbox.md +153 -0
- package/docs/slack-bot-minimal-guide.md +399 -0
- package/docs/v86.md +319 -0
- package/package.json +45 -0
- package/scripts/migrate-timestamps.ts +121 -0
- package/src/agent.ts +887 -0
- package/src/context.ts +666 -0
- package/src/download.ts +117 -0
- package/src/events.ts +385 -0
- package/src/log.ts +271 -0
- package/src/main.ts +334 -0
- package/src/sandbox.ts +238 -0
- package/src/slack.ts +635 -0
- package/src/store.ts +253 -0
- package/src/tools/attach.ts +47 -0
- package/src/tools/bash.ts +99 -0
- package/src/tools/edit.ts +165 -0
- package/src/tools/index.ts +19 -0
- package/src/tools/read.ts +165 -0
- package/src/tools/truncate.ts +236 -0
- package/src/tools/write.ts +45 -0
- package/tsconfig.build.json +9 -0
package/docs/sandbox.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Mom Docker Sandbox
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Mom can run tools either directly on the host or inside a Docker container for isolation.
|
|
6
|
+
|
|
7
|
+
## Why Docker?
|
|
8
|
+
|
|
9
|
+
When mom runs on your machine and is accessible via Slack, anyone in your workspace could potentially:
|
|
10
|
+
- Execute arbitrary commands on your machine
|
|
11
|
+
- Access your files, credentials, etc.
|
|
12
|
+
- Cause damage via prompt injection
|
|
13
|
+
|
|
14
|
+
The Docker sandbox isolates mom's tools to a container where she can only access what you explicitly mount.
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 1. Create and start the container
|
|
20
|
+
cd packages/mom
|
|
21
|
+
./docker.sh create ./data
|
|
22
|
+
|
|
23
|
+
# 2. Run mom with Docker sandbox
|
|
24
|
+
mom --sandbox=docker:mom-sandbox ./data
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## How It Works
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌─────────────────────────────────────────────────────┐
|
|
31
|
+
│ Host │
|
|
32
|
+
│ │
|
|
33
|
+
│ mom process (Node.js) │
|
|
34
|
+
│ ├── Slack connection │
|
|
35
|
+
│ ├── LLM API calls │
|
|
36
|
+
│ └── Tool execution ──────┐ │
|
|
37
|
+
│ ▼ │
|
|
38
|
+
│ ┌─────────────────────────┐ │
|
|
39
|
+
│ │ Docker Container │ │
|
|
40
|
+
│ │ ├── bash, git, gh, etc │ │
|
|
41
|
+
│ │ └── /workspace (mount) │ │
|
|
42
|
+
│ └─────────────────────────┘ │
|
|
43
|
+
└─────────────────────────────────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- Mom process runs on host (handles Slack, LLM calls)
|
|
47
|
+
- All tool execution (`bash`, `read`, `write`, `edit`) happens inside the container
|
|
48
|
+
- Only `/workspace` (your data dir) is accessible to the container
|
|
49
|
+
|
|
50
|
+
## Container Setup
|
|
51
|
+
|
|
52
|
+
Use the provided script:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
./docker.sh create <data-dir> # Create and start container
|
|
56
|
+
./docker.sh start # Start existing container
|
|
57
|
+
./docker.sh stop # Stop container
|
|
58
|
+
./docker.sh remove # Remove container
|
|
59
|
+
./docker.sh status # Check if running
|
|
60
|
+
./docker.sh shell # Open shell in container
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Or manually:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
docker run -d --name mom-sandbox \
|
|
67
|
+
-v /path/to/mom-data:/workspace \
|
|
68
|
+
alpine:latest tail -f /dev/null
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Mom Manages Her Own Computer
|
|
72
|
+
|
|
73
|
+
The container is treated as mom's personal computer. She can:
|
|
74
|
+
|
|
75
|
+
- Install tools: `apk add github-cli git curl`
|
|
76
|
+
- Configure credentials: `gh auth login`
|
|
77
|
+
- Create files and directories
|
|
78
|
+
- Persist state across restarts
|
|
79
|
+
|
|
80
|
+
When mom needs a tool, she installs it. When she needs credentials, she asks you.
|
|
81
|
+
|
|
82
|
+
### Example Flow
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
User: "@mom check the spine-runtimes repo"
|
|
86
|
+
Mom: "I need gh CLI. Installing..."
|
|
87
|
+
(runs: apk add github-cli)
|
|
88
|
+
Mom: "I need a GitHub token. Please provide one."
|
|
89
|
+
User: "ghp_xxxx..."
|
|
90
|
+
Mom: (runs: echo "ghp_xxxx" | gh auth login --with-token)
|
|
91
|
+
Mom: "Done. Checking repo..."
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Persistence
|
|
95
|
+
|
|
96
|
+
The container persists across:
|
|
97
|
+
- `docker stop` / `docker start`
|
|
98
|
+
- Host reboots
|
|
99
|
+
|
|
100
|
+
Installed tools and configs remain until you `docker rm` the container.
|
|
101
|
+
|
|
102
|
+
To start fresh: `./docker.sh remove && ./docker.sh create ./data`
|
|
103
|
+
|
|
104
|
+
## CLI Options
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Run on host (default, no isolation)
|
|
108
|
+
mom ./data
|
|
109
|
+
|
|
110
|
+
# Run with Docker sandbox
|
|
111
|
+
mom --sandbox=docker:mom-sandbox ./data
|
|
112
|
+
|
|
113
|
+
# Explicit host mode
|
|
114
|
+
mom --sandbox=host ./data
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Security Considerations
|
|
118
|
+
|
|
119
|
+
**What the container CAN do:**
|
|
120
|
+
- Read/write files in `/workspace` (your data dir)
|
|
121
|
+
- Make network requests (for git, gh, curl, etc.)
|
|
122
|
+
- Install packages
|
|
123
|
+
- Run any commands
|
|
124
|
+
|
|
125
|
+
**What the container CANNOT do:**
|
|
126
|
+
- Access files outside `/workspace`
|
|
127
|
+
- Access your host's credentials
|
|
128
|
+
- Affect your host system
|
|
129
|
+
|
|
130
|
+
**For maximum security:**
|
|
131
|
+
1. Create a dedicated GitHub bot account with limited repo access
|
|
132
|
+
2. Only share that bot's token with mom
|
|
133
|
+
3. Don't mount sensitive directories
|
|
134
|
+
|
|
135
|
+
## Troubleshooting
|
|
136
|
+
|
|
137
|
+
### Container not running
|
|
138
|
+
```bash
|
|
139
|
+
./docker.sh status # Check status
|
|
140
|
+
./docker.sh start # Start it
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Reset container
|
|
144
|
+
```bash
|
|
145
|
+
./docker.sh remove
|
|
146
|
+
./docker.sh create ./data
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Missing tools
|
|
150
|
+
Ask mom to install them, or manually:
|
|
151
|
+
```bash
|
|
152
|
+
docker exec mom-sandbox apk add <package>
|
|
153
|
+
```
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# Minimal Slack Bot Setup (No Web Server, WebSocket Only)
|
|
2
|
+
|
|
3
|
+
Here's how to connect your Node.js agent to Slack using **Socket Mode** - no Express, no HTTP server, just WebSockets and callbacks.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Dependencies
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @slack/socket-mode @slack/web-api
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
That's it. Two packages:
|
|
14
|
+
- `@slack/socket-mode` - Receives events via WebSocket
|
|
15
|
+
- `@slack/web-api` - Sends messages back to Slack
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 2. Get Your Tokens
|
|
20
|
+
|
|
21
|
+
You need **TWO tokens**:
|
|
22
|
+
|
|
23
|
+
### A. Bot Token (`xoxb-...`)
|
|
24
|
+
1. Go to https://api.slack.com/apps
|
|
25
|
+
2. Create app → "From scratch"
|
|
26
|
+
3. Click "OAuth & Permissions" in sidebar
|
|
27
|
+
4. Add **Bot Token Scopes** (all 16):
|
|
28
|
+
```
|
|
29
|
+
app_mentions:read
|
|
30
|
+
channels:history
|
|
31
|
+
channels:join
|
|
32
|
+
channels:read
|
|
33
|
+
chat:write
|
|
34
|
+
files:read
|
|
35
|
+
files:write
|
|
36
|
+
groups:history
|
|
37
|
+
groups:read
|
|
38
|
+
im:history
|
|
39
|
+
im:read
|
|
40
|
+
im:write
|
|
41
|
+
mpim:history
|
|
42
|
+
mpim:read
|
|
43
|
+
mpim:write
|
|
44
|
+
users:read
|
|
45
|
+
```
|
|
46
|
+
5. Click "Install to Workspace" at top
|
|
47
|
+
6. Copy the **Bot User OAuth Token** (starts with `xoxb-`)
|
|
48
|
+
|
|
49
|
+
### B. App-Level Token (`xapp-...`)
|
|
50
|
+
1. In same app, click "Basic Information" in sidebar
|
|
51
|
+
2. Scroll to "App-Level Tokens"
|
|
52
|
+
3. Click "Generate Token and Scopes"
|
|
53
|
+
4. Name it whatever (e.g., "socket-token")
|
|
54
|
+
5. Add scope: `connections:write`
|
|
55
|
+
6. Click "Generate"
|
|
56
|
+
7. Copy the token (starts with `xapp-`)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. Enable Socket Mode
|
|
61
|
+
|
|
62
|
+
1. Go to https://api.slack.com/apps → select your app
|
|
63
|
+
2. Click **"Socket Mode"** in sidebar
|
|
64
|
+
3. Toggle **"Enable Socket Mode"** to ON
|
|
65
|
+
4. This routes your app's interactions and events over WebSockets instead of public HTTP endpoints
|
|
66
|
+
5. Done - no webhook URL needed!
|
|
67
|
+
|
|
68
|
+
**Note:** Socket Mode is intended for internal apps in development or behind a firewall. Not for apps distributed via Slack Marketplace.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 4. Enable Direct Messages
|
|
73
|
+
|
|
74
|
+
1. Go to https://api.slack.com/apps → select your app
|
|
75
|
+
2. Click **"App Home"** in sidebar
|
|
76
|
+
3. Scroll to **"Show Tabs"** section
|
|
77
|
+
4. Check **"Allow users to send Slash commands and messages from the messages tab"**
|
|
78
|
+
5. Save
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 5. Subscribe to Events
|
|
83
|
+
|
|
84
|
+
1. Go to https://api.slack.com/apps → select your app
|
|
85
|
+
2. Click **"Event Subscriptions"** in sidebar
|
|
86
|
+
3. Toggle **"Enable Events"** to ON
|
|
87
|
+
4. **Important:** No Request URL needed (Socket Mode handles this)
|
|
88
|
+
5. Expand **"Subscribe to bot events"**
|
|
89
|
+
6. Click **"Add Bot User Event"** and add:
|
|
90
|
+
- `app_mention` (required - to see when bot is mentioned)
|
|
91
|
+
- `message.channels` (required - to log all channel messages for context)
|
|
92
|
+
- `message.groups` (optional - to see private channel messages)
|
|
93
|
+
- `message.im` (required - to see DMs)
|
|
94
|
+
7. Click **"Save Changes"** at bottom
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 6. Store Tokens
|
|
99
|
+
|
|
100
|
+
Create `.env` file:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
SLACK_BOT_TOKEN=xoxb-your-bot-token-here
|
|
104
|
+
SLACK_APP_TOKEN=xapp-your-app-token-here
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Add to `.gitignore`:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
echo ".env" >> .gitignore
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 7. Minimal Working Code
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
require('dotenv').config();
|
|
119
|
+
const { SocketModeClient } = require('@slack/socket-mode');
|
|
120
|
+
const { WebClient } = require('@slack/web-api');
|
|
121
|
+
|
|
122
|
+
const socketClient = new SocketModeClient({
|
|
123
|
+
appToken: process.env.SLACK_APP_TOKEN
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const webClient = new WebClient(process.env.SLACK_BOT_TOKEN);
|
|
127
|
+
|
|
128
|
+
// Listen for app mentions (@mom do something)
|
|
129
|
+
socketClient.on('app_mention', async ({ event, ack }) => {
|
|
130
|
+
try {
|
|
131
|
+
// Acknowledge receipt
|
|
132
|
+
await ack();
|
|
133
|
+
|
|
134
|
+
console.log('Mentioned:', event.text);
|
|
135
|
+
console.log('Channel:', event.channel);
|
|
136
|
+
console.log('User:', event.user);
|
|
137
|
+
|
|
138
|
+
// Process with your agent
|
|
139
|
+
const response = await yourAgentFunction(event.text);
|
|
140
|
+
|
|
141
|
+
// Send response
|
|
142
|
+
await webClient.chat.postMessage({
|
|
143
|
+
channel: event.channel,
|
|
144
|
+
text: response
|
|
145
|
+
});
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.error('Error:', error);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Start the connection
|
|
152
|
+
(async () => {
|
|
153
|
+
await socketClient.start();
|
|
154
|
+
console.log('⚡️ Bot connected and listening!');
|
|
155
|
+
})();
|
|
156
|
+
|
|
157
|
+
// Your existing agent logic
|
|
158
|
+
async function yourAgentFunction(text) {
|
|
159
|
+
// Your code here
|
|
160
|
+
return "I processed: " + text;
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**That's it. No web server. Just run it:**
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
node bot.js
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 8. Listen to ALL Events (Not Just Mentions)
|
|
173
|
+
|
|
174
|
+
If you want to see every message in channels/DMs the bot is in:
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Listen to all Slack events
|
|
178
|
+
socketClient.on('slack_event', async ({ event, body, ack }) => {
|
|
179
|
+
await ack();
|
|
180
|
+
|
|
181
|
+
console.log('Event type:', event.type);
|
|
182
|
+
console.log('Event data:', event);
|
|
183
|
+
|
|
184
|
+
if (event.type === 'message' && event.subtype === undefined) {
|
|
185
|
+
// Regular message (not bot message, not edited, etc.)
|
|
186
|
+
console.log('Message:', event.text);
|
|
187
|
+
console.log('Channel:', event.channel);
|
|
188
|
+
console.log('User:', event.user);
|
|
189
|
+
|
|
190
|
+
// Your logic here
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 9. Common Operations
|
|
198
|
+
|
|
199
|
+
### Send a message
|
|
200
|
+
```javascript
|
|
201
|
+
await webClient.chat.postMessage({
|
|
202
|
+
channel: 'C12345', // or channel ID from event
|
|
203
|
+
text: 'Hello!'
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Send a DM
|
|
208
|
+
```javascript
|
|
209
|
+
// Open DM channel with user
|
|
210
|
+
const result = await webClient.conversations.open({
|
|
211
|
+
users: 'U12345' // user ID
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Send message to that DM
|
|
215
|
+
await webClient.chat.postMessage({
|
|
216
|
+
channel: result.channel.id,
|
|
217
|
+
text: 'Hey there!'
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### List channels
|
|
222
|
+
```javascript
|
|
223
|
+
const channels = await webClient.conversations.list({
|
|
224
|
+
types: 'public_channel,private_channel'
|
|
225
|
+
});
|
|
226
|
+
console.log(channels.channels);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Get channel members
|
|
230
|
+
```javascript
|
|
231
|
+
const members = await webClient.conversations.members({
|
|
232
|
+
channel: 'C12345'
|
|
233
|
+
});
|
|
234
|
+
console.log(members.members); // Array of user IDs
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Get user info
|
|
238
|
+
```javascript
|
|
239
|
+
const user = await webClient.users.info({
|
|
240
|
+
user: 'U12345'
|
|
241
|
+
});
|
|
242
|
+
console.log(user.user.name);
|
|
243
|
+
console.log(user.user.real_name);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Join a channel
|
|
247
|
+
```javascript
|
|
248
|
+
await webClient.conversations.join({
|
|
249
|
+
channel: 'C12345'
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Upload a file
|
|
254
|
+
```javascript
|
|
255
|
+
await webClient.files.uploadV2({
|
|
256
|
+
channel_id: 'C12345',
|
|
257
|
+
file: fs.createReadStream('./file.pdf'),
|
|
258
|
+
filename: 'document.pdf',
|
|
259
|
+
title: 'My Document'
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 10. Complete Example with Your Agent
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
require('dotenv').config();
|
|
269
|
+
const { SocketModeClient } = require('@slack/socket-mode');
|
|
270
|
+
const { WebClient } = require('@slack/web-api');
|
|
271
|
+
|
|
272
|
+
const socketClient = new SocketModeClient({
|
|
273
|
+
appToken: process.env.SLACK_APP_TOKEN
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
const webClient = new WebClient(process.env.SLACK_BOT_TOKEN);
|
|
277
|
+
|
|
278
|
+
// Your existing agent/AI/whatever
|
|
279
|
+
class MyAgent {
|
|
280
|
+
async process(message, context) {
|
|
281
|
+
// Your complex logic here
|
|
282
|
+
// context has: user, channel, etc.
|
|
283
|
+
return `Processed: ${message}`;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const agent = new MyAgent();
|
|
288
|
+
|
|
289
|
+
// Handle mentions
|
|
290
|
+
socketClient.on('app_mention', async ({ event, ack }) => {
|
|
291
|
+
await ack();
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
// Remove the @mention from text
|
|
295
|
+
const text = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();
|
|
296
|
+
|
|
297
|
+
// Process with your agent
|
|
298
|
+
const response = await agent.process(text, {
|
|
299
|
+
user: event.user,
|
|
300
|
+
channel: event.channel
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Send response
|
|
304
|
+
await webClient.chat.postMessage({
|
|
305
|
+
channel: event.channel,
|
|
306
|
+
text: response
|
|
307
|
+
});
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error('Error processing mention:', error);
|
|
310
|
+
|
|
311
|
+
// Send error message
|
|
312
|
+
await webClient.chat.postMessage({
|
|
313
|
+
channel: event.channel,
|
|
314
|
+
text: 'Sorry, something went wrong!'
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Start
|
|
320
|
+
(async () => {
|
|
321
|
+
await socketClient.start();
|
|
322
|
+
console.log('⚡️ Agent connected to Slack!');
|
|
323
|
+
})();
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## 11. Available Event Types
|
|
329
|
+
|
|
330
|
+
You subscribed to these in step 4:
|
|
331
|
+
|
|
332
|
+
- `app_mention` - Someone @mentioned the bot
|
|
333
|
+
- `message` - Any message in a channel/DM the bot is in
|
|
334
|
+
|
|
335
|
+
Event object structure:
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
{
|
|
339
|
+
type: 'app_mention' or 'message',
|
|
340
|
+
text: 'the message text',
|
|
341
|
+
user: 'U12345', // who sent it
|
|
342
|
+
channel: 'C12345', // where it was sent
|
|
343
|
+
ts: '1234567890.123456' // timestamp
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## 12. Advantages of Socket Mode
|
|
350
|
+
|
|
351
|
+
✅ **No web server needed** - just run your script
|
|
352
|
+
✅ **No public URL needed** - works behind firewall
|
|
353
|
+
✅ **No ngrok** - works on localhost
|
|
354
|
+
✅ **Auto-reconnect** - SDK handles connection drops
|
|
355
|
+
✅ **Event-driven** - just listen to callbacks
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## 13. Disadvantages
|
|
360
|
+
|
|
361
|
+
❌ Can't distribute to Slack App Directory (only for your workspace)
|
|
362
|
+
❌ Script must be running to receive messages (unlike webhooks)
|
|
363
|
+
❌ Max 10 concurrent connections per app
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Important Notes
|
|
368
|
+
|
|
369
|
+
1. **You MUST call `ack()`** on every event or Slack will retry
|
|
370
|
+
2. **Bot token** (`xoxb-`) is for sending messages
|
|
371
|
+
3. **App token** (`xapp-`) is for receiving events via WebSocket
|
|
372
|
+
4. **Connection is persistent** - your script stays running
|
|
373
|
+
5. **No URL validation** needed (unlike HTTP webhooks)
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Troubleshooting
|
|
378
|
+
|
|
379
|
+
### "invalid_auth" error
|
|
380
|
+
- Check you're using the right tokens
|
|
381
|
+
- Bot token for WebClient, App token for SocketModeClient
|
|
382
|
+
|
|
383
|
+
### "missing_scope" error
|
|
384
|
+
- Make sure you added all 16 bot scopes
|
|
385
|
+
- Reinstall the app after adding scopes
|
|
386
|
+
|
|
387
|
+
### Not receiving events
|
|
388
|
+
- Check Socket Mode is enabled
|
|
389
|
+
- Check you subscribed to events in "Event Subscriptions"
|
|
390
|
+
- Make sure bot is in the channel (or use `channels:join`)
|
|
391
|
+
|
|
392
|
+
### Bot doesn't respond to mentions
|
|
393
|
+
- Must subscribe to `app_mention` event
|
|
394
|
+
- Bot must be installed to workspace
|
|
395
|
+
- Check `await ack()` is called
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
That's it. No HTTP server bullshit. Just WebSockets and callbacks.
|