FrameBridge 0.3.1 community source release

This commit is contained in:
FrameBridge Development committed 2026-10-26 22:09:18 -04:00
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
@@ -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
@@ -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