@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.
- package/.opencode/command/mattermost-connect.md +5 -0
- package/.opencode/command/mattermost-disconnect.md +5 -0
- package/.opencode/command/mattermost-monitor.md +12 -0
- package/.opencode/command/mattermost-status.md +5 -0
- package/.opencode/command/speckit.analyze.md +184 -0
- package/.opencode/command/speckit.checklist.md +294 -0
- package/.opencode/command/speckit.clarify.md +181 -0
- package/.opencode/command/speckit.constitution.md +82 -0
- package/.opencode/command/speckit.implement.md +135 -0
- package/.opencode/command/speckit.plan.md +89 -0
- package/.opencode/command/speckit.specify.md +258 -0
- package/.opencode/command/speckit.tasks.md +137 -0
- package/.opencode/command/speckit.taskstoissues.md +30 -0
- package/.opencode/plugin/mattermost-control/event-handlers/compaction.ts +61 -0
- package/.opencode/plugin/mattermost-control/event-handlers/file.ts +36 -0
- package/.opencode/plugin/mattermost-control/event-handlers/index.ts +14 -0
- package/.opencode/plugin/mattermost-control/event-handlers/message.ts +124 -0
- package/.opencode/plugin/mattermost-control/event-handlers/permission.ts +34 -0
- package/.opencode/plugin/mattermost-control/event-handlers/question.ts +92 -0
- package/.opencode/plugin/mattermost-control/event-handlers/session.ts +100 -0
- package/.opencode/plugin/mattermost-control/event-handlers/todo.ts +33 -0
- package/.opencode/plugin/mattermost-control/event-handlers/tool.ts +76 -0
- package/.opencode/plugin/mattermost-control/formatters.ts +202 -0
- package/.opencode/plugin/mattermost-control/index.ts +964 -0
- package/.opencode/plugin/mattermost-control/package.json +12 -0
- package/.opencode/plugin/mattermost-control/state.ts +180 -0
- package/.opencode/plugin/mattermost-control/timers.ts +96 -0
- package/.opencode/plugin/mattermost-control/tools/connect.ts +563 -0
- package/.opencode/plugin/mattermost-control/tools/file.ts +41 -0
- package/.opencode/plugin/mattermost-control/tools/index.ts +12 -0
- package/.opencode/plugin/mattermost-control/tools/monitor.ts +183 -0
- package/.opencode/plugin/mattermost-control/tools/schedule.ts +253 -0
- package/.opencode/plugin/mattermost-control/tools/session.ts +120 -0
- package/.opencode/plugin/mattermost-control/types.ts +107 -0
- package/LICENSE +21 -0
- package/README.md +1280 -0
- package/opencode-shared +359 -0
- package/opencode-shared-restart +495 -0
- package/opencode-shared-stop +90 -0
- package/package.json +65 -0
- package/src/clients/mattermost-client.ts +221 -0
- package/src/clients/websocket-client.ts +199 -0
- package/src/command-handler.ts +1035 -0
- package/src/config.ts +170 -0
- package/src/context-builder.ts +309 -0
- package/src/file-completion-handler.ts +521 -0
- package/src/file-handler.ts +242 -0
- package/src/guest-approval-handler.ts +223 -0
- package/src/logger.ts +73 -0
- package/src/merge-handler.ts +335 -0
- package/src/message-router.ts +151 -0
- package/src/models/index.ts +197 -0
- package/src/models/routing.ts +50 -0
- package/src/models/thread-mapping.ts +40 -0
- package/src/monitor-service.ts +222 -0
- package/src/notification-service.ts +118 -0
- package/src/opencode-session-registry.ts +370 -0
- package/src/persistence/team-store.ts +396 -0
- package/src/persistence/thread-mapping-store.ts +258 -0
- package/src/question-handler.ts +401 -0
- package/src/reaction-handler.ts +111 -0
- package/src/response-streamer.ts +364 -0
- package/src/scheduler/schedule-store.ts +261 -0
- package/src/scheduler/scheduler-service.ts +349 -0
- package/src/session-manager.ts +142 -0
- package/src/session-ownership-handler.ts +253 -0
- package/src/status-indicator.ts +279 -0
- package/src/thread-manager.ts +231 -0
- package/src/todo-manager.ts +162 -0
package/opencode-shared
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# opencode-shared - Start or attach to a shared OpenCode server
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# ./opencode-shared [options]
|
|
7
|
+
#
|
|
8
|
+
# Options are passed through to 'opencode attach' (e.g., --session <id>)
|
|
9
|
+
#
|
|
10
|
+
# Environment variables:
|
|
11
|
+
# OPENCODE_SERVER_PORT - Port for the shared server (default: 4096)
|
|
12
|
+
# OPENCODE_SERVER_PASSWORD - Password for server authentication (optional)
|
|
13
|
+
# OPENCODE_SERVER_LOG - Log file path (default: /tmp/opencode-server.log)
|
|
14
|
+
#
|
|
15
|
+
# Auto-restart configuration:
|
|
16
|
+
# OPENCODE_AUTO_RESTART - Enable auto-restart (default: true)
|
|
17
|
+
# OPENCODE_MONITOR_INTERVAL - Health check interval in seconds (default: 2)
|
|
18
|
+
# OPENCODE_RESTART_MAX_ATTEMPTS - Max restarts in window before backoff (default: 5)
|
|
19
|
+
# OPENCODE_RESTART_WINDOW - Time window for counting restarts in seconds (default: 300)
|
|
20
|
+
# OPENCODE_RESTART_BACKOFF_BASE - Base backoff time in seconds (default: 1)
|
|
21
|
+
# OPENCODE_RESTART_BACKOFF_MAX - Maximum backoff time in seconds (default: 60)
|
|
22
|
+
# OPENCODE_HEALTH_TIMEOUT - Health check timeout in seconds (default: 2)
|
|
23
|
+
# OPENCODE_HEALTH_FAIL_THRESHOLD - Consecutive health failures before restart (default: 3)
|
|
24
|
+
# OPENCODE_STARTUP_TIMEOUT - Server startup timeout in seconds (default: 15)
|
|
25
|
+
#
|
|
26
|
+
|
|
27
|
+
set -euo pipefail
|
|
28
|
+
|
|
29
|
+
# =============================================================================
|
|
30
|
+
# Configuration
|
|
31
|
+
# =============================================================================
|
|
32
|
+
|
|
33
|
+
PORT="${OPENCODE_SERVER_PORT:-4096}"
|
|
34
|
+
SERVER_URL="http://localhost:${PORT}"
|
|
35
|
+
|
|
36
|
+
# Log files
|
|
37
|
+
SERVER_LOG="${OPENCODE_SERVER_LOG:-/tmp/opencode-server.log}"
|
|
38
|
+
SUPERVISOR_LOG="${OPENCODE_SUPERVISOR_LOG:-/tmp/opencode-server.supervisor.log}"
|
|
39
|
+
|
|
40
|
+
# State files
|
|
41
|
+
PIDFILE="/tmp/opencode-server.pid"
|
|
42
|
+
SUPERVISOR_PIDFILE="/tmp/opencode-server.supervisor.pid"
|
|
43
|
+
STOP_FLAG="/tmp/opencode-server.stop"
|
|
44
|
+
LOCKDIR="/tmp/opencode-server.supervisor.lock"
|
|
45
|
+
|
|
46
|
+
# Auto-restart settings
|
|
47
|
+
AUTO_RESTART="${OPENCODE_AUTO_RESTART:-true}"
|
|
48
|
+
MONITOR_INTERVAL="${OPENCODE_MONITOR_INTERVAL:-2}"
|
|
49
|
+
STARTUP_TIMEOUT="${OPENCODE_STARTUP_TIMEOUT:-15}"
|
|
50
|
+
|
|
51
|
+
# Health check settings
|
|
52
|
+
HEALTH_PATH="${OPENCODE_HEALTH_PATH:-/global/health}"
|
|
53
|
+
HEALTH_TIMEOUT="${OPENCODE_HEALTH_TIMEOUT:-2}"
|
|
54
|
+
HEALTH_FAIL_THRESHOLD="${OPENCODE_HEALTH_FAIL_THRESHOLD:-3}"
|
|
55
|
+
|
|
56
|
+
# Restart/backoff settings
|
|
57
|
+
RESTART_MAX="${OPENCODE_RESTART_MAX_ATTEMPTS:-5}"
|
|
58
|
+
RESTART_WINDOW="${OPENCODE_RESTART_WINDOW:-300}"
|
|
59
|
+
BACKOFF_BASE="${OPENCODE_RESTART_BACKOFF_BASE:-1}"
|
|
60
|
+
BACKOFF_MAX="${OPENCODE_RESTART_BACKOFF_MAX:-60}"
|
|
61
|
+
|
|
62
|
+
# =============================================================================
|
|
63
|
+
# Utility Functions
|
|
64
|
+
# =============================================================================
|
|
65
|
+
|
|
66
|
+
# Timestamp for logging
|
|
67
|
+
ts() { date -Iseconds 2>/dev/null || date '+%Y-%m-%dT%H:%M:%S'; }
|
|
68
|
+
|
|
69
|
+
# Log to supervisor log file
|
|
70
|
+
log_supervisor() {
|
|
71
|
+
printf '%s [supervisor] %s\n' "$(ts)" "$*" >> "$SUPERVISOR_LOG"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Log to stdout
|
|
75
|
+
log_info() {
|
|
76
|
+
echo "$*"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# =============================================================================
|
|
80
|
+
# Server Health & Status Functions
|
|
81
|
+
# =============================================================================
|
|
82
|
+
|
|
83
|
+
# Check if server PID is alive
|
|
84
|
+
pid_alive() {
|
|
85
|
+
[[ -f "$PIDFILE" ]] || return 1
|
|
86
|
+
local pid
|
|
87
|
+
pid="$(cat "$PIDFILE" 2>/dev/null || true)"
|
|
88
|
+
[[ -n "${pid:-}" ]] || return 1
|
|
89
|
+
kill -0 "$pid" 2>/dev/null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Check server health via HTTP endpoint
|
|
93
|
+
health_ok() {
|
|
94
|
+
curl -fsS --max-time "$HEALTH_TIMEOUT" "${SERVER_URL}${HEALTH_PATH}" >/dev/null 2>&1 || \
|
|
95
|
+
curl -fsS --max-time "$HEALTH_TIMEOUT" "${SERVER_URL}/health" >/dev/null 2>&1 || \
|
|
96
|
+
curl -fsS --max-time "$HEALTH_TIMEOUT" "${SERVER_URL}" >/dev/null 2>&1
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Check if server is running (PID alive + responding)
|
|
100
|
+
is_server_running() {
|
|
101
|
+
if [[ -f "$PIDFILE" ]]; then
|
|
102
|
+
local pid
|
|
103
|
+
pid=$(cat "$PIDFILE" 2>/dev/null || true)
|
|
104
|
+
if [[ -n "${pid:-}" ]] && kill -0 "$pid" 2>/dev/null; then
|
|
105
|
+
# Process exists, verify it's actually responding
|
|
106
|
+
if health_ok || nc -z localhost "$PORT" 2>/dev/null; then
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
# Stale PID file, remove it
|
|
111
|
+
rm -f "$PIDFILE"
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# No PID file, but check if something is listening on the port anyway
|
|
115
|
+
if nc -z localhost "$PORT" 2>/dev/null; then
|
|
116
|
+
return 0
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
return 1
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# =============================================================================
|
|
123
|
+
# Server Lifecycle Functions
|
|
124
|
+
# =============================================================================
|
|
125
|
+
|
|
126
|
+
# Start the server in the background
|
|
127
|
+
start_server() {
|
|
128
|
+
log_info "Starting OpenCode shared server on port ${PORT}..."
|
|
129
|
+
|
|
130
|
+
rm -f "$PIDFILE"
|
|
131
|
+
nohup opencode serve --port "$PORT" >> "$SERVER_LOG" 2>&1 &
|
|
132
|
+
local server_pid=$!
|
|
133
|
+
echo "$server_pid" > "$PIDFILE"
|
|
134
|
+
|
|
135
|
+
log_info "Server process started (PID: ${server_pid})"
|
|
136
|
+
log_info "Server logs: ${SERVER_LOG}"
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# Wait for server to become ready
|
|
140
|
+
wait_server_ready() {
|
|
141
|
+
local max_attempts=$((STARTUP_TIMEOUT * 2)) # Check every 0.5s
|
|
142
|
+
local attempt=0
|
|
143
|
+
|
|
144
|
+
while [[ $attempt -lt $max_attempts ]]; do
|
|
145
|
+
if nc -z localhost "$PORT" 2>/dev/null; then
|
|
146
|
+
return 0
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
# Check if process is still running
|
|
150
|
+
if ! pid_alive; then
|
|
151
|
+
return 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
sleep 0.5
|
|
155
|
+
attempt=$((attempt + 1))
|
|
156
|
+
done
|
|
157
|
+
|
|
158
|
+
return 1
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
# Start server and wait for it to be ready
|
|
162
|
+
start_server_and_wait() {
|
|
163
|
+
start_server
|
|
164
|
+
|
|
165
|
+
if wait_server_ready; then
|
|
166
|
+
local pid
|
|
167
|
+
pid=$(cat "$PIDFILE" 2>/dev/null || echo "unknown")
|
|
168
|
+
log_info "Server ready (PID: ${pid})"
|
|
169
|
+
return 0
|
|
170
|
+
else
|
|
171
|
+
log_info "Error: Server failed to start within ${STARTUP_TIMEOUT} seconds. Check logs: ${SERVER_LOG}"
|
|
172
|
+
rm -f "$PIDFILE"
|
|
173
|
+
return 1
|
|
174
|
+
fi
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# =============================================================================
|
|
178
|
+
# Supervisor Functions
|
|
179
|
+
# =============================================================================
|
|
180
|
+
|
|
181
|
+
# Calculate exponential backoff time
|
|
182
|
+
calc_backoff() {
|
|
183
|
+
local n="$1"
|
|
184
|
+
local backoff=$((BACKOFF_BASE * (2 ** (n - 1))))
|
|
185
|
+
if [[ $backoff -gt $BACKOFF_MAX ]]; then
|
|
186
|
+
backoff="$BACKOFF_MAX"
|
|
187
|
+
fi
|
|
188
|
+
echo "$backoff"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# The supervisor loop - monitors and restarts server
|
|
192
|
+
supervise() {
|
|
193
|
+
# Acquire lock (only one supervisor allowed)
|
|
194
|
+
if ! mkdir "$LOCKDIR" 2>/dev/null; then
|
|
195
|
+
# Another supervisor is running
|
|
196
|
+
exit 0
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# Save our PID
|
|
200
|
+
echo "$$" > "$SUPERVISOR_PIDFILE"
|
|
201
|
+
log_supervisor "supervisor started pid=$$"
|
|
202
|
+
|
|
203
|
+
# Cleanup on exit
|
|
204
|
+
trap 'rm -f "$SUPERVISOR_PIDFILE"; rmdir "$LOCKDIR" 2>/dev/null || true; log_supervisor "supervisor stopped"' EXIT
|
|
205
|
+
|
|
206
|
+
# Track restart times for backoff calculation
|
|
207
|
+
local -a restart_times=()
|
|
208
|
+
local health_fail_count=0
|
|
209
|
+
|
|
210
|
+
while true; do
|
|
211
|
+
# Check for stop flag
|
|
212
|
+
if [[ -f "$STOP_FLAG" ]]; then
|
|
213
|
+
log_supervisor "stop flag detected, exiting"
|
|
214
|
+
break
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# Check server health
|
|
218
|
+
if pid_alive && health_ok; then
|
|
219
|
+
# Server is healthy
|
|
220
|
+
health_fail_count=0
|
|
221
|
+
sleep "$MONITOR_INTERVAL"
|
|
222
|
+
continue
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Server might be unhealthy or down
|
|
226
|
+
if pid_alive && ! health_ok; then
|
|
227
|
+
# Process alive but not responding to health checks
|
|
228
|
+
health_fail_count=$((health_fail_count + 1))
|
|
229
|
+
log_supervisor "health check failed (${health_fail_count}/${HEALTH_FAIL_THRESHOLD})"
|
|
230
|
+
|
|
231
|
+
if [[ $health_fail_count -lt $HEALTH_FAIL_THRESHOLD ]]; then
|
|
232
|
+
sleep "$MONITOR_INTERVAL"
|
|
233
|
+
continue
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
# Threshold exceeded, kill and restart
|
|
237
|
+
log_supervisor "health threshold exceeded, killing server"
|
|
238
|
+
local pid
|
|
239
|
+
pid=$(cat "$PIDFILE" 2>/dev/null || true)
|
|
240
|
+
if [[ -n "${pid:-}" ]]; then
|
|
241
|
+
kill "$pid" 2>/dev/null || true
|
|
242
|
+
sleep 1
|
|
243
|
+
kill -9 "$pid" 2>/dev/null || true
|
|
244
|
+
fi
|
|
245
|
+
rm -f "$PIDFILE"
|
|
246
|
+
health_fail_count=0
|
|
247
|
+
else
|
|
248
|
+
# Server is down
|
|
249
|
+
log_supervisor "server down, preparing restart"
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
# Re-check stop flag before restart
|
|
253
|
+
if [[ -f "$STOP_FLAG" ]]; then
|
|
254
|
+
log_supervisor "stop flag detected before restart, exiting"
|
|
255
|
+
break
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
# Calculate restarts in window for backoff
|
|
259
|
+
local now
|
|
260
|
+
now="$(date +%s)"
|
|
261
|
+
local -a recent=()
|
|
262
|
+
for t in "${restart_times[@]:-}"; do
|
|
263
|
+
if [[ $((now - t)) -lt $RESTART_WINDOW ]]; then
|
|
264
|
+
recent+=("$t")
|
|
265
|
+
fi
|
|
266
|
+
done
|
|
267
|
+
restart_times=("${recent[@]}")
|
|
268
|
+
restart_times+=("$now")
|
|
269
|
+
|
|
270
|
+
local restart_count="${#restart_times[@]}"
|
|
271
|
+
|
|
272
|
+
# Apply backoff if too many restarts
|
|
273
|
+
if [[ $restart_count -gt 1 ]]; then
|
|
274
|
+
local backoff
|
|
275
|
+
backoff="$(calc_backoff "$restart_count")"
|
|
276
|
+
log_supervisor "backoff ${backoff}s (restart #${restart_count} in ${RESTART_WINDOW}s window)"
|
|
277
|
+
sleep "$backoff"
|
|
278
|
+
|
|
279
|
+
# Re-check stop flag after backoff
|
|
280
|
+
if [[ -f "$STOP_FLAG" ]]; then
|
|
281
|
+
log_supervisor "stop flag detected after backoff, exiting"
|
|
282
|
+
break
|
|
283
|
+
fi
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
# Restart the server
|
|
287
|
+
log_supervisor "restarting server..."
|
|
288
|
+
start_server
|
|
289
|
+
|
|
290
|
+
if wait_server_ready; then
|
|
291
|
+
local pid
|
|
292
|
+
pid=$(cat "$PIDFILE" 2>/dev/null || echo "unknown")
|
|
293
|
+
log_supervisor "server restarted successfully (PID: ${pid})"
|
|
294
|
+
else
|
|
295
|
+
log_supervisor "server failed to start, will retry"
|
|
296
|
+
rm -f "$PIDFILE"
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
sleep "$MONITOR_INTERVAL"
|
|
300
|
+
done
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
# Ensure supervisor is running (spawn if needed)
|
|
304
|
+
ensure_supervisor_running() {
|
|
305
|
+
[[ "$AUTO_RESTART" == "true" ]] || return 0
|
|
306
|
+
|
|
307
|
+
# Check if supervisor is already running
|
|
308
|
+
if [[ -f "$SUPERVISOR_PIDFILE" ]]; then
|
|
309
|
+
local spid
|
|
310
|
+
spid="$(cat "$SUPERVISOR_PIDFILE" 2>/dev/null || true)"
|
|
311
|
+
if [[ -n "${spid:-}" ]] && kill -0 "$spid" 2>/dev/null; then
|
|
312
|
+
# Supervisor already running
|
|
313
|
+
return 0
|
|
314
|
+
fi
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
# Clear stale stop flag from previous runs
|
|
318
|
+
rm -f "$STOP_FLAG"
|
|
319
|
+
|
|
320
|
+
# Spawn supervisor as background process
|
|
321
|
+
log_info "Starting auto-restart supervisor..."
|
|
322
|
+
nohup "$0" --supervise >> "$SUPERVISOR_LOG" 2>&1 &
|
|
323
|
+
|
|
324
|
+
# Give it a moment to start
|
|
325
|
+
sleep 0.2
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
# =============================================================================
|
|
329
|
+
# Main Entry Point
|
|
330
|
+
# =============================================================================
|
|
331
|
+
|
|
332
|
+
main() {
|
|
333
|
+
# Handle supervisor mode
|
|
334
|
+
if [[ "${1:-}" == "--supervise" ]]; then
|
|
335
|
+
supervise
|
|
336
|
+
exit 0
|
|
337
|
+
fi
|
|
338
|
+
|
|
339
|
+
# Normal launcher mode
|
|
340
|
+
|
|
341
|
+
# Clear any stale stop flag
|
|
342
|
+
rm -f "$STOP_FLAG"
|
|
343
|
+
|
|
344
|
+
if is_server_running; then
|
|
345
|
+
log_info "Connecting to existing OpenCode server at ${SERVER_URL}"
|
|
346
|
+
else
|
|
347
|
+
if ! start_server_and_wait; then
|
|
348
|
+
exit 1
|
|
349
|
+
fi
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
# Ensure supervisor is running for auto-restart
|
|
353
|
+
ensure_supervisor_running
|
|
354
|
+
|
|
355
|
+
# Attach to the server, passing through any additional arguments
|
|
356
|
+
exec opencode attach "$SERVER_URL" "$@"
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
main "$@"
|