rms-devremote 3.0.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 (68) hide show
  1. package/README.md +154 -0
  2. package/dist/commands/attach.d.ts +2 -0
  3. package/dist/commands/attach.js +10 -0
  4. package/dist/commands/check.d.ts +2 -0
  5. package/dist/commands/check.js +210 -0
  6. package/dist/commands/clean.d.ts +2 -0
  7. package/dist/commands/clean.js +177 -0
  8. package/dist/commands/dashboard.d.ts +2 -0
  9. package/dist/commands/dashboard.js +57 -0
  10. package/dist/commands/link.d.ts +2 -0
  11. package/dist/commands/link.js +112 -0
  12. package/dist/commands/ping.d.ts +2 -0
  13. package/dist/commands/ping.js +21 -0
  14. package/dist/commands/setup.d.ts +2 -0
  15. package/dist/commands/setup.js +54 -0
  16. package/dist/commands/status.d.ts +2 -0
  17. package/dist/commands/status.js +65 -0
  18. package/dist/commands/unlink.d.ts +2 -0
  19. package/dist/commands/unlink.js +53 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +55 -0
  22. package/dist/server/auth.d.ts +6 -0
  23. package/dist/server/auth.js +32 -0
  24. package/dist/server/frontend.d.ts +4 -0
  25. package/dist/server/frontend.js +886 -0
  26. package/dist/server/index.d.ts +1 -0
  27. package/dist/server/index.js +283 -0
  28. package/dist/server/terminal.d.ts +14 -0
  29. package/dist/server/terminal.js +43 -0
  30. package/dist/services/battery-worker.d.ts +1 -0
  31. package/dist/services/battery-worker.js +2 -0
  32. package/dist/services/battery.d.ts +27 -0
  33. package/dist/services/battery.js +152 -0
  34. package/dist/services/config.d.ts +63 -0
  35. package/dist/services/config.js +84 -0
  36. package/dist/services/docker.d.ts +25 -0
  37. package/dist/services/docker.js +75 -0
  38. package/dist/services/hooks.d.ts +15 -0
  39. package/dist/services/hooks.js +111 -0
  40. package/dist/services/ntfy.d.ts +19 -0
  41. package/dist/services/ntfy.js +63 -0
  42. package/dist/services/process.d.ts +30 -0
  43. package/dist/services/process.js +90 -0
  44. package/dist/services/proxy-worker.d.ts +1 -0
  45. package/dist/services/proxy-worker.js +12 -0
  46. package/dist/services/proxy.d.ts +4 -0
  47. package/dist/services/proxy.js +195 -0
  48. package/dist/services/shell.d.ts +22 -0
  49. package/dist/services/shell.js +47 -0
  50. package/dist/services/tmux.d.ts +30 -0
  51. package/dist/services/tmux.js +74 -0
  52. package/dist/services/ttyd.d.ts +28 -0
  53. package/dist/services/ttyd.js +71 -0
  54. package/dist/setup-server/routes.d.ts +4 -0
  55. package/dist/setup-server/routes.js +177 -0
  56. package/dist/setup-server/server.d.ts +4 -0
  57. package/dist/setup-server/server.js +32 -0
  58. package/docker/docker-compose.yml +24 -0
  59. package/docker/ntfy/server.yml +6 -0
  60. package/package.json +61 -0
  61. package/scripts/claude-remote.sh +583 -0
  62. package/scripts/hooks/notify.sh +68 -0
  63. package/scripts/notify.sh +54 -0
  64. package/scripts/startup.sh +29 -0
  65. package/scripts/update-check.sh +25 -0
  66. package/src/setup-server/public/index.html +21 -0
  67. package/src/setup-server/public/setup.css +475 -0
  68. package/src/setup-server/public/setup.js +687 -0
@@ -0,0 +1,54 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ EVENT="${1:-}"
5
+ STDIN_JSON=""
6
+ if [ ! -t 0 ]; then
7
+ STDIN_JSON="$(cat)"
8
+ fi
9
+
10
+ # Load config
11
+ source ~/.rms-devremote/.env
12
+
13
+ send_notification() {
14
+ local body="$1"
15
+ local priority="${2:-default}"
16
+ curl -s \
17
+ -u "admin:${NTFY_ADMIN_PASSWORD}" \
18
+ -H "Title: rms-devremote" \
19
+ -H "Priority: ${priority}" \
20
+ -H "Click: https://${TERMINAL_DOMAIN}" \
21
+ -d "${body}" \
22
+ "http://localhost:${NTFY_PORT:-2586}/${NTFY_TOPIC}" > /dev/null 2>&1 || true
23
+ }
24
+
25
+ case "$EVENT" in
26
+ tool-use)
27
+ TOOL_NAME="unknown"
28
+ if [ -n "$STDIN_JSON" ] && command -v jq &> /dev/null; then
29
+ TOOL_NAME=$(echo "$STDIN_JSON" | jq -r '.tool_name // "unknown"')
30
+ fi
31
+ send_notification "Claude veut utiliser: ${TOOL_NAME}" "high"
32
+ ;;
33
+ notification)
34
+ MSG=""
35
+ if [ -n "$STDIN_JSON" ] && command -v jq &> /dev/null; then
36
+ MSG=$(echo "$STDIN_JSON" | jq -r '.message // ""')
37
+ fi
38
+ send_notification "Claude: ${MSG}" "high"
39
+ ;;
40
+ stop)
41
+ EXIT_CODE="0"
42
+ if [ -n "$STDIN_JSON" ] && command -v jq &> /dev/null; then
43
+ EXIT_CODE=$(echo "$STDIN_JSON" | jq -r '.exit_code // "0"')
44
+ fi
45
+ if [ "$EXIT_CODE" = "0" ]; then
46
+ send_notification "Claude a termine" "default"
47
+ else
48
+ send_notification "Erreur Claude (code: ${EXIT_CODE})" "urgent"
49
+ fi
50
+ ;;
51
+ test)
52
+ send_notification "Test rms-devremote -- les notifications marchent !" "default"
53
+ ;;
54
+ esac
@@ -0,0 +1,29 @@
1
+ #!/bin/bash
2
+ # Startup wrapper: setup hooks, update Claude Code, then launch code-server
3
+ set -e
4
+
5
+ # Merge hooks into Claude Code settings (only inside container)
6
+ HOOKS_FILE="/home/coder/scripts/../hooks.json"
7
+ CLAUDE_SETTINGS="/home/coder/.claude/settings.json"
8
+
9
+ if [ -f "/home/coder/hooks.json" ]; then
10
+ HOOKS_FILE="/home/coder/hooks.json"
11
+ fi
12
+
13
+ if [ -f "$HOOKS_FILE" ] && command -v jq &> /dev/null; then
14
+ if [ -f "$CLAUDE_SETTINGS" ]; then
15
+ # Merge hooks into existing settings
16
+ TMP=$(mktemp)
17
+ jq -s '.[0] * .[1]' "$CLAUDE_SETTINGS" "$HOOKS_FILE" > "$TMP" && mv "$TMP" "$CLAUDE_SETTINGS"
18
+ else
19
+ mkdir -p "$(dirname "$CLAUDE_SETTINGS")"
20
+ cp "$HOOKS_FILE" "$CLAUDE_SETTINGS"
21
+ fi
22
+ echo "[claude-remote] Hooks configured"
23
+ fi
24
+
25
+ # Run update check (non-fatal)
26
+ /usr/local/bin/update-claude-code.sh || true
27
+
28
+ # Launch code-server with original entrypoint behavior
29
+ exec dumb-init fixuid -q /usr/bin/code-server "$@"
@@ -0,0 +1,25 @@
1
+ #!/bin/bash
2
+ # Runs at container startup via Dockerfile ENTRYPOINT wrapper
3
+ # Checks if a newer version of Claude Code is available and updates if so
4
+ # Falls back gracefully if npm registry is unreachable
5
+
6
+ set -euo pipefail
7
+
8
+ PACKAGE="@anthropic-ai/claude-code"
9
+
10
+ echo "[claude-remote] Checking for Claude Code updates..."
11
+
12
+ CURRENT=$(npm list -g "$PACKAGE" --depth=0 2>/dev/null | grep "$PACKAGE" | sed 's/.*@//' || echo "none")
13
+ LATEST=$(npm view "$PACKAGE" version 2>/dev/null || echo "unknown")
14
+
15
+ if [ "$LATEST" = "unknown" ]; then
16
+ echo "[claude-remote] Cannot reach npm registry, skipping update check"
17
+ elif [ "$CURRENT" = "none" ]; then
18
+ echo "[claude-remote] Claude Code not found, installing..."
19
+ npm install -g "$PACKAGE"
20
+ elif [ "$CURRENT" != "$LATEST" ]; then
21
+ echo "[claude-remote] Updating Claude Code: $CURRENT -> $LATEST"
22
+ npm install -g "$PACKAGE"
23
+ else
24
+ echo "[claude-remote] Claude Code is up to date ($CURRENT)"
25
+ fi
@@ -0,0 +1,21 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>RMS DevRemote — Setup</title>
7
+ <link rel="stylesheet" href="setup.css">
8
+ </head>
9
+ <body>
10
+ <div class="header">
11
+ <h1>RMS DevRemote</h1>
12
+ <p>Assistant de configuration</p>
13
+ </div>
14
+
15
+ <div class="step-indicator" id="step-indicator"></div>
16
+
17
+ <div id="step-container"></div>
18
+
19
+ <script src="setup.js"></script>
20
+ </body>
21
+ </html>
@@ -0,0 +1,475 @@
1
+ /* ============================================================
2
+ RMS DevRemote — Setup Wizard — Dark Terminal Theme
3
+ ============================================================ */
4
+
5
+ *, *::before, *::after {
6
+ box-sizing: border-box;
7
+ margin: 0;
8
+ padding: 0;
9
+ }
10
+
11
+ :root {
12
+ --bg: #0f0f23;
13
+ --card-bg: #1a1a2e;
14
+ --card-border: #2a2a4e;
15
+ --accent: #00d4aa;
16
+ --danger: #e94560;
17
+ --text: #e0e0f0;
18
+ --text-muted: #8888aa;
19
+ --input-bg: #12122a;
20
+ --input-border:#333366;
21
+ --btn-bg: #00d4aa;
22
+ --btn-text: #0f0f23;
23
+ --step-done: #00d4aa;
24
+ --step-active: #e94560;
25
+ --step-idle: #333366;
26
+ }
27
+
28
+ html, body {
29
+ height: 100%;
30
+ }
31
+
32
+ body {
33
+ background: var(--bg);
34
+ color: var(--text);
35
+ font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
36
+ font-size: 14px;
37
+ line-height: 1.6;
38
+ min-height: 100vh;
39
+ display: flex;
40
+ flex-direction: column;
41
+ align-items: center;
42
+ padding: 24px 16px 48px;
43
+ }
44
+
45
+ /* ============================================================
46
+ Header
47
+ ============================================================ */
48
+ .header {
49
+ text-align: center;
50
+ margin-bottom: 32px;
51
+ }
52
+
53
+ .header h1 {
54
+ font-size: 1.6rem;
55
+ font-weight: 700;
56
+ color: var(--accent);
57
+ letter-spacing: 2px;
58
+ text-transform: uppercase;
59
+ }
60
+
61
+ .header p {
62
+ color: var(--text-muted);
63
+ font-size: 0.85rem;
64
+ margin-top: 4px;
65
+ }
66
+
67
+ /* ============================================================
68
+ Step indicator
69
+ ============================================================ */
70
+ .step-indicator {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ gap: 0;
75
+ margin-bottom: 32px;
76
+ flex-wrap: wrap;
77
+ row-gap: 8px;
78
+ }
79
+
80
+ .step-dot {
81
+ width: 28px;
82
+ height: 28px;
83
+ border-radius: 50%;
84
+ background: var(--step-idle);
85
+ border: 2px solid transparent;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ font-size: 11px;
90
+ font-weight: 700;
91
+ color: var(--text-muted);
92
+ transition: background 0.3s, color 0.3s, border-color 0.3s;
93
+ flex-shrink: 0;
94
+ }
95
+
96
+ .step-dot.done {
97
+ background: var(--step-done);
98
+ color: var(--bg);
99
+ }
100
+
101
+ .step-dot.active {
102
+ background: var(--card-bg);
103
+ border-color: var(--step-active);
104
+ color: var(--step-active);
105
+ }
106
+
107
+ .step-line {
108
+ width: 24px;
109
+ height: 2px;
110
+ background: var(--step-idle);
111
+ transition: background 0.3s;
112
+ flex-shrink: 0;
113
+ }
114
+
115
+ .step-line.done {
116
+ background: var(--step-done);
117
+ }
118
+
119
+ /* ============================================================
120
+ Card
121
+ ============================================================ */
122
+ .card {
123
+ background: var(--card-bg);
124
+ border: 1px solid var(--card-border);
125
+ border-radius: 12px;
126
+ padding: 28px 24px;
127
+ width: 100%;
128
+ max-width: 620px;
129
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
130
+ }
131
+
132
+ .card h2 {
133
+ font-size: 1.1rem;
134
+ font-weight: 700;
135
+ color: var(--accent);
136
+ margin-bottom: 6px;
137
+ letter-spacing: 1px;
138
+ }
139
+
140
+ .card .subtitle {
141
+ color: var(--text-muted);
142
+ font-size: 0.82rem;
143
+ margin-bottom: 20px;
144
+ }
145
+
146
+ /* ============================================================
147
+ Form elements
148
+ ============================================================ */
149
+ .field {
150
+ margin-bottom: 16px;
151
+ }
152
+
153
+ .field label {
154
+ display: block;
155
+ font-size: 0.8rem;
156
+ color: var(--text-muted);
157
+ margin-bottom: 6px;
158
+ letter-spacing: 0.5px;
159
+ }
160
+
161
+ .field input {
162
+ width: 100%;
163
+ background: var(--input-bg);
164
+ border: 1px solid var(--input-border);
165
+ border-radius: 6px;
166
+ color: var(--text);
167
+ font-family: inherit;
168
+ font-size: 0.9rem;
169
+ padding: 9px 12px;
170
+ outline: none;
171
+ transition: border-color 0.2s;
172
+ }
173
+
174
+ .field input:focus {
175
+ border-color: var(--accent);
176
+ }
177
+
178
+ .field input::placeholder {
179
+ color: var(--text-muted);
180
+ opacity: 0.6;
181
+ }
182
+
183
+ /* PIN input group */
184
+ .pin-group {
185
+ display: flex;
186
+ gap: 10px;
187
+ justify-content: center;
188
+ margin: 12px 0;
189
+ }
190
+
191
+ .pin-group input {
192
+ width: 46px;
193
+ height: 54px;
194
+ text-align: center;
195
+ font-size: 1.4rem;
196
+ font-weight: 700;
197
+ background: var(--input-bg);
198
+ border: 1px solid var(--input-border);
199
+ border-radius: 8px;
200
+ color: var(--text);
201
+ font-family: inherit;
202
+ outline: none;
203
+ transition: border-color 0.2s;
204
+ }
205
+
206
+ .pin-group input:focus {
207
+ border-color: var(--accent);
208
+ }
209
+
210
+ /* Input with inline button */
211
+ .input-row {
212
+ display: flex;
213
+ gap: 8px;
214
+ }
215
+
216
+ .input-row input {
217
+ flex: 1;
218
+ }
219
+
220
+ /* ============================================================
221
+ Buttons
222
+ ============================================================ */
223
+ .btn {
224
+ display: inline-flex;
225
+ align-items: center;
226
+ gap: 6px;
227
+ background: var(--btn-bg);
228
+ color: var(--btn-text);
229
+ border: none;
230
+ border-radius: 6px;
231
+ font-family: inherit;
232
+ font-size: 0.88rem;
233
+ font-weight: 700;
234
+ padding: 9px 18px;
235
+ cursor: pointer;
236
+ transition: opacity 0.2s, transform 0.1s;
237
+ letter-spacing: 0.5px;
238
+ }
239
+
240
+ .btn:hover {
241
+ opacity: 0.88;
242
+ }
243
+
244
+ .btn:active {
245
+ transform: scale(0.97);
246
+ }
247
+
248
+ .btn.secondary {
249
+ background: var(--card-border);
250
+ color: var(--text);
251
+ }
252
+
253
+ .btn.danger {
254
+ background: var(--danger);
255
+ color: #fff;
256
+ }
257
+
258
+ .btn.small {
259
+ font-size: 0.75rem;
260
+ padding: 4px 10px;
261
+ }
262
+
263
+ .btn:disabled {
264
+ opacity: 0.4;
265
+ cursor: not-allowed;
266
+ }
267
+
268
+ /* ============================================================
269
+ Prereq checklist
270
+ ============================================================ */
271
+ .prereq-list {
272
+ list-style: none;
273
+ margin: 16px 0;
274
+ }
275
+
276
+ .prereq-list li {
277
+ display: flex;
278
+ align-items: center;
279
+ gap: 12px;
280
+ padding: 8px 0;
281
+ border-bottom: 1px solid var(--card-border);
282
+ font-size: 0.88rem;
283
+ }
284
+
285
+ .prereq-list li:last-child {
286
+ border-bottom: none;
287
+ }
288
+
289
+ .prereq-icon {
290
+ font-size: 1rem;
291
+ width: 20px;
292
+ text-align: center;
293
+ }
294
+
295
+ .prereq-icon.ok { color: var(--accent); }
296
+ .prereq-icon.fail { color: var(--danger); }
297
+ .prereq-icon.pending { color: var(--text-muted); }
298
+
299
+ /* ============================================================
300
+ Info block / Credentials
301
+ ============================================================ */
302
+ .info-block {
303
+ background: var(--input-bg);
304
+ border: 1px solid var(--input-border);
305
+ border-radius: 8px;
306
+ padding: 14px 16px;
307
+ margin: 12px 0;
308
+ }
309
+
310
+ .info-block .info-row {
311
+ display: flex;
312
+ align-items: center;
313
+ justify-content: space-between;
314
+ gap: 12px;
315
+ padding: 5px 0;
316
+ font-size: 0.85rem;
317
+ }
318
+
319
+ .info-block .info-label {
320
+ color: var(--text-muted);
321
+ font-size: 0.78rem;
322
+ flex-shrink: 0;
323
+ }
324
+
325
+ .info-block .info-value {
326
+ font-family: monospace;
327
+ color: var(--text);
328
+ word-break: break-all;
329
+ flex: 1;
330
+ text-align: right;
331
+ }
332
+
333
+ /* ============================================================
334
+ Progress / WebSocket status
335
+ ============================================================ */
336
+ .progress-wrap {
337
+ margin: 20px 0;
338
+ }
339
+
340
+ .progress-bar-track {
341
+ background: var(--input-bg);
342
+ border-radius: 999px;
343
+ height: 6px;
344
+ overflow: hidden;
345
+ margin-bottom: 10px;
346
+ }
347
+
348
+ .progress-bar-fill {
349
+ height: 100%;
350
+ background: var(--accent);
351
+ border-radius: 999px;
352
+ transition: width 0.4s ease;
353
+ width: 0%;
354
+ }
355
+
356
+ .progress-log {
357
+ background: var(--input-bg);
358
+ border: 1px solid var(--input-border);
359
+ border-radius: 6px;
360
+ padding: 12px;
361
+ font-size: 0.8rem;
362
+ min-height: 80px;
363
+ color: var(--text-muted);
364
+ white-space: pre-wrap;
365
+ word-break: break-all;
366
+ }
367
+
368
+ .progress-log .log-line {
369
+ display: block;
370
+ margin-bottom: 3px;
371
+ }
372
+
373
+ .progress-log .log-line.ok { color: var(--accent); }
374
+ .progress-log .log-line.err { color: var(--danger); }
375
+
376
+ /* ============================================================
377
+ Instructions block
378
+ ============================================================ */
379
+ .instructions {
380
+ background: var(--input-bg);
381
+ border-left: 3px solid var(--accent);
382
+ border-radius: 0 6px 6px 0;
383
+ padding: 12px 14px;
384
+ margin: 12px 0;
385
+ font-size: 0.83rem;
386
+ color: var(--text-muted);
387
+ line-height: 1.8;
388
+ }
389
+
390
+ .instructions a {
391
+ color: var(--accent);
392
+ }
393
+
394
+ /* ============================================================
395
+ Navigation buttons row
396
+ ============================================================ */
397
+ .nav-row {
398
+ display: flex;
399
+ justify-content: space-between;
400
+ align-items: center;
401
+ margin-top: 24px;
402
+ gap: 12px;
403
+ }
404
+
405
+ /* ============================================================
406
+ Alert / Banner
407
+ ============================================================ */
408
+ .alert {
409
+ padding: 10px 14px;
410
+ border-radius: 6px;
411
+ font-size: 0.83rem;
412
+ margin: 12px 0;
413
+ }
414
+
415
+ .alert.success {
416
+ background: rgba(0, 212, 170, 0.12);
417
+ border: 1px solid var(--accent);
418
+ color: var(--accent);
419
+ }
420
+
421
+ .alert.error {
422
+ background: rgba(233, 69, 96, 0.12);
423
+ border: 1px solid var(--danger);
424
+ color: var(--danger);
425
+ }
426
+
427
+ /* ============================================================
428
+ Summary step
429
+ ============================================================ */
430
+ .summary-section {
431
+ margin-bottom: 18px;
432
+ }
433
+
434
+ .summary-section h3 {
435
+ font-size: 0.78rem;
436
+ text-transform: uppercase;
437
+ letter-spacing: 1px;
438
+ color: var(--text-muted);
439
+ margin-bottom: 8px;
440
+ }
441
+
442
+ /* ============================================================
443
+ Responsive
444
+ ============================================================ */
445
+ @media (max-width: 480px) {
446
+ .card {
447
+ padding: 20px 14px;
448
+ border-radius: 10px;
449
+ }
450
+
451
+ .step-line {
452
+ width: 12px;
453
+ }
454
+
455
+ .step-dot {
456
+ width: 24px;
457
+ height: 24px;
458
+ font-size: 10px;
459
+ }
460
+
461
+ .pin-group input {
462
+ width: 38px;
463
+ height: 46px;
464
+ font-size: 1.2rem;
465
+ }
466
+
467
+ .nav-row {
468
+ flex-direction: column-reverse;
469
+ }
470
+
471
+ .btn {
472
+ width: 100%;
473
+ justify-content: center;
474
+ }
475
+ }