247-cli 2.0.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/dist/db/index.d.ts.map +1 -1
- package/agent/dist/db/index.js +26 -0
- package/agent/dist/db/index.js.map +1 -1
- package/agent/dist/db/push-subscriptions.d.ts +44 -0
- package/agent/dist/db/push-subscriptions.d.ts.map +1 -0
- package/agent/dist/db/push-subscriptions.js +98 -0
- package/agent/dist/db/push-subscriptions.js.map +1 -0
- package/agent/dist/db/schema.d.ts +2 -2
- package/agent/dist/db/schema.d.ts.map +1 -1
- package/agent/dist/db/schema.js +13 -1
- package/agent/dist/db/schema.js.map +1 -1
- package/agent/dist/lib/init-script.d.ts.map +1 -1
- package/agent/dist/lib/init-script.js +198 -92
- package/agent/dist/lib/init-script.js.map +1 -1
- package/agent/dist/push/sender.d.ts +26 -0
- package/agent/dist/push/sender.d.ts.map +1 -0
- package/agent/dist/push/sender.js +122 -0
- package/agent/dist/push/sender.js.map +1 -0
- package/agent/dist/push/vapid.d.ts +25 -0
- package/agent/dist/push/vapid.d.ts.map +1 -0
- package/agent/dist/push/vapid.js +81 -0
- package/agent/dist/push/vapid.js.map +1 -0
- package/agent/dist/routes/push.d.ts +7 -0
- package/agent/dist/routes/push.d.ts.map +1 -0
- package/agent/dist/routes/push.js +98 -0
- package/agent/dist/routes/push.js.map +1 -0
- package/agent/dist/server.d.ts.map +1 -1
- package/agent/dist/server.js +5 -0
- package/agent/dist/server.js.map +1 -1
- package/agent/dist/status.d.ts.map +1 -1
- package/agent/dist/status.js +17 -8
- package/agent/dist/status.js.map +1 -1
- package/agent/node_modules/247-shared/package.json +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -149,104 +149,187 @@ alias gco='git checkout'
|
|
|
149
149
|
alias ll='ls -lah'
|
|
150
150
|
alias ..='cd ..'
|
|
151
151
|
alias ...='cd ../..'`;
|
|
152
|
-
// Animated
|
|
152
|
+
// Animated robot boot loader with starfield
|
|
153
153
|
// Skip animation in CI/test environments for faster startup
|
|
154
154
|
const loaderAnimation = `
|
|
155
155
|
# ═══════════════════════════════════════════════════════════════
|
|
156
|
-
# Animated Loader:
|
|
156
|
+
# Animated Loader: Robot AI boot sequence with starfield
|
|
157
157
|
# ═══════════════════════════════════════════════════════════════
|
|
158
158
|
|
|
159
|
-
# ANSI color codes
|
|
159
|
+
# ANSI color codes
|
|
160
160
|
C_RESET=$'\\033[0m'
|
|
161
161
|
C_ORANGE=$'\\033[38;5;${colors.orange}m'
|
|
162
162
|
C_GREEN=$'\\033[38;5;${colors.green}m'
|
|
163
163
|
C_CYAN=$'\\033[38;5;${colors.cyan}m'
|
|
164
164
|
C_MUTED=$'\\033[38;5;${colors.muted}m'
|
|
165
165
|
C_WHITE=$'\\033[38;5;${colors.white}m'
|
|
166
|
+
C_MAGENTA=$'\\033[38;5;${colors.magenta}m'
|
|
166
167
|
C_BOLD=$'\\033[1m'
|
|
167
168
|
C_DIM=$'\\033[2m'
|
|
168
169
|
|
|
169
170
|
# Skip animation in CI/test environments (set by terminal.ts)
|
|
170
171
|
if [ -n "$_247_SKIP_ANIMATION" ]; then
|
|
171
|
-
# Quick non-animated version for tests
|
|
172
172
|
: # No output, go straight to welcome message
|
|
173
173
|
else
|
|
174
174
|
|
|
175
175
|
# Hide cursor during animation
|
|
176
176
|
printf "\\033[?25l"
|
|
177
|
-
|
|
178
|
-
# Clear screen
|
|
179
177
|
clear
|
|
180
178
|
|
|
181
|
-
#
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
#
|
|
186
|
-
|
|
187
|
-
#
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
printf "
|
|
211
|
-
printf "\\033[38;5;${colors.
|
|
212
|
-
printf "
|
|
213
|
-
printf "\\033[38;5;${colors.
|
|
214
|
-
|
|
215
|
-
printf "
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
179
|
+
# Terminal dimensions
|
|
180
|
+
COLS=$(tput cols 2>/dev/null || echo 80)
|
|
181
|
+
ROWS=$(tput lines 2>/dev/null || echo 24)
|
|
182
|
+
|
|
183
|
+
# ─────────────────────────────────────────────────────────────
|
|
184
|
+
# MOBILE FALLBACK: Simplified animation for narrow terminals
|
|
185
|
+
# ─────────────────────────────────────────────────────────────
|
|
186
|
+
if [ "$COLS" -lt 60 ]; then
|
|
187
|
+
# Simple centered animation for mobile
|
|
188
|
+
cx=$((COLS / 2 - 3))
|
|
189
|
+
|
|
190
|
+
printf "\\n\\n"
|
|
191
|
+
printf "%*s\\033[38;5;${colors.orange}m\\033[1m247\\033[0m\\n" "$cx" ""
|
|
192
|
+
printf "\\n"
|
|
193
|
+
printf "%*s\\033[38;5;${colors.muted}m┌───┐\\033[0m\\n" "$((cx-1))" ""
|
|
194
|
+
printf "%*s\\033[38;5;${colors.muted}m│\\033[38;5;${colors.cyan}m- -\\033[38;5;${colors.muted}m│\\033[0m\\n" "$((cx-1))" ""
|
|
195
|
+
printf "%*s\\033[38;5;${colors.muted}m└───┘\\033[0m\\n" "$((cx-1))" ""
|
|
196
|
+
sleep 0.3
|
|
197
|
+
|
|
198
|
+
# Wake up
|
|
199
|
+
printf "\\033[5;$((cx-1))H\\033[38;5;${colors.white}m┌───┐\\033[0m"
|
|
200
|
+
printf "\\033[6;$((cx-1))H\\033[38;5;${colors.white}m│\\033[38;5;${colors.cyan}m◕ ◕\\033[38;5;${colors.white}m│\\033[0m"
|
|
201
|
+
printf "\\033[7;$((cx-1))H\\033[38;5;${colors.white}m└───┘\\033[0m"
|
|
202
|
+
sleep 0.4
|
|
203
|
+
|
|
204
|
+
# Progress - simple version for mobile
|
|
205
|
+
for p in 25 50 75 100; do
|
|
206
|
+
filled=$((p / 10))
|
|
207
|
+
empty=$((10 - filled))
|
|
208
|
+
printf "\\033[9;$((cx-5))H\\033[K"
|
|
209
|
+
printf "\\033[38;5;${colors.orange}m"
|
|
210
|
+
j=0; while [ $j -lt $filled ]; do printf "█"; j=$((j+1)); done
|
|
211
|
+
printf "\\033[38;5;${colors.muted}m"
|
|
212
|
+
j=0; while [ $j -lt $empty ]; do printf "░"; j=$((j+1)); done
|
|
213
|
+
printf "\\033[0m %d%%" "$p"
|
|
214
|
+
sleep 0.2
|
|
215
|
+
done
|
|
216
|
+
|
|
217
|
+
sleep 0.3
|
|
218
|
+
printf "\\033[?25h"
|
|
219
|
+
clear
|
|
220
|
+
else
|
|
221
|
+
|
|
222
|
+
# ─────────────────────────────────────────────────────────────
|
|
223
|
+
# STARFIELD: Twinkling stars background
|
|
224
|
+
# ─────────────────────────────────────────────────────────────
|
|
225
|
+
declare -a STAR_X STAR_Y STAR_CHAR
|
|
226
|
+
STAR_CHARS=("." "·" "+" "*" "✦" "✧")
|
|
227
|
+
NUM_STARS=25
|
|
228
|
+
|
|
229
|
+
init_stars() {
|
|
230
|
+
for i in $(seq 0 $((NUM_STARS - 1))); do
|
|
231
|
+
STAR_X[$i]=$((RANDOM % (COLS - 2) + 1))
|
|
232
|
+
STAR_Y[$i]=$((RANDOM % (ROWS - 6) + 1))
|
|
233
|
+
STAR_CHAR[$i]=\${STAR_CHARS[$((RANDOM % \${#STAR_CHARS[@]}))]}
|
|
234
|
+
done
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
draw_stars() {
|
|
238
|
+
local frame=$1
|
|
239
|
+
for i in $(seq 0 $((NUM_STARS - 1))); do
|
|
240
|
+
local x=\${STAR_X[$i]}
|
|
241
|
+
local y=\${STAR_Y[$i]}
|
|
242
|
+
local char_idx=$(( (frame + i) % \${#STAR_CHARS[@]} ))
|
|
243
|
+
local char=\${STAR_CHARS[$char_idx]}
|
|
244
|
+
# Twinkle effect: some stars dim/bright
|
|
245
|
+
if [ $(( (frame + i) % 3 )) -eq 0 ]; then
|
|
246
|
+
printf "\\033[\${y};\${x}H\\033[38;5;${colors.muted}m$char\\033[0m"
|
|
223
247
|
else
|
|
224
|
-
printf "\\033[
|
|
248
|
+
printf "\\033[\${y};\${x}H\\033[38;5;${colors.white}m$char\\033[0m"
|
|
225
249
|
fi
|
|
250
|
+
done
|
|
251
|
+
}
|
|
226
252
|
|
|
227
|
-
|
|
228
|
-
|
|
253
|
+
# ─────────────────────────────────────────────────────────────
|
|
254
|
+
# ROBOT: Cute AI robot with expressions
|
|
255
|
+
# ─────────────────────────────────────────────────────────────
|
|
256
|
+
draw_robot() {
|
|
257
|
+
local state=$1 # boot, think, happy
|
|
258
|
+
local cx=$((COLS / 2 - 4))
|
|
259
|
+
local cy=8
|
|
260
|
+
|
|
261
|
+
# Clear robot area
|
|
262
|
+
for row in $(seq $cy $((cy + 5))); do
|
|
263
|
+
printf "\\033[$row;$((cx-2))H "
|
|
229
264
|
done
|
|
230
265
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
266
|
+
case $state in
|
|
267
|
+
boot)
|
|
268
|
+
printf "\\033[$cy;\${cx}H\\033[38;5;${colors.muted}m ┌───┐\\033[0m"
|
|
269
|
+
printf "\\033[$((cy+1));\${cx}H\\033[38;5;${colors.muted}m │\\033[38;5;${colors.cyan}m- -\\033[38;5;${colors.muted}m│\\033[0m"
|
|
270
|
+
printf "\\033[$((cy+2));\${cx}H\\033[38;5;${colors.muted}m │ \\033[38;5;${colors.white}m▽\\033[38;5;${colors.muted}m │\\033[0m"
|
|
271
|
+
printf "\\033[$((cy+3));\${cx}H\\033[38;5;${colors.muted}m └─┬─┘\\033[0m"
|
|
272
|
+
printf "\\033[$((cy+4));\${cx}H\\033[38;5;${colors.muted}m /|\\\\\\033[0m"
|
|
273
|
+
;;
|
|
274
|
+
think)
|
|
275
|
+
printf "\\033[$cy;\${cx}H\\033[38;5;${colors.white}m ┌───┐\\033[0m"
|
|
276
|
+
printf "\\033[$((cy+1));\${cx}H\\033[38;5;${colors.white}m │\\033[38;5;${colors.cyan}m◔ ◔\\033[38;5;${colors.white}m│\\033[0m"
|
|
277
|
+
printf "\\033[$((cy+2));\${cx}H\\033[38;5;${colors.white}m │ \\033[38;5;${colors.orange}m○\\033[38;5;${colors.white}m │\\033[0m"
|
|
278
|
+
printf "\\033[$((cy+3));\${cx}H\\033[38;5;${colors.white}m └─┬─┘\\033[0m"
|
|
279
|
+
printf "\\033[$((cy+4));\${cx}H\\033[38;5;${colors.white}m /|\\\\\\033[0m"
|
|
280
|
+
# Thinking sparkle
|
|
281
|
+
printf "\\033[$((cy-1));$((cx+8))H\\033[38;5;${colors.magenta}m✦\\033[0m"
|
|
282
|
+
;;
|
|
283
|
+
happy)
|
|
284
|
+
printf "\\033[$cy;\${cx}H\\033[38;5;${colors.white}m ┌───┐\\033[0m"
|
|
285
|
+
printf "\\033[$((cy+1));\${cx}H\\033[38;5;${colors.white}m │\\033[38;5;${colors.cyan}m◕ ◕\\033[38;5;${colors.white}m│\\033[0m"
|
|
286
|
+
printf "\\033[$((cy+2));\${cx}H\\033[38;5;${colors.white}m │ \\033[38;5;${colors.green}m◡\\033[38;5;${colors.white}m │\\033[0m"
|
|
287
|
+
printf "\\033[$((cy+3));\${cx}H\\033[38;5;${colors.white}m └─┬─┘\\033[0m"
|
|
288
|
+
printf "\\033[$((cy+4));\${cx}H\\033[38;5;${colors.white}m \\\\|/\\033[0m"
|
|
289
|
+
# Happy sparkles
|
|
290
|
+
printf "\\033[$((cy-1));$((cx-1))H\\033[38;5;${colors.orange}m✧\\033[0m"
|
|
291
|
+
printf "\\033[$cy;$((cx+9))H\\033[38;5;${colors.green}m✦\\033[0m"
|
|
292
|
+
printf "\\033[$((cy+2));$((cx-2))H\\033[38;5;${colors.cyan}m·\\033[0m"
|
|
293
|
+
;;
|
|
294
|
+
esac
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# ─────────────────────────────────────────────────────────────
|
|
298
|
+
# LOGO: 247 with scan effect
|
|
299
|
+
# ─────────────────────────────────────────────────────────────
|
|
300
|
+
draw_logo() {
|
|
301
|
+
local scan_pos=$1
|
|
302
|
+
local lx=$((COLS / 2 - 12))
|
|
303
|
+
local ly=2
|
|
304
|
+
|
|
305
|
+
# Logo lines
|
|
306
|
+
local L1=" ██████ ██ ██ ███████"
|
|
307
|
+
local L2=" ██ ██ ██ ██"
|
|
308
|
+
local L3=" █████ ██████ ██"
|
|
309
|
+
local L4=" ██ ██ ██"
|
|
310
|
+
local L5=" ███████ ██ ██"
|
|
311
|
+
|
|
312
|
+
# Draw with optional scan highlight
|
|
313
|
+
local lines=("$L1" "$L2" "$L3" "$L4" "$L5")
|
|
314
|
+
for i in $(seq 0 4); do
|
|
315
|
+
printf "\\033[$((ly + i));\${lx}H"
|
|
316
|
+
if [ "$scan_pos" -eq "$i" ]; then
|
|
317
|
+
printf "\\033[38;5;${colors.white}m\\033[1m\${lines[$i]}\\033[0m"
|
|
318
|
+
else
|
|
319
|
+
printf "\\033[38;5;${colors.orange}m\${lines[$i]}\\033[0m"
|
|
320
|
+
fi
|
|
321
|
+
done
|
|
243
322
|
}
|
|
244
323
|
|
|
245
|
-
#
|
|
324
|
+
# ─────────────────────────────────────────────────────────────
|
|
325
|
+
# PROGRESS BAR: Animated with gradient
|
|
326
|
+
# ─────────────────────────────────────────────────────────────
|
|
246
327
|
show_progress() {
|
|
247
|
-
local steps=("
|
|
328
|
+
local steps=("⚡ Booting up..." "🔧 Loading config..." "🌐 Connecting..." "✨ Ready!")
|
|
248
329
|
local total=\${#steps[@]}
|
|
249
|
-
local bar_width=
|
|
330
|
+
local bar_width=30
|
|
331
|
+
local bx=$((COLS / 2 - bar_width / 2 - 3))
|
|
332
|
+
local by=16
|
|
250
333
|
|
|
251
334
|
for i in "\${!steps[@]}"; do
|
|
252
335
|
local step=\${steps[$i]}
|
|
@@ -254,46 +337,69 @@ show_progress() {
|
|
|
254
337
|
local filled=$(( progress * bar_width / 100 ))
|
|
255
338
|
local empty=$(( bar_width - filled ))
|
|
256
339
|
|
|
257
|
-
#
|
|
258
|
-
|
|
259
|
-
|
|
340
|
+
# Draw starfield frame
|
|
341
|
+
draw_stars $i
|
|
342
|
+
|
|
343
|
+
# Progress bar with rounded corners
|
|
344
|
+
printf "\\033[$by;\${bx}H\\033[K"
|
|
345
|
+
printf "\\033[38;5;${colors.muted}m╭\\033[0m"
|
|
260
346
|
printf "\\033[38;5;${colors.orange}m%*s\\033[0m" "$filled" "" | tr ' ' '█'
|
|
261
347
|
printf "\\033[38;5;${colors.muted}m%*s\\033[0m" "$empty" "" | tr ' ' '░'
|
|
262
|
-
printf "\\033[38;5;${colors.muted}m
|
|
348
|
+
printf "\\033[38;5;${colors.muted}m╮\\033[0m"
|
|
263
349
|
printf " \\033[38;5;${colors.cyan}m%3d%%\\033[0m" "$progress"
|
|
264
350
|
|
|
265
|
-
# Status
|
|
266
|
-
printf "\\033[
|
|
267
|
-
printf "
|
|
351
|
+
# Status message
|
|
352
|
+
printf "\\033[$((by + 1));\${bx}H\\033[K"
|
|
353
|
+
printf "\\033[38;5;${colors.muted}m $step\\033[0m"
|
|
268
354
|
|
|
269
|
-
sleep 0.
|
|
355
|
+
sleep 0.35
|
|
270
356
|
done
|
|
271
357
|
}
|
|
272
358
|
|
|
273
|
-
#
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
359
|
+
# ─────────────────────────────────────────────────────────────
|
|
360
|
+
# MAIN ANIMATION SEQUENCE (~3s)
|
|
361
|
+
# ─────────────────────────────────────────────────────────────
|
|
362
|
+
init_stars
|
|
363
|
+
|
|
364
|
+
# Phase 1: Starfield appears (0.2s)
|
|
365
|
+
for f in $(seq 0 2); do
|
|
366
|
+
draw_stars $f
|
|
367
|
+
sleep 0.07
|
|
368
|
+
done
|
|
369
|
+
|
|
370
|
+
# Phase 2: Logo with scan effect (0.6s)
|
|
371
|
+
for scan in $(seq 0 5); do
|
|
372
|
+
draw_logo $((scan % 6))
|
|
373
|
+
draw_stars $scan
|
|
374
|
+
sleep 0.1
|
|
375
|
+
done
|
|
376
|
+
draw_logo -1 # Final state (no highlight)
|
|
377
|
+
|
|
378
|
+
# Phase 3: Robot boot sequence (0.8s)
|
|
379
|
+
draw_robot "boot"
|
|
380
|
+
sleep 0.25
|
|
381
|
+
draw_stars 7
|
|
382
|
+
draw_robot "think"
|
|
383
|
+
sleep 0.35
|
|
384
|
+
draw_stars 8
|
|
385
|
+
|
|
386
|
+
# Phase 4: Progress bar (1.0s)
|
|
287
387
|
show_progress
|
|
288
388
|
|
|
289
|
-
|
|
389
|
+
# Phase 5: Robot happy (0.4s)
|
|
390
|
+
draw_robot "happy"
|
|
391
|
+
for f in $(seq 9 12); do
|
|
392
|
+
draw_stars $f
|
|
393
|
+
sleep 0.08
|
|
394
|
+
done
|
|
290
395
|
|
|
291
|
-
# Show cursor
|
|
396
|
+
# Show cursor
|
|
292
397
|
printf "\\033[?25h"
|
|
293
|
-
|
|
294
|
-
sleep 0.6
|
|
398
|
+
sleep 0.3
|
|
295
399
|
clear
|
|
296
400
|
|
|
401
|
+
fi # End of desktop/mobile conditional
|
|
402
|
+
|
|
297
403
|
fi # End of animation conditional`;
|
|
298
404
|
const welcomeMessage = `
|
|
299
405
|
${loaderAnimation}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-script.js","sourceRoot":"","sources":["../../src/lib/init-script.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAS7B;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA0B;IAC3D,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,GAAG,EAAE,EAAE,KAAK,GAAG,eAAe,EAAE,EAAE,GAAG,OAAO,CAAC;IAE5F,MAAM,cAAc,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAElD,+BAA+B;IAC/B,MAAM,aAAa,GAAa,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QACzD,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACjC,aAAa,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,MAAM,MAAM,GAAG;QACb,MAAM,EAAE,KAAK,EAAE,mBAAmB;QAClC,KAAK,EAAE,KAAK,EAAE,UAAU;QACxB,IAAI,EAAE,IAAI,EAAE,UAAU;QACtB,KAAK,EAAE,KAAK,EAAE,UAAU;QACxB,OAAO,EAAE,KAAK,EAAE,uBAAuB;QACvC,GAAG,EAAE,KAAK,EAAE,kBAAkB;QAC9B,KAAK,EAAE,KAAK,EAAE,UAAU;KACzB,CAAC;IAEF,yBAAyB;IACzB,MAAM,gBAAgB,GAAG;;sBAEL,cAAc;sBACd,cAAc;sBACd,cAAc;sBACd,cAAc;sBACd,cAAc,qEAAqE,cAAc;sBACjG,cAAc;sBACd,cAAc;sBACd,cAAc,sCAAsC,CAAC;IAEzE,kDAAkD;IAClD,wEAAwE;IACxE,MAAM,gBAAgB,GAAG;;;;;;;;;4BASC,MAAM,CAAC,GAAG;;;;;;;;iCAQL,MAAM,CAAC,OAAO;;;;;;;;;;;;;;;mCAeZ,MAAM,CAAC,MAAM,2CAA2C,MAAM,CAAC,MAAM;;mCAErE,MAAM,CAAC,KAAK,oBAAoB,MAAM,CAAC,KAAK,wDAAwD,MAAM,CAAC,KAAK,iCAAiC,MAAM,CAAC,MAAM;;;;qCAI5J,CAAC;IAEpC,MAAM,eAAe,GAAG;;;;;;;;;;;mBAWP,MAAM,CAAC,GAAG;;;;;;;gDAOmB,MAAM,CAAC,OAAO;;;;;6BAKjC,MAAM,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM;;6BAEvC,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,0BAA0B,MAAM,CAAC,KAAK,WAAW,MAAM,CAAC,MAAM;;;;gCAI3F,CAAC;IAE/B,MAAM,aAAa,GACjB,KAAK,KAAK,KAAK;QACb,CAAC,CAAC;;;;;;;wBAOgB;QAClB,CAAC,CAAC;;;;;;oBAMY,CAAC;IAEnB,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;qBAeG,CAAC;IAEpB,
|
|
1
|
+
{"version":3,"file":"init-script.js","sourceRoot":"","sources":["../../src/lib/init-script.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification sender.
|
|
3
|
+
* Sends Web Push notifications to all subscribed clients.
|
|
4
|
+
*/
|
|
5
|
+
import type { WSSessionInfo } from '247-shared';
|
|
6
|
+
export interface PushPayload {
|
|
7
|
+
title: string;
|
|
8
|
+
body: string;
|
|
9
|
+
tag: string;
|
|
10
|
+
url: string;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Send push notification for a session status update.
|
|
15
|
+
* Only sends if status is 'needs_attention'.
|
|
16
|
+
*/
|
|
17
|
+
export declare function sendPushNotification(session: WSSessionInfo): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Send a test push notification.
|
|
20
|
+
* Useful for verifying setup.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sendTestNotification(): Promise<{
|
|
23
|
+
sent: number;
|
|
24
|
+
failed: number;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=sender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.d.ts","sourceRoot":"","sources":["../../src/push/sender.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,YAAY,CAAC;AAGjE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAmCD;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDhF;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BtF"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push notification sender.
|
|
3
|
+
* Sends Web Push notifications to all subscribed clients.
|
|
4
|
+
*/
|
|
5
|
+
import webpush from 'web-push';
|
|
6
|
+
import * as pushDb from '../db/push-subscriptions.js';
|
|
7
|
+
/**
|
|
8
|
+
* Get notification message based on attention reason.
|
|
9
|
+
*/
|
|
10
|
+
function getNotificationMessage(reason) {
|
|
11
|
+
switch (reason) {
|
|
12
|
+
case 'permission':
|
|
13
|
+
return {
|
|
14
|
+
title: 'Action requise',
|
|
15
|
+
body: 'Claude a besoin de votre autorisation pour continuer.',
|
|
16
|
+
};
|
|
17
|
+
case 'input':
|
|
18
|
+
return {
|
|
19
|
+
title: 'Réponse attendue',
|
|
20
|
+
body: 'Claude attend votre réponse pour continuer.',
|
|
21
|
+
};
|
|
22
|
+
case 'plan_approval':
|
|
23
|
+
return {
|
|
24
|
+
title: 'Plan à valider',
|
|
25
|
+
body: 'Claude a terminé son plan et attend votre validation.',
|
|
26
|
+
};
|
|
27
|
+
case 'task_complete':
|
|
28
|
+
return {
|
|
29
|
+
title: 'Tâche terminée',
|
|
30
|
+
body: 'Claude a terminé sa tâche.',
|
|
31
|
+
};
|
|
32
|
+
default:
|
|
33
|
+
return {
|
|
34
|
+
title: 'Attention requise',
|
|
35
|
+
body: 'Une session nécessite votre attention.',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Send push notification for a session status update.
|
|
41
|
+
* Only sends if status is 'needs_attention'.
|
|
42
|
+
*/
|
|
43
|
+
export async function sendPushNotification(session) {
|
|
44
|
+
// Only send for needs_attention status
|
|
45
|
+
if (session.status !== 'needs_attention') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const subscriptions = pushDb.getAllSubscriptions();
|
|
49
|
+
if (subscriptions.length === 0) {
|
|
50
|
+
console.log('[Push] No subscriptions, skipping push notification');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const { title, body } = getNotificationMessage(session.attentionReason || 'input');
|
|
54
|
+
const payload = {
|
|
55
|
+
title: `${title} - ${session.name}`,
|
|
56
|
+
body,
|
|
57
|
+
tag: `session-${session.name}`,
|
|
58
|
+
url: `/?session=${encodeURIComponent(session.name)}`,
|
|
59
|
+
timestamp: Date.now(),
|
|
60
|
+
};
|
|
61
|
+
const payloadStr = JSON.stringify(payload);
|
|
62
|
+
const invalidEndpoints = [];
|
|
63
|
+
console.log(`[Push] Sending notification to ${subscriptions.length} subscriber(s)`);
|
|
64
|
+
// Send to all subscriptions in parallel
|
|
65
|
+
const results = await Promise.allSettled(subscriptions.map(async (dbSub) => {
|
|
66
|
+
const subscription = pushDb.toWebPushSubscription(dbSub);
|
|
67
|
+
try {
|
|
68
|
+
await webpush.sendNotification(subscription, payloadStr);
|
|
69
|
+
return { success: true, endpoint: dbSub.endpoint };
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
const error = err;
|
|
73
|
+
// 404 or 410 means subscription is no longer valid
|
|
74
|
+
if (error.statusCode === 404 || error.statusCode === 410) {
|
|
75
|
+
invalidEndpoints.push(dbSub.endpoint);
|
|
76
|
+
console.log(`[Push] Subscription expired: ${dbSub.endpoint.substring(0, 50)}...`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.error(`[Push] Failed to send:`, error);
|
|
80
|
+
}
|
|
81
|
+
return { success: false, endpoint: dbSub.endpoint };
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
// Clean up invalid subscriptions
|
|
85
|
+
if (invalidEndpoints.length > 0) {
|
|
86
|
+
const deleted = pushDb.deleteInvalidSubscriptions(invalidEndpoints);
|
|
87
|
+
console.log(`[Push] Cleaned up ${deleted} invalid subscription(s)`);
|
|
88
|
+
}
|
|
89
|
+
const successful = results.filter((r) => r.status === 'fulfilled' && r.value.success).length;
|
|
90
|
+
console.log(`[Push] Sent ${successful}/${subscriptions.length} notification(s)`);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Send a test push notification.
|
|
94
|
+
* Useful for verifying setup.
|
|
95
|
+
*/
|
|
96
|
+
export async function sendTestNotification() {
|
|
97
|
+
const subscriptions = pushDb.getAllSubscriptions();
|
|
98
|
+
if (subscriptions.length === 0) {
|
|
99
|
+
return { sent: 0, failed: 0 };
|
|
100
|
+
}
|
|
101
|
+
const payload = {
|
|
102
|
+
title: 'Test Notification',
|
|
103
|
+
body: 'Les notifications push fonctionnent !',
|
|
104
|
+
tag: 'test',
|
|
105
|
+
url: '/',
|
|
106
|
+
timestamp: Date.now(),
|
|
107
|
+
};
|
|
108
|
+
const payloadStr = JSON.stringify(payload);
|
|
109
|
+
let sent = 0;
|
|
110
|
+
let failed = 0;
|
|
111
|
+
for (const dbSub of subscriptions) {
|
|
112
|
+
try {
|
|
113
|
+
await webpush.sendNotification(pushDb.toWebPushSubscription(dbSub), payloadStr);
|
|
114
|
+
sent++;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
failed++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { sent, failed };
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=sender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender.js","sourceRoot":"","sources":["../../src/push/sender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VAPID key management for Web Push notifications.
|
|
3
|
+
* Keys are generated once and stored in ~/.247/vapid.json
|
|
4
|
+
*/
|
|
5
|
+
interface VapidKeys {
|
|
6
|
+
publicKey: string;
|
|
7
|
+
privateKey: string;
|
|
8
|
+
subject: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Get or generate VAPID keys.
|
|
12
|
+
* Keys are cached in memory and persisted to disk.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getVapidKeys(): VapidKeys;
|
|
15
|
+
/**
|
|
16
|
+
* Get the public VAPID key (for client subscription).
|
|
17
|
+
*/
|
|
18
|
+
export declare function getPublicVapidKey(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Initialize web-push with VAPID keys.
|
|
21
|
+
* Call this at server startup.
|
|
22
|
+
*/
|
|
23
|
+
export declare function initWebPush(): void;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=vapid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vapid.d.ts","sourceRoot":"","sources":["../../src/push/vapid.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,UAAU,SAAS;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD;;;GAGG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAgDxC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAUlC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VAPID key management for Web Push notifications.
|
|
3
|
+
* Keys are generated once and stored in ~/.247/vapid.json
|
|
4
|
+
*/
|
|
5
|
+
import webpush from 'web-push';
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
7
|
+
import { resolve, dirname } from 'path';
|
|
8
|
+
const CONFIG_DIR = resolve(process.env.HOME || '~', '.247');
|
|
9
|
+
const VAPID_FILE = resolve(CONFIG_DIR, 'vapid.json');
|
|
10
|
+
let cachedKeys = null;
|
|
11
|
+
/**
|
|
12
|
+
* Get or generate VAPID keys.
|
|
13
|
+
* Keys are cached in memory and persisted to disk.
|
|
14
|
+
*/
|
|
15
|
+
export function getVapidKeys() {
|
|
16
|
+
if (cachedKeys) {
|
|
17
|
+
return cachedKeys;
|
|
18
|
+
}
|
|
19
|
+
// Try to load from file
|
|
20
|
+
if (existsSync(VAPID_FILE)) {
|
|
21
|
+
try {
|
|
22
|
+
const content = readFileSync(VAPID_FILE, 'utf-8');
|
|
23
|
+
const loaded = JSON.parse(content);
|
|
24
|
+
// Validate that all required fields exist
|
|
25
|
+
if (loaded.publicKey && loaded.privateKey && loaded.subject) {
|
|
26
|
+
cachedKeys = loaded;
|
|
27
|
+
console.log('[VAPID] Loaded keys from file');
|
|
28
|
+
return cachedKeys;
|
|
29
|
+
}
|
|
30
|
+
// Keys incomplete, will regenerate
|
|
31
|
+
console.log('[VAPID] Loaded keys are incomplete, regenerating...');
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error('[VAPID] Failed to load keys, regenerating:', err);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Generate new keys
|
|
38
|
+
console.log('[VAPID] Generating new keys...');
|
|
39
|
+
const keys = webpush.generateVAPIDKeys();
|
|
40
|
+
cachedKeys = {
|
|
41
|
+
publicKey: keys.publicKey,
|
|
42
|
+
privateKey: keys.privateKey,
|
|
43
|
+
subject: 'mailto:247@quivr.com', // Required for VAPID
|
|
44
|
+
};
|
|
45
|
+
// Persist to file
|
|
46
|
+
try {
|
|
47
|
+
const dir = dirname(VAPID_FILE);
|
|
48
|
+
if (!existsSync(dir)) {
|
|
49
|
+
mkdirSync(dir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
writeFileSync(VAPID_FILE, JSON.stringify(cachedKeys, null, 2));
|
|
52
|
+
console.log('[VAPID] Keys saved to:', VAPID_FILE);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error('[VAPID] Failed to save keys:', err);
|
|
56
|
+
}
|
|
57
|
+
return cachedKeys;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the public VAPID key (for client subscription).
|
|
61
|
+
*/
|
|
62
|
+
export function getPublicVapidKey() {
|
|
63
|
+
return getVapidKeys().publicKey;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Initialize web-push with VAPID keys.
|
|
67
|
+
* Call this at server startup.
|
|
68
|
+
*/
|
|
69
|
+
export function initWebPush() {
|
|
70
|
+
try {
|
|
71
|
+
const keys = getVapidKeys();
|
|
72
|
+
webpush.setVapidDetails(keys.subject, keys.publicKey, keys.privateKey);
|
|
73
|
+
console.log('[VAPID] web-push initialized');
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
// In test environments, we may not have proper config directory access
|
|
77
|
+
console.warn('[VAPID] Failed to initialize web-push:', err.message);
|
|
78
|
+
console.warn('[VAPID] Push notifications will be disabled');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=vapid.js.map
|