fwinit 1.3.11 → 1.4.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 +3 -2
- package/dist/index.js +47 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -65,8 +65,9 @@ Pregunta qué backend querés (ASP.NET, Express, Fastify, Node.js Vanilla) y qu
|
|
|
65
65
|
mi-proyecto/
|
|
66
66
|
├── backend/ # API (template elegido — trae su DB: Prisma o EF)
|
|
67
67
|
├── frontend/ # App (template frontend elegido)
|
|
68
|
-
├── .gitignore # .atl/ · odd · .opencode/
|
|
68
|
+
├── .gitignore # .atl/ · odd · .opencode/ · .pi/
|
|
69
69
|
├── .opencode/ # Skills de opencode (create-specs incluida)
|
|
70
|
+
├── .pi/ # Mismo bundle de skills para Pi (badlogic)
|
|
70
71
|
├── README.md # Cómo correr backend y frontend
|
|
71
72
|
└── specs/ # La creás con /create-specs
|
|
72
73
|
```
|
|
@@ -122,7 +123,7 @@ El runtime `bun` de un template se porta automáticamente a `node` (npm/pnpm) si
|
|
|
122
123
|
2. Extrae y copia el template (o los dos, `backend/` + `frontend/`) al proyecto
|
|
123
124
|
3. Sustituye el nombre del proyecto (package.json, app.json de Expo, proyectos ASP.NET con "Example")
|
|
124
125
|
4. Si corresponde, porta el template de runtime bun a node (npm/pnpm)
|
|
125
|
-
5. Instala `.opencode/` con la skill `create-specs` y el comando `/create-specs`
|
|
126
|
+
5. Instala `.opencode/` y `.pi/` con la skill `create-specs` y el comando `/create-specs` (mismo bundle para opencode y Pi: elegí el agente que quieras)
|
|
126
127
|
6. Limpia los lock files (cada proyecto instala los suyos)
|
|
127
128
|
7. Si lo elegís (o pasás `--git`), inicializa un repositorio git en la raíz
|
|
128
129
|
8. Te muestra los próximos pasos (install y dev de cada carpeta)
|
package/dist/index.js
CHANGED
|
@@ -467,7 +467,7 @@ async function writeRootGitignore(projectPath) {
|
|
|
467
467
|
} catch {
|
|
468
468
|
await writeFile2(
|
|
469
469
|
gitignorePath,
|
|
470
|
-
"# AI dev state\n.atl/\nodd\n.opencode/\n"
|
|
470
|
+
"# AI dev state\n.atl/\nodd\n.opencode/\n.pi/\n"
|
|
471
471
|
);
|
|
472
472
|
}
|
|
473
473
|
}
|
|
@@ -505,7 +505,7 @@ async function writeRootFiles(info) {
|
|
|
505
505
|
"",
|
|
506
506
|
`- \`backend/\` \u2014 ${info.backend.description}`,
|
|
507
507
|
`- \`frontend/\` \u2014 ${info.frontend.description}`,
|
|
508
|
-
"- `.opencode/` \u2014 skills de
|
|
508
|
+
"- `.opencode/` y `.pi/` \u2014 skills de agentes: `/create-specs` para las specs + biblioteca de dise\xF1o (dark-luxury, minimal-light, neo-brutalist, glassmorphism). Mismo bundle en `.opencode/` (opencode) y `.pi/` (Pi)",
|
|
509
509
|
"- `specs/` \u2014 especificaciones del proyecto",
|
|
510
510
|
"",
|
|
511
511
|
"## Backend",
|
|
@@ -540,7 +540,8 @@ function getCliVersion() {
|
|
|
540
540
|
return "0.0.0";
|
|
541
541
|
}
|
|
542
542
|
}
|
|
543
|
-
|
|
543
|
+
var AGENT_DIRS = [".opencode", ".pi"];
|
|
544
|
+
async function installAgentSkills(repoRoot, projectPath) {
|
|
544
545
|
const skill = join2(repoRoot, "skills", "create-specs", "SKILL.md");
|
|
545
546
|
const command = join2(repoRoot, "skills", "create-specs", "command.md");
|
|
546
547
|
const designDir = join2(repoRoot, "skills", "design");
|
|
@@ -550,50 +551,49 @@ async function installOpenCodeFiles(repoRoot, projectPath) {
|
|
|
550
551
|
} catch {
|
|
551
552
|
return;
|
|
552
553
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
await mkdir2(join2(projectPath, ".opencode", "commands"), {
|
|
557
|
-
recursive: true
|
|
558
|
-
});
|
|
559
|
-
await cp2(
|
|
560
|
-
skill,
|
|
561
|
-
join2(projectPath, ".opencode", "skills", "create-specs", "SKILL.md")
|
|
562
|
-
);
|
|
563
|
-
await cp2(
|
|
564
|
-
command,
|
|
565
|
-
join2(projectPath, ".opencode", "commands", "create-specs.md")
|
|
566
|
-
);
|
|
567
|
-
try {
|
|
554
|
+
for (const agentDir of AGENT_DIRS) {
|
|
555
|
+
const skillsDir = join2(projectPath, agentDir, "skills");
|
|
556
|
+
const commandsDir = join2(projectPath, agentDir, "commands");
|
|
568
557
|
const examplesDir = join2(repoRoot, "skills", "create-specs", "examples");
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
examplesDir
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
});
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
const designCommandsDir = join2(designDir, "commands");
|
|
586
|
-
await access(designCommandsDir);
|
|
587
|
-
const commandFiles = (await readdir2(designCommandsDir)).filter(
|
|
588
|
-
(f) => f.endsWith(".md")
|
|
589
|
-
);
|
|
590
|
-
for (const file of commandFiles) {
|
|
558
|
+
let hasExamples = false;
|
|
559
|
+
try {
|
|
560
|
+
await access(examplesDir);
|
|
561
|
+
hasExamples = true;
|
|
562
|
+
} catch {
|
|
563
|
+
}
|
|
564
|
+
let hasDesign = false;
|
|
565
|
+
try {
|
|
566
|
+
await access(designDir);
|
|
567
|
+
hasDesign = true;
|
|
568
|
+
} catch {
|
|
569
|
+
}
|
|
570
|
+
await mkdir2(join2(skillsDir, "create-specs"), { recursive: true });
|
|
571
|
+
await mkdir2(commandsDir, { recursive: true });
|
|
572
|
+
await cp2(skill, join2(skillsDir, "create-specs", "SKILL.md"));
|
|
573
|
+
if (hasExamples) {
|
|
591
574
|
await cp2(
|
|
592
|
-
|
|
593
|
-
join2(
|
|
575
|
+
examplesDir,
|
|
576
|
+
join2(skillsDir, "create-specs", "examples"),
|
|
577
|
+
{ recursive: true }
|
|
594
578
|
);
|
|
595
579
|
}
|
|
596
|
-
|
|
580
|
+
await cp2(command, join2(commandsDir, "create-specs.md"));
|
|
581
|
+
if (hasDesign) {
|
|
582
|
+
await cp2(designDir, join2(skillsDir, "design"), { recursive: true });
|
|
583
|
+
try {
|
|
584
|
+
const designCommandsDir = join2(designDir, "commands");
|
|
585
|
+
const commandFiles = (await readdir2(designCommandsDir)).filter(
|
|
586
|
+
(f) => f.endsWith(".md")
|
|
587
|
+
);
|
|
588
|
+
for (const file of commandFiles) {
|
|
589
|
+
await cp2(
|
|
590
|
+
join2(designCommandsDir, file),
|
|
591
|
+
join2(commandsDir, file)
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
} catch {
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
597
|
}
|
|
598
598
|
}
|
|
599
599
|
async function readTemplatePostInit(dir) {
|
|
@@ -621,7 +621,7 @@ async function createFullStackProject(projectPath, backendTpl, frontendTpl, pm)
|
|
|
621
621
|
);
|
|
622
622
|
await substituteTemplate(backendPath, projectName, backendTpl.folder);
|
|
623
623
|
await substituteTemplate(frontendPath, projectName, frontendTpl.folder);
|
|
624
|
-
await
|
|
624
|
+
await installAgentSkills(repoRoot, projectPath);
|
|
625
625
|
if (backendTpl.runtime === "bun" && pm !== "bun") {
|
|
626
626
|
await adaptToNodeRuntime(backendPath);
|
|
627
627
|
}
|
|
@@ -652,7 +652,7 @@ async function createFullStackProject(projectPath, backendTpl, frontendTpl, pm)
|
|
|
652
652
|
);
|
|
653
653
|
console.log(
|
|
654
654
|
chalk.dim(
|
|
655
|
-
" Estructura: backend/ (API) \xB7 frontend/ (app) \xB7 .opencode/ y specs/ (al mismo nivel)\n"
|
|
655
|
+
" Estructura: backend/ (API) \xB7 frontend/ (app) \xB7 .opencode/, .pi/ y specs/ (al mismo nivel)\n"
|
|
656
656
|
)
|
|
657
657
|
);
|
|
658
658
|
}
|
|
@@ -797,7 +797,7 @@ program.argument("[template]", "Template a usar (o 'fullstack' para backend + fr
|
|
|
797
797
|
spinner.text = "Creando proyecto...";
|
|
798
798
|
await copyTemplate(templatePath, codePath);
|
|
799
799
|
await substituteTemplate(codePath, projectName, template.folder);
|
|
800
|
-
await
|
|
800
|
+
await installAgentSkills(repoRoot, projectPath);
|
|
801
801
|
if (useLayerLayout) {
|
|
802
802
|
await writeRootGitignore(projectPath);
|
|
803
803
|
}
|
|
@@ -816,7 +816,7 @@ program.argument("[template]", "Template a usar (o 'fullstack' para backend + fr
|
|
|
816
816
|
if (useLayerLayout) {
|
|
817
817
|
console.log(
|
|
818
818
|
chalk.dim(
|
|
819
|
-
` Estructura: ${layer}/ (c\xF3digo) \xB7 .opencode/ y specs/ (al mismo nivel)
|
|
819
|
+
` Estructura: ${layer}/ (c\xF3digo) \xB7 .opencode/, .pi/ y specs/ (al mismo nivel)
|
|
820
820
|
`
|
|
821
821
|
)
|
|
822
822
|
);
|