f881b7703b
- statusline.sh: muestra los ultimos 7 estados previos como emojis atenuados (DIM) separados por │, entre el objetivo y la fase actual. El historial se guarda en el goal JSON (campo .history), colapsando estados consecutivos repetidos, hasta 12 entradas. - goal_phase_worker.sh: dos modos. 'stop' (tras la respuesta del asistente, con filtro de trabajo real) y 'prompt' (tras el prompt del usuario, clasifica la intencion para feedback inmediato). Nuevo veredicto 'sin_cambio' para preguntas/charla que no implican cambio de actividad; ante la duda, no toca. Ambos modos mantienen el historial. - goal_tracker.sh: en cada prompt con objetivo activo lanza el worker en modo prompt (background) ademas del Stop hook. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
2.9 KiB
Bash
Executable File
59 lines
2.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# UserPromptSubmit hook del sistema de objetivo+fase por terminal.
|
|
#
|
|
# Dos funciones:
|
|
# 1) Si tu prompt empieza por "objetivo:" (o "meta:" / "goal:"), fija el objetivo
|
|
# de esta terminal leyendolo DIRECTAMENTE de tu prompt, sin intervencion del
|
|
# modelo. "objetivo: clear" (o -, none, borrar, quitar, reset) lo elimina.
|
|
# 2) En cualquier otro caso, inyecta el estado actual (goal+phase) como contexto
|
|
# para que el modelo sepa donde esta el archivo y que objetivo hay vigente.
|
|
#
|
|
# La FASE no la toca este hook: la mantiene el Stop hook (goal_phase_eval.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"
|
|
PROMPT=$(printf '%s' "$INPUT" | jq -r '.prompt // ""' 2>/dev/null)
|
|
|
|
# 1) Fijar/limpiar el objetivo leyendo el prompt del usuario.
|
|
GOAL_LINE=$(printf '%s' "$PROMPT" | grep -ioE '^[[:space:]]*(objetivo|meta|goal)[[:space:]]*:[[:space:]]*.+' | head -1)
|
|
if [ -n "$GOAL_LINE" ]; then
|
|
NEWGOAL=$(printf '%s' "$GOAL_LINE" | sed -E 's/^[^:]*:[[:space:]]*//; s/[[:space:]]+$//')
|
|
case "$NEWGOAL" in
|
|
-|clear|none|borrar|quitar|reset)
|
|
rm -f "$F"
|
|
echo "GOAL-TRACKER: objetivo de esta terminal borrado. El statusline deja de mostrar la linea de objetivo."
|
|
exit 0
|
|
;;
|
|
esac
|
|
if [ -f "$F" ]; then
|
|
PH=$(jq -r '.phase // "planificando"' "$F" 2>/dev/null)
|
|
else
|
|
PH="planificando"
|
|
fi
|
|
TMP="${F}.tmp.$$"
|
|
if jq -n --arg g "$NEWGOAL" --arg p "$PH" '{goal:$g, phase:$p}' > "$TMP" 2>/dev/null; then
|
|
mv "$TMP" "$F"
|
|
else
|
|
rm -f "$TMP"
|
|
fi
|
|
echo "GOAL-TRACKER: objetivo fijado desde tu prompt -> \"$NEWGOAL\" (phase=$PH). El statusline ya lo muestra; la fase la mantiene el Stop hook automaticamente."
|
|
exit 0
|
|
fi
|
|
|
|
# 2) Informativo + clasificacion inmediata desde el prompt.
|
|
if [ -f "$F" ]; then
|
|
G=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
|
P=$(jq -r '.phase // ""' "$F" 2>/dev/null)
|
|
# Clasifica la fase ya, desde la intencion del prompt (modo prompt, background).
|
|
# 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
|
|
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
|
|
exit 0
|