e976fb303a
- /rename escribe el nombre en FleetView (.rename del goal). NO renombra el titulo de la sesion de Claude Code: el built-in /rename usa estado interno y no re-lee el transcript, asi que un evento ai-title no cambia el prompt bar (comprobado). - objetivo provisional: el primer prompt fija un goal placeholder hasta que haiku genera el definitivo, para que el statusline no quede vacio. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
3.0 KiB
Bash
Executable File
67 lines
3.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# Autogeneracion de objetivo + DoD a partir del primer prompt sustantivo de una
|
|
# terminal que aun no tiene objetivo. Lo lanza goal_tracker.sh en background (no
|
|
# bloquea el turno). Usa ask_llm (haiku, API directa; nunca `claude -p`).
|
|
#
|
|
# Args: <session_id> <goal_json_file> <prompt_text>
|
|
|
|
SID="$1"
|
|
F="$2"
|
|
PROMPT="$3"
|
|
|
|
# Si ya existe objetivo DEFINITIVO (usuario manual u otro autogen ya termino), no
|
|
# pisar. Un archivo PROVISIONAL (.provisional=true) SI se pisa: es el placeholder
|
|
# (= texto del usuario) que pusimos para que el statusline no quede vacio.
|
|
if [ -f "$F" ] && [ "$(jq -r '.provisional // false' "$F" 2>/dev/null)" != "true" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
PY="$HOME/fn_registry/python/.venv/bin/python3"
|
|
ASK="$HOME/fn_registry/python/functions/core/ask_llm.py"
|
|
[ -x "$PY" ] || exit 0
|
|
[ -f "$ASK" ] || exit 0
|
|
|
|
P=$(printf '%s' "$PROMPT" | tail -c 2000)
|
|
[ -z "$P" ] && exit 0
|
|
|
|
SYS="Dado el PRIMER mensaje de un usuario a un asistente de codigo en una terminal, infiere un OBJETIVO breve de la tarea (maximo 8 palabras, en espanol, sin comillas), un DoD breve (definition of done: condicion concreta de 'terminado', maximo 8 palabras, en espanol) y EXACTAMENTE 3 EMOJIS que representen visualmente la tarea (3 emojis pegados, sin espacios ni texto entre ellos). Responde SOLO un objeto JSON en una sola linea, sin markdown ni texto extra: {\"goal\":\"...\",\"dod\":\"...\",\"emojis\":\"🔭✨🌌\"}. Si el mensaje es un saludo, charla trivial o no describe ninguna tarea, responde exactamente {}."
|
|
|
|
RAW=$("$PY" "$ASK" --system "$SYS" "$P" 2>/dev/null)
|
|
[ -z "$RAW" ] && exit 0
|
|
|
|
# Extraer el primer objeto JSON de la salida (tolerante a texto/markdown extra).
|
|
JSON=$(printf '%s' "$RAW" | tr '\n' ' ' | grep -o '{[^{}]*}' | head -1)
|
|
[ -z "$JSON" ] && exit 0
|
|
|
|
GOAL=$(printf '%s' "$JSON" | jq -r '.goal // ""' 2>/dev/null)
|
|
DOD=$(printf '%s' "$JSON" | jq -r '.dod // ""' 2>/dev/null)
|
|
EMOJIS=$(printf '%s' "$JSON" | jq -r '.emojis // ""' 2>/dev/null)
|
|
[ -z "$GOAL" ] && exit 0
|
|
|
|
# Carrera: si entre tanto aparecio un objetivo DEFINITIVO (manual), respetarlo.
|
|
# Si solo esta el provisional, lo pisamos abajo con el definitivo.
|
|
if [ -f "$F" ] && [ "$(jq -r '.provisional // false' "$F" 2>/dev/null)" != "true" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
TMP="${F}.tmp.$$"
|
|
if [ -f "$F" ]; then
|
|
# Pisar el provisional: fija goal/dod/emojis definitivos y quita el flag,
|
|
# preservando phase/history/prompts que el provisional ya hubiera acumulado.
|
|
if jq --arg g "$GOAL" --arg d "$DOD" --arg e "$EMOJIS" \
|
|
'del(.provisional) | .goal=$g | (if $d != "" then .dod=$d else . end) | (if $e != "" then .emojis=$e else . end)' \
|
|
"$F" > "$TMP" 2>/dev/null; then
|
|
mv "$TMP" "$F"
|
|
else
|
|
rm -f "$TMP"
|
|
fi
|
|
else
|
|
if jq -n --arg g "$GOAL" --arg d "$DOD" --arg e "$EMOJIS" --arg p "$P" \
|
|
'{goal:$g, phase:"planificando", history:["planificando"], prompts:[$p]} | (if $d != "" then .dod=$d else . end) | (if $e != "" then .emojis=$e else . end)' > "$TMP" 2>/dev/null; then
|
|
mv "$TMP" "$F"
|
|
else
|
|
rm -f "$TMP"
|
|
fi
|
|
fi
|
|
exit 0
|