@ronaldjdevfs/forge 1.0.2 → 1.2.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/README.md +132 -10
- package/package.json +6 -3
- package/skills/forge/SKILL.md +86 -15
- package/skills/forge/profiles/express-drizzle.md +107 -0
- package/skills/forge/profiles/fastify-mongodb.md +103 -0
- package/skills/forge/profiles/fastify-prisma.md +81 -0
- package/skills/forge/profiles/nestjs-mongodb.md +92 -0
- package/skills/forge/profiles/nestjs-postgres.md +98 -0
- package/skills/forge/reference/api-design.md +62 -0
- package/skills/forge/reference/assay.md +82 -0
- package/skills/forge/reference/cast.md +81 -7
- package/skills/forge/reference/data-patterns.md +86 -0
- package/skills/forge/reference/di-strategies.md +50 -0
- package/skills/forge/reference/errors.md +65 -0
- package/skills/forge/reference/events.md +95 -0
- package/skills/forge/reference/help.md +40 -0
- package/skills/forge/reference/hooks.md +62 -0
- package/skills/forge/reference/observability.md +66 -0
- package/skills/forge/reference/patterns.md +52 -0
- package/skills/forge/reference/principles.md +6 -0
- package/skills/forge/reference/reforge.md +69 -5
- package/skills/forge/reference/relocate.md +15 -2
- package/skills/forge/reference/security-patterns.md +87 -0
- package/skills/forge/reference/testing-patterns.md +69 -0
- package/skills/forge/scripts/assay.mjs +481 -0
- package/skills/forge/scripts/context.mjs +147 -43
- package/skills/forge/scripts/detect.mjs +371 -22
- package/skills/forge/scripts/forge-api.mjs +373 -0
- package/skills/forge/scripts/forge-config.mjs +268 -0
- package/skills/forge/scripts/forge-signals.mjs +131 -0
- package/skills/forge/scripts/forge-state.mjs +97 -0
- package/skills/forge/scripts/formatter.mjs +133 -0
- package/skills/forge/scripts/graph.mjs +5 -21
- package/skills/forge/scripts/hook.mjs +250 -0
- package/skills/forge/scripts/inspect.mjs +171 -22
- package/skills/forge/scripts/parse-imports.mjs +249 -0
- package/skills/forge/scripts/pin.mjs +151 -0
- package/skills/forge/scripts/posttool.mjs +224 -0
- package/skills/forge/scripts/profile.mjs +124 -20
- package/skills/forge/scripts/registry/rules.mjs +344 -0
- package/skills/forge/scripts/rename.mjs +669 -0
- package/skills/forge/scripts/rollback.mjs +213 -0
- package/skills/forge/scripts/update.mjs +114 -0
- package/skills/forge/templates/agents/claude/CLAUDE.md +98 -0
- package/skills/forge/templates/agents/cursor/.cursorrules +80 -0
- package/skills/forge/templates/feature/domain-error.ts.md +9 -0
- package/skills/forge/templates/feature/domain-event.ts.md +9 -0
- package/skills/forge/templates/feature/event-handler.ts.md +10 -0
- package/skills/forge/templates/feature/use-case.ts.md +10 -2
- package/skills/forge/tests/core.test.mjs +403 -0
- package/src/agents.mjs +55 -0
- package/src/cli.js +127 -54
- package/src/wizard.mjs +474 -0
- package/logo.png +0 -0
package/src/cli.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { copyFileSync, mkdirSync, existsSync,
|
|
3
|
+
import { copyFileSync, mkdirSync, existsSync, writeFileSync, readFileSync, cpSync } from "fs";
|
|
4
4
|
import { join, dirname, relative } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
+
import { spinner, log } from "@clack/prompts";
|
|
8
|
+
import { runWizard } from "./wizard.mjs";
|
|
7
9
|
|
|
8
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
+
const SKILL_SRC = join(__dirname, "..", "skills", "forge");
|
|
12
|
+
const AGENTS_TEMPLATES = join(SKILL_SRC, "templates", "agents");
|
|
11
13
|
|
|
12
14
|
function getTargetDir(global) {
|
|
13
15
|
if (global) {
|
|
@@ -30,16 +32,7 @@ function getConfigDir(global) {
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
function copyRecursive(src, dest) {
|
|
33
|
-
|
|
34
|
-
for (const entry of readdirSync(src)) {
|
|
35
|
-
const srcPath = join(src, entry);
|
|
36
|
-
const destPath = join(dest, entry);
|
|
37
|
-
if (statSync(srcPath).isDirectory()) {
|
|
38
|
-
copyRecursive(srcPath, destPath);
|
|
39
|
-
} else {
|
|
40
|
-
copyFileSync(srcPath, destPath);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
35
|
+
cpSync(src, dest, { recursive: true, force: true });
|
|
43
36
|
}
|
|
44
37
|
|
|
45
38
|
function detectPM(configDir) {
|
|
@@ -62,7 +55,6 @@ function ensureDependencies(configDir) {
|
|
|
62
55
|
if (!pkg.dependencies["@opencode-ai/plugin"]) {
|
|
63
56
|
pkg.dependencies["@opencode-ai/plugin"] = "1.17.9";
|
|
64
57
|
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
65
|
-
console.log(` ✓ Actualizado ${relative(process.cwd(), pkgPath)}`);
|
|
66
58
|
}
|
|
67
59
|
|
|
68
60
|
const pm = detectPM(configDir);
|
|
@@ -74,30 +66,28 @@ function ensureDependencies(configDir) {
|
|
|
74
66
|
|
|
75
67
|
try {
|
|
76
68
|
runPM(pm);
|
|
77
|
-
console.log(` ✓ Dependencias instaladas (${pm})`);
|
|
78
69
|
} catch {
|
|
79
70
|
for (const fallback of order[pm]) {
|
|
80
71
|
try {
|
|
81
72
|
runPM(fallback);
|
|
82
|
-
console.log(` ✓ Dependencias instaladas (${fallback})`);
|
|
83
73
|
return;
|
|
84
|
-
} catch {}
|
|
74
|
+
} catch { }
|
|
85
75
|
}
|
|
86
|
-
|
|
76
|
+
log.warn("No se pudieron instalar dependencias. Ejecutá 'pnpm install' | 'npm install' manualmente en " + configDir);
|
|
87
77
|
}
|
|
88
78
|
}
|
|
89
79
|
|
|
90
80
|
const COMMANDS = [
|
|
91
|
-
{ name: "forge-forge",
|
|
92
|
-
{ name: "forge-cast",
|
|
81
|
+
{ name: "forge-forge", desc: "Forge — inicializar proyecto arquitectónicamente" },
|
|
82
|
+
{ name: "forge-cast", desc: "Cast — crear un nuevo feature hexagonal desde cero" },
|
|
93
83
|
{ name: "forge-inspect", desc: "Inspect — inspeccionar la conformidad arquitectónica" },
|
|
94
|
-
{ name: "forge-relocate",desc: "Relocate — migrar feature legacy a la nueva estructura" },
|
|
84
|
+
{ name: "forge-relocate", desc: "Relocate — migrar feature legacy a la nueva estructura" },
|
|
95
85
|
{ name: "forge-reforge", desc: "Reforge — refactorizar la arquitectura de un feature" },
|
|
96
|
-
{ name: "forge-quench",
|
|
97
|
-
{ name: "forge-temper",
|
|
98
|
-
{ name: "forge-chain",
|
|
99
|
-
{ name: "forge-inscribe",desc: "Inscribe — generar y mantener ARCHITECTURE.md" },
|
|
100
|
-
{ name: "forge-smelt",
|
|
86
|
+
{ name: "forge-quench", desc: "Quench — verificar reglas arquitectónicas del proyecto" },
|
|
87
|
+
{ name: "forge-temper", desc: "Temper — endurecer la arquitectura (DI, seguridad)" },
|
|
88
|
+
{ name: "forge-chain", desc: "Chain — analizar cadena de dependencias entre features" },
|
|
89
|
+
{ name: "forge-inscribe", desc: "Inscribe — generar y mantener ARCHITECTURE.md" },
|
|
90
|
+
{ name: "forge-smelt", desc: "Smelt — extraer código reutilizable a shared/" },
|
|
101
91
|
];
|
|
102
92
|
|
|
103
93
|
function generateCommands(configDir) {
|
|
@@ -116,46 +106,111 @@ function generateCommands(configDir) {
|
|
|
116
106
|
].join("\n");
|
|
117
107
|
writeFileSync(join(cmdsDir, `${cmd.name}.md`), content);
|
|
118
108
|
}
|
|
119
|
-
console.log(` ✓ Comandos /forge-* generados en .opencode/commands/`);
|
|
120
109
|
}
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
console.log(`
|
|
124
|
-
Forge — Architecture OS
|
|
125
|
-
|
|
126
|
-
USO
|
|
127
|
-
forge install Instalar skill en el proyecto actual
|
|
128
|
-
forge install --global Instalar globalmente (~/.config/opencode/)
|
|
129
|
-
forge skills install (alias del comando install)
|
|
130
|
-
|
|
131
|
-
OPCIONES
|
|
132
|
-
-g, --global Instalar en ~/.config/opencode/skills/forge/
|
|
133
|
-
-h, --help Mostrar esta ayuda
|
|
134
|
-
`);
|
|
135
|
-
}
|
|
111
|
+
// --- Direct installers ---
|
|
136
112
|
|
|
137
|
-
function
|
|
113
|
+
async function installOpenCode(isGlobal = false) {
|
|
138
114
|
if (!existsSync(SKILL_SRC)) {
|
|
139
|
-
|
|
115
|
+
log.error("No se encuentra skills/forge/ en el paquete. ¿Corrupto?");
|
|
140
116
|
process.exit(1);
|
|
141
117
|
}
|
|
142
118
|
|
|
143
|
-
const target = getTargetDir(
|
|
144
|
-
const configDir = getConfigDir(
|
|
119
|
+
const target = getTargetDir(isGlobal);
|
|
120
|
+
const configDir = getConfigDir(isGlobal);
|
|
121
|
+
const rel = relative(process.cwd(), target);
|
|
145
122
|
|
|
146
|
-
|
|
147
|
-
console.log(` ${"=".repeat(40)}`);
|
|
148
|
-
console.log(` Destino: ${target}\n`);
|
|
123
|
+
const s = spinner();
|
|
149
124
|
|
|
125
|
+
s.start("Copiando skill a " + rel);
|
|
150
126
|
copyRecursive(SKILL_SRC, target);
|
|
151
|
-
|
|
127
|
+
s.stop("Skill copiada a " + rel);
|
|
128
|
+
|
|
129
|
+
s.start("Generando comandos /forge-*");
|
|
152
130
|
generateCommands(configDir);
|
|
131
|
+
s.stop("Comandos generados en " + relative(process.cwd(), join(configDir, "commands")));
|
|
132
|
+
|
|
133
|
+
s.start("Instalando dependencias");
|
|
153
134
|
ensureDependencies(configDir);
|
|
154
|
-
|
|
155
|
-
|
|
135
|
+
s.stop("Dependencias instaladas");
|
|
136
|
+
|
|
137
|
+
log.success("OpenCode configurado correctamente");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function installCursor() {
|
|
141
|
+
const src = join(AGENTS_TEMPLATES, "cursor", ".cursorrules");
|
|
142
|
+
const dest = join(process.cwd(), ".cursorrules");
|
|
143
|
+
|
|
144
|
+
if (!existsSync(src)) {
|
|
145
|
+
log.error("Template .cursorrules no encontrado");
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const s = spinner();
|
|
150
|
+
s.start("Creando .cursorrules");
|
|
151
|
+
copyFileSync(src, dest);
|
|
152
|
+
s.stop(".cursorrules creado");
|
|
153
|
+
|
|
154
|
+
log.success("Cursor configurado correctamente");
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
function
|
|
157
|
+
async function installClaude() {
|
|
158
|
+
const claudeDir = join(process.cwd(), ".claude");
|
|
159
|
+
const src = join(AGENTS_TEMPLATES, "claude", "CLAUDE.md");
|
|
160
|
+
const dest = join(claudeDir, "CLAUDE.md");
|
|
161
|
+
|
|
162
|
+
if (!existsSync(src)) {
|
|
163
|
+
log.error("Template CLAUDE.md no encontrado");
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const s = spinner();
|
|
168
|
+
s.start("Creando .claude/CLAUDE.md");
|
|
169
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
170
|
+
copyFileSync(src, dest);
|
|
171
|
+
s.stop(".claude/CLAUDE.md creado");
|
|
172
|
+
|
|
173
|
+
log.success("Claude Code configurado correctamente");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function installAgents(selected, isGlobal = false) {
|
|
177
|
+
for (const agent of selected) {
|
|
178
|
+
switch (agent) {
|
|
179
|
+
case "opencode":
|
|
180
|
+
await installOpenCode(isGlobal);
|
|
181
|
+
break;
|
|
182
|
+
case "cursor":
|
|
183
|
+
await installCursor();
|
|
184
|
+
break;
|
|
185
|
+
case "claude":
|
|
186
|
+
await installClaude();
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// --- CLI ---
|
|
193
|
+
|
|
194
|
+
function printHelp() {
|
|
195
|
+
console.log(`
|
|
196
|
+
⚔️ Forge — Architecture OS
|
|
197
|
+
|
|
198
|
+
USO
|
|
199
|
+
forge install Mostrar wizard interactivo de instalación
|
|
200
|
+
forge install --opencode Instalar solo para OpenCode
|
|
201
|
+
forge install --cursor Instalar solo para Cursor
|
|
202
|
+
forge install --claude Instalar solo para Claude Code
|
|
203
|
+
forge install --all Instalar para todos los agentes
|
|
204
|
+
forge install --global Instalar OpenCode globalmente (~/.config/opencode/)
|
|
205
|
+
forge install --help Mostrar esta ayuda
|
|
206
|
+
|
|
207
|
+
OPCIONES
|
|
208
|
+
-g, --global Instalar OpenCode en ~/.config/opencode/skills/forge/
|
|
209
|
+
-h, --help Mostrar esta ayuda
|
|
210
|
+
`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function main() {
|
|
159
214
|
const args = process.argv.slice(2);
|
|
160
215
|
const isHelp = args.includes("-h") || args.includes("--help");
|
|
161
216
|
const isGlobal = args.includes("-g") || args.includes("--global");
|
|
@@ -165,15 +220,33 @@ function main() {
|
|
|
165
220
|
return;
|
|
166
221
|
}
|
|
167
222
|
|
|
223
|
+
const hasOpenCode = args.includes("--opencode");
|
|
224
|
+
const hasCursor = args.includes("--cursor");
|
|
225
|
+
const hasClaude = args.includes("--claude");
|
|
226
|
+
const hasAll = args.includes("--all");
|
|
227
|
+
|
|
168
228
|
const subcommandIndex = args.indexOf("skills");
|
|
169
229
|
const command = subcommandIndex !== -1 ? args[subcommandIndex + 1] : args[0];
|
|
170
230
|
|
|
171
231
|
if (command === "install") {
|
|
172
|
-
|
|
232
|
+
if (hasAll) {
|
|
233
|
+
await installAgents(["opencode", "cursor", "claude"], isGlobal);
|
|
234
|
+
} else if (hasOpenCode || hasCursor || hasClaude) {
|
|
235
|
+
const selected = [];
|
|
236
|
+
if (hasOpenCode) selected.push("opencode");
|
|
237
|
+
if (hasCursor) selected.push("cursor");
|
|
238
|
+
if (hasClaude) selected.push("claude");
|
|
239
|
+
await installAgents(selected, isGlobal);
|
|
240
|
+
} else {
|
|
241
|
+
await runWizard();
|
|
242
|
+
}
|
|
173
243
|
} else {
|
|
174
244
|
printHelp();
|
|
175
245
|
process.exit(1);
|
|
176
246
|
}
|
|
177
247
|
}
|
|
178
248
|
|
|
179
|
-
main()
|
|
249
|
+
main().catch((err) => {
|
|
250
|
+
console.error("[ERROR]", err.message);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
});
|