@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.
Files changed (53) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/doctor.d.ts.map +1 -1
  3. package/dist/commands/doctor.js +4 -3
  4. package/dist/commands/doctor.js.map +1 -1
  5. package/dist/commands/generate.js +1 -1
  6. package/dist/commands/generate.js.map +1 -1
  7. package/dist/commands/init.js +2 -2
  8. package/dist/commands/init.js.map +1 -1
  9. package/dist/lib/generators/codex.d.ts.map +1 -1
  10. package/dist/lib/generators/codex.js +10 -8
  11. package/dist/lib/generators/codex.js.map +1 -1
  12. package/dist/lib/generators/kiro.d.ts +1 -1
  13. package/dist/lib/generators/kiro.d.ts.map +1 -1
  14. package/dist/lib/generators/kiro.js +15 -16
  15. package/dist/lib/generators/kiro.js.map +1 -1
  16. package/dist/lib/generators/opencode.d.ts.map +1 -1
  17. package/dist/lib/generators/opencode.js +13 -12
  18. package/dist/lib/generators/opencode.js.map +1 -1
  19. package/dist/lib/paths.d.ts +1 -2
  20. package/dist/lib/paths.d.ts.map +1 -1
  21. package/dist/lib/paths.js +12 -16
  22. package/dist/lib/paths.js.map +1 -1
  23. package/dist/version.d.ts +1 -1
  24. package/dist/version.js +1 -1
  25. package/package.json +2 -2
  26. package/assets/adapters/claude-code/generate-claude-md.py +0 -304
  27. package/assets/adapters/codex/generate-codex-config.py +0 -269
  28. package/assets/adapters/codex/hooks/codex.yaml.tpl +0 -43
  29. package/assets/adapters/codex/hooks/forge-codex-finish.sh +0 -158
  30. package/assets/adapters/codex/hooks/forge-codex-start.sh +0 -186
  31. package/assets/adapters/kiro/generate-steering.py +0 -367
  32. package/assets/adapters/opencode/generate-agents-md.py +0 -262
  33. package/assets/core/hooks/pre-bash-check.py +0 -202
  34. package/assets/core/hooks/pre-edit-check.py +0 -317
  35. package/assets/forge.py +0 -1265
  36. package/assets/requirements.txt +0 -2
  37. package/assets/scripts/aitmpl-search.py +0 -808
  38. package/assets/scripts/forge-add-opportunities.py +0 -92
  39. package/assets/scripts/forge-audit.py +0 -1061
  40. package/assets/scripts/forge-generate-all.py +0 -283
  41. package/assets/scripts/forge-init.py +0 -900
  42. package/assets/scripts/forge-migrate-project-yaml.py +0 -397
  43. package/assets/scripts/forge-scaffold-profile.py +0 -181
  44. package/assets/scripts/forge-teardown.py +0 -193
  45. package/assets/scripts/forge-validate-project-yaml.py +0 -457
  46. package/assets/scripts/forge-wizard.py +0 -1003
  47. package/assets/scripts/setup-codex.sh +0 -229
  48. package/assets/scripts/team-install.sh +0 -147
  49. package/assets/scripts/token-stats.py +0 -201
  50. package/dist/lib/python.d.ts +0 -4
  51. package/dist/lib/python.d.ts.map +0 -1
  52. package/dist/lib/python.js +0 -46
  53. package/dist/lib/python.js.map +0 -1
@@ -1,304 +0,0 @@
1
- #!/usr/bin/env python3
2
- # Copyright 2026 Cristian Correa — Apache License 2.0
3
- # https://github.com/cristiancorreau/forge
4
- """
5
- Genera CLAUDE.md para un proyecto usando forge.
6
-
7
- Usage:
8
- python3 .agentic/adapters/claude-code/generate-claude-md.py
9
-
10
- Lee project.yaml en la raíz y genera CLAUDE.md adaptado al stack del proyecto.
11
- Si ya existe un CLAUDE.md, muestra el diff antes de sobreescribir.
12
-
13
- Requiere: pyyaml
14
- """
15
- import os
16
- import sys
17
- from pathlib import Path
18
-
19
- FORCE = "--force" in sys.argv
20
-
21
- try:
22
- import yaml
23
- except ImportError:
24
- print("ERROR: pyyaml requerido. pip install pyyaml", file=sys.stderr)
25
- sys.exit(1)
26
-
27
-
28
- def find_project_root() -> Path:
29
- here = Path.cwd()
30
- for p in [here] + list(here.parents):
31
- if (p / "project.yaml").exists():
32
- return p
33
- raise FileNotFoundError("No se encontró project.yaml")
34
-
35
-
36
- def _render_phases(config: dict) -> str:
37
- sprint = config.get("sprint", {})
38
- current = sprint.get("current", 1)
39
- phases = sprint.get("phases", [])
40
- if not phases:
41
- return (
42
- f"- **Sprint actual:** Sprint {current}\n"
43
- "- **Completadas:** —\n"
44
- "- **En curso:** —\n"
45
- "- **Pendientes:** —"
46
- )
47
- lines = [f"- **Sprint actual:** Sprint {current}"]
48
- for phase in phases:
49
- pid = phase.get("id", "?")
50
- name = phase.get("name", "")
51
- specs = phase.get("specs", [])
52
- status = phase.get("status", "pendiente")
53
- spec_list = ", ".join(specs) if specs else "—"
54
- lines.append(f"- **Fase {pid} — {name}** ({status}): {spec_list}")
55
- return "\n".join(lines)
56
-
57
-
58
- _AGENT_TRIGGER = {
59
- "orchestrator": ("tareas multi-agente, análisis de >3 archivos, descomposición de features completas", None),
60
- "backend-engineer": ("endpoints, middleware, validaciones, lógica de negocio", "api"),
61
- "api-engineer": ("endpoints REST, middleware, validaciones, migraciones de BD", "api"),
62
- "frontend-engineer": ("componentes UI, páginas, estilos, integración con API", "frontend"),
63
- "admin-engineer": ("UI de gestión interna, dashboards de admin", "admin"),
64
- "mobile-engineer": ("pantallas móviles, navegación, stores de estado", "mobile"),
65
- "fullstack-engineer": ("features full-stack end-to-end que abarcan backend y frontend", None),
66
- "test-engineer": ("tests unitarios, integración, E2E — nunca código de producción", "tests"),
67
- "docs-writer": ("specs, ADRs, READMEs, documentación — nunca código de producción", "specs"),
68
- "compliance-reviewer": ("revisión de PRs con PII, consentimientos, logs de auditoría", None),
69
- "security-auditor": ("auditoría de vulnerabilidades, revisión de dependencias, pentest", None),
70
- "migration-specialist": ("migraciones de versión de framework (ej: L6→L13)", "migrations"),
71
- "wp-engineer": ("temas WordPress, FSE, Gutenberg, child themes", "frontend"),
72
- "divi-engineer": ("layouts Divi 5, módulos custom, Divi Builder", "frontend"),
73
- "elementor-engineer": ("templates Elementor Pro, widgets custom", "frontend"),
74
- "scanner-engineer": ("scraping, crawling, extracción estructurada de datos", "scanner"),
75
- }
76
-
77
-
78
- def _build_agent_scope_table(agents_cfg: dict, paths: dict) -> str:
79
- active = agents_cfg.get("active", [])
80
- compliance = agents_cfg.get("compliance", [])
81
- agent_paths = {**(paths or {})}
82
- rows = []
83
- for agent in active + compliance:
84
- trigger, path_key = _AGENT_TRIGGER.get(agent, ("implementación", None))
85
- scope = agent_paths.get(path_key) if path_key else None
86
- scope_str = f"`{scope}`" if scope else "`/`"
87
- rows.append(f"| `{agent}` | {scope_str} | {trigger} |")
88
- if not rows:
89
- return ""
90
- header = (
91
- "## Agentes y su scope\n\n"
92
- "| Agente | Scope | Cuándo usarlo |\n"
93
- "|--------|-------|---------------|\n"
94
- )
95
- return header + "\n".join(rows) + "\n\n> Invocar el agente del scope correcto, no el orchestrator, para tareas acotadas.\n\n"
96
-
97
-
98
- def generate_claude_md(config: dict) -> str:
99
- proj = config.get("project", {})
100
- stack = config.get("stack", {})
101
- team = config.get("team", {})
102
- compliance_cfg = config.get("compliance", {})
103
- agents_cfg = config.get("agents", {})
104
- paths = config.get("paths", {})
105
-
106
- name = proj.get("name", "Mi Proyecto")
107
- description = proj.get("description", "")
108
- language = proj.get("language", "typescript")
109
- backend = stack.get("backend") or "N/A"
110
- frontend = stack.get("frontend") or "N/A"
111
- database = stack.get("database") or "N/A"
112
- frameworks = compliance_cfg.get("frameworks", [])
113
- specs_path = paths.get("specs", "docs/specs")
114
- progress_path = paths.get("progress", "docs/progress.html")
115
- agent_scope_section = _build_agent_scope_table(agents_cfg, paths)
116
-
117
- # Agentes activos
118
- active = agents_cfg.get("active", [])
119
-
120
- # Comandos según lenguaje
121
- if language == "typescript":
122
- dev_cmd = "pnpm dev"
123
- test_cmd = "pnpm test"
124
- lint_cmd = "pnpm lint"
125
- build_cmd = "pnpm build"
126
- elif language == "python":
127
- dev_cmd = "python manage.py runserver # o uvicorn main:app"
128
- test_cmd = "pytest"
129
- lint_cmd = "ruff check ."
130
- build_cmd = "# no aplica"
131
- elif language == "ruby":
132
- dev_cmd = "rails server"
133
- test_cmd = "bundle exec rspec"
134
- lint_cmd = "rubocop"
135
- build_cmd = "# no aplica"
136
- elif language == "go":
137
- dev_cmd = "go run ./cmd/..."
138
- test_cmd = "go test ./..."
139
- lint_cmd = "golangci-lint run"
140
- build_cmd = "go build ./..."
141
- elif language == "php":
142
- dev_cmd = "php artisan serve # o php -S localhost:8000 -t public"
143
- test_cmd = "vendor/bin/phpunit # o ./vendor/bin/pest"
144
- lint_cmd = "vendor/bin/phpstan analyse"
145
- build_cmd = "composer install --no-dev --optimize-autoloader"
146
- elif language == "mixed":
147
- dev_cmd = "# ver documentación del proyecto (stack mixto)"
148
- test_cmd = "# ver documentación del proyecto (stack mixto)"
149
- lint_cmd = "# ver documentación del proyecto (stack mixto)"
150
- build_cmd = "# ver documentación del proyecto (stack mixto)"
151
- else:
152
- dev_cmd = "# ver documentación del proyecto"
153
- test_cmd = "# ver documentación del proyecto"
154
- lint_cmd = "# ver documentación del proyecto"
155
- build_cmd = "# ver documentación del proyecto"
156
-
157
- compliance_section = ""
158
- if frameworks:
159
- compliance_section = f"""
160
- ## Compliance activo
161
-
162
- Este proyecto opera bajo los siguientes marcos regulatorios:
163
- {chr(10).join(f'- **{f.upper()}**' for f in frameworks)}
164
-
165
- Reglas no-negociables:
166
- - Sin datos personales en logs de stdout
167
- - Consentimiento explícito antes de cualquier tracker no esencial
168
- - Logs de auditoría append-only (sin UPDATE/DELETE)
169
- - Derechos del titular implementados (acceso, rectificación, supresión, oposición, portabilidad)
170
- """
171
-
172
- return f"""# CLAUDE.md — {name}
173
-
174
- > Generado por forge. Actualizar project.yaml para cambiar la configuración.
175
- > Si actualizás el código de manera que invalide algo aquí, actualizá este archivo en el mismo PR.
176
-
177
- ## Misión del proyecto
178
-
179
- {description}
180
-
181
- ## Stack
182
-
183
- - **Lenguaje**: {language}
184
- - **Backend**: {backend}
185
- - **Frontend**: {frontend}
186
- - **Base de datos**: {database}
187
- - **Testing**: {", ".join(stack.get("testing", []))}
188
-
189
- {agent_scope_section}## Estructura
190
-
191
- ```
192
- {proj.get("slug", "proyecto")}/
193
- ├── CLAUDE.md ← Estás acá
194
- ├── AGENTS.md ← Convenciones del agent team
195
- ├── project.yaml ← Config de forge (fuente de verdad)
196
- ├── {specs_path}/ ← Specs de features (requeridas antes de implementar)
197
- └── {progress_path} ← Dashboard de progreso del proyecto
198
- ```
199
-
200
- ## Cómo trabajar (SDD)
201
-
202
- Cuando recibás una tarea:
203
-
204
- 1. **Identificá la spec.** Si no está en `{specs_path}/`, pará y pedí que se cree.
205
- 2. **Leé la spec correspondiente.**
206
- 3. **Leé el `CLAUDE.md` del módulo** que vas a modificar (si existe).
207
- 4. **Proponé opciones** para decisiones arquitectónicas no cubiertas por la spec.
208
- 5. **Esperá aprobación** antes de generar código.
209
- 6. **Tests** junto con la implementación, no al final.
210
- 7. **Al terminar**, actualizá la spec con decisiones tomadas durante la implementación.
211
- 8. **Antes de cerrar**: `{test_cmd}`, `{lint_cmd}`.
212
- {compliance_section}
213
- ## Phases activas y estado
214
-
215
- {_render_phases(config)}
216
-
217
- > Actualizar `project.yaml` (sprint.phases) para reflejar el estado real.
218
-
219
- ## Comandos frecuentes
220
-
221
- ```bash
222
- {dev_cmd} # Desarrollo
223
- {test_cmd} # Tests
224
- {lint_cmd} # Lint
225
- {build_cmd} # Build
226
- ```
227
-
228
- ## Qué NO hacer
229
-
230
- - No implementar sin spec en `{specs_path}/`
231
- - No hardcodear tokens, passwords o secrets
232
- - No usar `any` en TypeScript sin comentario que explique por qué
233
- - No commits con `console.log` o `print` de depuración
234
- - No hacer force push a main/master
235
- """
236
-
237
-
238
- def _generate_architecture_rules(root: Path, forge: Path, config: dict):
239
- """Crea .claude/architecture.rules desde el template si no existe. Nunca sobreescribe."""
240
- dst = root / ".claude" / "architecture.rules"
241
- if dst.exists():
242
- return
243
-
244
- # Buscar el template en forge
245
- tpl_path = forge / "core" / "templates" / "claude-md" / "architecture.rules"
246
- if not tpl_path.exists():
247
- return
248
-
249
- project_name = config.get("project", {}).get("name", "Mi Proyecto")
250
- content = tpl_path.read_text(encoding="utf-8")
251
- content = content.replace("<NOMBRE_PROYECTO>", project_name)
252
-
253
- dst.parent.mkdir(parents=True, exist_ok=True)
254
- dst.write_text(content, encoding="utf-8")
255
- print(f"[OK] .claude/architecture.rules — creado desde template")
256
-
257
-
258
- def _find_forge_dir(root: Path) -> Path:
259
- """Localiza el directorio de forge relativo a este script."""
260
- # Este script está en forge/adapters/claude-code/generate-claude-md.py
261
- script_dir = Path(__file__).parent
262
- # forge_dir = forge/
263
- candidate = script_dir.parent.parent
264
- if (candidate / "core").exists():
265
- return candidate
266
- # Fallback: buscar .agentic o forge en la raíz del proyecto
267
- for name in (".agentic", "forge"):
268
- c = root / name
269
- if (c / "core").exists():
270
- return c
271
- return candidate
272
-
273
-
274
- def main():
275
- try:
276
- root = find_project_root()
277
- except FileNotFoundError as e:
278
- print(f"ERROR: {e}", file=sys.stderr)
279
- sys.exit(1)
280
-
281
- with open(root / "project.yaml") as f:
282
- config = yaml.safe_load(f)
283
-
284
- content = generate_claude_md(config)
285
- output_path = root / "CLAUDE.md"
286
-
287
- if output_path.exists() and not FORCE:
288
- print(f"CLAUDE.md ya existe en {root}. Sobreescribir? [s/N] ", end="")
289
- resp = input().strip().lower()
290
- if resp not in ("s", "si", "sí", "y", "yes"):
291
- print("Cancelado.")
292
- sys.exit(0)
293
-
294
- with open(output_path, "w") as f:
295
- f.write(content)
296
-
297
- print(f"CLAUDE.md generado en {output_path}")
298
-
299
- forge = _find_forge_dir(root)
300
- _generate_architecture_rules(root, forge, config)
301
-
302
-
303
- if __name__ == "__main__":
304
- main()
@@ -1,269 +0,0 @@
1
- #!/usr/bin/env python3
2
- # Copyright 2026 Cristian Correa — Apache License 2.0
3
- # https://github.com/cristiancorreau/forge
4
- """
5
- generate-codex-config.py — Genera AGENTS.md para Codex CLI (OpenAI).
6
-
7
- Usage:
8
- python3 .agentic/adapters/codex/generate-codex-config.py
9
-
10
- Lee project.yaml en la raíz y genera AGENTS.md enriquecido para Codex CLI.
11
-
12
- Diferencias respecto al adapter OpenCode:
13
- - Incluye sección "Workflow SDD" con pasos explícitos (Codex opera autónomamente)
14
- - Incluye "Security rules" y "Autonomy limits" inline (crítico para ejecución sin supervisión)
15
- - Header identifica el archivo como generado para Codex CLI
16
-
17
- Codex CLI lee AGENTS.md desde la raíz del repositorio como contexto del agente.
18
- Referencia: https://github.com/openai/codex
19
-
20
- Requiere: pyyaml
21
- """
22
- from __future__ import annotations
23
-
24
- import sys
25
- from pathlib import Path
26
-
27
- try:
28
- import yaml
29
- except ImportError:
30
- print("ERROR: pyyaml requerido. pip install pyyaml", file=sys.stderr)
31
- sys.exit(1)
32
-
33
-
34
- def find_project_root() -> Path:
35
- here = Path.cwd()
36
- for p in [here] + list(here.parents):
37
- if (p / "project.yaml").exists():
38
- return p
39
- raise FileNotFoundError("No se encontró project.yaml")
40
-
41
-
42
- def find_forge_dir() -> Path:
43
- root = find_project_root()
44
- for candidate in [root / ".agentic", root / "forge", Path(__file__).parent.parent.parent]:
45
- if (candidate / "core").exists():
46
- return candidate
47
- raise FileNotFoundError("No se encontró el directorio forge con core/")
48
-
49
-
50
- def read_agent_description(forge: Path, name: str, profiles: list[str]) -> str:
51
- """Lee el frontmatter description del agente desde forge (profiles > core)."""
52
- for profile in profiles:
53
- p = forge / "profiles" / profile / "agents" / f"{name}.md"
54
- if p.exists():
55
- content = p.read_text()
56
- for line in content.splitlines():
57
- if line.startswith("description:"):
58
- return line.split(":", 1)[1].strip().strip('"')
59
- p = forge / "core" / "agents" / f"{name}.md"
60
- if p.exists():
61
- content = p.read_text()
62
- for line in content.splitlines():
63
- if line.startswith("description:"):
64
- return line.split(":", 1)[1].strip().strip('"')
65
- return "Agente de implementación"
66
-
67
-
68
- def generate_agents_md(config: dict, forge: Path) -> str:
69
- """
70
- Genera AGENTS.md enriquecido para Codex CLI.
71
-
72
- Codex CLI opera autónomamente en terminal: las reglas de seguridad y los
73
- límites de autonomía deben estar inline en AGENTS.md, no en un archivo
74
- separado, para que el agente las reciba como contexto en cada sesión.
75
- """
76
- proj = config.get("project", {})
77
- agents_cfg = config.get("agents", {})
78
- compliance_cfg = config.get("compliance", {})
79
- stack = config.get("stack", {})
80
- paths = config.get("paths", {})
81
-
82
- name = proj.get("name", "Mi Proyecto")
83
- description = proj.get("description", "")
84
- language = proj.get("language", "typescript")
85
- active = agents_cfg.get("active", [])
86
- compliance = agents_cfg.get("compliance", [])
87
- specialized = agents_cfg.get("specialized", [])
88
- profiles = agents_cfg.get("profiles", [])
89
- frameworks = compliance_cfg.get("frameworks", [])
90
- specs_path = paths.get("specs", "docs/specs")
91
-
92
- if frameworks and "compliance-reviewer" not in active + compliance:
93
- compliance = list(set(compliance + ["compliance-reviewer"]))
94
-
95
- lines = [
96
- f"# AGENTS.md — {name}",
97
- "",
98
- f"> Generado por forge (adapter Codex CLI).",
99
- f"> Fuente de verdad: `project.yaml`. Re-ejecutar `generate-codex-config.py` al cambiar agentes.",
100
- "",
101
- ]
102
-
103
- if description:
104
- lines += [description, ""]
105
-
106
- lines += [
107
- "## Stack",
108
- "",
109
- f"- **Lenguaje:** {language}",
110
- f"- **Backend:** {stack.get('backend') or 'N/A'}",
111
- f"- **Frontend:** {stack.get('frontend') or 'N/A'}",
112
- f"- **Base de datos:** {stack.get('database') or 'N/A'}",
113
- f"- **Testing:** {', '.join(stack.get('testing', []))}",
114
- "",
115
- "## Workflow: Spec-Driven Development",
116
- "",
117
- "Antes de implementar cualquier feature:",
118
- "",
119
- f"1. Verificar que existe una spec en `{specs_path}/`.",
120
- "2. Si no existe, crearla y esperar aprobación antes de codificar.",
121
- "3. Implementar con tests junto al código, no al final.",
122
- "4. Actualizar la spec con decisiones tomadas durante la implementación.",
123
- "",
124
- "## Reglas de seguridad (no negociables)",
125
- "",
126
- "- Sin hardcodear tokens, passwords ni secrets — usar variables de entorno.",
127
- "- Parámetros preparados en todas las queries SQL — nunca concatenar input del usuario.",
128
- "- PII nunca en logs de stdout.",
129
- "- Verificar autenticación Y autorización en cada endpoint de API.",
130
- "- Sin force push a main/master.",
131
- "",
132
- "## Límites de autonomía",
133
- "",
134
- "- Modificar solo archivos dentro del scope declarado del agente.",
135
- "- Preguntar antes de eliminar archivos o ejecutar comandos destructivos.",
136
- "- Nunca hacer commit directo a main/master.",
137
- "- Correr los tests antes de marcar una tarea como completa.",
138
- "- Si una tarea requiere acceso a credenciales no disponibles, detenerse y reportar.",
139
- "",
140
- "## Roster de agentes",
141
- "",
142
- ]
143
-
144
- if active:
145
- lines += ["### Activos", ""]
146
- for agent in active:
147
- desc = read_agent_description(forge, agent, profiles)
148
- lines.append(f"#### `{agent}`")
149
- lines.append(desc)
150
- lines.append("")
151
-
152
- if compliance:
153
- lines += ["### Compliance y revisión", ""]
154
- for agent in compliance:
155
- desc = read_agent_description(forge, agent, profiles)
156
- lines.append(f"#### `{agent}`")
157
- lines.append(desc)
158
- lines.append("")
159
-
160
- if specialized:
161
- lines += ["### Especializados del proyecto", ""]
162
- for agent in specialized:
163
- desc = read_agent_description(forge, agent, profiles)
164
- lines.append(f"#### `{agent}`")
165
- lines.append(desc)
166
- lines.append("")
167
-
168
- if frameworks:
169
- lines += [
170
- "## Compliance activo",
171
- "",
172
- f"Marcos regulatorios: {', '.join(f.upper() for f in frameworks)}",
173
- "",
174
- "Incluir `compliance-reviewer` en toda tarea que toque:",
175
- "- Datos de usuarios o consentimientos",
176
- "- Logs de auditoría",
177
- "- Endpoints de derechos del titular (DSAR)",
178
- "",
179
- ]
180
-
181
- lines += [
182
- "## Forge v2 Commands",
183
- "",
184
- "Codex CLI no soporta slash commands. Usa las plantillas de prompt de",
185
- "`adapters/codex/commands/` copiando su contenido directamente en tu sesión.",
186
- "",
187
- "| Comando | Archivo | Cuándo usarlo |",
188
- "|---------|---------|---------------|",
189
- "| plan | `adapters/codex/commands/plan.md` | Antes de implementar — verifica o crea la spec |",
190
- "| work | `adapters/codex/commands/work.md` | Implementar una feature con spec APPROVED |",
191
- "| review | `adapters/codex/commands/review.md` | Revisar código o cambios antes del merge |",
192
- "| ship | `adapters/codex/commands/ship.md` | Verificar que el proyecto está listo para deploy |",
193
- "| session-start | `adapters/codex/commands/session-start.md` | Al iniciar cada sesión de trabajo |",
194
- "| session-close | `adapters/codex/commands/session-close.md` | Al cerrar cada sesión de trabajo |",
195
- "",
196
- "### Flujo SDD recomendado",
197
- "",
198
- "```",
199
- "1. session-start → verificar ambiente y branch",
200
- "2. plan → spec antes que código (DRAFT → APPROVED)",
201
- "3. work → implementar con tests (spec APPROVED → IMPLEMENTED)",
202
- "4. review → checklist de seguridad y calidad",
203
- "5. ship → verificar build, tests y variables antes del deploy",
204
- "6. session-close → registrar progreso y limpiar",
205
- "```",
206
- "",
207
- "## Reglas de producción (pre-bash-check)",
208
- "",
209
- "Los siguientes comandos están bloqueados en contexto de producción.",
210
- "Si necesitás ejecutarlos, hacelo manualmente en la terminal con plena consciencia:",
211
- "",
212
- "- `--force-reset` — puede destruir datos de base de datos",
213
- "- `prisma migrate reset` — borra y re-crea la base de datos",
214
- "- `DROP TABLE` / `DROP DATABASE` — destruye tablas o bases de datos",
215
- "- `TRUNCATE` — elimina todos los registros de una tabla",
216
- "- `DELETE FROM <tabla>;` — sin cláusula WHERE, elimina todo",
217
- "- `dropdb` — elimina una base de datos completa",
218
- "- `rm -rf /` — elimina recursivamente desde la raíz",
219
- "- `git push --force` sin `--with-lease` — sobreescribe historial remoto",
220
- "",
221
- "Contexto de producción = la URL de producción o el project_id aparecen",
222
- "en el comando, o hay variables de entorno `PROD_*` / `PRODUCTION_*` activas.",
223
- "",
224
- "Lección del 2026-04-28: --force-reset borró 225 usuarios y 35 formularios",
225
- "en producción. Estas reglas existen por eso.",
226
- "",
227
- "## Branch guard (pre-edit-check)",
228
- "",
229
- "No editar archivos de código fuente directamente en `main` o `master`.",
230
- "",
231
- "Archivos de código = `.py`, `.ts`, `.js`, `.tsx`, `.jsx`, `.php`, `.rb`,",
232
- "`.go`, `.rs`, `.java`, `.cs`, `.cpp`, `.c`, `.sh`",
233
- "",
234
- "Excenciones permitidas en rama protegida:",
235
- "- Archivos de documentación (`docs/`, `.md`)",
236
- "- Archivos de configuración en raíz (`.yaml`, `.yml`, `.json`)",
237
- "- `CLAUDE.md`, `AGENTS.md`, `README.md`, `CHANGELOG.md`",
238
- "",
239
- "Si estás en `main` o `master`, crea una feature branch primero:",
240
- "```bash",
241
- "git checkout -b feature/<tema>-$(date +%Y-%m-%d)",
242
- "```",
243
- "",
244
- ]
245
-
246
- return "\n".join(lines)
247
-
248
-
249
- def main():
250
- try:
251
- root = find_project_root()
252
- forge = find_forge_dir()
253
- except FileNotFoundError as e:
254
- print(f"ERROR: {e}", file=sys.stderr)
255
- sys.exit(1)
256
-
257
- with open(root / "project.yaml") as f:
258
- config = yaml.safe_load(f)
259
-
260
- content = generate_agents_md(config, forge)
261
- output_path = root / "AGENTS.md"
262
- with open(output_path, "w") as f:
263
- f.write(content)
264
- print(f" [OK] AGENTS.md generado en {output_path}")
265
- print(" (adapter Codex: incluye SDD workflow + security rules + autonomy limits)")
266
-
267
-
268
- if __name__ == "__main__":
269
- main()
@@ -1,43 +0,0 @@
1
- # .codex/codex.yaml — Forge v2 hooks para Codex CLI
2
- #
3
- # Generar con: cp adapters/codex/hooks/codex.yaml.tpl .codex/codex.yaml
4
- # O usar: bash scripts/setup-codex.sh
5
- #
6
- # SOPORTE DE HOOKS EN CODEX CLI (estado a 2025):
7
- # onStart — se ejecuta al inicio de cada sesión de Codex. Equivalente
8
- # al hook SessionStart / UserPromptSubmit de Claude Code.
9
- # onFinish — se ejecuta al finalizar cada sesión de Codex. Equivalente
10
- # al hook Stop de Claude Code.
11
- # onDiff — se ejecuta cuando Codex aplica cambios al filesystem.
12
- # No tiene equivalente directo en Claude Code.
13
- #
14
- # NO SOPORTADO en Codex CLI (a diferencia de Claude Code):
15
- # - PreToolUse: Codex no puede interceptar herramientas individuales
16
- # antes de ejecutarlas. Las reglas de pre-bash-check.py y
17
- # pre-edit-check.py NO tienen equivalente automático en Codex.
18
- # Esas reglas están embebidas en AGENTS.md como instrucciones de texto
19
- # para que el agente las respete voluntariamente.
20
- # - PostToolUse: tampoco soportado.
21
- #
22
- # IMPLICACIÓN: La capa de seguridad de Codex es instruccional (AGENTS.md),
23
- # no mecánica (hooks que bloquean). Para proyectos de alto riesgo, preferir
24
- # Claude Code que sí puede bloquear comandos destructivos antes de ejecutarlos.
25
-
26
- model: o4-mini # Cambiar según preferencia: o4-mini | o3 | gpt-4o
27
-
28
- hooks:
29
- # Ejecutado al inicio de cada sesión.
30
- # Equivalent: Claude Code SessionStart / UserPromptSubmit hook.
31
- # Verifica herramientas disponibles, branch, cambios sin commitear,
32
- # project.yaml y variables de entorno de producción activas.
33
- onStart: bash .codex/forge-codex-start.sh
34
-
35
- # Ejecutado al finalizar cada sesión.
36
- # Equivalent: Claude Code Stop hook (post-turn-check.sh).
37
- # Detecta archivos modificados y corre type-check / syntax-check.
38
- onFinish: bash .codex/forge-codex-finish.sh
39
-
40
- # onDiff: no configurado por defecto.
41
- # Se puede usar para correr linters en los archivos cambiados.
42
- # Ejemplo: onDiff: bash -c 'echo "$CODEX_DIFF_FILES" | xargs eslint --fix'
43
- # onDiff: ""