Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e2b5ac56eb | |||
| 86252b7d2c | |||
| e976fb303a | |||
| 8e53e0818e | |||
| bb735cad17 | |||
| 0e8d2d2ff2 | |||
| ffb3f9b270 | |||
| 1b769a9666 | |||
| 963b3bd7e1 |
@@ -19,10 +19,14 @@ Wrapper sobre `tbd_branch_create_bash_infra`. La función del registry maneja to
|
||||
|
||||
2. **Llamar la función del registry**:
|
||||
```bash
|
||||
source /home/lucas/fn_registry/bash/functions/infra/tbd_branch_create.sh
|
||||
tbd_branch_create issue 0021 hot-reload
|
||||
# Path portable (cualquier PC): FN_REGISTRY_ROOT si está, si no ~/fn_registry.
|
||||
# Se invoca con `bash` (no `source`): el script llama a tbd_branch_create con
|
||||
# los argumentos al ejecutarse directamente, y así funciona aunque la shell de
|
||||
# la sesión sea zsh (evita el fallo de BASH_SOURCE).
|
||||
FN_TBD="${FN_REGISTRY_ROOT:-$HOME/fn_registry}/bash/functions/infra/tbd_branch_create.sh"
|
||||
bash "$FN_TBD" issue 0021 hot-reload
|
||||
# o
|
||||
tbd_branch_create quick fix-typo-readme
|
||||
bash "$FN_TBD" quick fix-typo-readme
|
||||
```
|
||||
|
||||
La función:
|
||||
|
||||
@@ -81,8 +81,11 @@ Si autocontenido, saltar.
|
||||
### 5. Cerrar la rama (registry)
|
||||
|
||||
```bash
|
||||
source /home/lucas/fn_registry/bash/functions/infra/tbd_branch_finish.sh
|
||||
tbd_branch_finish "<descripción corta del merge>"
|
||||
# Path portable (cualquier PC): FN_REGISTRY_ROOT si está, si no ~/fn_registry.
|
||||
# Se invoca con `bash` (no `source`): el script tiene un entry point que llama a
|
||||
# tbd_branch_finish con los argumentos cuando se ejecuta directamente, y así
|
||||
# funciona aunque la shell de la sesión sea zsh (evita el fallo de BASH_SOURCE).
|
||||
bash "${FN_REGISTRY_ROOT:-$HOME/fn_registry}/bash/functions/infra/tbd_branch_finish.sh" "<descripción corta del merge>"
|
||||
```
|
||||
|
||||
La función:
|
||||
|
||||
@@ -9,8 +9,12 @@ SID="$1"
|
||||
F="$2"
|
||||
PROMPT="$3"
|
||||
|
||||
# Si ya existe objetivo (lo creo otro proceso o el usuario), no pisar.
|
||||
[ -f "$F" ] && exit 0
|
||||
# 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"
|
||||
@@ -20,7 +24,7 @@ ASK="$HOME/fn_registry/python/functions/core/ask_llm.py"
|
||||
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) y un DoD breve (definition of done: condicion concreta de 'terminado', maximo 8 palabras, en espanol). Responde SOLO un objeto JSON en una sola linea, sin markdown ni texto extra: {\"goal\":\"...\",\"dod\":\"...\"}. Si el mensaje es un saludo, charla trivial o no describe ninguna tarea, responde exactamente {}."
|
||||
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
|
||||
@@ -31,16 +35,32 @@ JSON=$(printf '%s' "$RAW" | tr '\n' ' ' | grep -o '{[^{}]*}' | head -1)
|
||||
|
||||
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 se creo el archivo, no pisar.
|
||||
[ -f "$F" ] && 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 jq -n --arg g "$GOAL" --arg d "$DOD" --arg p "$P" \
|
||||
'{goal:$g, phase:"planificando", history:["planificando"], prompts:[$p]} | if $d != "" then .dod=$d else . end' > "$TMP" 2>/dev/null; then
|
||||
mv "$TMP" "$F"
|
||||
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
|
||||
rm -f "$TMP"
|
||||
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
|
||||
|
||||
@@ -1,48 +1,22 @@
|
||||
#!/bin/bash
|
||||
# Ajusta SOLO el DoD para mantenerlo coherente con los prompts del usuario hacia
|
||||
# el objetivo. El OBJETIVO es fijo (identificativo de la terminal) y NUNCA se
|
||||
# toca aqui. Lo lanza goal_tracker.sh en background (no bloquea). Usa ask_llm
|
||||
# (haiku, API directa; nunca `claude -p`, ver regla llm_invocation.md).
|
||||
# DESACTIVADO (2026-06-21): este hook regeneraba el campo `.dod` (movil) del
|
||||
# goal.json llamando a un LLM (haiku via ask_llm.py) en CADA prompt de CADA
|
||||
# sesion. Con muchas sesiones de la flota activas a la vez eso amplificaba el
|
||||
# rate-limit compartido de la organizacion ("Server is temporarily limiting
|
||||
# requests"). Una request API por turno por agente = coste innecesario.
|
||||
#
|
||||
# Args: <session_id> <goal_json_file>
|
||||
|
||||
SID="$1"
|
||||
F="$2"
|
||||
|
||||
[ -f "$F" ] || exit 0
|
||||
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
|
||||
|
||||
GOAL=$(jq -r '.goal // ""' "$F" 2>/dev/null)
|
||||
[ -z "$GOAL" ] && exit 0
|
||||
DOD=$(jq -r '.dod // ""' "$F" 2>/dev/null)
|
||||
PROMPTS=$(jq -r '(.prompts // []) | to_entries | map("\(.key+1). \(.value)") | join("\n")' "$F" 2>/dev/null)
|
||||
[ -z "$PROMPTS" ] && exit 0
|
||||
|
||||
SYS="Dado un OBJETIVO fijo de una terminal de trabajo y los prompts del usuario, define o ajusta el DoD (definition of done): la condicion concreta de 'terminado' para ese objetivo, coherente con lo que el usuario va pidiendo. El OBJETIVO no se toca, solo el DoD. Responde SOLO JSON en una linea, sin markdown: {\"dod\":\"...\"}. dod en espanol, breve, maximo 9 palabras. Si el DoD actual ya es adecuado, devuelvelo igual."
|
||||
|
||||
PROMPT="OBJETIVO (fijo, no lo cambies): ${GOAL}
|
||||
DoD ACTUAL: ${DOD}
|
||||
|
||||
PROMPTS DEL USUARIO (orden cronologico):
|
||||
${PROMPTS}
|
||||
|
||||
Responde el JSON con el DoD:"
|
||||
|
||||
RAW=$("$PY" "$ASK" --system "$SYS" "$PROMPT" 2>/dev/null)
|
||||
[ -z "$RAW" ] && exit 0
|
||||
JSON=$(printf '%s' "$RAW" | tr '\n' ' ' | grep -o '{[^{}]*}' | head -1)
|
||||
[ -z "$JSON" ] && exit 0
|
||||
|
||||
ND=$(printf '%s' "$JSON" | jq -r '.dod // ""' 2>/dev/null)
|
||||
[ -z "$ND" ] && exit 0
|
||||
|
||||
TMP="${F}.tmp.$$"
|
||||
if jq --arg d "$ND" '.dod=$d' "$F" > "$TMP" 2>/dev/null; then
|
||||
mv "$TMP" "$F"
|
||||
else
|
||||
rm -f "$TMP"
|
||||
fi
|
||||
# El `.dod` movil NO lo consume nadie: el parser de la flota
|
||||
# (functions/infra/list_claude_fleet.go, struct goalFile/readGoal) solo lee
|
||||
# goal/phase/emojis/rename/dod_contract/dod_status/role; ignora `.dod` por
|
||||
# completo. El criterio de aceptacion real que clasifica la flota es
|
||||
# `dod_contract` + `dod_status`, escrito por set_dod_contract.py (sin LLM) y
|
||||
# consumido por ClassifyFleetTermination. Ese sistema queda intacto.
|
||||
#
|
||||
# Por tanto la regeneracion del `.dod` movil con haiku se elimina por completo:
|
||||
# cero llamadas LLM por prompt. El objetivo+DoD inicial los sigue generando
|
||||
# goal_autogen.sh una sola vez por terminal (junto con goal/emojis, que si se
|
||||
# usan); el usuario puede ajustar el DoD a mano con "dod: ...".
|
||||
#
|
||||
# Se conserva el archivo como no-op para no romper ningun disparador historico
|
||||
# (defensa en profundidad). El disparo desde goal_tracker.sh tambien se retiro.
|
||||
exit 0
|
||||
|
||||
@@ -52,6 +52,10 @@ if [ -n "$GOAL_LINE" ]; then
|
||||
block "🎯 Objetivo fijado: ${NEWGOAL}"
|
||||
fi
|
||||
|
||||
# Nota: el rename de FleetView se hace ahora con alt+r DENTRO de la TUI (escribe
|
||||
# el campo .rename del goal directamente). Ya no se captura /rename en este hook,
|
||||
# asi el built-in /rename de Claude Code queda libre para renombrar la sesion.
|
||||
|
||||
# --- dod: <texto> ---
|
||||
DOD_LINE=$(printf '%s' "$PROMPT" | grep -ioE '^[[:space:]]*dod[[:space:]]*:[[:space:]]*.+' | head -1)
|
||||
if [ -n "$DOD_LINE" ]; then
|
||||
@@ -79,28 +83,47 @@ case "$PROMPT_TRIM" in
|
||||
block "⏸️ Fase marcada en pausa." ;;
|
||||
esac
|
||||
|
||||
# --- prompt NORMAL: pasa al agente + acumula para refinar el DoD + estado ---
|
||||
if [ -f "$F" ]; then
|
||||
# --- prompt NORMAL: pasa al agente + estado ---
|
||||
# Distinguimos dos situaciones por el flag .provisional del goal file:
|
||||
# - no existe el archivo -> primer prompt: ponemos objetivo PROVISIONAL = tu
|
||||
# texto + lanzamos autogen (haiku, UNA sola vez)
|
||||
# que lo definira.
|
||||
# - existe pero .provisional -> autogen aun no termino (o fallo): conservamos el
|
||||
# provisional y relanzamos autogen (idempotente,
|
||||
# self-healing).
|
||||
# - existe y NO provisional -> objetivo definitivo: solo mostramos estado.
|
||||
#
|
||||
# NOTA (2026-06-21): el campo `.dod` movil YA NO se regenera con LLM en cada
|
||||
# prompt. goal_refine.sh esta desactivado (era una request haiku por turno por
|
||||
# sesion -> amplificaba el rate-limit compartido de la organizacion). El `.dod`
|
||||
# movil no lo consume nadie; el criterio que clasifica la flota es `dod_contract`
|
||||
# + `dod_status` (set_dod_contract.py, sin LLM). El DoD inicial lo fija autogen
|
||||
# una vez; el usuario lo ajusta a mano con "dod: ...".
|
||||
PROV="false"
|
||||
[ -f "$F" ] && PROV=$(jq -r '.provisional // false' "$F" 2>/dev/null)
|
||||
|
||||
if [ -f "$F" ] && [ "$PROV" != "true" ]; 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 ajustar SOLO el DoD (background). El objetivo no cambia.
|
||||
echo "GOAL-TRACKER: file=$F | goal=\"$G\" dod=\"$D\" phase=\"$P\". El objetivo es fijo (identificativo de la terminal, NO lo cambies). El DoD inicial lo fija el autogen una vez (sin LLM por prompt); el usuario lo ajusta con \"dod: ...\" — NO lo regeneres tu. La fase la mantienen los hooks (PostToolUse=activo, Stop=reposo) — NO la escribas. Comandos meta del usuario (no los uses tu): objetivo:/dod:/pausa."
|
||||
else
|
||||
# Sin objetivo definitivo todavia. Mostramos de inmediato un objetivo PROVISIONAL
|
||||
# igual a tu propio texto (truncado), para que el statusline no quede vacio
|
||||
# mientras haiku genera el real en background. autogen pisara este provisional
|
||||
# con el definitivo al terminar (su guard respeta .provisional).
|
||||
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"
|
||||
if [ -f "$F" ]; then
|
||||
# Ya habia provisional: conserva su goal, solo acumula el prompt.
|
||||
jq --arg p "$PROMPT_TRIM" '.prompts = ((.prompts // []) + [$p])[-12:]' "$F" > "$TMP" 2>/dev/null && mv "$TMP" "$F" || rm -f "$TMP"
|
||||
else
|
||||
rm -f "$TMP"
|
||||
PROV_GOAL=$(printf '%s' "$PROMPT_TRIM" | head -c 70)
|
||||
jq -n --arg g "$PROV_GOAL" --arg p "$PROMPT_TRIM" \
|
||||
'{goal:$g, phase:"planificando", history:["planificando"], prompts:[$p], provisional:true}' > "$TMP" 2>/dev/null && mv "$TMP" "$F" || 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\". El objetivo es fijo (identificativo de la terminal, NO lo cambies). El DoD se ajusta solo con los prompts; la fase la mantienen los hooks (PostToolUse=activo, Stop=reposo) — NO la escribas. Comandos meta del usuario (no los uses tu): objetivo:/dod:/pausa."
|
||||
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). El usuario tambien puede fijarlo con \"objetivo: ...\" / \"dod: ...\"."
|
||||
echo "GOAL-TRACKER: file=$F (objetivo PROVISIONAL = tu texto; generando el objetivo+DoD real con haiku en background). El usuario tambien puede fijarlo con \"objetivo: ...\" / \"dod: ...\"."
|
||||
fi
|
||||
exit 0
|
||||
|
||||
+36
-6
@@ -4,34 +4,57 @@
|
||||
"Edit(~/.claude/**)",
|
||||
"Write(~/.claude/**)",
|
||||
"Edit(.claude/**)",
|
||||
"Write(.claude/**)"
|
||||
"Write(.claude/**)",
|
||||
"Bash(CGO_ENABLED=1 go test *)",
|
||||
"Bash(sqlite3 *)",
|
||||
"Read(//home/enmanuel/.claude/**)"
|
||||
],
|
||||
"deny": [
|
||||
"Edit(~/.claude/.git/**)",
|
||||
"Write(~/.claude/.git/**)",
|
||||
"Edit(.git/**)",
|
||||
"Write(.git/**)"
|
||||
]
|
||||
],
|
||||
"defaultMode": "dontAsk"
|
||||
},
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{ "type": "command", "command": "~/.claude/hooks/goal_tracker.sh" }
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/hooks/goal_tracker.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Notification": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/hooks/goal_notify.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"hooks": [
|
||||
{ "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" }
|
||||
{
|
||||
"type": "command",
|
||||
"command": "~/.claude/hooks/goal_phase_active.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -54,7 +77,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"language": "Español",
|
||||
"effortLevel": "xhigh",
|
||||
"voice": {
|
||||
"enabled": true,
|
||||
"mode": "hold"
|
||||
},
|
||||
"skipDangerousModePermissionPrompt": true,
|
||||
"agentPushNotifEnabled": false
|
||||
"preferredNotifChannel": "notifications_disabled",
|
||||
"agentPushNotifEnabled": false,
|
||||
"voiceEnabled": true
|
||||
}
|
||||
|
||||
+32
-1
@@ -45,6 +45,25 @@ if [ "$CONTEXT_PCT" -eq 0 ] && [ "$CONTEXT_USED" -gt 0 ]; then
|
||||
CONTEXT_PCT=$(echo "scale=0; $CONTEXT_USED * 100 / $CONTEXT_TOTAL" | bc)
|
||||
fi
|
||||
|
||||
# Persistir el contexto por sesión en un sidecar para que fleetview (y otras
|
||||
# herramientas) puedan mostrarlo sin tener este stdin. El statusline se re-ejecuta
|
||||
# cada pocos segundos, así que el dato se mantiene fresco mientras la sesión vive.
|
||||
if [ -n "$SESSION_ID" ]; then
|
||||
RTDIR="$HOME/.claude/runtime"
|
||||
mkdir -p "$RTDIR" 2>/dev/null
|
||||
RTF="$RTDIR/${SESSION_ID}.json"
|
||||
RTMP="${RTF}.tmp.$$"
|
||||
if jq -n \
|
||||
--argjson pct "${CONTEXT_PCT:-0}" \
|
||||
--argjson used "${CONTEXT_USED:-0}" \
|
||||
--argjson total "${CONTEXT_TOTAL:-200000}" \
|
||||
'{ctx_pct:$pct, ctx_used:$used, ctx_total:$total}' > "$RTMP" 2>/dev/null; then
|
||||
mv "$RTMP" "$RTF" 2>/dev/null
|
||||
else
|
||||
rm -f "$RTMP" 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
# Costos
|
||||
TOTAL_COST=$(echo "$INPUT" | jq -r '.cost.total_cost_usd // 0' | xargs printf "%.3f")
|
||||
SESSION_DURATION=$(echo "$INPUT" | jq -r '.cost.total_duration_ms // 0')
|
||||
@@ -304,9 +323,21 @@ if [ -n "$SESSION_ID" ] && [ -f "$GOAL_FILE" ]; then
|
||||
GOAL=$(jq -r '.goal // ""' "$GOAL_FILE" 2>/dev/null)
|
||||
PHASE=$(jq -r '.phase // ""' "$GOAL_FILE" 2>/dev/null)
|
||||
DOD=$(jq -r '.dod // ""' "$GOAL_FILE" 2>/dev/null)
|
||||
EMOJIS=$(jq -r '.emojis // ""' "$GOAL_FILE" 2>/dev/null)
|
||||
PROVISIONAL=$(jq -r '.provisional // false' "$GOAL_FILE" 2>/dev/null)
|
||||
if [ -n "$GOAL" ]; then
|
||||
GC=$(goal_color "$SESSION_ID")
|
||||
LEFT="${GC}🎯 ${GOAL}${RESET}"
|
||||
# Prefijo del objetivo:
|
||||
# - provisional (= tu propio texto, mientras haiku genera el real) -> ⏳ atenuado.
|
||||
# - los 3 emojis generados (representan la tarea, igual que FleetView).
|
||||
# - fallback al marcador generico de objetivo.
|
||||
if [ "$PROVISIONAL" = "true" ]; then
|
||||
LEFT="${GC}⏳ ${DIM}${GOAL}${RESET}"
|
||||
elif [ -n "$EMOJIS" ]; then
|
||||
LEFT="${GC}${EMOJIS} ${GOAL}${RESET}"
|
||||
else
|
||||
LEFT="${GC}🎯 ${GOAL}${RESET}"
|
||||
fi
|
||||
|
||||
LINE0="${LEFT}"
|
||||
|
||||
|
||||
+77
-9
@@ -54,20 +54,26 @@ done
|
||||
echo ""
|
||||
echo "=== Instalando archivos de configuración ==="
|
||||
|
||||
# 1. Status Line Script
|
||||
# 1. Status Line Script (enlace simbólico)
|
||||
STATUSLINE_SOURCE="$REPO_DIR/.claude/statusline.sh"
|
||||
STATUSLINE_TARGET="$CLAUDE_DIR/statusline.sh"
|
||||
|
||||
if [ -f "$STATUSLINE_SOURCE" ]; then
|
||||
if [ -f "$STATUSLINE_TARGET" ]; then
|
||||
BACKUP="$STATUSLINE_TARGET.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "Backup: statusline.sh -> $BACKUP"
|
||||
mv "$STATUSLINE_TARGET" "$BACKUP"
|
||||
chmod +x "$STATUSLINE_SOURCE"
|
||||
if [ -L "$STATUSLINE_TARGET" ] && [ "$(readlink "$STATUSLINE_TARGET")" = "$STATUSLINE_SOURCE" ]; then
|
||||
echo "OK: statusline.sh ya está enlazado correctamente"
|
||||
else
|
||||
# Symlink (roto o apuntando mal): borrar; archivo real: backup
|
||||
if [ -L "$STATUSLINE_TARGET" ]; then
|
||||
rm -f "$STATUSLINE_TARGET"
|
||||
elif [ -e "$STATUSLINE_TARGET" ]; then
|
||||
BACKUP="$STATUSLINE_TARGET.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "Backup: statusline.sh -> $BACKUP"
|
||||
mv "$STATUSLINE_TARGET" "$BACKUP"
|
||||
fi
|
||||
ln -s "$STATUSLINE_SOURCE" "$STATUSLINE_TARGET"
|
||||
echo "Enlazado: statusline.sh -> $STATUSLINE_SOURCE"
|
||||
fi
|
||||
|
||||
cp "$STATUSLINE_SOURCE" "$STATUSLINE_TARGET"
|
||||
chmod +x "$STATUSLINE_TARGET"
|
||||
echo "Copiado: statusline.sh (ejecutable)"
|
||||
else
|
||||
echo "WARN: statusline.sh no encontrado en el repo"
|
||||
fi
|
||||
@@ -96,6 +102,66 @@ else
|
||||
echo "WARN: settings.json no encontrado en el repo"
|
||||
fi
|
||||
|
||||
# 3. CLAUDE.md (enlace simbólico - preferencias globales)
|
||||
CLAUDEMD_SOURCE="$REPO_DIR/.claude/CLAUDE.md"
|
||||
CLAUDEMD_TARGET="$CLAUDE_DIR/CLAUDE.md"
|
||||
|
||||
if [ -f "$CLAUDEMD_SOURCE" ]; then
|
||||
if [ -L "$CLAUDEMD_TARGET" ] && [ "$(readlink "$CLAUDEMD_TARGET")" = "$CLAUDEMD_SOURCE" ]; then
|
||||
echo "OK: CLAUDE.md ya está enlazado correctamente"
|
||||
else
|
||||
# Symlink (roto o apuntando mal): borrar; archivo real: backup
|
||||
if [ -L "$CLAUDEMD_TARGET" ]; then
|
||||
rm -f "$CLAUDEMD_TARGET"
|
||||
elif [ -e "$CLAUDEMD_TARGET" ]; then
|
||||
BACKUP="$CLAUDEMD_TARGET.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "Backup: CLAUDE.md -> $BACKUP"
|
||||
mv "$CLAUDEMD_TARGET" "$BACKUP"
|
||||
fi
|
||||
ln -s "$CLAUDEMD_SOURCE" "$CLAUDEMD_TARGET"
|
||||
echo "Enlazado: CLAUDE.md -> $CLAUDEMD_SOURCE"
|
||||
fi
|
||||
else
|
||||
echo "WARN: CLAUDE.md no encontrado en el repo"
|
||||
fi
|
||||
|
||||
# === Instalando hooks (enlace simbólico por archivo) ===
|
||||
echo ""
|
||||
echo "=== Instalando hooks ==="
|
||||
|
||||
HOOKS_SOURCE_DIR="$REPO_DIR/.claude/hooks"
|
||||
HOOKS_TARGET_DIR="$CLAUDE_DIR/hooks"
|
||||
|
||||
if [ -d "$HOOKS_SOURCE_DIR" ]; then
|
||||
mkdir -p "$HOOKS_TARGET_DIR"
|
||||
for hook in "$HOOKS_SOURCE_DIR"/*.sh; do
|
||||
[ -e "$hook" ] || continue
|
||||
chmod +x "$hook"
|
||||
HOOK_NAME="$(basename "$hook")"
|
||||
HOOK_TARGET="$HOOKS_TARGET_DIR/$HOOK_NAME"
|
||||
|
||||
# Si ya es symlink correcto, saltar
|
||||
if [ -L "$HOOK_TARGET" ] && [ "$(readlink "$HOOK_TARGET")" = "$hook" ]; then
|
||||
echo "OK: hooks/$HOOK_NAME ya está enlazado correctamente"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Symlink (roto o apuntando mal): borrar sin backup; archivo real: backup
|
||||
if [ -L "$HOOK_TARGET" ]; then
|
||||
rm -f "$HOOK_TARGET"
|
||||
elif [ -e "$HOOK_TARGET" ]; then
|
||||
BACKUP="$HOOK_TARGET.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "Backup: hooks/$HOOK_NAME -> $BACKUP"
|
||||
mv "$HOOK_TARGET" "$BACKUP"
|
||||
fi
|
||||
|
||||
ln -s "$hook" "$HOOK_TARGET"
|
||||
echo "Enlazado: hooks/$HOOK_NAME -> $hook"
|
||||
done
|
||||
else
|
||||
echo "WARN: $HOOKS_SOURCE_DIR no existe, saltando hooks"
|
||||
fi
|
||||
|
||||
# === Limpieza de configuración que no debe cambiar ===
|
||||
echo ""
|
||||
echo "=== Limpiando configuración inmutable ==="
|
||||
@@ -189,6 +255,8 @@ echo "Tus comandos y configuración ahora están sincronizados con el repositori
|
||||
echo ""
|
||||
echo "Configuración instalada:"
|
||||
echo " • Skills, Agents y Commands enlazados simbólicamente"
|
||||
echo " • Hooks (goal_*.sh) enlazados simbólicamente"
|
||||
echo " • CLAUDE.md (preferencias globales) enlazado"
|
||||
echo " • Status Line configurada con vibecoding setup"
|
||||
echo " • Settings.json enlazado (compartido entre repos)"
|
||||
echo " • Backups viejos limpiados (>7 días)"
|
||||
|
||||
Reference in New Issue
Block a user