@cristiancorreau/forge 2.9.6 → 2.9.8
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/README.md +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +4 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/generate.js +1 -1
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/lib/generators/codex.d.ts.map +1 -1
- package/dist/lib/generators/codex.js +10 -8
- package/dist/lib/generators/codex.js.map +1 -1
- package/dist/lib/generators/kiro.d.ts +1 -1
- package/dist/lib/generators/kiro.d.ts.map +1 -1
- package/dist/lib/generators/kiro.js +15 -16
- package/dist/lib/generators/kiro.js.map +1 -1
- package/dist/lib/generators/opencode.d.ts.map +1 -1
- package/dist/lib/generators/opencode.js +13 -12
- package/dist/lib/generators/opencode.js.map +1 -1
- package/dist/lib/paths.d.ts +1 -2
- package/dist/lib/paths.d.ts.map +1 -1
- package/dist/lib/paths.js +12 -16
- package/dist/lib/paths.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/assets/adapters/claude-code/generate-claude-md.py +0 -304
- package/assets/adapters/codex/generate-codex-config.py +0 -269
- package/assets/adapters/codex/hooks/codex.yaml.tpl +0 -43
- package/assets/adapters/codex/hooks/forge-codex-finish.sh +0 -158
- package/assets/adapters/codex/hooks/forge-codex-start.sh +0 -186
- package/assets/adapters/kiro/generate-steering.py +0 -367
- package/assets/adapters/opencode/generate-agents-md.py +0 -262
- package/assets/core/hooks/pre-bash-check.py +0 -202
- package/assets/core/hooks/pre-edit-check.py +0 -317
- package/assets/forge.py +0 -1265
- package/assets/requirements.txt +0 -2
- package/assets/scripts/aitmpl-search.py +0 -808
- package/assets/scripts/forge-add-opportunities.py +0 -92
- package/assets/scripts/forge-audit.py +0 -1061
- package/assets/scripts/forge-generate-all.py +0 -283
- package/assets/scripts/forge-init.py +0 -900
- package/assets/scripts/forge-migrate-project-yaml.py +0 -397
- package/assets/scripts/forge-scaffold-profile.py +0 -181
- package/assets/scripts/forge-teardown.py +0 -193
- package/assets/scripts/forge-validate-project-yaml.py +0 -457
- package/assets/scripts/forge-wizard.py +0 -1003
- package/assets/scripts/setup-codex.sh +0 -229
- package/assets/scripts/team-install.sh +0 -147
- package/assets/scripts/token-stats.py +0 -201
- package/dist/lib/python.d.ts +0 -4
- package/dist/lib/python.d.ts.map +0 -1
- package/dist/lib/python.js +0 -46
- package/dist/lib/python.js.map +0 -1
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Forge v2 — Codex onFinish hook: forge-codex-finish.sh
|
|
3
|
-
#
|
|
4
|
-
# Se ejecuta al finalizar cada sesión de Codex CLI.
|
|
5
|
-
# Equivalente al hook post-turn-check.sh de Claude Code (Stop event).
|
|
6
|
-
#
|
|
7
|
-
# DIFERENCIAS vs Claude Code:
|
|
8
|
-
# - Claude Code: post-turn-check.sh corre después de CADA turno del agente.
|
|
9
|
-
# - Codex CLI: forge-codex-finish.sh corre al FINALIZAR la sesión completa,
|
|
10
|
-
# no después de cada mensaje individual. Codex no tiene un equivalente
|
|
11
|
-
# granular de "Stop por turno".
|
|
12
|
-
# - Claude Code Stop hook: puede imprimir al contexto del agente (el output
|
|
13
|
-
# se muestra como resultado del hook).
|
|
14
|
-
# - Codex CLI onFinish: el output se muestra en la terminal del usuario,
|
|
15
|
-
# pero puede no ser visible en el contexto del agente dependiendo de la
|
|
16
|
-
# versión de Codex.
|
|
17
|
-
#
|
|
18
|
-
# LIMITACIONES de Codex vs Claude Code:
|
|
19
|
-
# - No hay PreToolUse/PostToolUse hooks para interceptar herramientas individuales.
|
|
20
|
-
# - Los checks de este script son post-sesión, no post-turno.
|
|
21
|
-
#
|
|
22
|
-
# Instalación: este script debe copiarse o enlazarse en .codex/forge-codex-finish.sh
|
|
23
|
-
# El setup-codex.sh lo hace automáticamente.
|
|
24
|
-
|
|
25
|
-
set -uo pipefail
|
|
26
|
-
|
|
27
|
-
# ---------------------------------------------------------------------------
|
|
28
|
-
# Step 1 — Find modified files
|
|
29
|
-
# ---------------------------------------------------------------------------
|
|
30
|
-
MODIFIED=$(git diff --name-only HEAD 2>/dev/null || echo "")
|
|
31
|
-
STAGED=$(git diff --name-only --cached 2>/dev/null || echo "")
|
|
32
|
-
ALL_CHANGED="$MODIFIED $STAGED"
|
|
33
|
-
|
|
34
|
-
if [ -z "$(echo "$ALL_CHANGED" | tr -d '[:space:]')" ]; then
|
|
35
|
-
exit 0
|
|
36
|
-
fi
|
|
37
|
-
|
|
38
|
-
# ---------------------------------------------------------------------------
|
|
39
|
-
# Step 2 — Read project config
|
|
40
|
-
# ---------------------------------------------------------------------------
|
|
41
|
-
PKG_MGR=""
|
|
42
|
-
CUSTOM_CHECK=""
|
|
43
|
-
|
|
44
|
-
if [ -f "project.yaml" ]; then
|
|
45
|
-
PKG_MGR=$(python3 -c "
|
|
46
|
-
import yaml, sys
|
|
47
|
-
try:
|
|
48
|
-
d = yaml.safe_load(open('project.yaml'))
|
|
49
|
-
print(d.get('stack', {}).get('package_manager', ''))
|
|
50
|
-
except:
|
|
51
|
-
print('')
|
|
52
|
-
" 2>/dev/null || echo "")
|
|
53
|
-
|
|
54
|
-
CUSTOM_CHECK=$(python3 -c "
|
|
55
|
-
import yaml, sys
|
|
56
|
-
try:
|
|
57
|
-
d = yaml.safe_load(open('project.yaml'))
|
|
58
|
-
print(d.get('scripts', {}).get('check', ''))
|
|
59
|
-
except:
|
|
60
|
-
print('')
|
|
61
|
-
" 2>/dev/null || echo "")
|
|
62
|
-
fi
|
|
63
|
-
|
|
64
|
-
CHECK_OUTPUT=""
|
|
65
|
-
|
|
66
|
-
# ---------------------------------------------------------------------------
|
|
67
|
-
# Step 3 — Run checks
|
|
68
|
-
# ---------------------------------------------------------------------------
|
|
69
|
-
|
|
70
|
-
# Helper: check if any changed file matches a glob pattern
|
|
71
|
-
files_matching() {
|
|
72
|
-
local pattern="$1"
|
|
73
|
-
echo "$ALL_CHANGED" | tr ' ' '\n' | grep -E "$pattern" 2>/dev/null || true
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if [ -n "$CUSTOM_CHECK" ]; then
|
|
77
|
-
# Run user-defined check command
|
|
78
|
-
CHECK_OUTPUT=$(eval "$CUSTOM_CHECK" 2>&1 | head -20 || true)
|
|
79
|
-
|
|
80
|
-
else
|
|
81
|
-
# Auto-detect by file type
|
|
82
|
-
|
|
83
|
-
# TypeScript / JavaScript
|
|
84
|
-
TS_FILES=$(files_matching '\.(ts|tsx)$')
|
|
85
|
-
if [ -n "$TS_FILES" ]; then
|
|
86
|
-
if [ -f "turbo.json" ] && command -v pnpm &>/dev/null; then
|
|
87
|
-
TSC_OUTPUT=$(pnpm turbo typecheck 2>&1 | head -20 || pnpm tsc --noEmit 2>&1 | head -20 || true)
|
|
88
|
-
elif command -v pnpm &>/dev/null; then
|
|
89
|
-
TSC_OUTPUT=$(pnpm tsc --noEmit 2>&1 | head -20 || true)
|
|
90
|
-
elif command -v npx &>/dev/null; then
|
|
91
|
-
TSC_OUTPUT=$(npx tsc --noEmit 2>&1 | head -20 || true)
|
|
92
|
-
else
|
|
93
|
-
TSC_OUTPUT=""
|
|
94
|
-
fi
|
|
95
|
-
if [ -n "${TSC_OUTPUT:-}" ]; then
|
|
96
|
-
CHECK_OUTPUT="${CHECK_OUTPUT:+$CHECK_OUTPUT$'\n'}[tsc] $TSC_OUTPUT"
|
|
97
|
-
fi
|
|
98
|
-
fi
|
|
99
|
-
|
|
100
|
-
# PHP
|
|
101
|
-
PHP_FILES=$(files_matching '\.php$')
|
|
102
|
-
if [ -n "$PHP_FILES" ] && [ -f "composer.json" ]; then
|
|
103
|
-
if command -v composer &>/dev/null; then
|
|
104
|
-
PHP_OUTPUT=$(composer validate --no-check-publish 2>&1 | head -10 || true)
|
|
105
|
-
if [ -n "$PHP_OUTPUT" ]; then
|
|
106
|
-
CHECK_OUTPUT="${CHECK_OUTPUT:+$CHECK_OUTPUT$'\n'}[composer] $PHP_OUTPUT"
|
|
107
|
-
fi
|
|
108
|
-
fi
|
|
109
|
-
fi
|
|
110
|
-
|
|
111
|
-
# Python
|
|
112
|
-
PY_FILES=$(files_matching '\.py$')
|
|
113
|
-
if [ -n "$PY_FILES" ]; then
|
|
114
|
-
PY_OUTPUT=""
|
|
115
|
-
while IFS= read -r f; do
|
|
116
|
-
[ -z "$f" ] && continue
|
|
117
|
-
[ -f "$f" ] || continue
|
|
118
|
-
RESULT=$(python3 -m py_compile "$f" 2>&1 || true)
|
|
119
|
-
if [ -n "$RESULT" ]; then
|
|
120
|
-
PY_OUTPUT="${PY_OUTPUT:+$PY_OUTPUT$'\n'}$f: $RESULT"
|
|
121
|
-
fi
|
|
122
|
-
done <<< "$PY_FILES"
|
|
123
|
-
if [ -n "$PY_OUTPUT" ]; then
|
|
124
|
-
CHECK_OUTPUT="${CHECK_OUTPUT:+$CHECK_OUTPUT$'\n'}[python] $PY_OUTPUT"
|
|
125
|
-
fi
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
# Ruby
|
|
129
|
-
RB_FILES=$(files_matching '\.rb$')
|
|
130
|
-
if [ -n "$RB_FILES" ] && [ -f "Gemfile" ]; then
|
|
131
|
-
RB_OUTPUT=""
|
|
132
|
-
if command -v bundle &>/dev/null; then
|
|
133
|
-
while IFS= read -r f; do
|
|
134
|
-
[ -z "$f" ] && continue
|
|
135
|
-
[ -f "$f" ] || continue
|
|
136
|
-
RESULT=$(bundle exec ruby -c "$f" 2>&1 | head -10 || true)
|
|
137
|
-
if [ -n "$RESULT" ]; then
|
|
138
|
-
RB_OUTPUT="${RB_OUTPUT:+$RB_OUTPUT$'\n'}$f: $RESULT"
|
|
139
|
-
fi
|
|
140
|
-
done <<< "$RB_FILES"
|
|
141
|
-
fi
|
|
142
|
-
if [ -n "$RB_OUTPUT" ]; then
|
|
143
|
-
CHECK_OUTPUT="${CHECK_OUTPUT:+$CHECK_OUTPUT$'\n'}[ruby] $RB_OUTPUT"
|
|
144
|
-
fi
|
|
145
|
-
fi
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
|
-
# ---------------------------------------------------------------------------
|
|
149
|
-
# Step 4 — Report
|
|
150
|
-
# ---------------------------------------------------------------------------
|
|
151
|
-
if [ -n "$CHECK_OUTPUT" ]; then
|
|
152
|
-
echo "── Forge Codex post-session check ───────────"
|
|
153
|
-
echo "$CHECK_OUTPUT"
|
|
154
|
-
echo "─────────────────────────────────────────────"
|
|
155
|
-
fi
|
|
156
|
-
|
|
157
|
-
# Siempre exit 0 — este hook nunca bloquea.
|
|
158
|
-
exit 0
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Forge v2 — Codex onStart hook: forge-codex-start.sh
|
|
3
|
-
#
|
|
4
|
-
# Se ejecuta al inicio de cada sesión de Codex CLI.
|
|
5
|
-
# Equivalente al hook session-start.sh de Claude Code (UserPromptSubmit).
|
|
6
|
-
#
|
|
7
|
-
# DIFERENCIAS vs Claude Code:
|
|
8
|
-
# - Claude Code: session-start.sh corre en UserPromptSubmit (automático en cada sesión).
|
|
9
|
-
# - Codex CLI: este script corre en onStart (automático también, pero el timing
|
|
10
|
-
# exacto depende de la versión de Codex).
|
|
11
|
-
# - Claude Code: puede bloquear (exit 2) para detener la sesión.
|
|
12
|
-
# - Codex CLI: onStart no puede bloquear la sesión — solo puede imprimir advertencias.
|
|
13
|
-
# Exit 2 aquí no impide que Codex continúe; es informacional.
|
|
14
|
-
#
|
|
15
|
-
# LIMITACIONES de Codex vs Claude Code:
|
|
16
|
-
# - No hay PreToolUse: no se puede interceptar comandos individuales antes de ejecutarlos.
|
|
17
|
-
# - No hay PostToolUse: no se puede inspeccionar el resultado de cada tool call.
|
|
18
|
-
# - Las reglas de seguridad (pre-bash-check, branch guard) son instruccionales en
|
|
19
|
-
# AGENTS.md, no mecánicas. El agente debe respetar las reglas voluntariamente.
|
|
20
|
-
#
|
|
21
|
-
# Instalación: este script debe copiarse o enlazarse en .codex/forge-codex-start.sh
|
|
22
|
-
# El setup-codex.sh lo hace automáticamente.
|
|
23
|
-
|
|
24
|
-
set -uo pipefail
|
|
25
|
-
|
|
26
|
-
CHECKS_PASSED=0
|
|
27
|
-
CHECKS_TOTAL=0
|
|
28
|
-
OUTPUT=""
|
|
29
|
-
|
|
30
|
-
check() {
|
|
31
|
-
local name="$1"
|
|
32
|
-
local result="$2" # "ok" | "warn: <msg>" | "error: <msg>"
|
|
33
|
-
CHECKS_TOTAL=$((CHECKS_TOTAL + 1))
|
|
34
|
-
if [[ "$result" == "ok" ]]; then
|
|
35
|
-
CHECKS_PASSED=$((CHECKS_PASSED + 1))
|
|
36
|
-
elif [[ "$result" == error:* ]]; then
|
|
37
|
-
local msg="${result#error: }"
|
|
38
|
-
OUTPUT+=" error: ${msg}\n"
|
|
39
|
-
else
|
|
40
|
-
local msg="${result#warn: }"
|
|
41
|
-
OUTPUT+=" warn: ${msg}\n"
|
|
42
|
-
fi
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
# ---------------------------------------------------------------------------
|
|
46
|
-
# Check 1 — Herramientas básicas disponibles
|
|
47
|
-
# ---------------------------------------------------------------------------
|
|
48
|
-
if ! command -v git &>/dev/null; then
|
|
49
|
-
check "git" "error: git no está instalado o no está en PATH"
|
|
50
|
-
else
|
|
51
|
-
check "git" "ok"
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
if ! command -v python3 &>/dev/null; then
|
|
55
|
-
check "python3" "error: python3 no está instalado o no está en PATH"
|
|
56
|
-
else
|
|
57
|
-
check "python3" "ok"
|
|
58
|
-
fi
|
|
59
|
-
|
|
60
|
-
# ---------------------------------------------------------------------------
|
|
61
|
-
# Check 2 — Branch actual no es main/master
|
|
62
|
-
# ---------------------------------------------------------------------------
|
|
63
|
-
CURRENT_BRANCH="$(git branch --show-current 2>/dev/null || true)"
|
|
64
|
-
if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]]; then
|
|
65
|
-
check "branch" "warn: branch '${CURRENT_BRANCH}' — crea una feature branch antes de implementar: git checkout -b feature/<tema>-$(date +%Y-%m-%d)"
|
|
66
|
-
else
|
|
67
|
-
check "branch" "ok"
|
|
68
|
-
fi
|
|
69
|
-
|
|
70
|
-
# ---------------------------------------------------------------------------
|
|
71
|
-
# Check 3 — Cambios sin commitear
|
|
72
|
-
# ---------------------------------------------------------------------------
|
|
73
|
-
GIT_STATUS="$(git status --short 2>/dev/null || true)"
|
|
74
|
-
if [[ -n "$GIT_STATUS" ]]; then
|
|
75
|
-
check "uncommitted" "warn: cambios sin commitear en el worktree"
|
|
76
|
-
else
|
|
77
|
-
check "uncommitted" "ok"
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
# ---------------------------------------------------------------------------
|
|
81
|
-
# Check 4 — project.yaml existe
|
|
82
|
-
# ---------------------------------------------------------------------------
|
|
83
|
-
PROJECT_YAML=""
|
|
84
|
-
SEARCH_PATH="$(pwd)"
|
|
85
|
-
for _i in 1 2 3 4 5 6; do
|
|
86
|
-
if [[ -f "${SEARCH_PATH}/project.yaml" ]]; then
|
|
87
|
-
PROJECT_YAML="${SEARCH_PATH}/project.yaml"
|
|
88
|
-
break
|
|
89
|
-
fi
|
|
90
|
-
PARENT="$(dirname "$SEARCH_PATH")"
|
|
91
|
-
[[ "$PARENT" == "$SEARCH_PATH" ]] && break
|
|
92
|
-
SEARCH_PATH="$PARENT"
|
|
93
|
-
done
|
|
94
|
-
|
|
95
|
-
if [[ -z "$PROJECT_YAML" ]]; then
|
|
96
|
-
check "project.yaml" "warn: project.yaml no encontrado — ejecutar forge-wizard.py o scripts/setup-codex.sh"
|
|
97
|
-
else
|
|
98
|
-
check "project.yaml" "ok"
|
|
99
|
-
|
|
100
|
-
# Check 5 — project.yaml tiene campos requeridos
|
|
101
|
-
YAML_VALID="$(python3 - "$PROJECT_YAML" <<'PYEOF'
|
|
102
|
-
import sys, yaml
|
|
103
|
-
path = sys.argv[1]
|
|
104
|
-
try:
|
|
105
|
-
with open(path) as f:
|
|
106
|
-
data = yaml.safe_load(f)
|
|
107
|
-
if not isinstance(data, dict):
|
|
108
|
-
print("invalid")
|
|
109
|
-
sys.exit(0)
|
|
110
|
-
missing = []
|
|
111
|
-
project = data.get("project", {})
|
|
112
|
-
if not project.get("name"):
|
|
113
|
-
missing.append("project.name")
|
|
114
|
-
if not project.get("mode"):
|
|
115
|
-
missing.append("project.mode")
|
|
116
|
-
if missing:
|
|
117
|
-
print("missing:" + ",".join(missing))
|
|
118
|
-
else:
|
|
119
|
-
print("ok")
|
|
120
|
-
except Exception as e:
|
|
121
|
-
print(f"error:{e}")
|
|
122
|
-
PYEOF
|
|
123
|
-
)"
|
|
124
|
-
if [[ "$YAML_VALID" == "ok" ]]; then
|
|
125
|
-
check "project.yaml.fields" "ok"
|
|
126
|
-
elif [[ "$YAML_VALID" == missing:* ]]; then
|
|
127
|
-
MISSING_FIELDS="${YAML_VALID#missing:}"
|
|
128
|
-
check "project.yaml.fields" "warn: project.yaml faltan campos: ${MISSING_FIELDS}"
|
|
129
|
-
else
|
|
130
|
-
check "project.yaml.fields" "warn: project.yaml no se pudo parsear — verificar sintaxis"
|
|
131
|
-
fi
|
|
132
|
-
|
|
133
|
-
# Check 6 — Variables de entorno de producción activas
|
|
134
|
-
HAS_DEPLOY="$(python3 - "$PROJECT_YAML" <<'PYEOF'
|
|
135
|
-
import sys, yaml
|
|
136
|
-
path = sys.argv[1]
|
|
137
|
-
try:
|
|
138
|
-
with open(path) as f:
|
|
139
|
-
data = yaml.safe_load(f)
|
|
140
|
-
if isinstance(data, dict) and data.get("deploy"):
|
|
141
|
-
print("yes")
|
|
142
|
-
else:
|
|
143
|
-
print("no")
|
|
144
|
-
except Exception:
|
|
145
|
-
print("no")
|
|
146
|
-
PYEOF
|
|
147
|
-
)"
|
|
148
|
-
if [[ "$HAS_DEPLOY" == "yes" ]]; then
|
|
149
|
-
PROD_VARS=""
|
|
150
|
-
while IFS='=' read -r key _value; do
|
|
151
|
-
if [[ "$key" =~ ^(PROD_|PRODUCTION_|PROD$|PRODUCTION$) ]]; then
|
|
152
|
-
PROD_VARS+="${key} "
|
|
153
|
-
fi
|
|
154
|
-
done < <(env)
|
|
155
|
-
if [[ -n "$PROD_VARS" ]]; then
|
|
156
|
-
check "prod-env" "warn: variables de producción activas en sesión: ${PROD_VARS// /, } — verificar que es intencional"
|
|
157
|
-
else
|
|
158
|
-
check "prod-env" "ok"
|
|
159
|
-
fi
|
|
160
|
-
else
|
|
161
|
-
check "prod-env" "ok"
|
|
162
|
-
fi
|
|
163
|
-
fi
|
|
164
|
-
|
|
165
|
-
# ---------------------------------------------------------------------------
|
|
166
|
-
# Salida
|
|
167
|
-
# ---------------------------------------------------------------------------
|
|
168
|
-
WARNINGS=$((CHECKS_TOTAL - CHECKS_PASSED))
|
|
169
|
-
|
|
170
|
-
if [[ $WARNINGS -eq 0 ]]; then
|
|
171
|
-
# Silencioso — todo OK
|
|
172
|
-
exit 0
|
|
173
|
-
fi
|
|
174
|
-
|
|
175
|
-
# Construir etiquetas para el resumen
|
|
176
|
-
LABELS=""
|
|
177
|
-
[[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]] && LABELS+="[branch ${CURRENT_BRANCH}] "
|
|
178
|
-
[[ -n "$GIT_STATUS" ]] && LABELS+="[cambios sin commitear] "
|
|
179
|
-
[[ -z "$PROJECT_YAML" ]] && LABELS+="[sin project.yaml] "
|
|
180
|
-
|
|
181
|
-
printf "forge-codex session: %d advertencia(s) — %s\n" "$WARNINGS" "${LABELS%% }"
|
|
182
|
-
printf "%b" "$OUTPUT"
|
|
183
|
-
|
|
184
|
-
# Nota: en Codex CLI, onStart no puede bloquear la sesión.
|
|
185
|
-
# Salimos con 0 siempre — las advertencias son informacionales.
|
|
186
|
-
exit 0
|