feat(statusline): estados activo (deterministas) + reposo (haiku)
Separa el ciclo de trabajo en dos grupos con la fuente adecuada para cada uno: - ACTIVO (mientras se trabaja): lo marca el hook PostToolUse de forma determinista, sin LLM, segun la herramienta usada — Read/Grep/Glob -> investigando; Edit/Write -> haciendo; Bash con tests -> testeando; Bash de lectura (ls/cat/git status...) -> investigando; mcp fn_search/show/... -> investigando. Refleja en tiempo real lo que hace el asistente. - REPOSO (al parar y ceder el control): lo resuelve el Stop hook con ask_llm (haiku) -> hecho / pendiente_revision / bloqueado / en_pausa. Al parar nunca queda en un estado activo. Cambios: - goal_phase_active.sh: nuevo hook PostToolUse (mapa herramienta -> fase activa). - goal_phase_worker.sh: ahora solo produce estados de reposo; se elimina el modo prompt. Mantiene el gate (resuelve reposo solo si hubo trabajo o se venia de activo) y el historial. - goal_tracker.sh: deja de lanzar clasificacion LLM en el prompt (redundante); vuelve a fijar objetivo desde el prompt + informar estado. - statusline.sh: nuevo estado en_pausa (en pausa); set de fases reordenado. - settings.json: registra el hook PostToolUse. Resultado: 1 sola llamada haiku por turno (Stop); el estado activo es gratis y refleja las acciones reales en vez de la intencion del prompt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# PostToolUse hook: marca el estado ACTIVO de la tarea segun la herramienta que
|
||||||
|
# el asistente acaba de usar. Determinista, sin LLM, en tiempo real. Solo actua
|
||||||
|
# si la terminal tiene un objetivo fijado.
|
||||||
|
#
|
||||||
|
# El estado de REPOSO (al parar: hecho/pendiente_revision/bloqueado/en_pausa) lo
|
||||||
|
# pone el Stop hook (goal_phase_eval.sh + goal_phase_worker.sh).
|
||||||
|
|
||||||
|
INPUT=$(cat)
|
||||||
|
SID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty' 2>/dev/null)
|
||||||
|
[ -z "$SID" ] && exit 0
|
||||||
|
|
||||||
|
F="$HOME/.claude/goals/${SID}.json"
|
||||||
|
[ -f "$F" ] || exit 0
|
||||||
|
GOAL=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
||||||
|
[ -z "$GOAL" ] && exit 0
|
||||||
|
|
||||||
|
TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
|
||||||
|
[ -z "$TOOL" ] && exit 0
|
||||||
|
|
||||||
|
PHASE=""
|
||||||
|
case "$TOOL" in
|
||||||
|
Read|Grep|Glob|NotebookRead|WebFetch|WebSearch|ToolSearch)
|
||||||
|
PHASE=investigando ;;
|
||||||
|
Edit|Write|MultiEdit|NotebookEdit)
|
||||||
|
PHASE=haciendo ;;
|
||||||
|
Task|Agent|Workflow)
|
||||||
|
PHASE=haciendo ;;
|
||||||
|
Bash)
|
||||||
|
CMD=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""' 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
||||||
|
case "$CMD" in
|
||||||
|
*pytest*|*"go test"*|*ctest*|*jest*|*vitest*|*"npm test"*|*"npm run test"*|*"cargo test"*|*unittest*|*" test "*|*"./fn run"*test*)
|
||||||
|
PHASE=testeando ;;
|
||||||
|
ls|ls\ *|cat\ *|*grep*|find\ *|head\ *|tail\ *|stat\ *|tree*|rg\ *|fd\ *|*"git status"*|*"git log"*|*"git diff"*|*"git show"*|*"git branch"*)
|
||||||
|
PHASE=investigando ;;
|
||||||
|
*)
|
||||||
|
PHASE=haciendo ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
mcp__registry__fn_search|mcp__registry__fn_show|mcp__registry__fn_code|mcp__registry__fn_uses|mcp__registry__fn_list_domains|mcp__registry__fn_doctor|mcp__registry__fn_proposal)
|
||||||
|
PHASE=investigando ;;
|
||||||
|
mcp__registry__fn_run)
|
||||||
|
PHASE=haciendo ;;
|
||||||
|
*)
|
||||||
|
# Herramientas que no representan un cambio de actividad (TodoWrite,
|
||||||
|
# AskUserQuestion, etc.): no tocar la fase.
|
||||||
|
exit 0 ;;
|
||||||
|
esac
|
||||||
|
[ -z "$PHASE" ] && exit 0
|
||||||
|
|
||||||
|
# Escribir la fase + mantener historial (append solo si cambia respecto al
|
||||||
|
# ultimo; se conservan los ultimos 12 estados).
|
||||||
|
TMP="${F}.tmp.$$"
|
||||||
|
if jq --arg p "$PHASE" '
|
||||||
|
.phase = $p
|
||||||
|
| .history = (
|
||||||
|
( .history // [] ) as $h
|
||||||
|
| ( if ($h | length) > 0 and ($h[-1] == $p) then $h else ($h + [$p]) end )
|
||||||
|
| .[-12:]
|
||||||
|
)
|
||||||
|
' "$F" > "$TMP" 2>/dev/null; then
|
||||||
|
mv "$TMP" "$F"
|
||||||
|
else
|
||||||
|
rm -f "$TMP"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Worker del sistema objetivo+fase. Clasifica la fase de la tarea con ask_llm
|
# Worker del Stop hook: resuelve el estado de REPOSO de la tarea cuando el
|
||||||
# (haiku, API directa; nunca `claude -p`, ver regla llm_invocation.md) y la
|
# asistente para y cede el control. Clasifica con ask_llm (haiku, API directa;
|
||||||
# escribe en el goal JSON manteniendo un historial de estados.
|
# nunca `claude -p`, ver regla llm_invocation.md) y lo escribe en el goal JSON
|
||||||
|
# manteniendo el historial.
|
||||||
#
|
#
|
||||||
# Dos modos:
|
# El estado ACTIVO (mientras se trabaja: investigando/haciendo/testeando) lo
|
||||||
# stop (default): se lanza tras una respuesta del asistente. Lee el ultimo
|
# marca el hook PostToolUse (goal_phase_active.sh), de forma determinista. Este
|
||||||
# turno del transcript y SOLO reevalua si hubo trabajo real (tool_use);
|
# worker SOLO produce estados de reposo: hecho, pendiente_revision, bloqueado,
|
||||||
# en turnos de charla pura no toca nada.
|
# en_pausa.
|
||||||
# prompt : se lanza tras un prompt del usuario, para feedback inmediato. Usa la
|
|
||||||
# intencion del prompt. Si el prompt es charla/pregunta y no implica
|
|
||||||
# avanzar la tarea, el modelo responde sin_cambio y no se toca nada.
|
|
||||||
#
|
#
|
||||||
# Args: <session_id> <transcript_path> <goal_json> [mode] [prompt_text]
|
# Args: <session_id> <transcript_path> <goal_json>
|
||||||
|
|
||||||
SID="$1"
|
SID="$1"
|
||||||
TRANSCRIPT="$2"
|
TRANSCRIPT="$2"
|
||||||
F="$3"
|
F="$3"
|
||||||
MODE="${4:-stop}"
|
|
||||||
PROMPT_ARG="$5"
|
|
||||||
|
|
||||||
PY="$HOME/fn_registry/python/.venv/bin/python3"
|
PY="$HOME/fn_registry/python/.venv/bin/python3"
|
||||||
ASK="$HOME/fn_registry/python/functions/core/ask_llm.py"
|
ASK="$HOME/fn_registry/python/functions/core/ask_llm.py"
|
||||||
@@ -25,55 +21,58 @@ ASK="$HOME/fn_registry/python/functions/core/ask_llm.py"
|
|||||||
[ -x "$PY" ] || exit 0
|
[ -x "$PY" ] || exit 0
|
||||||
[ -f "$ASK" ] || exit 0
|
[ -f "$ASK" ] || exit 0
|
||||||
[ -f "$F" ] || exit 0
|
[ -f "$F" ] || exit 0
|
||||||
|
[ -f "$TRANSCRIPT" ] || exit 0
|
||||||
|
|
||||||
GOAL=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
GOAL=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
||||||
[ -z "$GOAL" ] && exit 0
|
[ -z "$GOAL" ] && exit 0
|
||||||
|
CUR=$(jq -r '.phase // ""' "$F" 2>/dev/null)
|
||||||
|
|
||||||
USER_MSG=""
|
is_active() {
|
||||||
|
case "$1" in
|
||||||
|
investigando|planificando|haciendo|testeando|puliendo) return 0 ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Una pasada de abajo a arriba sobre el turno actual: ultima respuesta de texto
|
||||||
|
# del asistente + ultima peticion del usuario + si hubo trabajo (tool_use).
|
||||||
LAST=""
|
LAST=""
|
||||||
|
USER_MSG=""
|
||||||
if [ "$MODE" = "prompt" ]; then
|
HAS_WORK=0
|
||||||
# Modo prompt: clasifica la intencion del mensaje recien enviado.
|
while IFS= read -r line; do
|
||||||
USER_MSG="$PROMPT_ARG"
|
t=$(printf '%s' "$line" | jq -r '.type // empty' 2>/dev/null)
|
||||||
[ -z "$USER_MSG" ] && exit 0
|
if [ "$t" = "assistant" ]; then
|
||||||
LAST="(el usuario acaba de enviar este mensaje; aun no hay respuesta del asistente)"
|
if [ -z "$LAST" ]; then
|
||||||
else
|
txt=$(printf '%s' "$line" | jq -r '(.message.content // [])[]? | select(.type=="text") | .text' 2>/dev/null)
|
||||||
# Modo stop: una sola pasada de abajo a arriba sobre el turno actual.
|
[ -n "$txt" ] && LAST="$txt"
|
||||||
# Captura la ultima respuesta de texto del asistente + detecta trabajo real.
|
|
||||||
[ -f "$TRANSCRIPT" ] || exit 0
|
|
||||||
HAS_WORK=0
|
|
||||||
while IFS= read -r line; do
|
|
||||||
t=$(printf '%s' "$line" | jq -r '.type // empty' 2>/dev/null)
|
|
||||||
if [ "$t" = "assistant" ]; then
|
|
||||||
if [ -z "$LAST" ]; then
|
|
||||||
txt=$(printf '%s' "$line" | jq -r '(.message.content // [])[]? | select(.type=="text") | .text' 2>/dev/null)
|
|
||||||
[ -n "$txt" ] && LAST="$txt"
|
|
||||||
fi
|
|
||||||
if printf '%s' "$line" | jq -e '(.message.content // [])[]? | select(.type=="tool_use")' >/dev/null 2>&1; then
|
|
||||||
HAS_WORK=1
|
|
||||||
fi
|
|
||||||
elif [ "$t" = "user" ]; then
|
|
||||||
ctype=$(printf '%s' "$line" | jq -r '.message.content | type' 2>/dev/null)
|
|
||||||
if [ "$ctype" = "string" ]; then
|
|
||||||
USER_MSG=$(printf '%s' "$line" | jq -r '.message.content' 2>/dev/null)
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
if ! printf '%s' "$line" | jq -e '(.message.content // [])[]? | select(.type=="tool_result")' >/dev/null 2>&1; then
|
|
||||||
USER_MSG=$(printf '%s' "$line" | jq -r '(.message.content // [])[]? | select(.type=="text") | .text' 2>/dev/null)
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done < <(tac "$TRANSCRIPT")
|
if printf '%s' "$line" | jq -e '(.message.content // [])[]? | select(.type=="tool_use")' >/dev/null 2>&1; then
|
||||||
|
HAS_WORK=1
|
||||||
|
fi
|
||||||
|
elif [ "$t" = "user" ]; then
|
||||||
|
ctype=$(printf '%s' "$line" | jq -r '.message.content | type' 2>/dev/null)
|
||||||
|
if [ "$ctype" = "string" ]; then
|
||||||
|
USER_MSG=$(printf '%s' "$line" | jq -r '.message.content' 2>/dev/null)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if ! printf '%s' "$line" | jq -e '(.message.content // [])[]? | select(.type=="tool_result")' >/dev/null 2>&1; then
|
||||||
|
USER_MSG=$(printf '%s' "$line" | jq -r '(.message.content // [])[]? | select(.type=="text") | .text' 2>/dev/null)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < <(tac "$TRANSCRIPT")
|
||||||
|
|
||||||
# Charla pura (sin trabajo en el turno): no tocar la fase.
|
# Solo resolver reposo si hubo trabajo este turno o si veniamos de un estado
|
||||||
[ "$HAS_WORK" = "0" ] && exit 0
|
# activo (paramos tras currar). Charla sobre un reposo previo: no tocar.
|
||||||
LAST=$(printf '%s' "$LAST" | tail -c 4000)
|
if [ "$HAS_WORK" = "0" ] && ! is_active "$CUR"; then
|
||||||
[ -z "$LAST" ] && exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
LAST=$(printf '%s' "$LAST" | tail -c 4000)
|
||||||
|
[ -z "$LAST" ] && exit 0
|
||||||
USER_MSG=$(printf '%s' "$USER_MSG" | tail -c 1500)
|
USER_MSG=$(printf '%s' "$USER_MSG" | tail -c 1500)
|
||||||
|
|
||||||
SYS="Eres un clasificador de fase de tarea. Recibes el objetivo, la ULTIMA PETICION DEL USUARIO (marca la intencion) y la ULTIMA RESPUESTA DEL ASISTENTE. Clasifica la actividad actual con UNA sola palabra de esta lista exacta, sin nada mas: investigando planificando haciendo testeando puliendo iterando pendiente_revision bloqueado hecho sin_cambio. Definiciones: investigando=explorando o leyendo ACTIVAMENTE codigo/archivos del proyecto como paso para avanzar la tarea (no una simple pregunta conceptual); planificando=disenando el enfoque sin ejecutar todavia; haciendo=implementando cambios; testeando=corriendo tests, probando o validando tecnicamente (si piden 'testea/prueba/valida', es testeando); puliendo=retoques finales sobre algo ya casi listo; iterando=ciclo continuo de ajustes pequenos; pendiente_revision=el asistente espera que el humano revise o decida algo importante; bloqueado=no puede avanzar por un error o falta de informacion; hecho=el objetivo esta claramente terminado y verificado; sin_cambio=la peticion NO implica un cambio de actividad: preguntas, peticiones de explicacion o aclaracion conceptual, comentarios, opiniones o dudas que no ordenan avanzar, modificar o probar la tarea. La peticion del usuario pesa: refleja que se pidio hacer. Usa 'hecho' SOLO si el trabajo esta completo y confirmado. Ante la duda entre una fase concreta y sin_cambio, prefiere sin_cambio."
|
SYS="El asistente acaba de PARAR y cede el control al usuario. Clasifica el estado de REPOSO en que queda la tarea. Responde UNA sola palabra, sin nada mas, de: hecho pendiente_revision bloqueado en_pausa sin_cambio. hecho=el objetivo esta completo y verificado; pendiente_revision=el asistente espera que el humano revise un resultado o decida algo importante; bloqueado=no puede avanzar por un error o por falta de informacion del usuario; en_pausa=hizo un avance y espera la siguiente indicacion, sin estar terminado ni bloqueado ni a la espera de revision; sin_cambio=el turno no altera el estado de reposo actual (charla irrelevante). Usa 'hecho' SOLO si el trabajo esta completo y confirmado, nunca si queda algo pendiente."
|
||||||
|
|
||||||
PROMPT="OBJETIVO DE LA TAREA: ${GOAL}
|
PROMPT="OBJETIVO DE LA TAREA: ${GOAL}
|
||||||
|
|
||||||
@@ -83,28 +82,24 @@ ${USER_MSG}
|
|||||||
ULTIMA RESPUESTA DEL ASISTENTE:
|
ULTIMA RESPUESTA DEL ASISTENTE:
|
||||||
${LAST}
|
${LAST}
|
||||||
|
|
||||||
Responde la fase actual (una sola palabra de la lista, o sin_cambio):"
|
Responde con una sola palabra de la lista permitida:"
|
||||||
|
|
||||||
RAW=$("$PY" "$ASK" --model claude-haiku-4-5-20251001 --system "$SYS" "$PROMPT" 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
RAW=$("$PY" "$ASK" --model claude-haiku-4-5-20251001 --system "$SYS" "$PROMPT" 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
||||||
[ -z "$RAW" ] && exit 0
|
[ -z "$RAW" ] && exit 0
|
||||||
|
|
||||||
# Normalizar la respuesta a un slug canonico (tolerante a verbosidad/acentos).
|
|
||||||
case "$RAW" in
|
case "$RAW" in
|
||||||
*sin_cambio*|*sincambio*|*ninguna*|*charla*) exit 0 ;;
|
*sin_cambio*|*sincambio*|*ninguna*|*charla*) exit 0 ;;
|
||||||
*pendiente*revis*|*revis*) PHASE=pendiente_revision ;;
|
*pendiente*revis*|*revis*) PHASE=pendiente_revision ;;
|
||||||
*investig*) PHASE=investigando ;;
|
*bloque*) PHASE=bloqueado ;;
|
||||||
*planific*) PHASE=planificando ;;
|
*hecho*|*complet*|*termin*|*done*) PHASE=hecho ;;
|
||||||
*test*) PHASE=testeando ;;
|
*pausa*|*pause*|*espera*|*siguiente*) PHASE=en_pausa ;;
|
||||||
*puli*) PHASE=puliendo ;;
|
# Si por error devuelve un estado activo al parar, lo tratamos como pausa.
|
||||||
*iter*) PHASE=iterando ;;
|
investigando|planificando|haciendo|testeando|puliendo) PHASE=en_pausa ;;
|
||||||
*bloque*) PHASE=bloqueado ;;
|
|
||||||
*hecho*|*complet*|*termin*|*done*) PHASE=hecho ;;
|
|
||||||
*hacien*|*implement*) PHASE=haciendo ;;
|
|
||||||
*) exit 0 ;;
|
*) exit 0 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Escribir la fase + mantener el historial (append solo si cambia respecto al
|
# Escribir la fase + mantener historial (append solo si cambia respecto al
|
||||||
# ultimo, para no llenar de repetidos; se conservan los ultimos 12 estados).
|
# ultimo; se conservan los ultimos 12 estados).
|
||||||
TMP="${F}.tmp.$$"
|
TMP="${F}.tmp.$$"
|
||||||
if jq --arg p "$PHASE" '
|
if jq --arg p "$PHASE" '
|
||||||
.phase = $p
|
.phase = $p
|
||||||
|
|||||||
@@ -43,15 +43,13 @@ if [ -n "$GOAL_LINE" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 2) Informativo + clasificacion inmediata desde el prompt.
|
# 2) Informativo: estado actual para el modelo.
|
||||||
|
# La fase la mantienen los hooks automaticamente: PostToolUse marca el estado
|
||||||
|
# ACTIVO segun las herramientas usadas; el Stop hook resuelve el REPOSO con haiku.
|
||||||
if [ -f "$F" ]; then
|
if [ -f "$F" ]; then
|
||||||
G=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
G=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
||||||
P=$(jq -r '.phase // ""' "$F" 2>/dev/null)
|
P=$(jq -r '.phase // ""' "$F" 2>/dev/null)
|
||||||
# Clasifica la fase ya, desde la intencion del prompt (modo prompt, background).
|
echo "GOAL-TRACKER: file=$F | goal=\"$G\" phase=\"$P\". La fase la mantienen los hooks automaticamente (PostToolUse = activo, Stop = reposo) — NO escribas la fase. El usuario fija el objetivo escribiendo \"objetivo: <texto>\"; si redefine la tarea en lenguaje natural, actualiza \"goal\" en ese JSON."
|
||||||
# El Stop hook la reevaluara despues con el resultado de la respuesta.
|
|
||||||
TRANSCRIPT=$(printf '%s' "$INPUT" | jq -r '.transcript_path // ""' 2>/dev/null)
|
|
||||||
nohup bash "$HOME/.claude/hooks/goal_phase_worker.sh" "$SID" "$TRANSCRIPT" "$F" prompt "$PROMPT" >/dev/null 2>&1 &
|
|
||||||
echo "GOAL-TRACKER: file=$F | goal=\"$G\" phase=\"$P\". La fase la mantienen los hooks automaticamente (tu prompt + mi respuesta) — NO escribas la fase. El usuario fija el objetivo escribiendo \"objetivo: <texto>\"; si redefine la tarea en lenguaje natural, actualiza \"goal\" en ese JSON."
|
|
||||||
else
|
else
|
||||||
echo "GOAL-TRACKER: file=$F (sin objetivo aun). El usuario fija el objetivo de la terminal escribiendo \"objetivo: <texto>\" (lo captura este hook directo de su prompt). Si describe una tarea clara sin ese prefijo, crea {\"goal\":\"<su objetivo>\",\"phase\":\"planificando\"} leyendo su prompt. Sin objetivo, ignora."
|
echo "GOAL-TRACKER: file=$F (sin objetivo aun). El usuario fija el objetivo de la terminal escribiendo \"objetivo: <texto>\" (lo captura este hook directo de su prompt). Si describe una tarea clara sin ese prefijo, crea {\"goal\":\"<su objetivo>\",\"phase\":\"planificando\"} leyendo su prompt. Sin objetivo, ignora."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -27,6 +27,13 @@
|
|||||||
{ "type": "command", "command": "~/.claude/hooks/goal_phase_eval.sh" }
|
{ "type": "command", "command": "~/.claude/hooks/goal_phase_eval.sh" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{ "type": "command", "command": "~/.claude/hooks/goal_phase_active.sh" }
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"statusLine": {
|
"statusLine": {
|
||||||
|
|||||||
@@ -116,10 +116,11 @@ phase_style() {
|
|||||||
haciendo) printf '🔨|33|haciendo' ;;
|
haciendo) printf '🔨|33|haciendo' ;;
|
||||||
testeando) printf '🧪|35|testeando' ;;
|
testeando) printf '🧪|35|testeando' ;;
|
||||||
puliendo) printf '✨|95|puliendo detalles' ;;
|
puliendo) printf '✨|95|puliendo detalles' ;;
|
||||||
iterando) printf '🔁|94|iterando' ;;
|
|
||||||
pendiente_revision) printf '👀|93|pendiente de revisión' ;;
|
pendiente_revision) printf '👀|93|pendiente de revisión' ;;
|
||||||
bloqueado) printf '⛔|31|bloqueado' ;;
|
bloqueado) printf '⛔|31|bloqueado' ;;
|
||||||
|
en_pausa) printf '⏸️|90|en pausa' ;;
|
||||||
hecho) printf '✅|32|hecho' ;;
|
hecho) printf '✅|32|hecho' ;;
|
||||||
|
iterando) printf '🔁|94|iterando' ;;
|
||||||
*) printf "•|90|$1" ;;
|
*) printf "•|90|$1" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user