mcp-rubber-duck 1.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.
Files changed (184) hide show
  1. package/.dockerignore +19 -0
  2. package/.env.desktop.example +145 -0
  3. package/.env.example +45 -0
  4. package/.env.pi.example +106 -0
  5. package/.env.template +165 -0
  6. package/.eslintrc.json +40 -0
  7. package/.github/ISSUE_TEMPLATE/bug_report.md +65 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.md +58 -0
  9. package/.github/ISSUE_TEMPLATE/question.md +67 -0
  10. package/.github/pull_request_template.md +111 -0
  11. package/.github/workflows/docker-build.yml +138 -0
  12. package/.github/workflows/release.yml +182 -0
  13. package/.github/workflows/security.yml +141 -0
  14. package/.github/workflows/semantic-release.yml +89 -0
  15. package/.prettierrc +10 -0
  16. package/.releaserc.json +66 -0
  17. package/CHANGELOG.md +95 -0
  18. package/CONTRIBUTING.md +242 -0
  19. package/Dockerfile +62 -0
  20. package/LICENSE +21 -0
  21. package/README.md +803 -0
  22. package/audit-ci.json +8 -0
  23. package/config/claude_desktop.json +14 -0
  24. package/config/config.example.json +91 -0
  25. package/dist/config/config.d.ts +51 -0
  26. package/dist/config/config.d.ts.map +1 -0
  27. package/dist/config/config.js +301 -0
  28. package/dist/config/config.js.map +1 -0
  29. package/dist/config/types.d.ts +356 -0
  30. package/dist/config/types.d.ts.map +1 -0
  31. package/dist/config/types.js +41 -0
  32. package/dist/config/types.js.map +1 -0
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +109 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/providers/duck-provider-enhanced.d.ts +29 -0
  38. package/dist/providers/duck-provider-enhanced.d.ts.map +1 -0
  39. package/dist/providers/duck-provider-enhanced.js +230 -0
  40. package/dist/providers/duck-provider-enhanced.js.map +1 -0
  41. package/dist/providers/enhanced-manager.d.ts +54 -0
  42. package/dist/providers/enhanced-manager.d.ts.map +1 -0
  43. package/dist/providers/enhanced-manager.js +217 -0
  44. package/dist/providers/enhanced-manager.js.map +1 -0
  45. package/dist/providers/manager.d.ts +28 -0
  46. package/dist/providers/manager.d.ts.map +1 -0
  47. package/dist/providers/manager.js +204 -0
  48. package/dist/providers/manager.js.map +1 -0
  49. package/dist/providers/provider.d.ts +29 -0
  50. package/dist/providers/provider.d.ts.map +1 -0
  51. package/dist/providers/provider.js +179 -0
  52. package/dist/providers/provider.js.map +1 -0
  53. package/dist/providers/types.d.ts +69 -0
  54. package/dist/providers/types.d.ts.map +1 -0
  55. package/dist/providers/types.js +2 -0
  56. package/dist/providers/types.js.map +1 -0
  57. package/dist/server.d.ts +24 -0
  58. package/dist/server.d.ts.map +1 -0
  59. package/dist/server.js +501 -0
  60. package/dist/server.js.map +1 -0
  61. package/dist/services/approval.d.ts +44 -0
  62. package/dist/services/approval.d.ts.map +1 -0
  63. package/dist/services/approval.js +159 -0
  64. package/dist/services/approval.js.map +1 -0
  65. package/dist/services/cache.d.ts +21 -0
  66. package/dist/services/cache.d.ts.map +1 -0
  67. package/dist/services/cache.js +63 -0
  68. package/dist/services/cache.js.map +1 -0
  69. package/dist/services/conversation.d.ts +24 -0
  70. package/dist/services/conversation.d.ts.map +1 -0
  71. package/dist/services/conversation.js +108 -0
  72. package/dist/services/conversation.js.map +1 -0
  73. package/dist/services/function-bridge.d.ts +41 -0
  74. package/dist/services/function-bridge.d.ts.map +1 -0
  75. package/dist/services/function-bridge.js +259 -0
  76. package/dist/services/function-bridge.js.map +1 -0
  77. package/dist/services/health.d.ts +17 -0
  78. package/dist/services/health.d.ts.map +1 -0
  79. package/dist/services/health.js +77 -0
  80. package/dist/services/health.js.map +1 -0
  81. package/dist/services/mcp-client-manager.d.ts +49 -0
  82. package/dist/services/mcp-client-manager.d.ts.map +1 -0
  83. package/dist/services/mcp-client-manager.js +279 -0
  84. package/dist/services/mcp-client-manager.js.map +1 -0
  85. package/dist/tools/approve-mcp-request.d.ts +9 -0
  86. package/dist/tools/approve-mcp-request.d.ts.map +1 -0
  87. package/dist/tools/approve-mcp-request.js +111 -0
  88. package/dist/tools/approve-mcp-request.js.map +1 -0
  89. package/dist/tools/ask-duck.d.ts +9 -0
  90. package/dist/tools/ask-duck.d.ts.map +1 -0
  91. package/dist/tools/ask-duck.js +43 -0
  92. package/dist/tools/ask-duck.js.map +1 -0
  93. package/dist/tools/chat-duck.d.ts +9 -0
  94. package/dist/tools/chat-duck.d.ts.map +1 -0
  95. package/dist/tools/chat-duck.js +57 -0
  96. package/dist/tools/chat-duck.js.map +1 -0
  97. package/dist/tools/clear-conversations.d.ts +8 -0
  98. package/dist/tools/clear-conversations.d.ts.map +1 -0
  99. package/dist/tools/clear-conversations.js +17 -0
  100. package/dist/tools/clear-conversations.js.map +1 -0
  101. package/dist/tools/compare-ducks.d.ts +8 -0
  102. package/dist/tools/compare-ducks.d.ts.map +1 -0
  103. package/dist/tools/compare-ducks.js +49 -0
  104. package/dist/tools/compare-ducks.js.map +1 -0
  105. package/dist/tools/duck-council.d.ts +8 -0
  106. package/dist/tools/duck-council.d.ts.map +1 -0
  107. package/dist/tools/duck-council.js +69 -0
  108. package/dist/tools/duck-council.js.map +1 -0
  109. package/dist/tools/get-pending-approvals.d.ts +15 -0
  110. package/dist/tools/get-pending-approvals.d.ts.map +1 -0
  111. package/dist/tools/get-pending-approvals.js +74 -0
  112. package/dist/tools/get-pending-approvals.js.map +1 -0
  113. package/dist/tools/list-ducks.d.ts +9 -0
  114. package/dist/tools/list-ducks.d.ts.map +1 -0
  115. package/dist/tools/list-ducks.js +47 -0
  116. package/dist/tools/list-ducks.js.map +1 -0
  117. package/dist/tools/list-models.d.ts +8 -0
  118. package/dist/tools/list-models.d.ts.map +1 -0
  119. package/dist/tools/list-models.js +72 -0
  120. package/dist/tools/list-models.js.map +1 -0
  121. package/dist/tools/mcp-status.d.ts +17 -0
  122. package/dist/tools/mcp-status.d.ts.map +1 -0
  123. package/dist/tools/mcp-status.js +100 -0
  124. package/dist/tools/mcp-status.js.map +1 -0
  125. package/dist/utils/ascii-art.d.ts +19 -0
  126. package/dist/utils/ascii-art.d.ts.map +1 -0
  127. package/dist/utils/ascii-art.js +73 -0
  128. package/dist/utils/ascii-art.js.map +1 -0
  129. package/dist/utils/logger.d.ts +3 -0
  130. package/dist/utils/logger.d.ts.map +1 -0
  131. package/dist/utils/logger.js +86 -0
  132. package/dist/utils/logger.js.map +1 -0
  133. package/dist/utils/safe-logger.d.ts +23 -0
  134. package/dist/utils/safe-logger.d.ts.map +1 -0
  135. package/dist/utils/safe-logger.js +145 -0
  136. package/dist/utils/safe-logger.js.map +1 -0
  137. package/docker-compose.yml +161 -0
  138. package/jest.config.js +26 -0
  139. package/package.json +65 -0
  140. package/scripts/build-multiarch.sh +290 -0
  141. package/scripts/deploy-raspbian.sh +410 -0
  142. package/scripts/deploy.sh +322 -0
  143. package/scripts/gh-deploy.sh +343 -0
  144. package/scripts/setup-docker-raspbian.sh +530 -0
  145. package/server.json +8 -0
  146. package/src/config/config.ts +357 -0
  147. package/src/config/types.ts +89 -0
  148. package/src/index.ts +114 -0
  149. package/src/providers/duck-provider-enhanced.ts +294 -0
  150. package/src/providers/enhanced-manager.ts +290 -0
  151. package/src/providers/manager.ts +257 -0
  152. package/src/providers/provider.ts +207 -0
  153. package/src/providers/types.ts +78 -0
  154. package/src/server.ts +603 -0
  155. package/src/services/approval.ts +225 -0
  156. package/src/services/cache.ts +79 -0
  157. package/src/services/conversation.ts +146 -0
  158. package/src/services/function-bridge.ts +329 -0
  159. package/src/services/health.ts +107 -0
  160. package/src/services/mcp-client-manager.ts +362 -0
  161. package/src/tools/approve-mcp-request.ts +126 -0
  162. package/src/tools/ask-duck.ts +74 -0
  163. package/src/tools/chat-duck.ts +82 -0
  164. package/src/tools/clear-conversations.ts +24 -0
  165. package/src/tools/compare-ducks.ts +67 -0
  166. package/src/tools/duck-council.ts +88 -0
  167. package/src/tools/get-pending-approvals.ts +90 -0
  168. package/src/tools/list-ducks.ts +65 -0
  169. package/src/tools/list-models.ts +101 -0
  170. package/src/tools/mcp-status.ts +117 -0
  171. package/src/utils/ascii-art.ts +85 -0
  172. package/src/utils/logger.ts +116 -0
  173. package/src/utils/safe-logger.ts +165 -0
  174. package/systemd/mcp-rubber-duck-with-ollama.service +55 -0
  175. package/systemd/mcp-rubber-duck.service +58 -0
  176. package/test-functionality.js +147 -0
  177. package/test-mcp-interface.js +221 -0
  178. package/tests/ascii-art.test.ts +36 -0
  179. package/tests/config.test.ts +239 -0
  180. package/tests/conversation.test.ts +308 -0
  181. package/tests/mcp-bridge.test.ts +291 -0
  182. package/tests/providers.test.ts +269 -0
  183. package/tests/tools/clear-conversations.test.ts +163 -0
  184. package/tsconfig.json +26 -0
@@ -0,0 +1,530 @@
1
+ #!/bin/bash
2
+
3
+ # MCP Rubber Duck - Raspberry Pi Docker Setup Script
4
+ # This script installs and configures Docker and Docker Compose on Raspberry Pi
5
+
6
+ set -euo pipefail
7
+
8
+ # Colors for output
9
+ RED='\033[0;31m'
10
+ GREEN='\033[0;32m'
11
+ YELLOW='\033[1;33m'
12
+ BLUE='\033[0;34m'
13
+ NC='\033[0m' # No Color
14
+
15
+ # Configuration
16
+ DOCKER_COMPOSE_VERSION="${DOCKER_COMPOSE_VERSION:-2.24.0}"
17
+ SETUP_SWAP="${SETUP_SWAP:-true}"
18
+ SWAP_SIZE="${SWAP_SIZE:-1G}"
19
+ ENABLE_MEMORY_CGROUPS="${ENABLE_MEMORY_CGROUPS:-true}"
20
+
21
+ # Functions
22
+ log() {
23
+ echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
24
+ }
25
+
26
+ warn() {
27
+ echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}"
28
+ }
29
+
30
+ error() {
31
+ echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
32
+ exit 1
33
+ }
34
+
35
+ info() {
36
+ echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $1${NC}"
37
+ }
38
+
39
+ print_usage() {
40
+ cat << EOF
41
+ Usage: $0 [OPTIONS]
42
+
43
+ Setup Docker and Docker Compose on Raspberry Pi for MCP Rubber Duck
44
+
45
+ OPTIONS:
46
+ --no-swap Don't setup swap file
47
+ --swap-size SIZE Swap file size (default: 1G)
48
+ --no-memory-cgroups Don't enable memory cgroups
49
+ --docker-compose-version Docker Compose version (default: 2.24.0)
50
+ --dry-run Show what would be done without executing
51
+ -y, --yes Assume yes to all prompts
52
+ -h, --help Show this help message
53
+
54
+ EXAMPLES:
55
+ # Full setup with defaults
56
+ $0
57
+
58
+ # Setup without swap
59
+ $0 --no-swap
60
+
61
+ # Custom swap size
62
+ $0 --swap-size 2G
63
+
64
+ # Dry run to see what would be done
65
+ $0 --dry-run
66
+
67
+ REQUIREMENTS:
68
+ - Raspberry Pi running Raspberry Pi OS (Debian-based)
69
+ - Internet connection
70
+ - sudo privileges
71
+
72
+ EOF
73
+ }
74
+
75
+ # System detection
76
+ detect_system() {
77
+ log "Detecting system..."
78
+
79
+ # Check if we're on Raspberry Pi
80
+ if [[ -f /proc/device-tree/model ]] && grep -q "Raspberry Pi" /proc/device-tree/model; then
81
+ PI_MODEL=$(tr -d '\0' < /proc/device-tree/model)
82
+ log "Detected: $PI_MODEL"
83
+ else
84
+ warn "This doesn't appear to be a Raspberry Pi"
85
+ fi
86
+
87
+ # Check OS
88
+ if [[ ! -f /etc/debian_version ]]; then
89
+ error "This script requires a Debian-based OS (Raspberry Pi OS recommended)"
90
+ fi
91
+
92
+ # Check architecture
93
+ ARCH=$(uname -m)
94
+ case $ARCH in
95
+ armv7l|armv6l)
96
+ DOCKER_ARCH="armhf"
97
+ ;;
98
+ aarch64|arm64)
99
+ DOCKER_ARCH="arm64"
100
+ ;;
101
+ x86_64)
102
+ DOCKER_ARCH="amd64"
103
+ warn "Running on x86_64, this setup is optimized for ARM"
104
+ ;;
105
+ *)
106
+ error "Unsupported architecture: $ARCH"
107
+ ;;
108
+ esac
109
+
110
+ info "Architecture: $ARCH (Docker arch: $DOCKER_ARCH)"
111
+
112
+ # Check memory
113
+ TOTAL_MEM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
114
+ TOTAL_MEM_MB=$((TOTAL_MEM_KB / 1024))
115
+ info "Total memory: ${TOTAL_MEM_MB}MB"
116
+
117
+ # Recommendations based on memory
118
+ if [[ $TOTAL_MEM_MB -lt 1024 ]]; then
119
+ warn "Low memory detected. Consider enabling swap and limiting container memory."
120
+ fi
121
+ }
122
+
123
+ # Update system
124
+ update_system() {
125
+ log "Updating system packages..."
126
+
127
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
128
+ info "DRY RUN: Would update system packages"
129
+ return
130
+ fi
131
+
132
+ sudo apt-get update
133
+ sudo apt-get upgrade -y
134
+
135
+ # Install prerequisites
136
+ sudo apt-get install -y \
137
+ apt-transport-https \
138
+ ca-certificates \
139
+ curl \
140
+ gnupg \
141
+ lsb-release \
142
+ software-properties-common \
143
+ git \
144
+ htop \
145
+ nano
146
+
147
+ log "✅ System updated"
148
+ }
149
+
150
+ # Setup memory cgroups
151
+ setup_memory_cgroups() {
152
+ if [[ "${ENABLE_MEMORY_CGROUPS}" != "true" ]]; then
153
+ info "Skipping memory cgroups setup"
154
+ return
155
+ fi
156
+
157
+ log "Setting up memory cgroups..."
158
+
159
+ local cmdline_file="/boot/cmdline.txt"
160
+ local boot_config="/boot/config.txt"
161
+
162
+ # Check if running on newer Raspberry Pi OS with /boot/firmware
163
+ if [[ -f "/boot/firmware/cmdline.txt" ]]; then
164
+ cmdline_file="/boot/firmware/cmdline.txt"
165
+ boot_config="/boot/firmware/config.txt"
166
+ fi
167
+
168
+ if [[ ! -f "$cmdline_file" ]]; then
169
+ warn "Cannot find cmdline.txt, skipping cgroups setup"
170
+ return
171
+ fi
172
+
173
+ # Check if cgroups are already enabled
174
+ if grep -q "cgroup_enable=memory" "$cmdline_file"; then
175
+ info "Memory cgroups already enabled"
176
+ else
177
+ log "Enabling memory cgroups..."
178
+
179
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
180
+ info "DRY RUN: Would enable memory cgroups in $cmdline_file"
181
+ else
182
+ # Backup original file
183
+ sudo cp "$cmdline_file" "$cmdline_file.backup.$(date +%Y%m%d_%H%M%S)"
184
+
185
+ # Add cgroup parameters
186
+ sudo sed -i '$ s/$/ cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1/' "$cmdline_file"
187
+
188
+ info "Memory cgroups enabled. Reboot required for changes to take effect."
189
+ REBOOT_REQUIRED=true
190
+ fi
191
+ fi
192
+
193
+ log "✅ Memory cgroups configured"
194
+ }
195
+
196
+ # Setup swap
197
+ setup_swap() {
198
+ if [[ "${SETUP_SWAP}" != "true" ]]; then
199
+ info "Skipping swap setup"
200
+ return
201
+ fi
202
+
203
+ log "Setting up swap file ($SWAP_SIZE)..."
204
+
205
+ # Check if swap is already active
206
+ if swapon --show | grep -q "/swapfile"; then
207
+ info "Swap file already exists and is active"
208
+ return
209
+ fi
210
+
211
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
212
+ info "DRY RUN: Would create ${SWAP_SIZE} swap file"
213
+ return
214
+ fi
215
+
216
+ # Create swap file
217
+ if [[ ! -f /swapfile ]]; then
218
+ log "Creating swap file..."
219
+ sudo fallocate -l "$SWAP_SIZE" /swapfile
220
+ sudo chmod 600 /swapfile
221
+ sudo mkswap /swapfile
222
+ fi
223
+
224
+ # Enable swap
225
+ sudo swapon /swapfile
226
+
227
+ # Add to fstab for persistence
228
+ if ! grep -q "/swapfile" /etc/fstab; then
229
+ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
230
+ fi
231
+
232
+ # Configure swappiness (how aggressively to use swap)
233
+ echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
234
+
235
+ log "✅ Swap configured: $(swapon --show)"
236
+ }
237
+
238
+ # Install Docker
239
+ install_docker() {
240
+ log "Installing Docker..."
241
+
242
+ if command -v docker &> /dev/null; then
243
+ DOCKER_VERSION=$(docker --version | cut -d' ' -f3 | sed 's/,//')
244
+ info "Docker already installed: $DOCKER_VERSION"
245
+
246
+ # Check if user is in docker group
247
+ if groups "$USER" | grep -q docker; then
248
+ info "User $USER is already in docker group"
249
+ else
250
+ log "Adding user $USER to docker group..."
251
+ if [[ "${DRY_RUN:-false}" != "true" ]]; then
252
+ sudo usermod -aG docker "$USER"
253
+ info "Please log out and log back in for group changes to take effect"
254
+ fi
255
+ fi
256
+ return
257
+ fi
258
+
259
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
260
+ info "DRY RUN: Would install Docker"
261
+ return
262
+ fi
263
+
264
+ # Install Docker using convenience script
265
+ log "Downloading Docker installation script..."
266
+ curl -fsSL https://get.docker.com -o get-docker.sh
267
+
268
+ log "Installing Docker..."
269
+ sudo sh get-docker.sh
270
+
271
+ # Add user to docker group
272
+ sudo usermod -aG docker "$USER"
273
+
274
+ # Enable and start Docker service
275
+ sudo systemctl enable docker
276
+ sudo systemctl start docker
277
+
278
+ # Cleanup
279
+ rm get-docker.sh
280
+
281
+ # Configure Docker for Raspberry Pi
282
+ configure_docker()
283
+
284
+ log "✅ Docker installed successfully"
285
+ info "Please log out and log back in for group changes to take effect"
286
+ }
287
+
288
+ # Configure Docker for Raspberry Pi
289
+ configure_docker() {
290
+ log "Configuring Docker for Raspberry Pi..."
291
+
292
+ # Create Docker daemon configuration
293
+ local docker_config="/etc/docker/daemon.json"
294
+
295
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
296
+ info "DRY RUN: Would configure Docker daemon"
297
+ return
298
+ fi
299
+
300
+ # Create Docker configuration
301
+ cat << 'EOF' | sudo tee "$docker_config"
302
+ {
303
+ "log-driver": "json-file",
304
+ "log-opts": {
305
+ "max-size": "10m",
306
+ "max-file": "3"
307
+ },
308
+ "storage-driver": "overlay2",
309
+ "default-ulimits": {
310
+ "nofile": {
311
+ "hard": 64000,
312
+ "soft": 32000
313
+ }
314
+ }
315
+ }
316
+ EOF
317
+
318
+ # Restart Docker to apply configuration
319
+ sudo systemctl restart docker
320
+
321
+ log "✅ Docker configured for Raspberry Pi"
322
+ }
323
+
324
+ # Install Docker Compose
325
+ install_docker_compose() {
326
+ log "Installing Docker Compose..."
327
+
328
+ if command -v docker-compose &> /dev/null; then
329
+ COMPOSE_VERSION=$(docker-compose --version | cut -d' ' -f4 | sed 's/,//')
330
+ info "Docker Compose already installed: $COMPOSE_VERSION"
331
+ return
332
+ fi
333
+
334
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
335
+ info "DRY RUN: Would install Docker Compose v$DOCKER_COMPOSE_VERSION"
336
+ return
337
+ fi
338
+
339
+ # Install Docker Compose
340
+ case $DOCKER_ARCH in
341
+ armhf|arm64)
342
+ # For ARM, install via pip
343
+ log "Installing Docker Compose via pip (ARM optimization)..."
344
+ sudo apt-get install -y python3-pip python3-dev libffi-dev
345
+ sudo pip3 install docker-compose=="$DOCKER_COMPOSE_VERSION"
346
+ ;;
347
+ amd64)
348
+ # For x86_64, download binary
349
+ log "Downloading Docker Compose binary..."
350
+ sudo curl -L "https://github.com/docker/compose/releases/download/v${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" \
351
+ -o /usr/local/bin/docker-compose
352
+ sudo chmod +x /usr/local/bin/docker-compose
353
+ ;;
354
+ esac
355
+
356
+ # Verify installation
357
+ docker-compose --version
358
+
359
+ log "✅ Docker Compose installed successfully"
360
+ }
361
+
362
+ # Performance optimizations
363
+ optimize_system() {
364
+ log "Applying Raspberry Pi optimizations..."
365
+
366
+ if [[ "${DRY_RUN:-false}" == "true" ]]; then
367
+ info "DRY RUN: Would apply system optimizations"
368
+ return
369
+ fi
370
+
371
+ # GPU memory split (give more RAM to system)
372
+ echo 'gpu_mem=16' | sudo tee -a /boot/config.txt
373
+
374
+ # Disable unnecessary services to save memory
375
+ sudo systemctl disable bluetooth
376
+ sudo systemctl disable hciuart
377
+
378
+ # Configure log rotation
379
+ cat << 'EOF' | sudo tee /etc/logrotate.d/docker-containers
380
+ /var/lib/docker/containers/*/*.log {
381
+ rotate 3
382
+ daily
383
+ compress
384
+ size=10M
385
+ missingok
386
+ delaycompress
387
+ copytruncate
388
+ }
389
+ EOF
390
+
391
+ log "✅ System optimizations applied"
392
+ }
393
+
394
+ # Verification
395
+ verify_installation() {
396
+ log "Verifying installation..."
397
+
398
+ # Check Docker
399
+ if ! command -v docker &> /dev/null; then
400
+ error "Docker is not installed or not in PATH"
401
+ fi
402
+
403
+ # Check Docker Compose
404
+ if ! command -v docker-compose &> /dev/null; then
405
+ error "Docker Compose is not installed or not in PATH"
406
+ fi
407
+
408
+ # Test Docker (if not dry run)
409
+ if [[ "${DRY_RUN:-false}" != "true" ]]; then
410
+ log "Testing Docker installation..."
411
+ if ! docker run --rm hello-world &> /dev/null; then
412
+ warn "Docker test failed. You may need to log out and log back in."
413
+ else
414
+ log "Docker test successful"
415
+ fi
416
+ fi
417
+
418
+ log "✅ Installation verified"
419
+ }
420
+
421
+ # Summary and next steps
422
+ show_summary() {
423
+ log "🎉 Setup completed successfully!"
424
+
425
+ echo
426
+ info "Installation Summary:"
427
+ echo " • Docker: $(docker --version 2>/dev/null || echo 'Installed')"
428
+ echo " • Docker Compose: $(docker-compose --version 2>/dev/null || echo 'Installed')"
429
+ echo " • Memory cgroups: $(grep -q 'cgroup_enable=memory' /boot/cmdline.txt 2>/dev/null && echo 'Enabled' || echo 'Disabled')"
430
+ echo " • Swap: $(swapon --show | grep -q '/swapfile' && echo 'Enabled' || echo 'Disabled')"
431
+
432
+ echo
433
+ log "Next steps:"
434
+ echo " 1. Log out and log back in to apply group changes"
435
+ if [[ "${REBOOT_REQUIRED:-false}" == "true" ]]; then
436
+ echo " 2. Reboot to enable memory cgroups: sudo reboot"
437
+ echo " 3. After reboot, deploy MCP Rubber Duck:"
438
+ else
439
+ echo " 2. Deploy MCP Rubber Duck:"
440
+ fi
441
+ echo " ./scripts/deploy-raspbian.sh"
442
+ echo " 4. Edit .env file with your API keys"
443
+ echo " 5. Monitor with: docker stats"
444
+
445
+ echo
446
+ log "Useful commands:"
447
+ echo " • Check Docker status: sudo systemctl status docker"
448
+ echo " • View Docker logs: sudo journalctl -u docker.service"
449
+ echo " • Monitor resources: htop"
450
+ echo " • Check memory: free -h"
451
+ echo " • Check swap: swapon --show"
452
+ }
453
+
454
+ # Parse command line arguments
455
+ while [[ $# -gt 0 ]]; do
456
+ case $1 in
457
+ --no-swap)
458
+ SETUP_SWAP="false"
459
+ shift
460
+ ;;
461
+ --swap-size)
462
+ SWAP_SIZE="$2"
463
+ shift 2
464
+ ;;
465
+ --no-memory-cgroups)
466
+ ENABLE_MEMORY_CGROUPS="false"
467
+ shift
468
+ ;;
469
+ --docker-compose-version)
470
+ DOCKER_COMPOSE_VERSION="$2"
471
+ shift 2
472
+ ;;
473
+ --dry-run)
474
+ DRY_RUN="true"
475
+ shift
476
+ ;;
477
+ -y|--yes)
478
+ ASSUME_YES="true"
479
+ shift
480
+ ;;
481
+ -h|--help)
482
+ print_usage
483
+ exit 0
484
+ ;;
485
+ *)
486
+ error "Unknown option: $1"
487
+ ;;
488
+ esac
489
+ done
490
+
491
+ # Check if running as root
492
+ if [[ $EUID -eq 0 ]]; then
493
+ error "This script should not be run as root. Run as your regular user."
494
+ fi
495
+
496
+ # Check for sudo access
497
+ if ! sudo -n true 2>/dev/null; then
498
+ error "This script requires sudo access. Please ensure you can run sudo commands."
499
+ fi
500
+
501
+ # Confirmation prompt
502
+ if [[ "${ASSUME_YES:-false}" != "true" && "${DRY_RUN:-false}" != "true" ]]; then
503
+ echo "This script will:"
504
+ echo " • Update system packages"
505
+ echo " • Install Docker and Docker Compose"
506
+ echo " • Configure memory cgroups (requires reboot)"
507
+ echo " • Setup swap file ($SWAP_SIZE)"
508
+ echo " • Apply Raspberry Pi optimizations"
509
+ echo
510
+ read -p "Continue? (y/N): " -r
511
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
512
+ log "Setup cancelled by user"
513
+ exit 0
514
+ fi
515
+ fi
516
+
517
+ # Main execution
518
+ log "Starting Raspberry Pi Docker setup for MCP Rubber Duck"
519
+
520
+ detect_system
521
+ update_system
522
+ setup_memory_cgroups
523
+ setup_swap
524
+ install_docker
525
+ install_docker_compose
526
+ optimize_system
527
+ verify_installation
528
+ show_summary
529
+
530
+ log "🚀 Setup completed! Happy ducking! 🦆"
package/server.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "io.github.nesquikm.rubber-duck",
3
+ "version": "1.0.0",
4
+ "description": "An MCP server that bridges to multiple OpenAI-compatible LLMs - your AI rubber duck debugging panel",
5
+ "packages": {
6
+ "npm": "mcp-rubber-duck"
7
+ }
8
+ }