FrameBridge 0.3.1 community source release
This commit is contained in:
commit
b23819fff1
1354 files changed
+343716
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
_lock = threading.Lock()
|
||||
_active = False
|
||||
|
||||
def _socket_path():
|
||||
runtime = Path(os.environ.get("XDG_RUNTIME_DIR", f"/run/user/{os.getuid()}"))
|
||||
return runtime / "framebridge-voice-r1.sock"
|
||||
|
||||
def _listen_worker():
|
||||
global _active
|
||||
try:
|
||||
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
s.settimeout(30)
|
||||
s.connect(str(_socket_path()))
|
||||
s.sendall(b'{"cmd":"listen_once"}\n')
|
||||
f = s.makefile("rb")
|
||||
f.readline() # respuesta local; NO se expone
|
||||
s.close()
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
with _lock:
|
||||
_active = False
|
||||
|
||||
def start_listen_once():
|
||||
global _active
|
||||
with _lock:
|
||||
if _active:
|
||||
return {"ok": True, "started": False, "reason": "already_active"}
|
||||
if not _socket_path().is_socket():
|
||||
return {"ok": False, "error": "VOICE_DAEMON_NOT_AVAILABLE"}
|
||||
_active = True
|
||||
threading.Thread(target=_listen_worker, daemon=True).start()
|
||||
return {"ok": True, "started": True}
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
_ALLOWED = {"escuchando", "pensando", "trabajando", "listo", "detenido"}
|
||||
_MAX_BYTES = 16384
|
||||
_MAX_AGE_SECONDS = 5.0
|
||||
|
||||
def read_voice_status(home=None):
|
||||
base = Path(home).expanduser() if home else Path.home()
|
||||
path = base / ".local/share/framebridge-voice/state-r1.json"
|
||||
|
||||
safe = {
|
||||
"state": "listo",
|
||||
"available": False,
|
||||
"updated_at": None,
|
||||
}
|
||||
|
||||
try:
|
||||
flags = os.O_RDONLY
|
||||
if hasattr(os, "O_NOFOLLOW"):
|
||||
flags |= os.O_NOFOLLOW
|
||||
if hasattr(os, "O_NONBLOCK"):
|
||||
flags |= os.O_NONBLOCK
|
||||
|
||||
fd = os.open(path, flags)
|
||||
try:
|
||||
st = os.fstat(fd)
|
||||
|
||||
if not stat.S_ISREG(st.st_mode):
|
||||
return safe
|
||||
|
||||
if st.st_uid != os.getuid():
|
||||
return safe
|
||||
|
||||
if st.st_size > _MAX_BYTES:
|
||||
return safe
|
||||
|
||||
raw = os.read(fd, _MAX_BYTES + 1)
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
if len(raw) > _MAX_BYTES:
|
||||
return safe
|
||||
|
||||
data = json.loads(raw.decode("utf-8"))
|
||||
|
||||
state = str(data.get("status", "listo")).lower()
|
||||
if state not in _ALLOWED:
|
||||
state = "listo"
|
||||
|
||||
updated = data.get("updated_at")
|
||||
if not isinstance(updated, (int, float)):
|
||||
return safe
|
||||
|
||||
age = max(0.0, time.time() - float(updated))
|
||||
|
||||
if age > _MAX_AGE_SECONDS:
|
||||
return safe
|
||||
|
||||
if state == "detenido":
|
||||
state = "listo"
|
||||
|
||||
return {
|
||||
"state": state,
|
||||
"available": True,
|
||||
"updated_at": float(updated),
|
||||
}
|
||||
|
||||
except (
|
||||
FileNotFoundError,
|
||||
PermissionError,
|
||||
OSError,
|
||||
ValueError,
|
||||
json.JSONDecodeError,
|
||||
):
|
||||
return safe
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env bash
|
||||
set +e
|
||||
|
||||
ACTION="$(printf '%s' "$1" | tr '[:lower:]' '[:upper:]')"
|
||||
[ -n "$ACTION" ] || ACTION="ENSURE"
|
||||
[ "$ACTION" = "OPEN" ] && ACTION="ENSURE"
|
||||
|
||||
case "$ACTION" in
|
||||
ENSURE|FOCUS|STATUS|CLOSE|TOGGLE) ;;
|
||||
*)
|
||||
echo "INTERACTIVE_TERMINAL_GATE=FAIL"
|
||||
echo "ERROR=INVALID_ACTION"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
TITLE="FrameBridge - Terminal"
|
||||
STATE_DIR="${FRAMEBRIDGE_UI_STATE_DIR:-$HOME/.local/share/framebridge/ui-state}"
|
||||
STATE_FILE="$STATE_DIR/interactive-terminal.window"
|
||||
DISPLAY_VALUE="$(printenv DISPLAY 2>/dev/null)"
|
||||
[ -n "$DISPLAY_VALUE" ] || DISPLAY_VALUE=":0"
|
||||
XAUTH_VALUE="$(printenv XAUTHORITY 2>/dev/null)"
|
||||
[ -n "$XAUTH_VALUE" ] || XAUTH_VALUE="$HOME/.Xauthority"
|
||||
|
||||
TERM_FG="#a8ffb5"
|
||||
TERM_BG="#010402"
|
||||
TERM_CURSOR="#c8ffd1"
|
||||
|
||||
mkdir -p "$STATE_DIR"
|
||||
chmod 700 "$STATE_DIR" 2>/dev/null || true
|
||||
|
||||
window_exists()
|
||||
{
|
||||
W="$1"
|
||||
[ -n "$W" ] || return 1
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool getwindowname "$W" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
read_state_window()
|
||||
{
|
||||
if [ -r "$STATE_FILE" ]; then
|
||||
head -n1 "$STATE_FILE" 2>/dev/null | tr -cd '0-9'
|
||||
fi
|
||||
}
|
||||
|
||||
write_state_window()
|
||||
{
|
||||
W="$1"
|
||||
printf '%s\n' "$W" > "$STATE_FILE"
|
||||
chmod 600 "$STATE_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
clear_state()
|
||||
{
|
||||
rm -f "$STATE_FILE"
|
||||
}
|
||||
|
||||
W="$(read_state_window)"
|
||||
if ! window_exists "$W"; then
|
||||
W=""
|
||||
clear_state
|
||||
fi
|
||||
|
||||
if [ "$ACTION" = "STATUS" ]; then
|
||||
echo "INTERACTIVE_TERMINAL_GATE=PASS"
|
||||
if [ -n "$W" ]; then
|
||||
echo "STATE=ON"
|
||||
echo "WINDOW_ID=$W"
|
||||
else
|
||||
echo "STATE=OFF"
|
||||
echo "WINDOW_ID="
|
||||
fi
|
||||
echo "INTERACTIVE=YES"
|
||||
echo "STYLE=GREEN_MONOCHROME"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$ACTION" = "TOGGLE" ]; then
|
||||
if [ -n "$W" ]; then
|
||||
ACTION="CLOSE"
|
||||
else
|
||||
ACTION="ENSURE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$ACTION" = "CLOSE" ]; then
|
||||
if [ -n "$W" ]; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool windowclose "$W" >/dev/null 2>&1 || true
|
||||
for _ in $(seq 1 30); do
|
||||
if ! window_exists "$W"; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
fi
|
||||
clear_state
|
||||
echo "INTERACTIVE_TERMINAL_GATE=PASS"
|
||||
echo "ACTION=CLOSE"
|
||||
echo "STATE=OFF"
|
||||
echo "WINDOW_ID="
|
||||
echo "INTERACTIVE=YES"
|
||||
echo "STYLE=GREEN_MONOCHROME"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$W" ]; then
|
||||
BEFORE="$(mktemp)"
|
||||
AFTER="$(mktemp)"
|
||||
trap 'rm -f "$BEFORE" "$AFTER"' EXIT
|
||||
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" wmctrl -lx 2>/dev/null | awk '$3 ~ /gnome-terminal-server.Gnome-terminal/ {print $1}' | sort -u > "$BEFORE"
|
||||
|
||||
export FB_TERM_TITLE="$TITLE"
|
||||
export FB_TERM_FG="$TERM_FG"
|
||||
export FB_TERM_BG="$TERM_BG"
|
||||
export FB_TERM_CURSOR="$TERM_CURSOR"
|
||||
|
||||
if command -v gnome-terminal >/dev/null 2>&1; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" gnome-terminal --title="$TITLE" -- bash -lc '
|
||||
printf "\033]0;%s\007" "$FB_TERM_TITLE"
|
||||
printf "\033]10;%s\007" "$FB_TERM_FG"
|
||||
printf "\033]11;%s\007" "$FB_TERM_BG"
|
||||
printf "\033]12;%s\007" "$FB_TERM_CURSOR"
|
||||
exec bash -l
|
||||
' >/dev/null 2>&1 &
|
||||
elif command -v xfce4-terminal >/dev/null 2>&1; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xfce4-terminal --title="$TITLE" --command="bash -lc 'printf \"\\033]10;$TERM_FG\\007\\033]11;$TERM_BG\\007\"; exec bash -l'" >/dev/null 2>&1 &
|
||||
elif command -v xterm >/dev/null 2>&1; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xterm -T "$TITLE" -fg "$TERM_FG" -bg "$TERM_BG" -e bash -l >/dev/null 2>&1 &
|
||||
else
|
||||
echo "INTERACTIVE_TERMINAL_GATE=FAIL"
|
||||
echo "ERROR=NO_SUPPORTED_TERMINAL"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
for _ in $(seq 1 50); do
|
||||
TITLE_W="$(DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool search --name "^$TITLE$" 2>/dev/null | tail -n1)"
|
||||
if window_exists "$TITLE_W"; then
|
||||
W="$TITLE_W"
|
||||
break
|
||||
fi
|
||||
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" wmctrl -lx 2>/dev/null | awk '$3 ~ /gnome-terminal-server.Gnome-terminal/ {print $1}' | sort -u > "$AFTER"
|
||||
|
||||
NEW_HEX="$(comm -13 "$BEFORE" "$AFTER" | tail -n1)"
|
||||
if [ -n "$NEW_HEX" ]; then
|
||||
W="$((NEW_HEX))"
|
||||
if window_exists "$W"; then
|
||||
break
|
||||
fi
|
||||
W=""
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
if [ -z "$W" ]; then
|
||||
echo "INTERACTIVE_TERMINAL_GATE=FAIL"
|
||||
echo "ERROR=WINDOW_NOT_FOUND"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
write_state_window "$W"
|
||||
fi
|
||||
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool windowactivate --sync "$W" >/dev/null 2>&1 || true
|
||||
|
||||
echo "INTERACTIVE_TERMINAL_GATE=PASS"
|
||||
echo "ACTION=$ACTION"
|
||||
echo "STATE=ON"
|
||||
echo "WINDOW_ID=$W"
|
||||
echo "INTERACTIVE=YES"
|
||||
echo "STYLE=GREEN_MONOCHROME"
|
||||
echo "TERM_FG=$TERM_FG"
|
||||
echo "TERM_BG=$TERM_BG"
|
||||
exit 0
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env bash
|
||||
set +e
|
||||
|
||||
ACTION="$(printf '%s' "$1" | tr '[:lower:]' '[:upper:]')"
|
||||
[ -n "$ACTION" ] || ACTION="ENSURE"
|
||||
|
||||
case "$ACTION" in
|
||||
ENSURE|FOCUS|STATUS) ;;
|
||||
*)
|
||||
echo "PROGRESS_CONSOLE_GATE=FAIL"
|
||||
echo "ERROR=INVALID_ACTION"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
TITLE="FrameBridge - Progreso DIG"
|
||||
LOG_DIR="${FRAMEBRIDGE_PROGRESS_DIR:-$HOME/.local/state/framebridge/progress}"
|
||||
LOG="${FRAMEBRIDGE_PROGRESS_LOG:-$LOG_DIR/framebridge-progress.log}"
|
||||
DISPLAY_VALUE="$(printenv DISPLAY 2>/dev/null)"
|
||||
[ -n "$DISPLAY_VALUE" ] || DISPLAY_VALUE=":0"
|
||||
XAUTH_VALUE="$(printenv XAUTHORITY 2>/dev/null)"
|
||||
[ -n "$XAUTH_VALUE" ] || XAUTH_VALUE="$HOME/.Xauthority"
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
chmod 700 "$LOG_DIR" 2>/dev/null || true
|
||||
touch "$LOG"
|
||||
chmod 600 "$LOG" 2>/dev/null || true
|
||||
|
||||
if [ ! -s "$LOG" ]; then
|
||||
cat > "$LOG" <<'HEADER'
|
||||
============================================================
|
||||
FRAMEBRIDGE ASUS // DIG PROGRESS
|
||||
MODO: SOLO LECTURA
|
||||
============================================================
|
||||
HEADER
|
||||
fi
|
||||
|
||||
find_window()
|
||||
{
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool search --name "^$TITLE$" 2>/dev/null | tail -n1
|
||||
}
|
||||
|
||||
W="$(find_window)"
|
||||
|
||||
if [ "$ACTION" = "STATUS" ]; then
|
||||
echo "PROGRESS_CONSOLE_GATE=PASS"
|
||||
if [ -n "$W" ]; then
|
||||
echo "STATE=ON"
|
||||
echo "WINDOW_ID=$W"
|
||||
else
|
||||
echo "STATE=OFF"
|
||||
echo "WINDOW_ID="
|
||||
fi
|
||||
echo "LOG=$LOG"
|
||||
echo "READ_ONLY=YES"
|
||||
echo "STYLE=GREEN_MONOCHROME_DIG"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$W" ]; then
|
||||
export FB_PROGRESS_LOG="$LOG"
|
||||
export FB_PROGRESS_TITLE="$TITLE"
|
||||
|
||||
if command -v gnome-terminal >/dev/null 2>&1; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" gnome-terminal --title="$TITLE" -- bash -lc '
|
||||
printf "\033]0;%s\007" "$FB_PROGRESS_TITLE"
|
||||
printf "\033]10;#a8ffb5\007"
|
||||
printf "\033]11;#010402\007"
|
||||
printf "\033[1;38;2;168;255;181m"
|
||||
printf "============================================================\n"
|
||||
printf " FRAMEBRIDGE // DIG PROGRESS // SOLO LECTURA\n"
|
||||
printf "============================================================\n"
|
||||
exec tail -n 200 -F "$FB_PROGRESS_LOG"
|
||||
' >/dev/null 2>&1 &
|
||||
elif command -v xterm >/dev/null 2>&1; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xterm -T "$TITLE" -fg "#a8ffb5" -bg "#010402" -e bash -lc 'exec tail -n 200 -F "$FB_PROGRESS_LOG"' >/dev/null 2>&1 &
|
||||
else
|
||||
echo "PROGRESS_CONSOLE_GATE=FAIL"
|
||||
echo "ERROR=NO_SUPPORTED_TERMINAL"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
for _ in $(seq 1 50); do
|
||||
W="$(find_window)"
|
||||
[ -n "$W" ] && break
|
||||
sleep 0.1
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$W" ]; then
|
||||
echo "PROGRESS_CONSOLE_GATE=FAIL"
|
||||
echo "ERROR=WINDOW_NOT_FOUND"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if command -v wmctrl >/dev/null 2>&1; then
|
||||
GEOM="$(DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool getdisplaygeometry 2>/dev/null)"
|
||||
SW="$(printf '%s' "$GEOM" | awk '{print $1}')"
|
||||
SH="$(printf '%s' "$GEOM" | awk '{print $2}')"
|
||||
if [ -n "$SW" ] && [ -n "$SH" ]; then
|
||||
H=330
|
||||
Y=$((SH - H - 28))
|
||||
[ "$Y" -lt 0 ] && Y=0
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" wmctrl -ir "$W" -e "0,0,$Y,$SW,$H" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$ACTION" = "FOCUS" ]; then
|
||||
DISPLAY="$DISPLAY_VALUE" XAUTHORITY="$XAUTH_VALUE" xdotool windowactivate --sync "$W" >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
echo "PROGRESS_CONSOLE_GATE=PASS"
|
||||
echo "ACTION=$ACTION"
|
||||
echo "STATE=ON"
|
||||
echo "WINDOW_ID=$W"
|
||||
echo "LOG=$LOG"
|
||||
echo "READ_ONLY=YES"
|
||||
echo "STYLE=GREEN_MONOCHROME_DIG"
|
||||
exit 0
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
SESSION="framebridge"
|
||||
tmux has-session -t "$SESSION" 2>/dev/null || tmux new-session -d -s "$SESSION"
|
||||
|
||||
if command -v gnome-terminal >/dev/null 2>&1; then
|
||||
exec gnome-terminal -- bash -lc "tmux attach -t '$SESSION'"
|
||||
elif command -v xfce4-terminal >/dev/null 2>&1; then
|
||||
exec xfce4-terminal --command="bash -lc \"tmux attach -t '$SESSION'\""
|
||||
elif command -v konsole >/dev/null 2>&1; then
|
||||
exec konsole -e bash -lc "tmux attach -t '$SESSION'"
|
||||
elif command -v xterm >/dev/null 2>&1; then
|
||||
exec xterm -e tmux attach -t "$SESSION"
|
||||
else
|
||||
echo "No encontré terminal gráfica compatible."
|
||||
echo "Ejecuta manualmente: tmux attach -t $SESSION"
|
||||
exit 1
|
||||
fi
|
||||
Reference in new issue
Block a user