@ronaldjdevfs/forge 1.2.0 → 1.3.1
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 +36 -21
- package/package.json +7 -2
- package/skills/forge/SKILL.md +56 -122
- package/skills/forge/command/forge.md +59 -14
- package/skills/forge/reference/adr.md +242 -0
- package/skills/forge/reference/anti-corruption-layer.md +340 -0
- package/skills/forge/reference/api-design.md +7 -0
- package/skills/forge/reference/api-versioning.md +354 -0
- package/skills/forge/reference/architectural-depth-checklist.md +311 -0
- package/skills/forge/reference/architecture-template.md +41 -0
- package/skills/forge/reference/assay.md +6 -0
- package/skills/forge/reference/bounded-contexts.md +311 -0
- package/skills/forge/reference/chain.md +6 -0
- package/skills/forge/reference/cohesion-checklist.md +256 -0
- package/skills/forge/reference/cqrs.md +286 -0
- package/skills/forge/reference/data-patterns.md +6 -0
- package/skills/forge/reference/di-strategies.md +6 -0
- package/skills/forge/reference/errors.md +5 -0
- package/skills/forge/reference/events.md +8 -0
- package/skills/forge/reference/evolutionary-architecture.md +300 -0
- package/skills/forge/reference/forge.md +7 -0
- package/skills/forge/reference/hooks.md +6 -0
- package/skills/forge/reference/idempotency.md +283 -0
- package/skills/forge/reference/inscribe.md +5 -0
- package/skills/forge/reference/inspect.md +6 -0
- package/skills/forge/reference/modular-monolith.md +252 -0
- package/skills/forge/reference/observability.md +5 -0
- package/skills/forge/reference/quench.md +5 -0
- package/skills/forge/reference/relocate.md +6 -0
- package/skills/forge/reference/sagas.md +359 -0
- package/skills/forge/reference/security-patterns.md +6 -0
- package/skills/forge/reference/smelt.md +6 -0
- package/skills/forge/reference/temper.md +6 -0
- package/skills/forge/reference/testing-patterns.md +6 -0
- package/skills/forge/reference/transactional-outbox.md +311 -0
- package/skills/forge/scripts/architecture.mjs +10 -5
- package/skills/forge/scripts/assay.mjs +2 -2
- package/skills/forge/scripts/chain.mjs +31 -5
- package/skills/forge/scripts/context.mjs +24 -4
- package/skills/forge/scripts/detect.mjs +39 -30
- package/skills/forge/scripts/forge-boot.mjs +108 -0
- package/skills/forge/scripts/forge-config.mjs +182 -3
- package/skills/forge/scripts/forge-state.mjs +1 -1
- package/skills/forge/scripts/forgeSentinel-lib.mjs +86 -0
- package/skills/forge/scripts/forgeSentinel.mjs +184 -0
- package/skills/forge/scripts/forgeSmith-admin.mjs +104 -0
- package/skills/forge/scripts/forgeSmith.mjs +164 -0
- package/skills/forge/scripts/graph.mjs +65 -9
- package/skills/forge/scripts/hook.mjs +2 -2
- package/skills/forge/scripts/inspect.mjs +56 -48
- package/skills/forge/scripts/parse-imports.mjs +0 -2
- package/skills/forge/scripts/pin.mjs +10 -3
- package/skills/forge/scripts/posttool.mjs +2 -2
- package/skills/forge/scripts/recommendation-engine.mjs +125 -0
- package/skills/forge/scripts/rollback.mjs +5 -3
- package/skills/forge/templates/agents/SKILL.md.template +283 -0
- package/skills/forge/templates/agents/agents/hooks.json +18 -0
- package/skills/forge/templates/agents/claude/CLAUDE.md +17 -16
- package/skills/forge/templates/agents/claude/settings.local.json +18 -0
- package/skills/forge/templates/agents/codex/hooks.json +18 -0
- package/skills/forge/templates/agents/cursor/.cursorrules +22 -5
- package/skills/forge/templates/agents/cursor/hooks.json +11 -0
- package/skills/forge/templates/agents/gemini/SKILL.md +13 -0
- package/skills/forge/templates/feature/acl-gateway.ts.md +52 -0
- package/skills/forge/templates/feature/acl-repository.ts.md +36 -0
- package/skills/forge/templates/feature/acl-translator.ts.md +24 -0
- package/skills/forge/templates/feature/cqrs-query.ts.md +40 -0
- package/skills/forge/templates/feature/outbox-repository.ts.md +36 -0
- package/skills/forge/templates/feature/saga-orchestrator.ts.md +72 -0
- package/skills/forge/templates/platform/outbox-relayer.ts.md +80 -0
- package/skills/forge/tests/core.test.mjs +284 -0
- package/src/agents.mjs +35 -2
- package/src/cli.js +112 -39
- package/src/wizard.mjs +142 -90
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { CYAN, GREEN, RED, YELLOW, BOLD, RESET, DIM, GRAY, SEVERITY_COLORS } from "./formatter.mjs";
|
|
4
|
+
|
|
5
|
+
function countByRule(violations) {
|
|
6
|
+
const counts = {};
|
|
7
|
+
for (const v of violations) {
|
|
8
|
+
const rule = v.rule || "other";
|
|
9
|
+
if (!counts[rule]) counts[rule] = [];
|
|
10
|
+
counts[rule].push(v);
|
|
11
|
+
}
|
|
12
|
+
return counts;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function buildPipeline(auditChecks, graph, ownership, profile, ctx) {
|
|
16
|
+
const violations = auditChecks.filter(c => !c.pass);
|
|
17
|
+
const pipeline = [];
|
|
18
|
+
|
|
19
|
+
// --- CRITICAL: R2 (platform→feature) → forge temper ---
|
|
20
|
+
const r2 = violations.filter(v => v.rule === "R2" || (v.fix && v.fix.includes("Extraer interfaz") && v.severity === "CRITICAL"));
|
|
21
|
+
if (r2.length > 0) {
|
|
22
|
+
pipeline.push({ command: "temper", args: "", priority: "CRITICAL", reason: `Corrige ${r2.length} violación(es) R2 (platform→feature)`, count: r2.length });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// --- ERROR: R3 (shared→feature) → forge reforge ---
|
|
26
|
+
const r3 = violations.filter(v => v.rule === "R3" || (v.fix && v.fix.includes("Feature no accede")));
|
|
27
|
+
// --- ERROR: R4 (shared→infra) → forge reforge ---
|
|
28
|
+
const r4 = violations.filter(v => v.rule === "R4" || (v.fix && v.fix.includes("Feature no importa otro feature")));
|
|
29
|
+
// --- ERROR: R8 (cross-feature) → forge reforge ---
|
|
30
|
+
const r8 = violations.filter(v => v.rule === "R8");
|
|
31
|
+
const sharedIssues = [...r3, ...r4, ...r8];
|
|
32
|
+
if (sharedIssues.length > 0) {
|
|
33
|
+
pipeline.push({ command: "reforge", args: "", priority: "ERROR", reason: `Corrige ${sharedIssues.length} violación(es) de capas (shared mal acoplado)`, count: sharedIssues.length });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// --- ERROR: R9 (cycles) → forge reforge ---
|
|
37
|
+
const r9 = violations.filter(v => v.rule === "R9" || (v.label && v.label.includes("Ciclo")));
|
|
38
|
+
if (r9.length > 0 || (graph && graph.hasCycles)) {
|
|
39
|
+
pipeline.push({ command: "reforge", args: "--cycles", priority: "ERROR", reason: `Elimina ${r9.length || 1} ciclo(s) de dependencia (R9)`, count: r9.length || 1 });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// --- R1 (feature→infra) → forge reforge ---
|
|
43
|
+
const r1 = violations.filter(v => v.rule === "R1");
|
|
44
|
+
if (r1.length > 0) {
|
|
45
|
+
pipeline.push({ command: "reforge", args: "", priority: "ERROR", reason: `Corrige ${r1.length} violación(es) R1 (feature→infra)`, count: r1.length });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// --- WARNING: orphan/misplaced → forge relocate ---
|
|
49
|
+
const orphans = ownership?.orphans || [];
|
|
50
|
+
const misplaced = ownership?.misplaced || [];
|
|
51
|
+
const duplicates = ownership?.duplicates || [];
|
|
52
|
+
const relocationCount = orphans.length + misplaced.length + duplicates.length;
|
|
53
|
+
if (relocationCount > 0) {
|
|
54
|
+
pipeline.push({ command: "relocate", args: "", priority: "WARNING", reason: `Migra ${relocationCount} componente(s) huérfanos/duplicados/mal ubicados`, count: relocationCount });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// --- WARNING: naming violations → forge reforge ---
|
|
58
|
+
const namingCount = violations.filter(v => v.severity === "SUGGESTION" && v.label && v.label.includes("Naming")).length;
|
|
59
|
+
if (namingCount > 0) {
|
|
60
|
+
pipeline.push({ command: "reforge", args: "<filename>", priority: "WARNING", reason: `Corrige ${namingCount} violación(es) de naming (ejecutar por feature)`, count: namingCount });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// --- Legacy features → forge relocate ---
|
|
64
|
+
const legacyCount = ctx?.features?.legacy?.length || 0;
|
|
65
|
+
if (legacyCount > 0) {
|
|
66
|
+
pipeline.push({ command: "relocate", args: "", priority: "WARNING", reason: `Migra ${legacyCount} feature(s) legacy a estructura hexagonal`, count: legacyCount });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- Missing platform → forge forge ---
|
|
70
|
+
if (ctx && !ctx.platform?.exists) {
|
|
71
|
+
pipeline.push({ command: "forge", args: "", priority: "INFO", reason: "Inicializa bootstrap de platform layer", count: 1 });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// --- Package dependencies → (not a forge command, just suggestion) ---
|
|
75
|
+
const profileSugs = profile?.suggestions || [];
|
|
76
|
+
if (profileSugs.length > 0) {
|
|
77
|
+
pipeline.push({ command: "profile", args: "--install", priority: "SUGGESTION", reason: `${profileSugs.length} dependencia(s) sugeridas por perfil`, count: profileSugs.length });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// --- Verify & finalize ---
|
|
81
|
+
if (pipeline.length > 0) {
|
|
82
|
+
pipeline.push({ command: "quench", args: "", priority: "INFO", reason: "Verifica que todas las correcciones pasen", count: 0 });
|
|
83
|
+
pipeline.push({ command: "inscribe", args: "", priority: "INFO", reason: "Actualiza ARCHITECTURE.md con el nuevo estado", count: 0 });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Sort by priority
|
|
87
|
+
const order = { CRITICAL: 0, ERROR: 1, WARNING: 2, INFO: 3, SUGGESTION: 4 };
|
|
88
|
+
pipeline.sort((a, b) => (order[a.priority] ?? 99) - (order[b.priority] ?? 99));
|
|
89
|
+
|
|
90
|
+
return pipeline;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function printPipeline(pipeline) {
|
|
94
|
+
if (!pipeline || pipeline.length === 0) return;
|
|
95
|
+
console.log(`\n${BOLD}${CYAN}═══ Pipeline recomendado ═══${RESET}`);
|
|
96
|
+
console.log(`${DIM}Para resolver los problemas encontrados, ejecuta en orden:${RESET}\n`);
|
|
97
|
+
let step = 1;
|
|
98
|
+
for (const item of pipeline) {
|
|
99
|
+
const color = SEVERITY_COLORS[item.priority] || GRAY;
|
|
100
|
+
const cmd = item.command === "forge" ? "forge forge" : `forge ${item.command}`;
|
|
101
|
+
const args = item.args ? ` ${item.args}` : "";
|
|
102
|
+
const countStr = item.count > 0 ? ` ${DIM}(${item.count})${RESET}` : "";
|
|
103
|
+
console.log(` ${GREEN}${step}.${RESET} ${BOLD}${CYAN}${cmd}${args}${RESET} ${DIM}→${RESET} ${color}${item.reason}${countStr}${RESET}`);
|
|
104
|
+
step++;
|
|
105
|
+
}
|
|
106
|
+
console.log();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function pipelineToJson(pipeline) {
|
|
110
|
+
return JSON.stringify({ pipeline }, null, 2);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* ── CLI ── */
|
|
114
|
+
if (process.argv[1] && (process.argv[1].endsWith("recommendation-engine.mjs") || process.argv[1].endsWith("recommendation-engine.js"))) {
|
|
115
|
+
const { buildContext } = await import("./context.mjs");
|
|
116
|
+
const ctx = await buildContext();
|
|
117
|
+
const features = ctx.features?.migrated || [];
|
|
118
|
+
const graph = ctx.graph;
|
|
119
|
+
const checks = [];
|
|
120
|
+
for (const [, cat] of Object.entries(ctx.checks || {})) {
|
|
121
|
+
if (cat.checks) checks.push(...cat.checks);
|
|
122
|
+
}
|
|
123
|
+
const pipeline = buildPipeline(checks, graph, ctx.ownership, ctx, ctx);
|
|
124
|
+
printPipeline(pipeline);
|
|
125
|
+
}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, cpSync, rmSync, statSync } from "fs";
|
|
20
20
|
import { join, relative, resolve, basename } from "path";
|
|
21
|
+
import { fileURLToPath } from "url";
|
|
21
22
|
import { execFileSync } from "child_process";
|
|
22
23
|
|
|
23
24
|
const ROOT = process.cwd();
|
|
@@ -157,7 +158,8 @@ export function listBackups(target) {
|
|
|
157
158
|
|
|
158
159
|
export function verifyAfterChange() {
|
|
159
160
|
try {
|
|
160
|
-
const
|
|
161
|
+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
162
|
+
const out = shell("node", [join(__dirname, "inspect.mjs"), "--diff", "--json"]);
|
|
161
163
|
if (!out) return { score: 0, improved: false, error: "inspect falló" };
|
|
162
164
|
|
|
163
165
|
const result = JSON.parse(out);
|
|
@@ -167,7 +169,7 @@ export function verifyAfterChange() {
|
|
|
167
169
|
let suggestedCommit = null;
|
|
168
170
|
if (improved && score > 0) {
|
|
169
171
|
const branch = shell("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
170
|
-
suggestedCommit = `git add -A && git commit -m "forge: relocate/reforge (score: ${score}
|
|
172
|
+
suggestedCommit = `git add -A && git commit -m "forge: relocate/reforge (score: ${score})"`;
|
|
171
173
|
}
|
|
172
174
|
|
|
173
175
|
return { score, improved, suggestedCommit };
|
|
@@ -205,7 +207,7 @@ if (action === "backup" && arg) {
|
|
|
205
207
|
console.error(`rollback: ${result.error}`);
|
|
206
208
|
process.exit(1);
|
|
207
209
|
}
|
|
208
|
-
console.log(`Score: ${result.score}
|
|
210
|
+
console.log(`Score: ${result.score} | ${result.improved ? "✓ Mejoró/igual" : "✘ Empeoró"}${result.suggestedCommit ? `\nSugerencia: ${result.suggestedCommit}` : ""}`);
|
|
209
211
|
process.exit(result.improved ? 0 : 1);
|
|
210
212
|
} else {
|
|
211
213
|
console.log("Uso: node rollback.mjs <backup|restore|list|verify> [target|id]");
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: forge
|
|
3
|
+
description: >
|
|
4
|
+
Architecture Operating System especializado en diseñar, construir, auditar,
|
|
5
|
+
proteger y evolucionar arquitecturas backend escalables basadas en features
|
|
6
|
+
(vertical slices), hexagonal architecture y DDD pragmático. Triggers:
|
|
7
|
+
"arquitectura", "migrar", "refactorizar", "features", "hexagonal",
|
|
8
|
+
"puertos y adaptadores", "clean architecture", "cast", "inspect",
|
|
9
|
+
"quench", "chain", "grafo", "graph", "nodo", "architecture graph",
|
|
10
|
+
"violaciones", "ownership", "platform", "infraestructura". Excluye
|
|
11
|
+
infraestructura (Docker, CI/CD), optimización de queries y cambios de
|
|
12
|
+
lógica de negocio sin reestructuración.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Forge — Backend Architecture Operating System
|
|
16
|
+
|
|
17
|
+
Forge es un **sistema operativo arquitectónico**. Diseña, construye, audita, protege y evoluciona arquitecturas backend completas. Opera sobre cualquier stack moderno modelando **cuatro dominios arquitectónicos**: **Platform**, **Features**, **Shared** e **Infrastructure**.
|
|
18
|
+
|
|
19
|
+
No es un template ni una guía. Es un orquestador.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Modelo Arquitectónico
|
|
24
|
+
|
|
25
|
+
Todo backend se modela en cuatro dominios:
|
|
26
|
+
|
|
27
|
+
| Layer | Propósito | Ejemplos |
|
|
28
|
+
|-------|-----------|----------|
|
|
29
|
+
| **Platform** | Backbone técnico global | config, database, http, server, logger, cache, security, events, di |
|
|
30
|
+
| **Features** | Capacidades de negocio | auth, users, payments |
|
|
31
|
+
| **Shared** | Componentes reutilizables puros | errors, contracts, types, utils |
|
|
32
|
+
| **Infrastructure** | Implementaciones concretas | prisma, mongodb, redis, mail |
|
|
33
|
+
|
|
34
|
+
### Dependency Rules
|
|
35
|
+
|
|
36
|
+
Permitido:
|
|
37
|
+
- `feature → platform`
|
|
38
|
+
- `feature → shared`
|
|
39
|
+
- `platform → infra`
|
|
40
|
+
- `adapter → infra`
|
|
41
|
+
- `feature → domain`
|
|
42
|
+
|
|
43
|
+
Prohibido:
|
|
44
|
+
- `feature → infra`
|
|
45
|
+
- `platform → feature`
|
|
46
|
+
- `shared → feature`
|
|
47
|
+
- `shared → infra`
|
|
48
|
+
- `domain → infra`
|
|
49
|
+
- `domain → platform`
|
|
50
|
+
- `infra → feature`
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Architecture Guidance
|
|
55
|
+
|
|
56
|
+
Ver `reference/principles.md` para el manifiesto completo y los 12 principios inquebrantables.
|
|
57
|
+
Ver `reference/patterns.md` para las convenciones de nomenclatura (PascalCase.artifact, kebab dirs, etc.).
|
|
58
|
+
En esencia:
|
|
59
|
+
|
|
60
|
+
| Principio | Regla |
|
|
61
|
+
|---|---|
|
|
62
|
+
| Cuatro dominios arquitectónicos | Platform, Features, Shared, Infrastructure con ownership estricto |
|
|
63
|
+
| Unidades autónomas | Cada feature es dueño de su dominio, aplicación y adapters |
|
|
64
|
+
| Dependencias unidireccionales | adapters → application → domain → (nada) |
|
|
65
|
+
| Cero lógica en controllers | El controller parsea, delega y responde |
|
|
66
|
+
| Cero BD fuera de repositorios | Los repositories son la única puerta a datos |
|
|
67
|
+
| DI disciplinada | Constructor injection, sin service locators |
|
|
68
|
+
| Cero acoplamiento directo entre features | Siempre vía interfaces inyectadas |
|
|
69
|
+
| Ownership obligatorio | Cada componente tiene un único propietario arquitectónico |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Boot Sequence (OBLIGATORIO — ejecutar siempre antes de responder)
|
|
74
|
+
|
|
75
|
+
ANTES de cualquier acción, Forge DEBE ejecutar esta secuencia. Si no lo haces, puedes dar respuestas incorrectas:
|
|
76
|
+
|
|
77
|
+
1. **context.mjs** — Detectar stack, platform, features, shared, infra, grafo, estado
|
|
78
|
+
2. **armorer.mjs** — Detectar ownership, huérfanos, duplicados, mal ubicados
|
|
79
|
+
3. **profile.mjs** — Determinar perfil tecnológico
|
|
80
|
+
4. **graph.mjs** — Construir grafo arquitectónico global (4 capas + 9 reglas)
|
|
81
|
+
5. **chain.mjs** — Analizar dependencias multi-capa
|
|
82
|
+
6. **inspect.mjs** — Auditoría completa con ownership + platform
|
|
83
|
+
7. **architecture.mjs** — Generar/actualizar ARCHITECTURE.md
|
|
84
|
+
8. **Ejecutar comando solicitado** — cast, quench, temper, etc.
|
|
85
|
+
9. **forgeSentinel** — Verificar cambios tras escritura
|
|
86
|
+
10. **Actualizar ARCHITECTURE.md** — Reflejar nuevo estado
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Template de setup que debes ejecutar:
|
|
90
|
+
ctx=$(node {{AGENT_PATH}}/scripts/context.mjs --json 2>/dev/null)
|
|
91
|
+
armorer=$(node {{AGENT_PATH}}/scripts/armorer.mjs --json 2>/dev/null)
|
|
92
|
+
profile=$(node {{AGENT_PATH}}/scripts/profile.mjs --extended 2>/dev/null)
|
|
93
|
+
graph=$(node {{AGENT_PATH}}/scripts/graph.mjs --json 2>/dev/null)
|
|
94
|
+
deps=$(node {{AGENT_PATH}}/scripts/chain.mjs --json 2>/dev/null)
|
|
95
|
+
inspect=$(node {{AGENT_PATH}}/scripts/inspect.mjs --json 2>/dev/null)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Command Routing
|
|
101
|
+
|
|
102
|
+
| Lenguaje natural | Comando | Archivo |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| "ayuda", "help", "comandos", "lista", "--help" | `forge --help` | `reference/help.md` |
|
|
105
|
+
| "inicializar", "setup", "empezar" | `forge` | `reference/forge.md` |
|
|
106
|
+
| "crear feature", "nuevo dominio" | `cast` | `reference/cast.md` |
|
|
107
|
+
| "inspeccionar", "diagnóstico", "evaluar" | `inspect` | `reference/inspect.md` |
|
|
108
|
+
| "trasladar", "mover", "reestructurar feature" | `relocate` | `reference/relocate.md` |
|
|
109
|
+
| "refactorizar", "rediseñar", "cambiar estructura" | `reforge` | `reference/reforge.md` |
|
|
110
|
+
| "verificar", "quench", "checklist" | `quench` | `reference/quench.md` |
|
|
111
|
+
| "templar", "endurecer", "mejorar" | `temper` | `reference/temper.md` |
|
|
112
|
+
| "cadena", "grafo", "acoplamiento" | `chain` | `scripts/chain.mjs` |
|
|
113
|
+
| "inscribir", "grabar", "ARCHITECTURE.md" | `inscribe` | `reference/inscribe.md` |
|
|
114
|
+
| "grafo", "graph", "nodo", "violaciones", "risk score" | `graph` | `scripts/graph.mjs` |
|
|
115
|
+
| "fundir", "compartir", "mover a shared" | `smelt` | `reference/smelt.md` |
|
|
116
|
+
| "ownership", "huérfanos", "armorer" | `inspect` | (incluido en auditoría) |
|
|
117
|
+
| "fijar", "pinar", "atajo", "shortcut" | `nail` | `scripts/pin.mjs` |
|
|
118
|
+
| "desfijar", "despinar", "remover atajo" | `unnail` | `scripts/pin.mjs` |
|
|
119
|
+
| "hook", "pre-commit", "githook", "validar commit" | `forge hook` | `reference/hooks.md` |
|
|
120
|
+
| "api", "contrato", "openapi", "swagger", "graphql" | `forge api` | `scripts/forge-api.mjs` |
|
|
121
|
+
| "rollback", "restaurar", "deshacer", "backup" | `forge rollback` | `scripts/rollback.mjs` |
|
|
122
|
+
| "estado", "state", "último audit" | `forge state --show` | `scripts/forge-state.mjs` |
|
|
123
|
+
| "examinar","calidad", "assay", "opinión", "personas", "critique", "evaluación cualitativa" | `assay` | `reference/assay.md` |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Execution Flow
|
|
128
|
+
|
|
129
|
+
Para cada comando, Forge sigue este flujo:
|
|
130
|
+
|
|
131
|
+
1. **Contexto**: Ejecutar `context.mjs` + `armorer.mjs` + `profile.mjs`
|
|
132
|
+
2. **Grafo**: Ejecutar `graph.mjs` + `chain.mjs`
|
|
133
|
+
3. **Auditoría**: Ejecutar `inspect.mjs`
|
|
134
|
+
4. **Referencia**: Cargar `reference/<command>.md`
|
|
135
|
+
5. **Ejecutar**: Aplicar el flujo definido en la referencia, usando los scripts según corresponda
|
|
136
|
+
6. **Verificar**: Ejecutar `scripts/detect.mjs` para verificar que no se introdujeron violaciones
|
|
137
|
+
7. **forgeSentinel**: Ejecutar `scripts/forgeSentinel.mjs --reminder`
|
|
138
|
+
8. **Actualizar ARCHITECTURE.md**: Reflejar el nuevo estado (`architecture.mjs`)
|
|
139
|
+
9. **Reportar**: Mostrar resultado al usuario con severidades
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Routing Rules
|
|
144
|
+
|
|
145
|
+
- Si el lenguaje natural matchea exactamente un comando, ejecutarlo directamente.
|
|
146
|
+
- Si hay ambigüedad, preguntar al usuario: "¿Quieres decir: cast, relocate o reforge?"
|
|
147
|
+
- Si el comando requiere un perfil que no está detectado, preguntar antes de continuar.
|
|
148
|
+
- Si el proyecto no tiene `src/features/` y el comando es `cast`, sugerir `forge` primero.
|
|
149
|
+
- Si el proyecto no tiene `src/platform/`, ejecutar `bootstrapPlatform()` automáticamente.
|
|
150
|
+
- Si `ARCHITECTURE.md` está desactualizado (fecha de auditoría > 7 días), sugerir `forge inscribe`.
|
|
151
|
+
- Todos los resultados se muestran con severidades: `[CRITICAL]`, `[ERROR]`, `[WARNING]`, `[INFO]`, `[SUGGESTION]`.
|
|
152
|
+
|
|
153
|
+
### Inline Ignores
|
|
154
|
+
|
|
155
|
+
Forge soporta comentarios inline para excepcionar violaciones línea por línea:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
// forge-ignore-next-line
|
|
159
|
+
import { something } from "../infra/prisma"; // ← esta línea no se reporta
|
|
160
|
+
|
|
161
|
+
// forge-ignore: R1
|
|
162
|
+
import { PrismaClient } from "../../infra/prisma/client"; // ← solo R1 ignorada
|
|
163
|
+
|
|
164
|
+
// forge-ignore: R1, R8
|
|
165
|
+
import { crossFeature } from "../other-feature/domain/Entity"; // ← R1 y R8 ignoradas
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## ARCHITECTURE.md
|
|
171
|
+
|
|
172
|
+
Forge mantiene un archivo `ARCHITECTURE.md` en la raíz del proyecto con el contexto persistente. Contiene:
|
|
173
|
+
|
|
174
|
+
```md
|
|
175
|
+
# Architecture State
|
|
176
|
+
|
|
177
|
+
- Project Name: <name>
|
|
178
|
+
- Framework: <detectado>
|
|
179
|
+
- Runtime: <detectado>
|
|
180
|
+
- Database: <detectado>
|
|
181
|
+
- ORM: <detectado>
|
|
182
|
+
- DI Strategy: <detectado>
|
|
183
|
+
- Profile: <detectado>
|
|
184
|
+
- Architecture: hexagonal-feature (Platform + Features + Shared + Infra)
|
|
185
|
+
- Last Audit: <fecha> (score: <puntaje>)
|
|
186
|
+
|
|
187
|
+
## Platform
|
|
188
|
+
- platform/config/
|
|
189
|
+
- platform/server/
|
|
190
|
+
...
|
|
191
|
+
|
|
192
|
+
## Features
|
|
193
|
+
- features/users/
|
|
194
|
+
...
|
|
195
|
+
|
|
196
|
+
## Shared
|
|
197
|
+
- shared/errors/
|
|
198
|
+
...
|
|
199
|
+
|
|
200
|
+
## Infrastructure
|
|
201
|
+
- infra/prisma/
|
|
202
|
+
...
|
|
203
|
+
|
|
204
|
+
## Ownership
|
|
205
|
+
- Health: healthy | degraded | critical
|
|
206
|
+
- Score: 0-100
|
|
207
|
+
- Orphans: 0
|
|
208
|
+
- Duplicates: 0
|
|
209
|
+
- Misplaced: 0
|
|
210
|
+
|
|
211
|
+
## Architecture Graph
|
|
212
|
+
...
|
|
213
|
+
|
|
214
|
+
## Dependency Health
|
|
215
|
+
...
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
El agente DEBE leer este archivo al inicio de cada interacción y actualizarlo al finalizar cada comando.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Module Index
|
|
223
|
+
|
|
224
|
+
| Módulo | Propósito |
|
|
225
|
+
|---|---|
|
|
226
|
+
| `reference/principles.md` | Manifiesto y 12 principios inquebrantables |
|
|
227
|
+
| `reference/patterns.md` | Convenciones de nomenclatura globales (PascalCase.artifact, kebab dirs, etc.) |
|
|
228
|
+
| `reference/errors.md` | Manejo de errores tipados en dominio y aplicación |
|
|
229
|
+
| `reference/di-strategies.md` | Estrategias de inyección de dependencias según tamaño |
|
|
230
|
+
| `reference/testing-patterns.md` | Pirámide de tests, unit mocks, integration tests |
|
|
231
|
+
| `reference/api-design.md` | REST / GraphQL, paginación, validación, contratos |
|
|
232
|
+
| `reference/observability.md` | Logging, tracing, métricas, health checks |
|
|
233
|
+
| `reference/data-patterns.md` | Repository, Unit of Work, CQRS, Event Sourcing |
|
|
234
|
+
| `reference/security-patterns.md` | AuthN, AuthZ, RBAC, rate limiting, validación |
|
|
235
|
+
| `reference/events.md` | Eventos de dominio, outbox pattern, sagas |
|
|
236
|
+
| `reference/hooks.md` | Git pre-commit hook para validación arquitectónica |
|
|
237
|
+
| `reference/help.md` | Lista completa de comandos y flags de Forge |
|
|
238
|
+
| `reference/assay.md` | Ensayo arquitectónico multi-persona — interpretación cualitativa del audit |
|
|
239
|
+
| `profiles/` | Perfiles tecnológicos detallados (Express, Fastify, NestJS, etc.) |
|
|
240
|
+
| `scripts/` | Scripts: context, detect, inspect, chain, profile, graph, architecture, armorer, bootstrap, forge-config, forge-signals, forge-state, forge-api, pin, update, rollback, hook, forgeSentinel, forgeSmith, forgeSentinel-lib, forgeSmith-admin, formatter, assay, registry/rules |
|
|
241
|
+
| `scripts/registry/rules.mjs` | Anti-pattern rule registry (R1-R9 + custom rules desacopladas de detect.mjs) |
|
|
242
|
+
| `scripts/formatter.mjs` | Output formatter unificado (JSON, tabla, severidad coloreada, scoreBar, formatCheck, formatViolation) |
|
|
243
|
+
| `scripts/forgeSentinel.mjs` | PostToolUse hook — analiza archivos modificados tras escritura y reporta violaciones |
|
|
244
|
+
| `scripts/forgeSentinel-lib.mjs` | Lógica compartida para hooks forgeSentinel y forgeSmith |
|
|
245
|
+
| `scripts/forgeSmith.mjs` | preToolUse gate — previene escrituras con violaciones CRITICAL/ERROR (Cursor) |
|
|
246
|
+
| `scripts/forgeSmith-admin.mjs` | Gestión de hooks (on/off/status) |
|
|
247
|
+
| `scripts/assay.mjs` | Motor de ensayo arquitectónico multi-persona (Bezos, Fowler, Hacker, PM, Arquitecta Senior) |
|
|
248
|
+
| `templates/feature/` | Templates de feature (entity, repository, uc, controller, routes, schema, mapper) |
|
|
249
|
+
| `templates/platform/` | Templates de platform (config, server, database, logger, http, di) |
|
|
250
|
+
| `templates/shared/` | Templates de shared (errors, contracts, types, utils) |
|
|
251
|
+
| `templates/infra/` | Templates de infra (prisma, mongodb, redis, mail) |
|
|
252
|
+
| `command/forge.md` | Definición del comando `/forge` para opencode |
|
|
253
|
+
|
|
254
|
+
### Tests
|
|
255
|
+
|
|
256
|
+
Forge incluye tests unitarios con `node:test` (sin dependencias externas).
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
node --test {{AGENT_PATH}}/tests/core.test.mjs
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
| Módulo | Tests | Descripción |
|
|
263
|
+
|--------|-------|-------------|
|
|
264
|
+
| `profile.mjs` | 8 | Detección de perfiles |
|
|
265
|
+
| `graph.mjs` | 1 | Grafo vacío |
|
|
266
|
+
| `armorer.mjs` | 1 | Ownership vacío |
|
|
267
|
+
| `forge-config.mjs` | 2 | Load/save state |
|
|
268
|
+
| `chain.mjs` | 1 | Grafo de dependencias vacío |
|
|
269
|
+
| `formatter.mjs` | 4 | Output format, colores, JSON |
|
|
270
|
+
| `registry/rules.mjs` | 4 | R1-R9, evaluación, custom rules |
|
|
271
|
+
| `detect.mjs` (inline ignores) | 5 | parseInlineIgnores, isIgnored |
|
|
272
|
+
| `forgeSentinel.mjs` | 1 | PostToolUse hook |
|
|
273
|
+
| `assay.mjs` | 4 | Personas, generateAssay, opiniones |
|
|
274
|
+
|
|
275
|
+
### Flags adicionales
|
|
276
|
+
|
|
277
|
+
| Flag | Comando | Descripción |
|
|
278
|
+
|---|---|---|
|
|
279
|
+
| `--fix` | `quench` | Auto-corrige violaciones WARNING/INFO (missing @injectable(), tsconfig, naming, container.resolve) |
|
|
280
|
+
| `--show-ignores` | `quench` | Muestra los inline ignores encontrados en el código |
|
|
281
|
+
| `--persona=<id>` | `assay` | Filtra ensayo por una persona (bezos, fowler, hacker, pm, senior) |
|
|
282
|
+
| `--save` | `assay` | Persiste ensayo en `.forge/assay/` |
|
|
283
|
+
| `--json` | `assay` | Salida JSON |
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Forge architecture guard: runs forgeSentinel after Edit/Write/apply_patch and surfaces architectural violations as system reminders.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PostToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Edit|Write|apply_patch",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"$(git rev-parse --show-toplevel)/.agents/skills/forge/scripts/forgeSentinel.mjs\" --hook",
|
|
11
|
+
"timeout": 10,
|
|
12
|
+
"statusMessage": "forgeSentinel — checking architecture"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -4,17 +4,18 @@ Forge es un sistema operativo arquitectónico para backend. Diseña, construye,
|
|
|
4
4
|
|
|
5
5
|
## Boot Sequence
|
|
6
6
|
|
|
7
|
-
Ejecutar en orden antes de cualquier acción
|
|
8
|
-
|
|
9
|
-
1. `node .
|
|
10
|
-
2. `node .
|
|
11
|
-
3. `node .
|
|
12
|
-
4. `node .
|
|
13
|
-
5. `node .
|
|
14
|
-
6. `node .
|
|
15
|
-
7. `node .
|
|
7
|
+
Ejecutar en orden antes de cualquier acción. Todos los paths son relativos a `.claude/skills/forge/`:
|
|
8
|
+
|
|
9
|
+
1. `node .claude/skills/forge/scripts/context.mjs` — stack + layers detection
|
|
10
|
+
2. `node .claude/skills/forge/scripts/armorer.mjs` — ownership, orphans, duplicates
|
|
11
|
+
3. `node .claude/skills/forge/scripts/profile.mjs --extended` — tech profile
|
|
12
|
+
4. `node .claude/skills/forge/scripts/graph.mjs --json` — 4-layer graph
|
|
13
|
+
5. `node .claude/skills/forge/scripts/chain.mjs --json` — dependency analysis
|
|
14
|
+
6. `node .claude/skills/forge/scripts/inspect.mjs --json` — full audit
|
|
15
|
+
7. `node .claude/skills/forge/scripts/architecture.mjs` — update ARCHITECTURE.md
|
|
16
16
|
8. Execute user command (cast, quench, relocate, etc.)
|
|
17
|
-
9. Run
|
|
17
|
+
9. Run `node .claude/skills/forge/scripts/forgeSentinel.mjs --reminder` — check changes
|
|
18
|
+
10. Run `architecture.mjs` again
|
|
18
19
|
|
|
19
20
|
## Architecture Model
|
|
20
21
|
|
|
@@ -88,11 +89,11 @@ Cuatro capas obligatorias:
|
|
|
88
89
|
|
|
89
90
|
## Key Files
|
|
90
91
|
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
-
|
|
92
|
+
- `.claude/skills/forge/SKILL.md` — orchestrator principal
|
|
93
|
+
- `.claude/skills/forge/reference/principles.md` — manifiesto y 15 principios
|
|
94
|
+
- `.claude/skills/forge/reference/patterns.md` — naming conventions
|
|
95
|
+
- `.claude/skills/forge/scripts/` — context, detect, inspect, chain, profile, graph, architecture, armorer, bootstrap, forgeSentinel, forgeSmith
|
|
96
|
+
- `.claude/skills/forge/profiles/` — 10 tech profiles (express, fastify, nestjs × mongodb, postgres, prisma, drizzle)
|
|
97
|
+
- `.claude/skills/forge/templates/` — templates para feature, platform, shared, infra
|
|
97
98
|
- `AGENTS.md` — guía para agentes de IA
|
|
98
99
|
- `ARCHITECTURE.md` — estado actual de la arquitectura
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Forge architecture guard: runs forgeSentinel after Edit/Write/MultiEdit and surfaces architectural violations as system reminders.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PostToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"${CLAUDE_PROJECT_DIR}/.claude/skills/forge/scripts/forgeSentinel.mjs\" --hook",
|
|
11
|
+
"timeout": 10,
|
|
12
|
+
"statusMessage": "forgeSentinel — checking architecture"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Forge architecture guard: runs forgeSentinel after Edit/Write/apply_patch and surfaces architectural violations as system reminders.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PostToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Edit|Write|apply_patch",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"$(git rev-parse --show-toplevel)/.agents/skills/forge/scripts/forgeSentinel.mjs\" --hook",
|
|
11
|
+
"timeout": 10,
|
|
12
|
+
"statusMessage": "forgeSentinel — checking architecture"
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
You are an AI assistant for a project that uses Forge — a Backend Architecture Operating System. Tu función es ayudar a diseñar, construir, auditar y evolucionar la arquitectura usando Arquitectura Hexagonal, DDD pragmático y vertical slices.
|
|
2
2
|
|
|
3
|
+
All forge scripts are in `.cursor/skills/forge/scripts/`.
|
|
4
|
+
|
|
3
5
|
## Architecture Model
|
|
4
6
|
|
|
5
7
|
The project uses four mandatory layers:
|
|
@@ -27,6 +29,21 @@ src/
|
|
|
27
29
|
- R8: cross-feature direct imports
|
|
28
30
|
- R9: cycles
|
|
29
31
|
|
|
32
|
+
## Boot Sequence
|
|
33
|
+
|
|
34
|
+
Ejecutar en orden antes de cualquier acción:
|
|
35
|
+
|
|
36
|
+
1. `node .cursor/skills/forge/scripts/context.mjs` — stack + layers detection
|
|
37
|
+
2. `node .cursor/skills/forge/scripts/armorer.mjs` — ownership, orphans, duplicates
|
|
38
|
+
3. `node .cursor/skills/forge/scripts/profile.mjs --extended` — tech profile
|
|
39
|
+
4. `node .cursor/skills/forge/scripts/graph.mjs --json` — 4-layer graph
|
|
40
|
+
5. `node .cursor/skills/forge/scripts/chain.mjs --json` — dependency analysis
|
|
41
|
+
6. `node .cursor/skills/forge/scripts/inspect.mjs --json` — full audit
|
|
42
|
+
7. `node .cursor/skills/forge/scripts/architecture.mjs` — update ARCHITECTURE.md
|
|
43
|
+
8. Execute user command (cast, quench, relocate, etc.)
|
|
44
|
+
9. Run `node .cursor/skills/forge/scripts/forgeSentinel.mjs --reminder`
|
|
45
|
+
10. Run `architecture.mjs` again
|
|
46
|
+
|
|
30
47
|
## Naming Conventions
|
|
31
48
|
|
|
32
49
|
| Element | Convention | Example |
|
|
@@ -71,10 +88,10 @@ src/
|
|
|
71
88
|
|
|
72
89
|
## Key Files Reference
|
|
73
90
|
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
91
|
+
- `.cursor/skills/forge/SKILL.md` — orchestrator
|
|
92
|
+
- `.cursor/skills/forge/reference/principles.md` — 15 principles
|
|
93
|
+
- `.cursor/skills/forge/reference/patterns.md` — naming conventions
|
|
94
|
+
- `.cursor/skills/forge/scripts/` — all engine scripts
|
|
95
|
+
- `.cursor/skills/forge/profiles/` — tech profiles
|
|
79
96
|
- `AGENTS.md` — agent guide
|
|
80
97
|
- `ARCHITECTURE.md` — current architecture state
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: forge
|
|
3
|
+
description: >
|
|
4
|
+
Architecture Operating System especializado en diseñar, construir, auditar,
|
|
5
|
+
proteger y evolucionar arquitecturas backend escalables basadas en features
|
|
6
|
+
(vertical slices), hexagonal architecture y DDD pragmático.
|
|
7
|
+
allowed-tools:
|
|
8
|
+
- Bash(node .gemini/skills/forge/scripts/*)
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Forge — Backend Architecture Operating System
|
|
12
|
+
|
|
13
|
+
Ver `.gemini/skills/forge/SKILL.md` para la guía completa.
|