Nueva versión de OnlyOffice Docs

Desde el equipo de ONLYOFFICE se han puesto en contacto con nosotros para contarnos que ya está disponible ONLYOFFICE Docs 10.0, la versión más reciente de su suite ofimática de código abierto y autohospedada. Sirve para trabajar con documentos, hojas de cálculo, presentaciones, formularios rellenables, archivos PDF y diagramas.

Según nos indican, esta versión trae unas 50 funciones nuevas, más de 1.000 errores corregidos y unas 35 vulnerabilidades solucionadas.

Principales novedades de ONLYOFFICE Docs 10.0

Estas son las novedades más importantes que destacan desde ONLYOFFICE: read more

Leer más » Comentar

EOF

EOF

Leer más » 1 Comentario

CERN

cern

Leer más » Comentar

Agua

agua

Leer más » Comentar

Aire acondicionado

aire-acondicionado

Leer más » Comentar

Eclipse

eclipse

Leer más » Comentar

Monitoriza tu consumo de Claude Code en GNOME con Python y AppIndicator

Si trabajas a diario con Claude Code, seguramente te haya pasado: estás a mitad de una tarea larga y de pronto te quedas sin cuota. Existe el comando /usage dentro de Claude Code, pero hay que pararse a escribirlo. Lo cómodo sería tener el dato siempre delante, en la barra superior de Ubuntu.

En este artículo montamos justo eso: un indicador que muestra de forma permanente el porcentaje consumido de la sesión de 5 horas y el de la cuota semanal, con el tiempo que falta para cada reset. Se refresca solo cada minuto y arranca automáticamente al iniciar sesión.

De dónde salen los datos

Claude Code guarda sus credenciales OAuth en ~/.claude/.credentials.json. Dentro hay un accessToken que sirve para consultar el mismo endpoint que usa internamente el comando /usage:

TOKEN=$(python3 -c "import json;print(json.load(open('$HOME/.claude/.credentials.json'))['claudeAiOauth']['accessToken'])")

curl -s https://api.anthropic.com/api/oauth/usage \
  -H "Authorization: Bearer $TOKEN" \
  -H "anthropic-beta: oauth-2025-04-20"

La respuesta trae bastantes campos, pero los dos que nos interesan son estos:

{
  "five_hour": {
    "utilization": 56.0,
    "resets_at": "2026-08-08T11:30:00+00:00"
  },
  "seven_day": {
    "utilization": 14.0,
    "resets_at": "2026-08-13T20:00:00+00:00"
  }
}

utilization es el porcentaje consumido y resets_at la marca temporal en UTC en la que ese contador vuelve a cero. Con eso ya tenemos todo lo necesario.

Un aviso antes de seguir: ese token da acceso a tu cuenta. Úsalo solo en local y no lo pegues en ningún sitio público, ni en capturas de pantalla ni en pastebins.

Por qué una app de bandeja y no una extensión de GNOME

El primer impulso es escribir una extensión de GNOME Shell, que es lo que pinta texto nativo en la barra. Y funciona, pero tiene un inconveniente serio en Ubuntu moderno: bajo Wayland, una extensión recién instalada no se carga hasta que reinicias GNOME Shell, y eso significa cerrar sesión. El clásico Alt+F2 seguido de r solo funciona en X11.

La alternativa que evita el cierre de sesión es una aplicación de bandeja con AyatanaAppIndicator3. Se apoya en la extensión ubuntu-appindicators, que Ubuntu trae activada de serie, y se registra en caliente: la lanzas y aparece al instante.

El script del indicador

Guarda esto en ~/.local/bin/claude-usage-indicator.py:

#!/usr/bin/env python3 import fcntl import json import sys import urllib.request from datetime import datetime, timezone from pathlib import Path import gi gi.require_version("Gtk", "3.0") gi.require_version("AyatanaAppIndicator3", "0.1") from gi.repository import AyatanaAppIndicator3 as AppIndicator from gi.repository import GLib, Gtk CRED = Path.home() / ".claude" / ".credentials.json" URL = "https://api.anthropic.com/api/oauth/usage" REFRESH_SECONDS = 60 def eta(iso): if not iso: return "" try: t = datetime.fromisoformat(iso) except ValueError: return "" secs = (t - datetime.now(timezone.utc)).total_seconds() if secs <= 0: return "0m" d, rem = divmod(int(secs), 86400) h, m = divmod(rem // 60, 60) if d: return f"{d}d{h}h" if h: return f"{h}h{m:02d}m" return f"{m}m" def reset_clock(iso): if not iso: return "" try: t = datetime.fromisoformat(iso).astimezone() except ValueError: return "" return t.strftime("%a %d %H:%M") def fetch(): token = json.loads(CRED.read_text())["claudeAiOauth"]["accessToken"] req = urllib.request.Request( URL, headers={ "Authorization": f"Bearer {token}", "anthropic-beta": "oauth-2025-04-20", }, ) with urllib.request.urlopen(req, timeout=8) as r: return json.load(r) class Indicator: def __init__(self): self.ind = AppIndicator.Indicator.new( "claude-usage", "utilities-system-monitor-symbolic", AppIndicator.IndicatorCategory.SYSTEM_SERVICES, ) self.ind.set_status(AppIndicator.IndicatorStatus.ACTIVE) self.menu = Gtk.Menu() self.detail = Gtk.MenuItem(label="Cargando...") self.detail.set_sensitive(False) self.menu.append(self.detail) self.menu.append(Gtk.SeparatorMenuItem()) refresh = Gtk.MenuItem(label="Actualizar ahora") refresh.connect("activate", lambda _w: self.refresh()) self.menu.append(refresh) quit_item = Gtk.MenuItem(label="Salir") quit_item.connect("activate", lambda _w: Gtk.main_quit()) self.menu.append(quit_item) self.menu.show_all() self.ind.set_menu(self.menu) self.refresh() GLib.timeout_add_seconds(REFRESH_SECONDS, self.refresh) def refresh(self): try: d = fetch() s, w = d["five_hour"], d["seven_day"] sp, wp = int(round(s["utilization"])), int(round(w["utilization"])) label = f"S {sp}% ({eta(s['resets_at'])}) · W {wp}% ({eta(w['resets_at'])})" detail = ( f"Sesion 5h: {sp}% -> resetea {reset_clock(s['resets_at'])}\n" f"Semanal: {wp}% -> resetea {reset_clock(w['resets_at'])}" ) except Exception as e: label = "Claude: --" detail = f"Sin datos: {e}" self.ind.set_label(label, "S 100% (0h00m) · W 100% (0d0h)") self.detail.set_label(detail) return GLib.SOURCE_CONTINUE if __name__ == "__main__": _lock = open("/tmp/claude-usage-indicator.lock", "w") try: fcntl.flock(_lock, fcntl.LOCK_EX | fcntl.LOCK_NB) except BlockingIOError: print("Ya hay una instancia en ejecucion.", file=sys.stderr) sys.exit(0) Indicator() Gtk.main() read more

Leer más » Comentar

No soy yo

no-soy-yo

Leer más » Comentar

Sin batería

sin-bateria

Leer más » Comentar

432 CVEs

432cve

Leer más » Comentar