opencode-wyvern 0.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.
@@ -0,0 +1,418 @@
1
+ # ---- OpenCode Wyvern (auto-generato) ----
2
+ # Personalizza: OC_SERVER / OC_DIR
3
+ export OC_SERVER='__OC_SERVER__'
4
+ export OC_DIR='__OC_DIR__'
5
+
6
+ oc-path() {
7
+ if [ -z "$OC_OPENCODE" ]; then
8
+ OC_OPENCODE=$(ssh -o BatchMode=yes "$OC_SERVER" "(command -v opencode || ls -t \$HOME/.nvm/versions/node/*/bin/opencode 2>/dev/null | head -n1)" 2>/dev/null | head -n1)
9
+ [ -n "$OC_OPENCODE" ] || OC_OPENCODE='opencode'
10
+ fi
11
+ echo "$OC_OPENCODE"
12
+ }
13
+
14
+ oc-connect() {
15
+ local key="$HOME/.ssh/id_ed25519"
16
+ local pub="$key.pub"
17
+ if [ ! -f "$key" ]; then
18
+ echo "[..] Genero SSH key..."
19
+ ssh-keygen -t ed25519 -C "${USER}@client" -f "$key" -N ""
20
+ fi
21
+ echo "[..] Installo chiave sul server (password una volta)..."
22
+ cat "$pub" | ssh "$OC_SERVER" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && echo CHIAVE_INSTALLATA"
23
+ echo "[..] Verifico autenticazione a chiave..."
24
+ if ssh -o BatchMode=yes "$OC_SERVER" "echo OK" 2>/dev/null; then
25
+ echo -e "${GREEN}[OK] Autenticazione SSH a chiave attiva!${NC}"
26
+ else
27
+ echo -e "${RED}[FAIL] La chiave non e' stata accettata.${NC}"
28
+ fi
29
+ }
30
+
31
+ oc() {
32
+ local oc; oc="$(oc-path)"
33
+ ssh -t "$OC_SERVER" "cd $OC_DIR && $oc"
34
+ }
35
+
36
+ oc-ssh() {
37
+ ssh "$OC_SERVER"
38
+ }
39
+
40
+ oc-sessions-today() {
41
+ local list back
42
+ list="$(oc-sessions-all)"
43
+ [ -z "$list" ] && return 0
44
+ back=$(( $(date +%s) - 86400 ))
45
+ printf '%s\n' "$list" | awk -F '\t' -v m="$back" '($1/1000)>=m{print $2"\t"$3"\t"$4}'
46
+ }
47
+
48
+ oc-cache-save() {
49
+ local f="${XDG_CACHE_HOME:-$HOME/.cache}/opencode-wyvern/sessions.tsv"
50
+ if [ -n "$1" ]; then
51
+ mkdir -p "$(dirname "$f")"
52
+ printf '%s' "$1" > "$f"
53
+ fi
54
+ }
55
+
56
+ oc-cache-load() {
57
+ cat "${XDG_CACHE_HOME:-$HOME/.cache}/opencode-wyvern/sessions.tsv" 2>/dev/null
58
+ }
59
+
60
+ oc-sessions-all() {
61
+ local oc b64 out
62
+ py='import json,sys
63
+ raw=sys.stdin.read()
64
+ i=raw.find("[\n")
65
+ if i<0:
66
+ i=raw.find("[")
67
+ d=json.loads(raw[i:])
68
+ for s in d:
69
+ u=s.get("updated") or 0
70
+ title=(s.get("title") or "").replace("\t"," ").replace("\n"," ")
71
+ print(str(u)+"\t"+s.get("id","")+"\t"+title+"\t"+s.get("directory",""))'
72
+ b64=$(printf '%s' "$py" | base64 -w0)
73
+ oc="$(oc-path)"
74
+ out="$(ssh -n -o BatchMode=yes "$OC_SERVER" "cd ~ && $oc --pure session list --format json 2>/dev/null | python3 -c \"import base64;exec(base64.b64decode('$b64').decode())\"" 2>/dev/null | sort -t $'\t' -k1,1nr)"
75
+ [ -z "$out" ] && return 0
76
+ oc-cache-save "$out"
77
+ printf '%s\n' "$out"
78
+ }
79
+
80
+ oc-find() {
81
+ local search="$1" limit="${2:-30}" i id title dir date
82
+ local list; list="$(oc-sessions-all)"
83
+ if [ -z "$list" ]; then
84
+ echo -e "${YELLOW}[WARN] Nessuna sessione trovata (o SSH a chiave non configurato - esegui oc-connect).${NC}"
85
+ return 1
86
+ fi
87
+ if [ -n "$search" ]; then
88
+ list=$(printf '%s\n' "$list" | grep -iF -- "$search")
89
+ fi
90
+ if [ -z "$list" ]; then
91
+ echo -e "${YELLOW}[WARN] Nessuna sessione corrispondente a: $search${NC}"
92
+ return 1
93
+ fi
94
+ if [ -n "$search" ]; then
95
+ echo -e "${CYAN}Risultati per \"$search\" (max $limit):${NC}"
96
+ else
97
+ echo -e "${CYAN}Sessioni recenti (max $limit):${NC}"
98
+ fi
99
+ printf '%s\n' "$list" | head -n "$limit" | nl -w2 -s'. ' | while read -r _line; do
100
+ idx=$(printf '%s' "$_line" | cut -d. -f1 | tr -d ' ')
101
+ rest=$(printf '%s' "$_line" | cut -d. -f2- | sed 's/^ //')
102
+ id=$(printf '%s' "$rest" | cut -f2)
103
+ title=$(printf '%s' "$rest" | cut -f3)
104
+ dir=$(printf '%s' "$rest" | cut -f4)
105
+ date=$(date -d "@$((id_epoch))" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "?")
106
+ id_epoch=$(( $(printf '%s' "$rest" | cut -f1) / 1000 ))
107
+ printf ' %2d. [%s] %s (%s) %s\n' "$idx" "${id:0:12}" "$title" "$date" "$dir"
108
+ done
109
+ echo ""
110
+ read -rp "Numero da aprire (INVIO per annullare): " choice
111
+ if [ "$choice" -ge 1 ] 2>/dev/null && [ "$choice" -le "$limit" ]; then
112
+ line=$(printf '%s\n' "$list" | head -n "$choice" | tail -n1)
113
+ id=$(printf '%s' "$line" | cut -f2)
114
+ dir=$(printf '%s' "$line" | cut -f4)
115
+ [ -n "$id" ] && oc-go "$id" "$dir" --no-recap
116
+ fi
117
+ }
118
+
119
+ oc-sessions() {
120
+ local list; list="$(oc-sessions-today)"
121
+ if [ -z "$list" ]; then
122
+ echo -e "${YELLOW}[WARN] Nessuna sessione nelle ultime 24 ore (o SSH a chiave non configurato - esegui oc-connect).${NC}"
123
+ return 1
124
+ fi
125
+ echo -e "${CYAN}Sessioni nelle ultime 24 ore:${NC}"
126
+ local i=0
127
+ while IFS=$'\t' read -r id title dir; do
128
+ i=$((i+1))
129
+ printf ' %d. [%s] %s\n' "$i" "${id:0:12}" "$title"
130
+ done <<< "$list"
131
+ }
132
+
133
+ oc-delete() {
134
+ local search="$1" i idx id title dir line choice confirm list
135
+ list="$(oc-sessions-all)"
136
+ if [ -z "$list" ]; then
137
+ echo -e "${YELLOW}[WARN] Nessuna sessione trovata.${NC}"
138
+ return 1
139
+ fi
140
+ if [ -n "$search" ]; then
141
+ list=$(printf '%s\n' "$list" | awk -F $'\t' -v s="$search" 'index($3, s) || index($2, s)')
142
+ fi
143
+ if [ -z "$list" ]; then
144
+ echo -e "${YELLOW}[WARN] Nessuna sessione corrispondente a: $search${NC}"
145
+ return 1
146
+ fi
147
+ echo -e "${CYAN}Sessioni (seleziona da eliminare):${NC}"
148
+ printf '%s\n' "$list" | head -n 30 | nl -w2 -s'. ' | while read -r _line; do
149
+ idx=$(printf '%s' "$_line" | cut -d. -f1 | tr -d ' ')
150
+ rest=$(printf '%s' "$_line" | cut -d. -f2- | sed 's/^ //')
151
+ id=$(printf '%s' "$rest" | cut -f2)
152
+ title=$(printf '%s' "$rest" | cut -f3)
153
+ date=$(date -d "@$(( $(printf '%s' "$rest" | cut -f1) / 1000 ))" "+%Y-%m-%d %H:%M" 2>/dev/null || echo "?")
154
+ printf ' %2d. [%s] %s (%s)\n' "$idx" "${id:0:12}" "$title" "$date"
155
+ done
156
+ echo ""
157
+ read -rp "Numero da eliminare (INVIO per annullare): " choice
158
+ [ "$choice" -ge 1 ] 2>/dev/null || return 0
159
+ line=$(printf '%s\n' "$list" | head -n "$choice" | tail -n1)
160
+ [ -n "$line" ] || { echo -e "${YELLOW}Indice fuori range.${NC}"; return 1; }
161
+ id=$(printf '%s' "$line" | cut -f2)
162
+ title=$(printf '%s' "$line" | cut -f3)
163
+ read -rp "Eliminare definitivamente la sessione '$title'? (s/N): " confirm
164
+ case "$confirm" in
165
+ s|S|si|SI|sì|SÌ|y|Y|yes|YES) ;;
166
+ *) echo -e "${YELLOW}Annullato.${NC}"; return 0 ;;
167
+ esac
168
+ local oc; oc="$(oc-path)"
169
+ ssh -o BatchMode=yes "$OC_SERVER" "cd ~ && $oc --pure session delete $id </dev/null" 2>&1 | grep -v '^\[claude-mem\]' || true
170
+ echo -e "${GREEN}[OK] Sessione eliminata: $title${NC}"
171
+ }
172
+
173
+ oc-go() {
174
+ local id="$1" dir="${2:-~}" norecap=0 oc exit_code
175
+ [ "$3" = "--no-recap" ] && norecap=1
176
+ oc="$(oc-path)"
177
+ mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}/opencode-wyvern"
178
+ printf '%s\t%s\n' "$id" "${dir:-~}" > "${XDG_CACHE_HOME:-$HOME/.cache}/opencode-wyvern/last.tsv"
179
+ if [ "$dir" = "~" ] || [ -z "$dir" ]; then
180
+ ssh -t -o ConnectTimeout=8 "$OC_SERVER" "cd ~ && $oc -s $id"
181
+ else
182
+ ssh -t -o ConnectTimeout=8 "$OC_SERVER" "mkdir -p '$dir' && cd '$dir' && $oc -s $id"
183
+ fi
184
+ exit_code=$?
185
+ [ "$norecap" = "0" ] && oc-recap "$exit_code"
186
+ return 0
187
+ }
188
+
189
+ oc-recap() {
190
+ local last_exit="${1:--1}" err_time live cached list bar back m i id title dir updated last choice ss cid ctitle cdir
191
+ err_time="$(date '+%Y-%m-%d %H:%M:%S')"
192
+ bar="=============================================="
193
+ echo ""
194
+ echo -e "${CYAN}${bar}${NC}"
195
+ echo -e "${CYAN}Connessione terminata. Riepilogo per riprendere:${NC}"
196
+ echo -e "${CYAN}${bar}${NC}"
197
+ live="$(oc-sessions-today 2>/dev/null)"
198
+ if [ -z "$live" ]; then
199
+ cached="$(oc-cache-load)"
200
+ if [ -n "$cached" ]; then
201
+ m="$(stat -c %y "${XDG_CACHE_HOME:-$HOME/.cache}/opencode-wyvern/sessions.tsv" 2>/dev/null | cut -d'.' -f1)"
202
+ echo -e "${RED} [!] Connessione persa alle $err_time (SSH exit $last_exit).${NC}"
203
+ echo -e "${YELLOW} Errore: il server non risponde / raggiungibile.${NC}"
204
+ echo -e "${DARKGRAY:-} Riepilogo salvato localmente il $m: riprendi appena torna la connessione.${NC}"
205
+ echo ""
206
+ back=$(( $(date +%s) - 86400 ))
207
+ list="$(printf '%s\n' "$cached" | awk -F '\t' -v m="$back" '($1/1000)>=m{print $2"\t"$3"\t"$4"\t"$1}')"
208
+ else
209
+ echo -e "${RED} [!] Connessione persa alle $err_time (SSH exit $last_exit).${NC}"
210
+ echo -e "${YELLOW} Errore: il server non risponde / raggiungibile.${NC}"
211
+ echo -e "${YELLOW} Nessun riepilogo salvato: il client non si era mai collegato.${NC}"
212
+ echo -e "${DARKGRAY:-} Quando il server torna su: oc-recap${NC}"
213
+ return 1
214
+ fi
215
+ else
216
+ list="$live"
217
+ fi
218
+ if [ -z "$list" ]; then
219
+ echo -e "${YELLOW} Nessuna sessione nelle ultime 24 ore nel riepilogo.${NC}"
220
+ return 1
221
+ fi
222
+ i=0
223
+ while IFS=$'\t' read -r id title dir updated; do
224
+ i=$((i+1))
225
+ last="$( [ -n "$updated" ] && date -d "@$(( updated / 1000 ))" '+%H:%M' 2>/dev/null )"
226
+ echo ""
227
+ printf ' %2d) %s [%s...]\n' "$i" "$title" "${id:0:12}"
228
+ printf ' in: %s (ultimo aggiornamento %s)\n' "${dir:-~}" "$last"
229
+ printf ' run: opencode -s %s\n' "$id"
230
+ printf ' oc-go: oc-go -Id %c%s%c -Dir %c%s%c\n' "'" "$id" "'" "'" "${dir:-~}" "'"
231
+ done <<< "$list"
232
+ echo ""
233
+ printf "Scelta (1..%s riprendi, r riprova, n nuova sessione, INVIO esci): " "$i"
234
+ read -r choice || true
235
+ case "$choice" in
236
+ '' ) echo -e "${DARKGRAY:-} Per riprendere in seguito: oc-recap oppure oc-resume${NC}"
237
+ return 0 ;;
238
+ r|R|riprova )
239
+ echo -e "${CYAN} Riprovo la connessione...${NC}"
240
+ OC_OPENCODE=""
241
+ oc-recap -1
242
+ return 0 ;;
243
+ n|N )
244
+ echo -e "${CYAN} Nuova sessione...${NC}"
245
+ oc
246
+ return 0 ;;
247
+ * )
248
+ if [ "$choice" -ge 1 ] 2>/dev/null && [ "$choice" -le "$i" ]; then
249
+ ss="$(printf '%s\n' "$list" | sed -n "${choice}p")"
250
+ IFS=$'\t' read -r cid ctitle cdir _ <<< "$ss"
251
+ echo -e " ${CYAN}Riprendo: $ctitle${NC}"
252
+ oc-go "$cid" "$cdir"
253
+ else
254
+ echo -e "${YELLOW} Scelta non valida.${NC}"
255
+ fi
256
+ return 0 ;;
257
+ esac
258
+ }
259
+
260
+ oc-open-tab() {
261
+ local title="$1"; shift
262
+ local cmd="$1"; shift
263
+ if command -v gnome-terminal >/dev/null 2>&1; then
264
+ gnome-terminal --title "$title" -- bash -lc "$cmd"
265
+ elif command -v konsole >/dev/null 2>&1; then
266
+ konsole --new-tab -p tabtitle "$title" -e bash -lc "$cmd"
267
+ elif command -v xfce4-terminal >/dev/null 2>&1; then
268
+ xfce4-terminal --title "$title" -e "bash -lc \"$cmd\""
269
+ elif command -v xterm >/dev/null 2>&1; then
270
+ xterm -T "$title" -e bash -lc "$cmd"
271
+ else
272
+ echo -e "${RED}[FAIL] Nessun terminale grafico trovato per aprire i tab.${NC}"
273
+ fi
274
+ }
275
+
276
+ oc-resume() {
277
+ local list rest first_term=1 mode="$1" term
278
+ if [ "$mode" = "--all-tabs" ] || [ "$mode" = "-a" ]; then
279
+ first_term=0
280
+ fi
281
+ list="$(oc-sessions-today)"
282
+ if [ -z "$list" ]; then
283
+ if ! ssh -o BatchMode=yes -o ConnectTimeout=5 "$OC_SERVER" "echo PING_OK" 2>/dev/null | grep -q PING_OK; then
284
+ echo ""
285
+ echo -e "${RED} [!] Errore di connessione al server.${NC}"
286
+ local last_file last_id last_dir
287
+ last_file="${XDG_CACHE_HOME:-$HOME/.cache}/opencode-wyvern/last.tsv"
288
+ if [ -f "$last_file" ]; then
289
+ IFS=$'\t' read -r last_id last_dir < "$last_file"
290
+ if [ -n "$last_id" ]; then
291
+ echo -e "${CYAN} Riprendo automaticamente l'ultima sessione terminata...${NC}"
292
+ echo ""
293
+ oc-go "$last_id" "${last_dir:-~}"
294
+ return $?
295
+ fi
296
+ fi
297
+ echo -e "${YELLOW} Nessuna sessione da riprendere automaticamente.${NC}"
298
+ oc-recap
299
+ return 1
300
+ fi
301
+ echo -e "${YELLOW}[WARN] Nessuna sessione nelle ultime 24 ore (o SSH a chiave non configurato - esegui oc-connect).${NC}"
302
+ return 1
303
+ fi
304
+ term="$(oc-detect-terminal)"
305
+ if [ "$term" = "warp" ]; then
306
+ if [ "$first_term" = "1" ]; then
307
+ rest="$(printf '%s\n' "$list" | tail -n +2)"
308
+ if [ -n "$rest" ]; then
309
+ oc-warp-resume "$rest"
310
+ fi
311
+ local first_id first_dir
312
+ IFS=$'\t' read -r first_id _first_title first_dir <<< "$list"
313
+ echo -e " ${CYAN}Riprendo qui: $_first_title${NC}"
314
+ oc-go "$first_id" "$first_dir"
315
+ else
316
+ oc-warp-resume "$list"
317
+ fi
318
+ return $?
319
+ fi
320
+ if [ "$first_term" = "1" ]; then
321
+ rest="$(printf '%s\n' "$list" | tail -n +2)"
322
+ else
323
+ rest="$list"
324
+ fi
325
+ if [ -n "$rest" ]; then
326
+ while IFS=$'\t' read -r id title dir; do
327
+ echo -e " ${CYAN}Apro tab: $title${NC}"
328
+ oc-open-tab "$title" "oc-go '$id' '$dir'"
329
+ sleep 0.8
330
+ done <<< "$rest"
331
+ fi
332
+ if [ "$first_term" = "1" ]; then
333
+ local first_id first_dir
334
+ IFS=$'\t' read -r first_id _first_title first_dir <<< "$list"
335
+ echo -e " ${CYAN}Riprendo qui: $_first_title${NC}"
336
+ oc-go "$first_id" "$first_dir"
337
+ fi
338
+ }
339
+
340
+ oc-detect-terminal() {
341
+ if [ -n "$TERM_PROGRAM" ] && [ "${TERM_PROGRAM#*warp}" != "$TERM_PROGRAM" ]; then
342
+ echo "warp"; return
343
+ fi
344
+ if [ -n "${WARP_SESSION:-}" ] || [ -n "${WARP_PROJECT:-}" ]; then
345
+ echo "warp"; return
346
+ fi
347
+ if [ -n "$GNOME_TERMINAL_SERVICE" ] || [ -n "$GNOME_TERMINAL_SCREEN" ]; then
348
+ echo "gnome"; return
349
+ fi
350
+ case "$TERM" in
351
+ xterm*|rxvt*) echo "xterm"; return ;;
352
+ screen*) echo "screen"; return ;;
353
+ esac
354
+ echo "other"
355
+ }
356
+
357
+ oc-warp-resume() {
358
+ local list="$1" id title dir stem configs_dir i=0 toml created=""
359
+ if command -v xdg-open >/dev/null 2>&1; then
360
+ local open=xdg-open
361
+ else
362
+ local open=xdg-open
363
+ fi
364
+ configs_dir="${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/tab_configs"
365
+ if [ ! -d "$configs_dir" ]; then
366
+ configs_dir="${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal-preview/tab_configs"
367
+ fi
368
+ if [ ! -d "$configs_dir" ]; then
369
+ mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/tab_configs"
370
+ configs_dir="${XDG_DATA_HOME:-$HOME/.local/share}/warp-terminal/tab_configs"
371
+ fi
372
+ while IFS=$'\t' read -r id title dir; do
373
+ i=$((i+1))
374
+ stem="oc-resume-$i-$(date +%s%N)"
375
+ toml="$configs_dir/$stem.toml"
376
+ if [ "$dir" = "~" ] || [ -z "$dir" ]; then
377
+ dir='/home/'"$USER"
378
+ fi
379
+ local oc; oc="$(oc-path)"
380
+ title="$(printf '%s' "$title" | tr -d '"\\' | tr -s ' ')"
381
+ if [ "$dir" = "/home/$USER" ] || [ -z "$dir" ]; then
382
+ remote_cmd="cd ~ && $oc -s $id"
383
+ else
384
+ remote_cmd="mkdir -p '$dir' && cd '$dir' && $oc -s $id"
385
+ fi
386
+ cmd="ssh -t $OC_SERVER \"$remote_cmd\"; oc-recap"
387
+ printf 'name = "[oc] %s"\ntitle = "%s"\n[[panes]]\nid = "main"\ntype = "terminal"\nshell = "bash"\ncommands = ["%s"]\n' \
388
+ "$title" "$title" "$cmd" > "$toml"
389
+ echo -e " ${CYAN}Apro tab Warp: $title${NC}"
390
+ "$open" "warp://tab_config/$stem"
391
+ sleep 2
392
+ created="$created $toml"
393
+ done <<< "$list"
394
+ echo ""
395
+ echo -e "${DARKGRAY:-}Suggerimento: Ctrl+click su tutte le tab, tasto destro e 'New group with tab'.${NC}"
396
+ ( sleep 15; for f in $created; do rm -f "$f"; done ) >/dev/null 2>&1 &
397
+ return 0
398
+ }
399
+
400
+ oc-help() {
401
+ echo ""
402
+ echo -e "${CYAN}OpenCode Wyvern - comandi${NC}"
403
+ echo -e "${CYAN}============================${NC}"
404
+ echo ""
405
+ printf ' %-24s %s\n' "oc-connect" "Setup SSH key + autorizzazione server"
406
+ printf ' %-24s %s\n' "oc" "Nuova sessione opencode in $OC_DIR"
407
+ printf ' %-24s %s\n' "oc-ssh" "Apri sessione SSH interattiva"
408
+ printf ' %-24s %s\n' "oc-sessions" "Lista sessioni opencode (ultime 24h)"
409
+ printf ' %-24s %s\n' "oc-find [testo]" "Cerca sessioni globali per titolo e riapri"
410
+ printf ' %-24s %s\n' "oc-delete [testo]" "Cerca ed elimina sessioni"
411
+ printf ' %-24s %s\n' "oc-resume [--all-tabs]" "Riprende 1 sessione qui + 1 tab per le altre (o tutte in tab)"
412
+ printf ' %-24s %s\n' "oc-go <id> [dir]" "Riprende una sessione specifica"
413
+ printf ' %-24s %s\n' "oc-recap" "Riepilogo sessioni (usa cache se il server e'' giu')"
414
+ printf ' %-24s %s\n' "oc-help" "Questo aiuto"
415
+ echo ""
416
+ echo -e "${DARKGRAY:-}Nota: oc-ssh, oc-sessions, oc-resume richiedono SSH key configurata"
417
+ echo ""
418
+ }