elsabro 7.1.0 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/elsabro/execute.md +94 -1479
- package/flow-engine/src/executors.js +1 -1
- package/flow-engine/tests/skill-install.test.js +374 -0
- package/flows/development-flow.json +20 -20
- package/hooks/skill-discovery.sh +6 -4
- package/hooks/skill-install.sh +224 -0
- package/package.json +1 -1
- package/references/SYSTEM_INDEX.md +1 -1
- package/references/agent-teams-integration.md +7 -15
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# skill-install.sh - ELSABRO Skill Install Bridge (v1.0.0)
|
|
3
|
+
#
|
|
4
|
+
# Instala skills del vercel-labs/skills registry y valida archivos instalados.
|
|
5
|
+
# Companion de skill-discovery.sh — este script ejecuta lo que discovery recomienda.
|
|
6
|
+
#
|
|
7
|
+
# Comandos:
|
|
8
|
+
# check - Valida accesibilidad del registry (npx skills check)
|
|
9
|
+
# install "<cmd>" - Ejecuta install command con pre-checks y timeout (e.g. npx skills add ...)
|
|
10
|
+
# validate "<name>" - Verifica que skill instalado existe y tiene YAML frontmatter
|
|
11
|
+
#
|
|
12
|
+
# Output: JSON en stdout, logs en stderr
|
|
13
|
+
# Errores: Siempre exit 0, errores comunicados via JSON {"status":"error","message":"..."}
|
|
14
|
+
#
|
|
15
|
+
# Requiere: bash 4+, node/npm (para npx)
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
# ============================================================================
|
|
20
|
+
# CONFIGURACION
|
|
21
|
+
# ============================================================================
|
|
22
|
+
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
25
|
+
GLOBAL_SKILLS_DIR="${HOME}/.claude/skills"
|
|
26
|
+
CACHE_FILE="${PROJECT_ROOT}/.cache/skill-discovery-cache.json"
|
|
27
|
+
|
|
28
|
+
NPX_TIMEOUT=30 # segundos para install
|
|
29
|
+
CHECK_TIMEOUT=15 # segundos para check
|
|
30
|
+
|
|
31
|
+
# Portable timeout: use gtimeout (macOS/brew) > timeout (Linux) > no timeout
|
|
32
|
+
if command -v gtimeout >/dev/null 2>&1; then
|
|
33
|
+
TIMEOUT_CMD="gtimeout"
|
|
34
|
+
elif command -v timeout >/dev/null 2>&1; then
|
|
35
|
+
TIMEOUT_CMD="timeout"
|
|
36
|
+
else
|
|
37
|
+
TIMEOUT_CMD=""
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
run_with_timeout() {
|
|
41
|
+
local secs="$1"; shift
|
|
42
|
+
if [[ -n "$TIMEOUT_CMD" ]]; then
|
|
43
|
+
"$TIMEOUT_CMD" "$secs" "$@"
|
|
44
|
+
else
|
|
45
|
+
"$@"
|
|
46
|
+
fi
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# Colores para stderr
|
|
50
|
+
RED='\033[0;31m'
|
|
51
|
+
GREEN='\033[0;32m'
|
|
52
|
+
YELLOW='\033[1;33m'
|
|
53
|
+
NC='\033[0m'
|
|
54
|
+
PREFIX="[ELSABRO:install]"
|
|
55
|
+
|
|
56
|
+
# ============================================================================
|
|
57
|
+
# LOGGING (stderr only)
|
|
58
|
+
# ============================================================================
|
|
59
|
+
|
|
60
|
+
log_info() { echo -e "${GREEN}${PREFIX}${NC} $*" >&2; }
|
|
61
|
+
log_warn() { echo -e "${YELLOW}${PREFIX}${NC} $*" >&2; }
|
|
62
|
+
log_error() { echo -e "${RED}${PREFIX}${NC} $*" >&2; }
|
|
63
|
+
|
|
64
|
+
# ============================================================================
|
|
65
|
+
# JSON OUTPUT (stdout only)
|
|
66
|
+
# ============================================================================
|
|
67
|
+
|
|
68
|
+
json_ok() {
|
|
69
|
+
local extra="${1:-}"
|
|
70
|
+
if [[ -n "$extra" ]]; then
|
|
71
|
+
echo "{\"status\":\"ok\",$extra}"
|
|
72
|
+
else
|
|
73
|
+
echo '{"status":"ok"}'
|
|
74
|
+
fi
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
json_error() {
|
|
78
|
+
local msg="$1"
|
|
79
|
+
echo "{\"status\":\"error\",\"message\":\"$msg\"}"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# ============================================================================
|
|
83
|
+
# COMMAND: check
|
|
84
|
+
# Validates registry accessibility via npx skills check
|
|
85
|
+
# ============================================================================
|
|
86
|
+
|
|
87
|
+
cmd_check() {
|
|
88
|
+
log_info "Checking registry accessibility..."
|
|
89
|
+
|
|
90
|
+
command -v npx >/dev/null 2>&1 || { json_error "npx not found"; exit 0; }
|
|
91
|
+
|
|
92
|
+
local output
|
|
93
|
+
if output=$(run_with_timeout "$CHECK_TIMEOUT" npx -y skills check 2>&1); then
|
|
94
|
+
log_info "Registry accessible"
|
|
95
|
+
json_ok
|
|
96
|
+
else
|
|
97
|
+
log_error "Registry check failed: $output"
|
|
98
|
+
json_error "registry check failed"
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# ============================================================================
|
|
103
|
+
# COMMAND: install <install_cmd>
|
|
104
|
+
# Executes the given install command with pre-checks and timeout
|
|
105
|
+
# ============================================================================
|
|
106
|
+
|
|
107
|
+
cmd_install() {
|
|
108
|
+
local install_cmd="${1:-}"
|
|
109
|
+
|
|
110
|
+
if [[ -z "$install_cmd" ]]; then
|
|
111
|
+
json_error "install command required"
|
|
112
|
+
exit 0
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
log_info "Installing skill: $install_cmd"
|
|
116
|
+
|
|
117
|
+
# Pre-check: command format (defense-in-depth — only allow npx skills add ...)
|
|
118
|
+
if [[ ! "$install_cmd" =~ ^npx[[:space:]]+((-y|skills|add|--skill|--yes|-g|-a|claude-code|[a-zA-Z0-9/_-]+)[[:space:]]*)+$ ]]; then
|
|
119
|
+
json_error "install command failed format validation"
|
|
120
|
+
exit 0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Pre-check: npx available
|
|
124
|
+
command -v npx >/dev/null 2>&1 || { json_error "npx not found"; exit 0; }
|
|
125
|
+
|
|
126
|
+
# Pre-check: skills dir exists and is writable
|
|
127
|
+
if [[ ! -d "$GLOBAL_SKILLS_DIR" ]]; then
|
|
128
|
+
mkdir -p "$GLOBAL_SKILLS_DIR" 2>/dev/null || { json_error "$GLOBAL_SKILLS_DIR cannot be created"; exit 0; }
|
|
129
|
+
fi
|
|
130
|
+
test -w "$GLOBAL_SKILLS_DIR" || { json_error "$GLOBAL_SKILLS_DIR not writable"; exit 0; }
|
|
131
|
+
|
|
132
|
+
# Execute install command with timeout
|
|
133
|
+
local output
|
|
134
|
+
if output=$(run_with_timeout "$NPX_TIMEOUT" bash -c "$install_cmd" 2>&1); then
|
|
135
|
+
log_info "Install succeeded"
|
|
136
|
+
|
|
137
|
+
# Extract skill name from command (--skill <name>)
|
|
138
|
+
local skill_name
|
|
139
|
+
skill_name=$(echo "$install_cmd" | sed -n 's/.*--skill \([a-zA-Z0-9_-]*\).*/\1/p')
|
|
140
|
+
|
|
141
|
+
# Invalidate discovery cache (so next run sees skill as installed)
|
|
142
|
+
if [[ -f "$CACHE_FILE" ]]; then
|
|
143
|
+
rm -f "$CACHE_FILE"
|
|
144
|
+
log_info "Discovery cache invalidated"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
json_ok "\"skill\":\"$skill_name\""
|
|
148
|
+
else
|
|
149
|
+
local exit_code=$?
|
|
150
|
+
if [[ $exit_code -eq 124 ]]; then
|
|
151
|
+
log_error "Install timed out after ${NPX_TIMEOUT}s"
|
|
152
|
+
json_error "install timed out after ${NPX_TIMEOUT}s"
|
|
153
|
+
else
|
|
154
|
+
log_error "Install failed (exit $exit_code): $output"
|
|
155
|
+
json_error "install failed: $(echo "$output" | tail -1 | tr '"' "'")"
|
|
156
|
+
fi
|
|
157
|
+
fi
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
# ============================================================================
|
|
161
|
+
# COMMAND: validate <skill_name>
|
|
162
|
+
# Checks installed file exists and has YAML frontmatter
|
|
163
|
+
# ============================================================================
|
|
164
|
+
|
|
165
|
+
cmd_validate() {
|
|
166
|
+
local skill_name="${1:-}"
|
|
167
|
+
|
|
168
|
+
if [[ -z "$skill_name" ]]; then
|
|
169
|
+
json_error "skill name required"
|
|
170
|
+
exit 0
|
|
171
|
+
fi
|
|
172
|
+
|
|
173
|
+
log_info "Validating skill: $skill_name"
|
|
174
|
+
|
|
175
|
+
# Check flat file first: ~/.claude/skills/<name>.md
|
|
176
|
+
local flat_path="${GLOBAL_SKILLS_DIR}/${skill_name}.md"
|
|
177
|
+
if [[ -f "$flat_path" ]]; then
|
|
178
|
+
local first_line
|
|
179
|
+
first_line=$(head -1 "$flat_path")
|
|
180
|
+
if [[ "$first_line" == "---" ]]; then
|
|
181
|
+
log_info "Valid skill at $flat_path (YAML frontmatter)"
|
|
182
|
+
json_ok "\"path\":\"$flat_path\",\"has_frontmatter\":true"
|
|
183
|
+
else
|
|
184
|
+
log_warn "File exists but no YAML frontmatter: $flat_path"
|
|
185
|
+
json_ok "\"path\":\"$flat_path\",\"has_frontmatter\":false"
|
|
186
|
+
fi
|
|
187
|
+
return
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
# Check subdirectory fallback: ~/.claude/skills/<name>/SKILL.md
|
|
191
|
+
local subdir_path="${GLOBAL_SKILLS_DIR}/${skill_name}/SKILL.md"
|
|
192
|
+
if [[ -f "$subdir_path" ]]; then
|
|
193
|
+
local first_line
|
|
194
|
+
first_line=$(head -1 "$subdir_path")
|
|
195
|
+
if [[ "$first_line" == "---" ]]; then
|
|
196
|
+
log_info "Valid skill at $subdir_path (YAML frontmatter)"
|
|
197
|
+
json_ok "\"path\":\"$subdir_path\",\"has_frontmatter\":true"
|
|
198
|
+
else
|
|
199
|
+
log_warn "File exists but no YAML frontmatter: $subdir_path"
|
|
200
|
+
json_ok "\"path\":\"$subdir_path\",\"has_frontmatter\":false"
|
|
201
|
+
fi
|
|
202
|
+
return
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
log_error "Skill not found: checked $flat_path and $subdir_path"
|
|
206
|
+
json_error "skill file not found after install"
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
# ============================================================================
|
|
210
|
+
# MAIN
|
|
211
|
+
# ============================================================================
|
|
212
|
+
|
|
213
|
+
cmd="${1:-}"
|
|
214
|
+
shift || true
|
|
215
|
+
|
|
216
|
+
case "$cmd" in
|
|
217
|
+
check) cmd_check ;;
|
|
218
|
+
install) cmd_install "$@" ;;
|
|
219
|
+
validate) cmd_validate "$@" ;;
|
|
220
|
+
*)
|
|
221
|
+
json_error "unknown command: $cmd (use: check, install, validate)"
|
|
222
|
+
exit 0
|
|
223
|
+
;;
|
|
224
|
+
esac
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elsabro",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.3.0",
|
|
4
4
|
"description": "Sistema de desarrollo AI-powered para Claude Code - BMAD Method Integration, Spec-Driven Development, Party Mode, Next Step Suggestions, Stitch UI Design, Agent Teams, blocking code review, orquestación avanzada con flows declarativos",
|
|
5
5
|
"bin": {
|
|
6
6
|
"elsabro": "bin/install.js",
|
|
@@ -501,7 +501,7 @@ Para verificar que el sistema está correctamente configurado:
|
|
|
501
501
|
### Comandos Core
|
|
502
502
|
- [ ] `start.md` tiene sección `<enforcement>` y `<state_sync>`
|
|
503
503
|
- [ ] `plan.md` tiene sección `<state_sync>` y `dispatcher` en frontmatter
|
|
504
|
-
- [ ] `execute.md` tiene
|
|
504
|
+
- [ ] `execute.md` tiene sync config en frontmatter y referencia a @references/state-sync.md
|
|
505
505
|
- [ ] `verify-work.md` tiene sección `<state_sync>` y `dispatcher` en frontmatter
|
|
506
506
|
|
|
507
507
|
### Referencias
|
|
@@ -336,21 +336,13 @@ New "teams" profile added:
|
|
|
336
336
|
}
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
### execute.md
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
method: "agent-team" # v4.2.0: always agent-team for 2+ agents (Rule 8)
|
|
347
|
-
agent_team_config:
|
|
348
|
-
team_members: [elsabro-executor, elsabro-qa, elsabro-planner]
|
|
349
|
-
when: "always" # v4.2.0: mandatory, no longer conditional
|
|
350
|
-
verification:
|
|
351
|
-
blocking: true
|
|
352
|
-
max_review_iterations: 5
|
|
353
|
-
```
|
|
339
|
+
### execute.md Dispatch (v7.3.0+)
|
|
340
|
+
|
|
341
|
+
execute.md is a thin CLI wrapper. Agent Teams dispatch is in section `#3-dispatch (type: parallel)`.
|
|
342
|
+
The CLI flow engine + `callbacks.js` (`requiresTeam()` / `composeTeam()`) decide automatically
|
|
343
|
+
whether to use Agent Teams (2+ non-haiku branches) or loose subagents (all-haiku).
|
|
344
|
+
|
|
345
|
+
See: `commands/elsabro/execute.md#3-dispatch`
|
|
354
346
|
|
|
355
347
|
## Changelog (v4.0.0)
|
|
356
348
|
|