@shakudo/opencode-mattermost-control 0.3.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/.opencode/command/mattermost-connect.md +5 -0
  2. package/.opencode/command/mattermost-disconnect.md +5 -0
  3. package/.opencode/command/mattermost-monitor.md +12 -0
  4. package/.opencode/command/mattermost-status.md +5 -0
  5. package/.opencode/command/speckit.analyze.md +184 -0
  6. package/.opencode/command/speckit.checklist.md +294 -0
  7. package/.opencode/command/speckit.clarify.md +181 -0
  8. package/.opencode/command/speckit.constitution.md +82 -0
  9. package/.opencode/command/speckit.implement.md +135 -0
  10. package/.opencode/command/speckit.plan.md +89 -0
  11. package/.opencode/command/speckit.specify.md +258 -0
  12. package/.opencode/command/speckit.tasks.md +137 -0
  13. package/.opencode/command/speckit.taskstoissues.md +30 -0
  14. package/.opencode/plugin/mattermost-control/event-handlers/compaction.ts +61 -0
  15. package/.opencode/plugin/mattermost-control/event-handlers/file.ts +36 -0
  16. package/.opencode/plugin/mattermost-control/event-handlers/index.ts +14 -0
  17. package/.opencode/plugin/mattermost-control/event-handlers/message.ts +124 -0
  18. package/.opencode/plugin/mattermost-control/event-handlers/permission.ts +34 -0
  19. package/.opencode/plugin/mattermost-control/event-handlers/question.ts +92 -0
  20. package/.opencode/plugin/mattermost-control/event-handlers/session.ts +100 -0
  21. package/.opencode/plugin/mattermost-control/event-handlers/todo.ts +33 -0
  22. package/.opencode/plugin/mattermost-control/event-handlers/tool.ts +76 -0
  23. package/.opencode/plugin/mattermost-control/formatters.ts +202 -0
  24. package/.opencode/plugin/mattermost-control/index.ts +964 -0
  25. package/.opencode/plugin/mattermost-control/package.json +12 -0
  26. package/.opencode/plugin/mattermost-control/state.ts +180 -0
  27. package/.opencode/plugin/mattermost-control/timers.ts +96 -0
  28. package/.opencode/plugin/mattermost-control/tools/connect.ts +563 -0
  29. package/.opencode/plugin/mattermost-control/tools/file.ts +41 -0
  30. package/.opencode/plugin/mattermost-control/tools/index.ts +12 -0
  31. package/.opencode/plugin/mattermost-control/tools/monitor.ts +183 -0
  32. package/.opencode/plugin/mattermost-control/tools/schedule.ts +253 -0
  33. package/.opencode/plugin/mattermost-control/tools/session.ts +120 -0
  34. package/.opencode/plugin/mattermost-control/types.ts +107 -0
  35. package/LICENSE +21 -0
  36. package/README.md +1280 -0
  37. package/opencode-shared +359 -0
  38. package/opencode-shared-restart +495 -0
  39. package/opencode-shared-stop +90 -0
  40. package/package.json +65 -0
  41. package/src/clients/mattermost-client.ts +221 -0
  42. package/src/clients/websocket-client.ts +199 -0
  43. package/src/command-handler.ts +1035 -0
  44. package/src/config.ts +170 -0
  45. package/src/context-builder.ts +309 -0
  46. package/src/file-completion-handler.ts +521 -0
  47. package/src/file-handler.ts +242 -0
  48. package/src/guest-approval-handler.ts +223 -0
  49. package/src/logger.ts +73 -0
  50. package/src/merge-handler.ts +335 -0
  51. package/src/message-router.ts +151 -0
  52. package/src/models/index.ts +197 -0
  53. package/src/models/routing.ts +50 -0
  54. package/src/models/thread-mapping.ts +40 -0
  55. package/src/monitor-service.ts +222 -0
  56. package/src/notification-service.ts +118 -0
  57. package/src/opencode-session-registry.ts +370 -0
  58. package/src/persistence/team-store.ts +396 -0
  59. package/src/persistence/thread-mapping-store.ts +258 -0
  60. package/src/question-handler.ts +401 -0
  61. package/src/reaction-handler.ts +111 -0
  62. package/src/response-streamer.ts +364 -0
  63. package/src/scheduler/schedule-store.ts +261 -0
  64. package/src/scheduler/scheduler-service.ts +349 -0
  65. package/src/session-manager.ts +142 -0
  66. package/src/session-ownership-handler.ts +253 -0
  67. package/src/status-indicator.ts +279 -0
  68. package/src/thread-manager.ts +231 -0
  69. package/src/todo-manager.ts +162 -0
package/README.md ADDED
@@ -0,0 +1,1280 @@
1
+ # OpenCode Mattermost Control Plugin
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![npm version](https://badge.fury.io/js/opencode-mattermost-control.svg)](https://www.npmjs.com/package/opencode-mattermost-control)
5
+
6
+ Control [OpenCode](https://opencode.ai) remotely via Mattermost direct messages. Send prompts to your OpenCode session by messaging a bot user, and receive real-time streaming responses.
7
+
8
+ ## Features
9
+
10
+ ### Core Features
11
+ - **Thread-Per-Session**: Each OpenCode session automatically gets its own dedicated Mattermost thread for clean conversation isolation
12
+ - **Remote Control**: Send prompts to OpenCode via Mattermost DMs
13
+ - **Multi-Session Management**: Control multiple OpenCode sessions in parallel via separate threads
14
+ - **Session Monitoring**: Get DM alerts when sessions need attention (permission requests, idle, questions)
15
+ - **Real-time Streaming**: Responses stream back in chunks with intelligent buffering
16
+ - **File Attachments**: Send and receive files through Mattermost
17
+ - **Automatic Reconnection**: WebSocket auto-reconnects with exponential backoff
18
+
19
+ ### Real-time Status Display
20
+ - **Enhanced Status Indicator**: Shows processing state with elapsed time (e.g., `💻 Processing... (15s)`)
21
+ - **Tool Execution Display**: See which tools are being executed in real-time with timing
22
+ - **Live Shell Output**: Bash command output streams directly to Mattermost as it executes
23
+ - **Todo List Tracking**: View task progress during complex multi-step operations
24
+ - **Cost & Token Tracking**: Monitor LLM costs and token usage per session (e.g., `💰 $0.45 (+$0.03) | 125K tok`)
25
+
26
+ ### Model Selection
27
+ - **Per-Session Model Switching**: Use `!models` to list available models, select by number
28
+ - **Model Persistence**: Selected model persists for the session thread
29
+ - **Multi-Provider Support**: Switch between providers (Anthropic, OpenAI, etc.) on the fly
30
+
31
+ ### Multi-User Support
32
+ - **Owner Filtering**: Set `MATTERMOST_OWNER_USER_ID` to ensure your OpenCode instance only responds to your DMs
33
+ - **Shared Bot Account**: Multiple users can run separate OpenCode instances with the same bot
34
+ - **Per-User Sessions**: Each user's sessions are isolated
35
+
36
+ ### Channel Support (Group DMs, Public & Private Channels)
37
+ - **Any Channel Type**: Bot works in 1:1 DMs, Group DMs, Public channels (`O`), and Private channels (`P`)
38
+ - **Selective Response**: In channels (non-1:1 DM), the bot only responds when explicitly @mentioned (e.g., `@opencode-bot help me with this`)
39
+ - **Thread Context Injection**: When responding in channels, the bot automatically includes context from the last 5 messages in the thread
40
+ - **Smart Context Summarization**: If thread context exceeds 8K characters, it's automatically summarized using Claude Haiku to stay within token limits
41
+ - **1:1 DM Behavior Unchanged**: Direct messages respond to all messages without requiring @mention
42
+ - **Configurable Channel Types**: Use `OPENCODE_MM_ALLOWED_CHANNEL_TYPES` to restrict which channel types the bot responds to
43
+
44
+ ### Emoji Commands
45
+ React to any bot message with these emojis:
46
+ - ✅ Approve pending permission
47
+ - ❌ Deny pending permission
48
+ - 🛑 Cancel current operation
49
+ - 🔁 Retry last prompt
50
+ - 🗑️ Clear session files
51
+
52
+ ### Notifications
53
+ - Get notified on completion, errors, and status changes
54
+
55
+ ---
56
+
57
+ ## Quick Start for Humans
58
+
59
+ ### Prerequisites
60
+
61
+ - [OpenCode](https://opencode.ai) installed and configured
62
+ - A Mattermost instance with API access
63
+ - A Mattermost bot account with appropriate permissions
64
+ - [Bun](https://bun.sh) runtime (recommended) or Node.js 18+
65
+
66
+ ### Step 1: Install the Plugin
67
+
68
+ ```bash
69
+ # Using bun (recommended)
70
+ bun add -g opencode-mattermost-control
71
+
72
+ # Or using npm
73
+ npm install -g opencode-mattermost-control
74
+ ```
75
+
76
+ ### Step 2: Create a Mattermost Bot
77
+
78
+ 1. Go to your Mattermost **System Console** → **Integrations** → **Bot Accounts**
79
+ 2. Click **Add Bot Account**
80
+ 3. Give it a username (e.g., `opencode-bot`) and description
81
+ 4. Copy the generated **Access Token** - you'll need this!
82
+
83
+ ### Step 3: Set Environment Variables
84
+
85
+ ```bash
86
+ export MATTERMOST_TOKEN="your-bot-access-token"
87
+ export MATTERMOST_URL="https://your-mattermost-instance.com/api/v4"
88
+ ```
89
+
90
+ ### Step 4: Connect from OpenCode
91
+
92
+ ```bash
93
+ # Start OpenCode in your project
94
+ opencode
95
+
96
+ # Then type or use the tool:
97
+ mattermost_connect
98
+ ```
99
+
100
+ You should see:
101
+ ```
102
+ ✓ Connected to Mattermost as @opencode-bot
103
+ ✓ Listening for DMs
104
+ ✓ Project: your-project-name
105
+ ```
106
+
107
+ ### Step 5: Send Prompts via DM
108
+
109
+ Open Mattermost, find your bot user, and send it a direct message:
110
+ ```
111
+ Create a hello world function in Python
112
+ ```
113
+
114
+ The response will stream back in real-time!
115
+
116
+ ---
117
+
118
+ ## Quick Start for AI Agents
119
+
120
+ If you're an AI agent setting up this plugin, follow these steps:
121
+
122
+ ### 1. Install
123
+
124
+ ```bash
125
+ bun add -g opencode-mattermost-control
126
+ ```
127
+
128
+ ### 2. Configure Environment
129
+
130
+ Set these environment variables before starting OpenCode:
131
+
132
+ ```bash
133
+ export MATTERMOST_TOKEN="<bot-access-token>"
134
+ export MATTERMOST_URL="https://<mattermost-host>/api/v4"
135
+ ```
136
+
137
+ ### 3. Connect
138
+
139
+ Use the `mattermost_connect` tool to establish connection:
140
+
141
+ ```
142
+ mattermost_connect
143
+ ```
144
+
145
+ ### 4. Verify Connection
146
+
147
+ Use `mattermost_status` to confirm the connection is active.
148
+
149
+ ### 5. Available Tools
150
+
151
+ | Tool | Purpose |
152
+ |------|---------|
153
+ | `mattermost_connect` | Establish connection to Mattermost |
154
+ | `mattermost_disconnect` | Terminate connection |
155
+ | `mattermost_status` | Check connection state |
156
+ | `mattermost_list_sessions` | List available OpenCode sessions |
157
+ | `mattermost_select_session` | Select which session receives prompts |
158
+ | `mattermost_current_session` | Show currently targeted session |
159
+ | `mattermost_monitor` | Monitor session for events (permission, idle, question) |
160
+ | `mattermost_unmonitor` | Stop monitoring a session |
161
+ | `mattermost_send_file` | Upload a file to the current Mattermost thread |
162
+ | `mattermost_schedule_add` | Create a scheduled task with cron expression |
163
+ | `mattermost_schedule_list` | List all scheduled tasks |
164
+ | `mattermost_schedule_remove` | Delete a scheduled task |
165
+ | `mattermost_schedule_enable` | Enable a disabled scheduled task |
166
+ | `mattermost_schedule_disable` | Disable a scheduled task |
167
+ | `mattermost_schedule_run` | Run a scheduled task immediately |
168
+
169
+ ### 6. Handling DMs
170
+
171
+ Once connected, DMs to the bot are processed as follows:
172
+
173
+ **Prompt Format:**
174
+ ```
175
+ [Mattermost DM from @username]
176
+ [Reply-To: thread=abc123 post=xyz789 channel=dm_channel_id]
177
+ <user's message>
178
+ ```
179
+
180
+ The `Reply-To` line provides context for agents with other Mattermost integrations (MCP servers, direct API) to reply to the correct thread.
181
+
182
+ **Auto-Session Creation:**
183
+ When a user sends a prompt in the main DM channel (not in a thread), a new OpenCode session is automatically created with its own dedicated thread. This makes the main DM the "new session launcher" - use threads to continue existing sessions. This can be disabled with `OPENCODE_MM_AUTO_CREATE_SESSION=false`.
184
+
185
+ ### 7. Session Commands
186
+
187
+ Users can send these commands via DM to manage sessions:
188
+ - `!sessions` - List all available OpenCode sessions
189
+ - `!use <id>` - Switch to a specific session
190
+ - `!current` - Show currently selected session
191
+ - `!models` - List available models and select one for the current session
192
+ - `!model` - Show the currently selected model for this session
193
+ - `!help` - Show available commands
194
+
195
+ ---
196
+
197
+ ## Installation Options
198
+
199
+ ### Option A: Global Install (Recommended)
200
+
201
+ ```bash
202
+ # Install globally with bun
203
+ bun add -g opencode-mattermost-control
204
+
205
+ # Or with npm
206
+ npm install -g opencode-mattermost-control
207
+ ```
208
+
209
+ ### Option B: From Source
210
+
211
+ ```bash
212
+ git clone https://github.com/Shakudo-io/opencode-mattermost-plugin.git
213
+ cd opencode-mattermost-plugin
214
+ bun install
215
+ ```
216
+
217
+ ### Option C: Per-Project
218
+
219
+ Add to your project's `opencode.json`:
220
+
221
+ ```json
222
+ {
223
+ "$schema": "https://opencode.ai/config.json",
224
+ "plugins": ["opencode-mattermost-control"]
225
+ }
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Configuration Reference
231
+
232
+ ### Environment Variables
233
+
234
+ ```bash
235
+ # Required
236
+ export MATTERMOST_TOKEN="your-bot-access-token"
237
+ export MATTERMOST_URL="https://your-mattermost-instance.com/api/v4"
238
+
239
+ # Optional (with defaults)
240
+ export MATTERMOST_WS_URL="wss://your-mattermost-instance.com/api/v4/websocket"
241
+ export MATTERMOST_TEAM="your-team-name"
242
+ export MATTERMOST_DEBUG="false"
243
+ export MATTERMOST_AUTO_CONNECT="true" # auto-connect on plugin load
244
+
245
+ # Advanced options
246
+ export MATTERMOST_RECONNECT_INTERVAL="5000" # ms between reconnect attempts
247
+ export MATTERMOST_MAX_RECONNECT_ATTEMPTS="10" # max reconnection tries
248
+
249
+ # Streaming configuration
250
+ export OPENCODE_MM_BUFFER_SIZE="50" # characters before flushing
251
+ export OPENCODE_MM_MAX_DELAY="500" # max ms before forced flush
252
+ export OPENCODE_MM_EDIT_RATE_LIMIT="10" # max edits per second
253
+ export OPENCODE_MM_MAX_POST_LENGTH="15000" # max chars before splitting into multiple posts
254
+
255
+ # Session configuration
256
+ export OPENCODE_MM_SESSION_TIMEOUT="3600000" # 1 hour in ms
257
+ export OPENCODE_MM_MAX_SESSIONS="50" # max concurrent sessions
258
+ export OPENCODE_MM_ALLOWED_USERS="" # comma-separated user IDs (empty = all)
259
+ export OPENCODE_MM_AUTO_CREATE_SESSION="true" # auto-create session from main DM
260
+ export OPENCODE_MM_ALLOWED_CHANNEL_TYPES="D,G,O,P" # allowed channel types (D=DM, G=Group, O=Public, P=Private)
261
+
262
+ # Multi-user / Owner filtering
263
+ export MATTERMOST_OWNER_USER_ID="" # Only respond to DMs from this user ID
264
+ # Allows multiple OpenCode instances to share one bot
265
+
266
+ # File handling
267
+ export OPENCODE_MM_TEMP_DIR="/tmp/opencode-mm-plugin"
268
+ export OPENCODE_MM_MAX_FILE_SIZE="10485760" # 10MB
269
+ export OPENCODE_MM_ALLOWED_EXTENSIONS="*" # comma-separated or * for all
270
+
271
+ # Notifications
272
+ export OPENCODE_MM_NOTIFY_COMPLETION="true"
273
+ export OPENCODE_MM_NOTIFY_PERMISSION="true"
274
+ export OPENCODE_MM_NOTIFY_ERROR="true"
275
+ export OPENCODE_MM_NOTIFY_STATUS="true"
276
+
277
+ # Logging
278
+ export MM_PLUGIN_LOG_FILE="/tmp/opencode-mattermost-plugin.log"
279
+ ```
280
+
281
+ ### OpenCode Configuration
282
+
283
+ Add to global config (`~/.config/opencode/opencode.json`):
284
+
285
+ ```json
286
+ {
287
+ "plugins": ["opencode-mattermost-control"]
288
+ }
289
+ ```
290
+
291
+ Or per-project (`opencode.json` in project root):
292
+
293
+ ```json
294
+ {
295
+ "$schema": "https://opencode.ai/config.json",
296
+ "plugins": ["opencode-mattermost-control"]
297
+ }
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Usage Examples
303
+
304
+ ### Basic Workflow
305
+
306
+ ```bash
307
+ # 1. Start OpenCode
308
+ opencode
309
+
310
+ # 2. Connect to Mattermost
311
+ > mattermost_connect
312
+ ✓ Connected to Mattermost as @your-bot
313
+ ✓ Listening for DMs
314
+
315
+ # 3. Check status anytime
316
+ > mattermost_status
317
+
318
+ # 4. Disconnect when done
319
+ > mattermost_disconnect
320
+ ```
321
+
322
+ ### Thread-Per-Session Workflow
323
+
324
+ When the plugin connects, it automatically creates a dedicated Mattermost thread for each active OpenCode session. This provides clean conversation isolation and parallel session control.
325
+
326
+ **How it works:**
327
+ 1. When a new OpenCode session starts, a thread is automatically created in your DM with the bot
328
+ 2. The thread root post shows session info (project, directory, session ID)
329
+ 3. Post in the thread to send prompts to that specific session
330
+ 4. Responses stream back to the same thread
331
+ 5. When the session ends, the thread is marked as ended
332
+
333
+ **Example:**
334
+ ```
335
+ Bot: 🚀 OpenCode Session Started
336
+
337
+ Project: my-awesome-app
338
+ Directory: /home/user/projects/my-awesome-app
339
+ Session: ses_abc1
340
+ Started: 2024-01-15T10:30:00.000Z
341
+
342
+ Reply in this thread to send prompts to this session.
343
+
344
+ You (in thread): List all TypeScript files
345
+ Bot (in thread): [Streaming response...]
346
+ ```
347
+
348
+ **Main DM commands:**
349
+ - `!sessions` - List all sessions with links to their threads
350
+ - `!help` - Show available commands
351
+
352
+ **Thread behavior:**
353
+ - Prompts in main DM (outside threads) are rejected with guidance to use session threads
354
+ - Each thread maps to exactly one OpenCode session
355
+ - Thread posts are routed to the correct session automatically
356
+ - Ended sessions show a completion message and reject new prompts
357
+
358
+ ### Sending Files to Mattermost
359
+
360
+ OpenCode can send files directly to your Mattermost conversation thread using the `mattermost_send_file` tool:
361
+
362
+ **Example conversation:**
363
+ ```
364
+ You (in thread): Create a Python script that generates a report and send it to me
365
+ Bot: [Creates the file using Write tool]
366
+ Bot: [Uses mattermost_send_file to upload report.py]
367
+ File sent to Mattermost: report.py
368
+ ```
369
+
370
+ The tool automatically posts the file to the correct thread. Users can simply ask:
371
+ - "Send me the file you just created"
372
+ - "Upload that script to Mattermost"
373
+ - "Give me the report.pdf"
374
+
375
+ **Supported file types:** All common types including code files, documents (PDF, MD, TXT), images (PNG, JPG, GIF), and archives (ZIP).
376
+
377
+ **Size limit:** 10MB by default (configurable via `OPENCODE_MM_MAX_FILE_SIZE`).
378
+
379
+ ### Session Management Commands
380
+
381
+ When connected, you can manage multiple OpenCode sessions via DM commands:
382
+
383
+ | Command | Description |
384
+ |---------|-------------|
385
+ | `!sessions` | List all available OpenCode sessions with thread links |
386
+ | `!models` | List available models grouped by provider, select by number |
387
+ | `!model` | Show the currently selected model for this session |
388
+ | `!costs` | Show LLM token usage and costs for the current session |
389
+ | `!stop` | Cancel the current processing operation |
390
+ | `!merge <url>` | Merge another thread's conversation into the current session |
391
+ | `!reject` | Skip/cancel a pending AI question |
392
+ | `!help` | Display available commands and thread workflow |
393
+
394
+ **Example:**
395
+ ```
396
+ You: !sessions
397
+ Bot: 📋 Available Sessions (2)
398
+
399
+ 1. 🟢 my-awesome-app (ses_abc1) - 5m ago
400
+ 📁 /home/user/projects/my-awesome-app
401
+ 🔗 Thread: [Click to open]
402
+
403
+ 2. 🟢 another-project (ses_def2) - 2h ago
404
+ 📁 /home/user/projects/another-project
405
+ 🔗 Thread: [Click to open]
406
+
407
+ Reply in a session thread to send prompts.
408
+ ```
409
+
410
+ ### Model Selection
411
+
412
+ Switch between different LLM models on a per-session basis:
413
+
414
+ ```
415
+ You: !models
416
+ Bot: 🤖 Available Models
417
+
418
+ Anthropic
419
+ 1. claude-sonnet-4-20250514
420
+ 2. claude-3-5-haiku-20241022
421
+
422
+ OpenAI
423
+ 3. gpt-4o
424
+ 4. o3
425
+
426
+ Reply with a number to select a model.
427
+
428
+ You: 1
429
+ Bot: ✅ Model set to claude-sonnet-4-20250514 (Anthropic) for this session.
430
+ ```
431
+
432
+ The selected model persists for the session thread. Use `!model` to check the current selection.
433
+
434
+ ### Cost Tracking
435
+
436
+ Monitor LLM token usage and costs for your session using the `!costs` command:
437
+
438
+ ```
439
+ You: !costs
440
+ Bot: 💰 Session Costs (ses_abc1)
441
+
442
+ Total Cost: $0.47
443
+ Input Tokens: 125,432
444
+ Output Tokens: 8,291
445
+
446
+ Model: claude-sonnet-4-20250514
447
+ ```
448
+
449
+ The status indicator also shows running costs during responses: `💰 $0.45 (+$0.03) | 125K tok`
450
+
451
+ ### Thread Merging
452
+
453
+ Merge the context from one thread into another using the `!merge` command. This is useful when you want to continue a conversation from a different session thread while preserving its context.
454
+
455
+ **Usage:**
456
+ ```
457
+ !merge https://mattermost.example.com/team/pl/postid123
458
+ ```
459
+
460
+ **How it works:**
461
+ 1. Copy the URL of the thread you want to merge (source thread)
462
+ 2. Go to the thread you want to merge INTO (destination thread)
463
+ 3. Type `!merge <url>` with the source thread URL
464
+ 4. The source thread's conversation is summarized using AI and injected into the destination thread
465
+ 5. The source thread is marked as "merged" and locked
466
+
467
+ **Example:**
468
+ ```
469
+ [In destination thread]
470
+ You: !merge https://mattermost.dev.hyperplane.dev/shakudo/pl/abc123xyz
471
+
472
+ Bot: 🔀 **Merged Thread Context**
473
+
474
+ Merged conversation from [my-project (ses_abc1)](link):
475
+
476
+ ---
477
+
478
+ **Summary:**
479
+ - User requested implementation of a REST API for user management
480
+ - Discussed authentication approach (JWT tokens)
481
+ - Created User model with email, password, and role fields
482
+ - TODO: Implement password hashing and token refresh
483
+
484
+ ---
485
+ _Merged by @alice at 2026-01-26 15:30_
486
+ ```
487
+
488
+ **Source thread after merge:**
489
+ ```
490
+ Bot: 🔒 **Thread Merged**
491
+
492
+ This conversation has been merged into another thread.
493
+ Continue the conversation [here](link).
494
+
495
+ _Merged at 2026-01-26 15:30_
496
+ ```
497
+
498
+ **Restrictions:**
499
+ - Can only merge threads from the same OpenCode instance
500
+ - Cannot merge a thread into itself
501
+ - Cannot merge an already-merged thread
502
+ - Must have an active session in the destination thread
503
+
504
+ **What gets preserved:**
505
+ - AI-generated summary of key decisions and context
506
+ - Requirements and constraints discussed
507
+ - Actions taken and their outcomes
508
+ - Unfinished work and next steps
509
+
510
+ ### File Path Completion (`!!`)
511
+
512
+ Reference files directly in your prompts using the `!!` prefix. The bot will automatically find and include matching files from your project.
513
+
514
+ **Usage:**
515
+ ```
516
+ You: Look at !!src/config and tell me what settings are available
517
+ Bot: [Finds src/config.ts or similar, includes content, then responds]
518
+ ```
519
+
520
+ **How it works:**
521
+ 1. Type `!!` followed by a partial file path (e.g., `!!src/resp`)
522
+ 2. The bot searches for matching files in your project
523
+ 3. If exact match: file content is automatically included
524
+ 4. If multiple matches: bot prompts you to select from options
525
+
526
+ **Example with fuzzy matching:**
527
+ ```
528
+ You: Check !!handler for bugs
529
+
530
+ Bot: 🔍 Multiple files match "handler". Select one or more:
531
+
532
+ 1. src/command-handler.ts
533
+ 2. src/file-handler.ts
534
+ 3. src/question-handler.ts
535
+ 4. src/reaction-handler.ts
536
+
537
+ Reply with number(s) separated by commas (e.g., "1,3")
538
+
539
+ You: 1,2
540
+ Bot: [Includes both files and processes the original request]
541
+ ```
542
+
543
+ **Notes:**
544
+ - `!!` references inside code blocks are ignored
545
+ - You can include multiple `!!` references in one message
546
+ - Works with partial paths and fuzzy matching
547
+
548
+ ### Channel Usage (Group DMs, Public & Private Channels)
549
+
550
+ The bot can participate in any channel it's a member of: Group DMs, Public channels, and Private channels. In these channels, the bot uses **selective response** - it only responds when explicitly @mentioned.
551
+
552
+ **Supported channel types:**
553
+ - `D` - 1:1 Direct Messages (no @mention required)
554
+ - `G` - Group Direct Messages (@mention required)
555
+ - `O` - Public Channels (@mention required)
556
+ - `P` - Private Channels (@mention required)
557
+
558
+ **How it works:**
559
+ 1. Add the bot to a channel (Group DM, public, or private channel)
560
+ 2. @mention the bot when you want it to respond: `@opencode-bot explain this error`
561
+ 3. The bot automatically includes context from recent messages in the thread
562
+ 4. Messages without @mention are silently ignored
563
+
564
+ **Example:**
565
+ ```
566
+ Alice: Hey team, I'm seeing a weird error in the logs
567
+ Bob: Can you paste the stack trace?
568
+ Alice: [pastes error]
569
+ You: @opencode-bot can you explain what's causing this NullPointerException?
570
+ Bot: [Responds with explanation, having read the context from Alice and Bob's messages]
571
+ ```
572
+
573
+ **Context handling:**
574
+ - The bot reads the last 5 messages from the thread to understand the conversation
575
+ - If the context is too long (>8K characters), it's automatically summarized using Claude Haiku
576
+ - This ensures the bot has relevant context without consuming excessive tokens
577
+
578
+ **Restricting channel types:**
579
+ You can limit which channel types the bot responds to using the `OPENCODE_MM_ALLOWED_CHANNEL_TYPES` environment variable:
580
+ ```bash
581
+ # Only allow DMs and Group DMs (no public/private channels)
582
+ export OPENCODE_MM_ALLOWED_CHANNEL_TYPES="D,G"
583
+
584
+ # Only allow DMs (default 1:1 behavior)
585
+ export OPENCODE_MM_ALLOWED_CHANNEL_TYPES="D"
586
+
587
+ # All channel types (default)
588
+ export OPENCODE_MM_ALLOWED_CHANNEL_TYPES="D,G,O,P"
589
+ ```
590
+
591
+ **Note:** In regular 1:1 DMs, the bot responds to all messages without requiring @mention.
592
+
593
+ ### Guest Approval in Channels
594
+
595
+ When multiple users are in a channel with the bot, each OpenCode instance only processes messages from its owner (the user who owns the session). If another user @mentions the bot, the thread owner must approve the request.
596
+
597
+ **How it works:**
598
+ 1. User A (thread owner) creates a session by @mentioning the bot
599
+ 2. User B @mentions the bot in the same thread: `@opencode-bot help me with this`
600
+ 3. The bot posts an approval request visible to User A:
601
+ ```
602
+ 🔔 Guest Access Request
603
+
604
+ @userB wants to send a prompt to your session.
605
+
606
+ **Options:**
607
+ - Reply `1` to approve this message only
608
+ - Reply `2` to approve @userB permanently for this thread
609
+ - Reply `3` to approve ALL users in this thread
610
+ - Reply `deny` to reject
611
+
612
+ ⏰ Request expires in 30 minutes
613
+ ```
614
+ 4. User A replies with `1`, `2`, or `3`
615
+ 5. If approved, the original message from User B is processed
616
+
617
+ **Approval options:**
618
+ - **1 (Once)**: Approve this single message, future messages from this user still require approval
619
+ - **2 (User)**: Permanently approve this user - their future @mentions are processed automatically
620
+ - **3 (All)**: Approve all users - any user in the channel can send prompts without approval
621
+
622
+ **Persistence:** User approvals (option 2) and "approve all" settings (option 3) are stored in the thread mapping and persist across sessions.
623
+
624
+ **Example flow:**
625
+ ```
626
+ [Channel: #engineering with Alice, Bob, opencode-bot]
627
+
628
+ Alice: @opencode-bot analyze this code
629
+ Bot: [Creates session, responds to Alice]
630
+
631
+ Bob: @opencode-bot can you also check for security issues?
632
+ Bot: 🔔 Guest Access Request
633
+ @bob wants to send a prompt to your session...
634
+ Reply 1/2/3 or deny
635
+
636
+ Alice: 2
637
+ Bot: ✅ @bob is now approved for this thread.
638
+ Bot: [Processes Bob's request about security issues]
639
+
640
+ Bob: @opencode-bot what about performance?
641
+ Bot: [Processes automatically - Bob is pre-approved]
642
+ ```
643
+
644
+ ### Multi-User Setup (Shared Bot)
645
+
646
+ When multiple users want to run separate OpenCode instances with the same Mattermost bot account, use owner filtering to prevent conflicts:
647
+
648
+ ```bash
649
+ # User A's environment
650
+ export MATTERMOST_OWNER_USER_ID="user_a_id_here"
651
+
652
+ # User B's environment
653
+ export MATTERMOST_OWNER_USER_ID="user_b_id_here"
654
+ ```
655
+
656
+ Each OpenCode instance will only respond to DMs from its configured owner. To find your user ID, check your Mattermost profile or ask an admin.
657
+
658
+ ### Emoji Commands
659
+
660
+ React to any bot message with these emojis:
661
+
662
+ | Emoji | Action |
663
+ |-------|--------|
664
+ | ✅ | Approve pending permission request |
665
+ | ❌ | Deny pending permission request |
666
+ | 🛑 | Cancel current operation |
667
+ | 🔁 | Retry the last prompt |
668
+ | 🗑️ | Clear session temporary files |
669
+
670
+ ### AI Question Tool Support
671
+
672
+ When OpenCode uses the question tool to ask for clarification, the question appears directly in your Mattermost thread with numbered options:
673
+
674
+ ```
675
+ ### ❓ Language
676
+
677
+ Which language would you like to use?
678
+
679
+ **1.** TypeScript - _Modern JavaScript with types_
680
+ **2.** Python - _Great for data science_
681
+ **3.** Other - _Type your own answer_
682
+
683
+ ---
684
+ _Reply with a number or type your answer_
685
+ _Use `!reject` to skip this question_
686
+ ```
687
+
688
+ **How to respond:**
689
+ - Reply with a **number** (e.g., `1`) to select an option
690
+ - Reply with **multiple numbers** separated by commas for multi-select questions (e.g., `1, 3`)
691
+ - Type a **custom answer** directly (e.g., `Rust`)
692
+ - Use `!reject` or `!cancel` to skip the question (sends empty response to AI)
693
+
694
+ **Notes:**
695
+ - Questions expire after 30 minutes if not answered
696
+ - Only one question can be pending per session at a time
697
+ - Multi-question flows are supported (answer each question in sequence)
698
+
699
+ ### Session Monitoring
700
+
701
+ Monitor OpenCode sessions and receive DM alerts when they need attention. Works without requiring an active Mattermost connection.
702
+
703
+ ```bash
704
+ # Start monitoring the current session
705
+ > /mattermost-monitor
706
+
707
+ # Or use the tool directly
708
+ > mattermost_monitor targetUser="your-username"
709
+
710
+ # Stop monitoring
711
+ > mattermost_unmonitor
712
+ ```
713
+
714
+ **Alert types:**
715
+ - **Permission requested** - Session is waiting for permission approval
716
+ - **Session idle** - Session finished and is waiting for input
717
+ - **Question asked** - Session is asking a clarifying question
718
+
719
+ **Example alert:**
720
+ ```
721
+ 🔔 OpenCode Session Alert
722
+
723
+ Project: business-automation
724
+ Session: ses_4426 - Mattermost plugin codebase review
725
+ Directory: /root/gitrepos/business-automation
726
+
727
+ ⏳ Alert: Session is idle (waiting for input)
728
+
729
+ Use `!use ses_4426` in DM to connect to this session.
730
+ ```
731
+
732
+ **Options:**
733
+ - `sessionId` - Monitor a specific session (defaults to current)
734
+ - `targetUser` - Mattermost username to notify (required if not connected)
735
+ - `persistent` - Keep monitoring after each alert (default: true). Set to false for one-time alerts.
736
+
737
+ ### Scheduled Tasks
738
+
739
+ Create cron-based scheduled tasks that run prompts at specified times and DM you the results. Useful for automated reports, periodic checks, or recurring tasks.
740
+
741
+ **Available tools:**
742
+
743
+ | Tool | Description |
744
+ |------|-------------|
745
+ | `mattermost_schedule_add` | Create a new scheduled task |
746
+ | `mattermost_schedule_list` | List all scheduled tasks |
747
+ | `mattermost_schedule_remove` | Delete a scheduled task |
748
+ | `mattermost_schedule_enable` | Enable a disabled task |
749
+ | `mattermost_schedule_disable` | Disable a task without deleting |
750
+ | `mattermost_schedule_run` | Run a task immediately for testing |
751
+
752
+ **Example - Daily status report:**
753
+ ```
754
+ > mattermost_schedule_add name="morning-status" cron="0 9 * * *" prompt="Give me a summary of pending PRs and open issues" timezone="America/New_York"
755
+
756
+ ✅ Schedule created: morning-status
757
+ Cron: 0 9 * * * (America/New_York)
758
+ Next run: 2026-01-27 09:00:00
759
+ ```
760
+
761
+ **Example - Periodic health check:**
762
+ ```
763
+ > mattermost_schedule_add name="health-check" cron="0 */4 * * *" prompt="Check if all services are running and report any issues"
764
+
765
+ ✅ Schedule created: health-check
766
+ Cron: 0 */4 * * * (UTC)
767
+ Next run: 2026-01-26 20:00:00
768
+ ```
769
+
770
+ **Cron expression examples:**
771
+ - `0 9 * * *` - Every day at 9am
772
+ - `0 9,17 * * 1-5` - 9am and 5pm on weekdays
773
+ - `0 */4 * * *` - Every 4 hours
774
+ - `30 8 * * 1` - Every Monday at 8:30am
775
+
776
+ **Managing schedules:**
777
+ ```
778
+ > mattermost_schedule_list
779
+ 📋 Scheduled Tasks (2)
780
+
781
+ 1. ✅ morning-status
782
+ Cron: 0 9 * * * (America/New_York)
783
+ Next: 2026-01-27 09:00:00
784
+
785
+ 2. ✅ health-check
786
+ Cron: 0 */4 * * * (UTC)
787
+ Next: 2026-01-26 20:00:00
788
+
789
+ > mattermost_schedule_disable name="health-check"
790
+ ✅ Schedule disabled: health-check
791
+
792
+ > mattermost_schedule_run name="morning-status"
793
+ 🚀 Running schedule: morning-status
794
+ [Results are sent to your DM]
795
+ ```
796
+
797
+ ### Multi-Session Setup (Shared Server)
798
+
799
+ When controlling multiple OpenCode sessions via Mattermost, you need to run them on a **shared server** so that events (like incoming prompts) are visible across all TUIs.
800
+
801
+ **Why?** By default, each `opencode` command starts its own isolated server. Messages sent to one session won't appear in another session's TUI because they don't share the same event bus.
802
+
803
+ **Solution:** Use OpenCode's shared server mode:
804
+
805
+ #### Option 1: Manual Setup
806
+
807
+ ```bash
808
+ # Terminal 1 - Start the shared server
809
+ opencode serve --port 4096
810
+
811
+ # Terminal 2 - Attach first TUI (run mattermost_connect here)
812
+ cd /path/to/project-a
813
+ opencode attach http://localhost:4096
814
+
815
+ # Terminal 3 - Attach second TUI
816
+ cd /path/to/project-b
817
+ opencode attach http://localhost:4096
818
+ ```
819
+
820
+ #### Option 2: Using the Helper Script
821
+
822
+ A convenience script `opencode-shared` is provided that automatically manages the shared server:
823
+
824
+ ```bash
825
+ # First run - starts server in background, then attaches TUI
826
+ ./opencode-shared
827
+
828
+ # Subsequent runs - attaches to existing server
829
+ ./opencode-shared
830
+
831
+ # With optional password for security
832
+ OPENCODE_SERVER_PASSWORD="your-secret" ./opencode-shared
833
+ ```
834
+
835
+ The script:
836
+ - Checks if a shared server is already running on port 4096
837
+ - If not, starts one as a background process
838
+ - Attaches a TUI to the shared server
839
+ - Logs server output to `/tmp/opencode-server.log`
840
+
841
+ #### Restarting with Plugin Updates
842
+
843
+ Use `opencode-shared-restart` to restart OpenCode with optional plugin version changes:
844
+
845
+ ```bash
846
+ # Restart with current plugin version
847
+ opencode-shared-restart
848
+
849
+ # Update plugin and restart
850
+ opencode-shared-restart -v 0.2.59
851
+
852
+ # Rollback to a previous version
853
+ opencode-shared-restart --rollback 0.2.55
854
+
855
+ # Check current installed version
856
+ opencode-shared-restart --current
857
+
858
+ # List available versions
859
+ opencode-shared-restart --list
860
+
861
+ # Check status of last restart (after reconnecting)
862
+ opencode-shared-restart --status
863
+ ```
864
+
865
+ **How it works:**
866
+ The restart runs in a **detached background process** so it survives the OpenCode server restart. This is especially useful when an AI agent triggers the restart - the agent will be disconnected but the restart completes successfully.
867
+
868
+ After reconnecting to OpenCode, use `--status` to verify the restart succeeded:
869
+
870
+ ```bash
871
+ $ opencode-shared-restart --status
872
+ === Last Restart Status ===
873
+ Status: SUCCESS
874
+ Time: 2026-01-18T12:14:32+00:00
875
+ Plugin Version: 0.2.59
876
+ Message: Server running with v0.2.59
877
+ ```
878
+
879
+ **Automatic rollback:** If the specified version fails to start, the script automatically attempts to restore the previous working version and start the server with that instead.
880
+
881
+ #### Security Note
882
+
883
+ For production use, set `OPENCODE_SERVER_PASSWORD` environment variable on both server and client:
884
+
885
+ ```bash
886
+ export OPENCODE_SERVER_PASSWORD="your-secure-password"
887
+ opencode serve --port 4096
888
+
889
+ # In another terminal (same password required)
890
+ export OPENCODE_SERVER_PASSWORD="your-secure-password"
891
+ opencode attach http://localhost:4096
892
+ ```
893
+
894
+ ## Architecture
895
+
896
+ ![Architecture Diagram](docs/architecture.png)
897
+
898
+ **Data Flow:**
899
+ 1. User sends a DM to the bot in Mattermost
900
+ 2. Plugin receives the message via WebSocket
901
+ 3. Plugin forwards the prompt to OpenCode CLI
902
+ 4. OpenCode processes and streams responses back
903
+ 5. Plugin delivers chunked responses to Mattermost DM
904
+
905
+ ### Components
906
+
907
+ | Component | Description |
908
+ |-----------|-------------|
909
+ | `MattermostClient` | HTTP API client for posts, channels, files, reactions |
910
+ | `WebSocketClient` | Real-time event streaming for instant message detection |
911
+ | `SessionManager` | Per-user session tracking with timeout management |
912
+ | `OpenCodeSessionRegistry` | Discovers and tracks all available OpenCode sessions |
913
+ | `ThreadManager` | Creates and manages session threads, handles lifecycle |
914
+ | `ThreadMappingStore` | Persists thread-to-session mappings with indexes |
915
+ | `MessageRouter` | Routes messages to correct sessions based on thread context |
916
+ | `CommandHandler` | Processes `!commands` for session management |
917
+ | `ResponseStreamer` | Chunked message delivery to correct thread |
918
+ | `NotificationService` | Completion, error, and status notifications |
919
+ | `FileHandler` | Inbound/outbound file attachment processing |
920
+ | `ReactionHandler` | Emoji-based command execution |
921
+ | `MonitorService` | Session event monitoring and DM alerts |
922
+ | `QuestionHandler` | AI question tool support with user responses |
923
+ | `ContextBuilder` | Builds thread context for group DMs, with optional Haiku summarization |
924
+ | `MergeHandler` | Thread merging with AI summarization and source thread locking |
925
+ | `FileCompletionHandler` | `!!` file path completion with fuzzy matching |
926
+ | `GuestApprovalHandler` | Cross-user approval for shared channel sessions |
927
+ | `SessionOwnershipHandler` | Ownership confirmation for group DM sessions |
928
+ | `SchedulerService` | Cron-based scheduled task execution |
929
+
930
+ ## Project Structure
931
+
932
+ ```
933
+ opencode-mattermost-plugin/
934
+ ├── package.json
935
+ ├── tsconfig.json
936
+ ├── opencode.json
937
+ ├── .opencode/
938
+ │ └── plugin/
939
+ │ └── mattermost-control/
940
+ │ ├── index.ts # Main plugin entry point
941
+ │ └── package.json
942
+ └── src/
943
+ ├── clients/
944
+ │ ├── mattermost-client.ts # HTTP API client
945
+ │ └── websocket-client.ts # WebSocket client
946
+ ├── persistence/
947
+ │ └── thread-mapping-store.ts # Thread mapping persistence
948
+ ├── models/
949
+ │ ├── index.ts # TypeScript types
950
+ │ ├── thread-mapping.ts # Thread mapping Zod schemas
951
+ │ └── routing.ts # Message routing types
952
+ ├── scheduler/
953
+ │ ├── schedule-store.ts # Schedule persistence
954
+ │ └── scheduler-service.ts # Cron job execution
955
+ ├── command-handler.ts # !command processing
956
+ ├── config.ts # Configuration loading
957
+ ├── context-builder.ts # Group DM context building & summarization
958
+ ├── file-completion-handler.ts # !! file path completion
959
+ ├── file-handler.ts # File uploads/downloads
960
+ ├── guest-approval-handler.ts # Cross-user approval for channels
961
+ ├── logger.ts # File-based logging
962
+ ├── merge-handler.ts # Thread merging with AI summarization
963
+ ├── message-router.ts # Thread-aware message routing
964
+ ├── monitor-service.ts # Session monitoring and alerts
965
+ ├── notification-service.ts # Status notifications
966
+ ├── opencode-session-registry.ts # OpenCode session discovery
967
+ ├── question-handler.ts # AI question tool responses
968
+ ├── reaction-handler.ts # Emoji reaction handling
969
+ ├── response-streamer.ts # Streams responses to MM
970
+ ├── session-manager.ts # User session management
971
+ ├── session-ownership-handler.ts # Group DM ownership confirmation
972
+ ├── status-indicator.ts # Real-time status display
973
+ ├── thread-manager.ts # Thread lifecycle management
974
+ └── todo-manager.ts # Todo list tracking
975
+ ```
976
+
977
+ ## Updating the Plugin
978
+
979
+ OpenCode caches plugins in `~/.config/opencode/node_modules/`. Simply running `bun add -g` or `npm install -g` does **not** update the running plugin. Follow these steps:
980
+
981
+ ### Step 1: Update the Version Pin
982
+
983
+ Edit `~/.config/opencode/package.json` and update the version:
984
+
985
+ ```json
986
+ {
987
+ "dependencies": {
988
+ "@opencode-ai/plugin": "1.1.21",
989
+ "opencode-mattermost-control": "0.2.19" // <- Update this version
990
+ }
991
+ }
992
+ ```
993
+
994
+ ### Step 2: Clear the Cache
995
+
996
+ ```bash
997
+ # Remove cached package and lockfile
998
+ rm -rf ~/.config/opencode/node_modules/opencode-mattermost-control
999
+ rm -f ~/.config/opencode/bun.lock
1000
+ ```
1001
+
1002
+ ### Step 3: Install the New Version
1003
+
1004
+ ```bash
1005
+ cd ~/.config/opencode
1006
+ bun install
1007
+
1008
+ # If using a private registry (e.g., Verdaccio):
1009
+ bun install --registry http://your-registry-url:4873
1010
+ ```
1011
+
1012
+ ### Step 4: Restart OpenCode
1013
+
1014
+ **Critical**: You must completely restart OpenCode for the new plugin code to load. A `mattermost_disconnect` / `mattermost_connect` cycle only reconnects the WebSocket—it does **not** reload plugin code from disk.
1015
+
1016
+ ```bash
1017
+ # Exit OpenCode completely (Ctrl+C or close terminal)
1018
+ # Then start fresh:
1019
+ opencode
1020
+ ```
1021
+
1022
+ ### Step 5: Verify
1023
+
1024
+ After reconnecting, check the logs to confirm the new version is running:
1025
+
1026
+ ```bash
1027
+ tail -f /tmp/opencode-mattermost-plugin.log
1028
+ ```
1029
+
1030
+ ### Quick Update Script
1031
+
1032
+ ```bash
1033
+ #!/bin/bash
1034
+ # update-mattermost-plugin.sh
1035
+ VERSION="${1:-latest}"
1036
+
1037
+ echo "Updating opencode-mattermost-control to $VERSION..."
1038
+
1039
+ # Update package.json
1040
+ if [ "$VERSION" = "latest" ]; then
1041
+ # Fetch latest version from registry
1042
+ VERSION=$(curl -s http://verdaccio.hyperplane-verdaccio.svc.cluster.local:4873/opencode-mattermost-control | jq -r '.["dist-tags"].latest')
1043
+ fi
1044
+
1045
+ # Update version in package.json
1046
+ cd ~/.config/opencode
1047
+ cat package.json | jq ".dependencies[\"opencode-mattermost-control\"] = \"$VERSION\"" > package.json.tmp
1048
+ mv package.json.tmp package.json
1049
+
1050
+ # Clear cache and reinstall
1051
+ rm -rf node_modules/opencode-mattermost-control bun.lock
1052
+ bun install --registry http://verdaccio.hyperplane-verdaccio.svc.cluster.local:4873
1053
+
1054
+ echo "Updated to version $VERSION"
1055
+ echo "IMPORTANT: Restart OpenCode for changes to take effect!"
1056
+ ```
1057
+
1058
+ ---
1059
+
1060
+ ## Troubleshooting
1061
+
1062
+ ### "Not connected to Mattermost"
1063
+ Run `mattermost_connect` first.
1064
+
1065
+ ### "MATTERMOST_TOKEN environment variable is required"
1066
+ Set the `MATTERMOST_TOKEN` environment variable with your bot's access token.
1067
+
1068
+ ### WebSocket disconnects frequently
1069
+ Check network connectivity to the Mattermost server. The client auto-reconnects with exponential backoff.
1070
+
1071
+ ### Messages not appearing
1072
+ Ensure you're DMing the bot user directly, not posting in a channel.
1073
+
1074
+ ### Permission errors
1075
+ Verify your bot token has the required permissions:
1076
+ - Post messages
1077
+ - Read channels
1078
+ - Upload files (if using file attachments)
1079
+
1080
+ ### View logs
1081
+ ```bash
1082
+ tail -f /tmp/opencode-mattermost-plugin.log
1083
+ ```
1084
+
1085
+ ### Plugin not updating after install
1086
+ If you installed a new version but the old code is still running:
1087
+
1088
+ 1. OpenCode caches plugins in `~/.config/opencode/node_modules/`
1089
+ 2. Check the cached version: `cat ~/.config/opencode/node_modules/opencode-mattermost-control/package.json | grep version`
1090
+ 3. Follow the [Updating the Plugin](#updating-the-plugin) section above
1091
+ 4. **You must restart OpenCode completely** - disconnect/reconnect only refreshes the WebSocket, not the plugin code
1092
+
1093
+ ### Bot not responding to DMs
1094
+
1095
+ If your bot is connected but not responding to messages, check these common issues:
1096
+
1097
+ #### 1. Wrong Owner User ID
1098
+
1099
+ If you're using `MATTERMOST_OWNER_USER_ID` for multi-user setups, ensure it's set to your **actual Mattermost user ID**, not someone else's or a non-existent ID.
1100
+
1101
+ **Symptoms:**
1102
+ - Plugin log shows: `Ignoring 1:1 DM from non-owner user <your-user-id>`
1103
+ - Bot appears online but never responds
1104
+
1105
+ **Fix:**
1106
+ ```bash
1107
+ # Find your user ID (ask admin or check Mattermost profile API)
1108
+ # Then update your environment:
1109
+ export MATTERMOST_OWNER_USER_ID="your-actual-user-id"
1110
+ ```
1111
+
1112
+ #### 2. OpenCode Version Compatibility
1113
+
1114
+ Some OpenCode versions have plugin loading issues in server mode. If plugins aren't loading:
1115
+
1116
+ **Symptoms:**
1117
+ - `opencode serve` starts but plugin log shows no activity
1118
+ - No "Connected to Mattermost" message in logs
1119
+
1120
+ **Fix:**
1121
+ Try downgrading to a known working version:
1122
+ ```bash
1123
+ npm install -g opencode-ai@1.1.28
1124
+ ```
1125
+
1126
+ #### 3. Plugins Only Load When Session Created
1127
+
1128
+ **Critical:** Plugins don't load when `opencode serve` starts—they only initialize when a session is created.
1129
+
1130
+ **Symptoms:**
1131
+ - Server starts successfully
1132
+ - Plugin log is empty or shows no connection
1133
+ - Works fine with `opencode` (non-server mode)
1134
+
1135
+ **Fix:**
1136
+ After starting the server, create a session to bootstrap plugin loading:
1137
+ ```bash
1138
+ # Start server
1139
+ opencode serve --port 4096
1140
+
1141
+ # In another terminal, create a session to trigger plugin load
1142
+ curl -s -X POST http://localhost:4096/session \
1143
+ -H "Content-Type: application/json" \
1144
+ -d '{"directory": "/path/to/your/project"}'
1145
+ ```
1146
+
1147
+ **Startup script example:**
1148
+ ```bash
1149
+ #!/bin/bash
1150
+ # start-opencode-with-plugin.sh
1151
+
1152
+ PORT="${OPENCODE_SERVER_PORT:-4096}"
1153
+
1154
+ # Kill existing and start fresh
1155
+ pkill -f opencode 2>/dev/null || true
1156
+ sleep 2
1157
+
1158
+ # Start server
1159
+ cd /your/project/directory
1160
+ nohup opencode serve --port $PORT > /tmp/opencode-server.log 2>&1 &
1161
+ echo "Started OpenCode server on port $PORT"
1162
+
1163
+ # Wait for server
1164
+ for i in {1..30}; do
1165
+ curl -s http://localhost:$PORT/ > /dev/null 2>&1 && break
1166
+ sleep 1
1167
+ done
1168
+
1169
+ # Bootstrap plugins by creating a session
1170
+ curl -s -X POST http://localhost:$PORT/session \
1171
+ -H "Content-Type: application/json" \
1172
+ -d '{"directory": "/your/project/directory"}' > /dev/null 2>&1
1173
+
1174
+ echo "Created session to bootstrap plugins"
1175
+
1176
+ # Verify
1177
+ sleep 3
1178
+ if grep -q "Connected to Mattermost" /tmp/opencode-mattermost-plugin.log 2>/dev/null; then
1179
+ echo "✓ Plugin connected successfully!"
1180
+ else
1181
+ echo "⚠ Check /tmp/opencode-mattermost-plugin.log for issues"
1182
+ fi
1183
+ ```
1184
+
1185
+ #### 4. Missing Dependencies
1186
+
1187
+ If you see import errors in the plugin log:
1188
+
1189
+ **Fix:**
1190
+ ```bash
1191
+ cd ~/.config/opencode
1192
+ bun add axios # or other missing packages
1193
+ ```
1194
+
1195
+ ### Verifying Plugin is Working
1196
+
1197
+ Check these in order:
1198
+
1199
+ 1. **Server running:**
1200
+ ```bash
1201
+ curl http://localhost:4096/
1202
+ ```
1203
+
1204
+ 2. **Plugin log exists and shows connection:**
1205
+ ```bash
1206
+ tail /tmp/opencode-mattermost-plugin.log
1207
+ # Should show: "Connected to Mattermost as @your-bot"
1208
+ ```
1209
+
1210
+ 3. **Sessions discovered:**
1211
+ ```bash
1212
+ grep "session discovered" /tmp/opencode-mattermost-plugin.log
1213
+ ```
1214
+
1215
+ 4. **Test message received:**
1216
+ Send a DM to the bot and check logs for:
1217
+ - `Ignoring 1:1 DM from non-owner` = Owner ID mismatch
1218
+ - `Processing DM from` = Message being handled
1219
+ - No log entry = WebSocket not receiving events
1220
+
1221
+ ## Development
1222
+
1223
+ ### Setup
1224
+
1225
+ ```bash
1226
+ git clone https://github.com/Shakudo-io/opencode-mattermost-plugin.git
1227
+ cd opencode-mattermost-plugin
1228
+ bun install
1229
+ ```
1230
+
1231
+ ### Type Check
1232
+
1233
+ ```bash
1234
+ bun run typecheck
1235
+ ```
1236
+
1237
+ ### Run Tests
1238
+
1239
+ ```bash
1240
+ bun test
1241
+ ```
1242
+
1243
+ ### Publish
1244
+
1245
+ ```bash
1246
+ npm publish
1247
+ ```
1248
+
1249
+ ## Contributing
1250
+
1251
+ Contributions are welcome! Please feel free to submit a Pull Request.
1252
+
1253
+ 1. Fork the repository
1254
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
1255
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
1256
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
1257
+ 5. Open a Pull Request
1258
+
1259
+ ### Guidelines
1260
+
1261
+ - Follow the existing code style
1262
+ - Add tests for new features
1263
+ - Update documentation as needed
1264
+ - Keep commits atomic and well-described
1265
+
1266
+ ## Security
1267
+
1268
+ - Never commit tokens or credentials
1269
+ - Use environment variables for all sensitive configuration
1270
+ - Report security vulnerabilities privately
1271
+
1272
+ ## License
1273
+
1274
+ MIT License - see [LICENSE](LICENSE) for details.
1275
+
1276
+ ## Links
1277
+
1278
+ - [OpenCode Documentation](https://opencode.ai/docs/)
1279
+ - [Mattermost API Reference](https://api.mattermost.com/)
1280
+ - [Report Issues](https://github.com/Shakudo-io/opencode-mattermost-plugin/issues)