1840402453
El objetivo y el DoD dejan de quedarse congelados en el primer prompt: - goal_tracker acumula cada prompt sustantivo del usuario en .prompts y lanza goal_refine.sh (background, haiku) para mantener objetivo y DoD coherentes con TODO lo pedido (action refine), o dejarlos igual (action same). - goal_refine marca alert=true (action switch) cuando el ultimo prompt introduce una tarea completamente distinta del objetivo: senal de que la terminal mezcla tareas (principio: una terminal = una tarea). No cambia el objetivo, solo avisa. - statusline muestra ⚠️ en rojo antes del objetivo cuando alert=true. - Comando 'recalcular' (recalcula/replantea): fuerza regenerar objetivo+DoD desde los prompts y limpia la alerta (para cuando el cambio de tarea es intencional). - goal_autogen inicializa .prompts con el primer prompt. Coste: 1 haiku/prompt sustantivo en background (ademas del haiku de reposo del Stop), solicitado para mantener la coherencia. No bloquea el turno. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
117 lines
5.4 KiB
Bash
Executable File
117 lines
5.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# UserPromptSubmit hook del sistema de objetivo+fase por terminal.
|
|
#
|
|
# Comandos que lee directamente de tu prompt (sin intervencion del modelo):
|
|
# objetivo: <texto> fija el objetivo de la terminal (meta:/goal: equivalen).
|
|
# objetivo: clear lo borra (tambien -, none, borrar, quitar, reset).
|
|
# dod: <texto> fija un Definition of Done corto (se muestra junto al objetivo).
|
|
# dod: clear lo borra.
|
|
# pausa marca la fase en en_pausa. Util tras interrumpir con Ctrl-C,
|
|
# que en Claude Code no dispara ningun hook (no hay forma de
|
|
# detectar la interrupcion automaticamente).
|
|
# En cualquier otro caso, inyecta el estado actual como contexto para el modelo.
|
|
#
|
|
# La FASE la mantienen los hooks de fase: PostToolUse (activo) y Stop (reposo).
|
|
|
|
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)
|
|
PROMPT_TRIM=$(printf '%s' "$PROMPT" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')
|
|
|
|
# --- objetivo: <texto> (preserva el DoD si ya existia) ---
|
|
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."
|
|
exit 0 ;;
|
|
esac
|
|
if [ -f "$F" ]; then
|
|
PH=$(jq -r '.phase // "planificando"' "$F" 2>/dev/null)
|
|
DD=$(jq -r '.dod // ""' "$F" 2>/dev/null)
|
|
else
|
|
PH="planificando"; DD=""
|
|
fi
|
|
TMP="${F}.tmp.$$"
|
|
if jq -n --arg g "$NEWGOAL" --arg p "$PH" --arg d "$DD" \
|
|
'{goal:$g, phase:$p} | if $d != "" then .dod=$d else . end' > "$TMP" 2>/dev/null; then
|
|
mv "$TMP" "$F"
|
|
else
|
|
rm -f "$TMP"
|
|
fi
|
|
echo "GOAL-TRACKER: objetivo fijado desde tu prompt -> \"$NEWGOAL\"."
|
|
exit 0
|
|
fi
|
|
|
|
# --- dod: <texto> ---
|
|
DOD_LINE=$(printf '%s' "$PROMPT" | grep -ioE '^[[:space:]]*dod[[:space:]]*:[[:space:]]*.+' | head -1)
|
|
if [ -n "$DOD_LINE" ]; then
|
|
NEWDOD=$(printf '%s' "$DOD_LINE" | sed -E 's/^[^:]*:[[:space:]]*//; s/[[:space:]]+$//')
|
|
[ -f "$F" ] || { echo "GOAL-TRACKER: fija primero un objetivo (\"objetivo: ...\") antes del DoD."; exit 0; }
|
|
case "$NEWDOD" in
|
|
-|clear|none|borrar|quitar|reset)
|
|
TMP="${F}.tmp.$$"
|
|
jq 'del(.dod)' "$F" > "$TMP" 2>/dev/null && mv "$TMP" "$F"
|
|
echo "GOAL-TRACKER: DoD borrado."
|
|
exit 0 ;;
|
|
esac
|
|
TMP="${F}.tmp.$$"
|
|
if jq --arg d "$NEWDOD" '.dod=$d' "$F" > "$TMP" 2>/dev/null; then mv "$TMP" "$F"; else rm -f "$TMP"; fi
|
|
echo "GOAL-TRACKER: DoD fijado -> \"$NEWDOD\"."
|
|
exit 0
|
|
fi
|
|
|
|
# --- recalcular (regenera objetivo+DoD desde los prompts; limpia la alerta) ---
|
|
case "$PROMPT_TRIM" in
|
|
recalcular|recalcula|replantea|replantear|/recalcular)
|
|
[ -f "$F" ] || { echo "GOAL-TRACKER: no hay objetivo que recalcular."; exit 0; }
|
|
nohup bash "$HOME/.claude/hooks/goal_refine.sh" "$SID" "$F" force >/dev/null 2>&1 &
|
|
echo "GOAL-TRACKER: recalculando objetivo+DoD desde tus prompts (background)."
|
|
exit 0 ;;
|
|
esac
|
|
|
|
# --- pausa (marca manual; Ctrl-C no dispara hooks en Claude Code) ---
|
|
case "$PROMPT_TRIM" in
|
|
pausa|pause|pausar|"en pausa"|/pausa)
|
|
[ -f "$F" ] || exit 0
|
|
TMP="${F}.tmp.$$"
|
|
if jq '.phase="en_pausa" | .history=((.history // [])+["en_pausa"])[-12:]' "$F" > "$TMP" 2>/dev/null; then
|
|
mv "$TMP" "$F"
|
|
fi
|
|
echo "GOAL-TRACKER: fase marcada en_pausa."
|
|
exit 0 ;;
|
|
esac
|
|
|
|
# --- informativo: estado actual para el modelo ---
|
|
if [ -f "$F" ]; then
|
|
G=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
|
P=$(jq -r '.phase // ""' "$F" 2>/dev/null)
|
|
D=$(jq -r '.dod // ""' "$F" 2>/dev/null)
|
|
# Acumular el prompt y refinar objetivo+DoD para mantenerlos coherentes con
|
|
# todo lo pedido (background). Si el prompt es una tarea totalmente distinta,
|
|
# goal_refine marca alert=true (la terminal mezcla tareas).
|
|
if [ "${#PROMPT_TRIM}" -ge 12 ]; then
|
|
TMP="${F}.tmp.$$"
|
|
if jq --arg p "$PROMPT_TRIM" '.prompts = ((.prompts // []) + [$p])[-12:]' "$F" > "$TMP" 2>/dev/null; then
|
|
mv "$TMP" "$F"
|
|
else
|
|
rm -f "$TMP"
|
|
fi
|
|
nohup bash "$HOME/.claude/hooks/goal_refine.sh" "$SID" "$F" >/dev/null 2>&1 &
|
|
fi
|
|
echo "GOAL-TRACKER: file=$F | goal=\"$G\" dod=\"$D\" phase=\"$P\". La fase la mantienen los hooks (PostToolUse=activo, Stop=reposo) — NO la escribas. El usuario fija objetivo con \"objetivo: ...\" y un DoD corto con \"dod: ...\"; si redefine la tarea en lenguaje natural, actualiza \"goal\" en ese JSON. El objetivo/DoD se autorefinan con tus prompts; si ves ⚠️ es que la terminal esta mezclando tareas."
|
|
else
|
|
# Sin objetivo: autogenerar objetivo + DoD desde el primer prompt sustantivo,
|
|
# en background (no bloquea). Se omite para prompts triviales (saludos, ok...).
|
|
if [ "${#PROMPT_TRIM}" -ge 12 ]; then
|
|
nohup bash "$HOME/.claude/hooks/goal_autogen.sh" "$SID" "$F" "$PROMPT" >/dev/null 2>&1 &
|
|
fi
|
|
echo "GOAL-TRACKER: file=$F (sin objetivo aun). Autogenerando objetivo+DoD desde tu prompt en background (haiku). Tambien puedes fijarlo a mano con \"objetivo: <texto>\" / \"dod: <texto>\"."
|
|
fi
|
|
exit 0
|