project-mcp-server 2.0.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/LICENSE +21 -0
- package/README.md +335 -0
- package/dist/config.d.ts +15 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/actions.d.ts +9 -0
- package/dist/scanner/actions.js +77 -0
- package/dist/scanner/actions.js.map +1 -0
- package/dist/scanner/cache.d.ts +4 -0
- package/dist/scanner/cache.js +34 -0
- package/dist/scanner/cache.js.map +1 -0
- package/dist/scanner/components.d.ts +17 -0
- package/dist/scanner/components.js +74 -0
- package/dist/scanner/components.js.map +1 -0
- package/dist/scanner/prisma.d.ts +17 -0
- package/dist/scanner/prisma.js +75 -0
- package/dist/scanner/prisma.js.map +1 -0
- package/dist/scanner/routes.d.ts +11 -0
- package/dist/scanner/routes.js +98 -0
- package/dist/scanner/routes.js.map +1 -0
- package/dist/setup.d.ts +10 -0
- package/dist/setup.js +289 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/env/index.d.ts +2 -0
- package/dist/tools/env/index.js +152 -0
- package/dist/tools/env/index.js.map +1 -0
- package/dist/tools/generate/index.d.ts +2 -0
- package/dist/tools/generate/index.js +320 -0
- package/dist/tools/generate/index.js.map +1 -0
- package/dist/tools/project/index.d.ts +2 -0
- package/dist/tools/project/index.js +193 -0
- package/dist/tools/project/index.js.map +1 -0
- package/package.json +35 -0
- package/skills/commit.md +109 -0
- package/skills/infra.md +218 -0
- package/skills/nextauth.md +256 -0
- package/skills/nextjs.md +262 -0
- package/skills/prisma.md +281 -0
- package/skills/project-intelligence.SKILL.md +141 -0
- package/skills/security.md +353 -0
- package/skills/shadcn.md +299 -0
- package/skills/testing.md +188 -0
- package/skills/zod.md +253 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { exec } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { access } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { config } from "../../config.js";
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
async function run(cmd, cwd) {
|
|
9
|
+
try {
|
|
10
|
+
const { stdout, stderr } = await execAsync(cmd, {
|
|
11
|
+
cwd: cwd ?? config.projectRoot,
|
|
12
|
+
timeout: 30_000
|
|
13
|
+
});
|
|
14
|
+
return { ok: true, output: (stdout + stderr).trim() };
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
const e = err;
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
output: ((e.stdout ?? "") + (e.stderr ?? "") + (e.message ?? "")).trim()
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function registerEnvTools(server) {
|
|
25
|
+
// ─── env_status ────────────────────────────────────────────────────────────
|
|
26
|
+
server.registerTool("env_status", {
|
|
27
|
+
title: "Estado del entorno de desarrollo",
|
|
28
|
+
description: `Verifica el estado del entorno: Docker, .env.local y herramientas de desarrollo.
|
|
29
|
+
Llamar al inicio de una sesión para detectar problemas antes de codear.
|
|
30
|
+
|
|
31
|
+
Returns: estado de cada servicio con detalles de errores si los hay.`,
|
|
32
|
+
inputSchema: z.object({}).strict(),
|
|
33
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
34
|
+
}, async () => {
|
|
35
|
+
const [dockerPs, pnpmInstalled] = await Promise.all([
|
|
36
|
+
run("docker compose ps --format json"),
|
|
37
|
+
run("pnpm --version")
|
|
38
|
+
]);
|
|
39
|
+
// Verificar .env.local
|
|
40
|
+
const envPath = join(config.projectRoot, ".env.local");
|
|
41
|
+
let envExists = false;
|
|
42
|
+
try {
|
|
43
|
+
await access(envPath);
|
|
44
|
+
envExists = true;
|
|
45
|
+
}
|
|
46
|
+
catch { /* no existe */ }
|
|
47
|
+
// Parsear docker compose status
|
|
48
|
+
let dockerServices = [];
|
|
49
|
+
if (dockerPs.ok && dockerPs.output) {
|
|
50
|
+
try {
|
|
51
|
+
dockerServices = dockerPs.output
|
|
52
|
+
.split("\n")
|
|
53
|
+
.filter(Boolean)
|
|
54
|
+
.map(line => JSON.parse(line))
|
|
55
|
+
.map(s => ({ name: s.Name, status: s.Status }));
|
|
56
|
+
}
|
|
57
|
+
catch { /* format varies */ }
|
|
58
|
+
}
|
|
59
|
+
const status = {
|
|
60
|
+
ok: envExists,
|
|
61
|
+
docker: { running: dockerPs.ok, services: dockerServices },
|
|
62
|
+
env_file: { exists: envExists, path: ".env.local" },
|
|
63
|
+
pnpm: { ok: pnpmInstalled.ok, version: pnpmInstalled.output }
|
|
64
|
+
};
|
|
65
|
+
const lines = [
|
|
66
|
+
`## Estado del entorno`,
|
|
67
|
+
``,
|
|
68
|
+
dockerPs.ok ? `✓ Docker Compose activo (${dockerServices.length} servicios)` : `✗ Docker Compose no responde`,
|
|
69
|
+
...dockerServices.map(s => ` ${s.status.includes("Up") ? "↑" : "↓"} ${s.name}: ${s.status}`),
|
|
70
|
+
envExists ? `✓ .env.local presente` : `✗ .env.local no encontrado`,
|
|
71
|
+
pnpmInstalled.ok ? `✓ pnpm ${pnpmInstalled.output}` : `✗ pnpm no disponible`,
|
|
72
|
+
];
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
75
|
+
structuredContent: status
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
// ─── env_run_check ─────────────────────────────────────────────────────────
|
|
79
|
+
server.registerTool("env_run_check", {
|
|
80
|
+
title: "Ejecutar verificaciones de calidad",
|
|
81
|
+
description: `Ejecuta type-check, lint o tests en el proyecto y devuelve el resultado.
|
|
82
|
+
Usar antes de hacer commit o cuando el agente necesita verificar
|
|
83
|
+
que los cambios no rompieron nada.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
- check: qué verificación ejecutar
|
|
87
|
+
- scope: ruta específica a verificar (opcional, ej: "src/app/dashboard")
|
|
88
|
+
|
|
89
|
+
Returns: resultado del comando con errores y warnings.`,
|
|
90
|
+
inputSchema: z.object({
|
|
91
|
+
check: z.enum(["typecheck", "lint", "test", "build"]),
|
|
92
|
+
scope: z.string().optional()
|
|
93
|
+
.describe("Ruta específica a verificar (relativa al proyecto)")
|
|
94
|
+
}).strict(),
|
|
95
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
96
|
+
}, async ({ check, scope }) => {
|
|
97
|
+
const commands = {
|
|
98
|
+
typecheck: "pnpm tsc --noEmit",
|
|
99
|
+
lint: scope ? `pnpm eslint ${scope}` : "pnpm lint",
|
|
100
|
+
test: scope ? `pnpm test ${scope}` : "pnpm test --run",
|
|
101
|
+
build: "pnpm build"
|
|
102
|
+
};
|
|
103
|
+
const cmd = commands[check] ?? commands["typecheck"];
|
|
104
|
+
const result = await run(cmd);
|
|
105
|
+
const lines = [
|
|
106
|
+
`## ${check} ${result.ok ? "✓" : "✗"}`,
|
|
107
|
+
``,
|
|
108
|
+
result.output || "(sin output)"
|
|
109
|
+
];
|
|
110
|
+
if (!result.ok) {
|
|
111
|
+
lines.push("", `El check falló. Revisá los errores antes de continuar.`);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
115
|
+
structuredContent: { check, ok: result.ok, output: result.output }
|
|
116
|
+
};
|
|
117
|
+
});
|
|
118
|
+
// ─── env_prisma_status ─────────────────────────────────────────────────────
|
|
119
|
+
server.registerTool("env_prisma_status", {
|
|
120
|
+
title: "Estado de migraciones de Prisma",
|
|
121
|
+
description: `Verifica si hay migraciones pendientes y el estado actual de la DB.
|
|
122
|
+
Llamar antes de arrancar trabajo con la base de datos o cuando
|
|
123
|
+
hay cambios en los schemas de Prisma.
|
|
124
|
+
|
|
125
|
+
Returns: migraciones aplicadas, pendientes y estado de conexión.`,
|
|
126
|
+
inputSchema: z.object({}).strict(),
|
|
127
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
128
|
+
}, async () => {
|
|
129
|
+
const result = await run("pnpm prisma migrate status");
|
|
130
|
+
const hasPending = result.output.includes("following migration") &&
|
|
131
|
+
result.output.includes("have not yet been applied");
|
|
132
|
+
const isInSync = result.output.includes("Database schema is up to date");
|
|
133
|
+
const lines = [
|
|
134
|
+
`## Estado de Prisma`,
|
|
135
|
+
``,
|
|
136
|
+
isInSync ? `✓ Schema sincronizado — sin migraciones pendientes` :
|
|
137
|
+
hasPending ? `✗ Hay migraciones pendientes — correr: pnpm prisma migrate dev` :
|
|
138
|
+
`? Estado desconocido`,
|
|
139
|
+
``,
|
|
140
|
+
result.output
|
|
141
|
+
];
|
|
142
|
+
return {
|
|
143
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
144
|
+
structuredContent: {
|
|
145
|
+
inSync: isInSync,
|
|
146
|
+
hasPending,
|
|
147
|
+
output: result.output
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/env/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { scanPrismaSchemas } from "../../scanner/prisma.js";
|
|
3
|
+
function toPascalCase(str) {
|
|
4
|
+
return str.replace(/(^\w|[-_\s]\w)/g, m => m.replace(/[-_\s]/, "").toUpperCase());
|
|
5
|
+
}
|
|
6
|
+
function toCamelCase(str) {
|
|
7
|
+
const pascal = toPascalCase(str);
|
|
8
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
9
|
+
}
|
|
10
|
+
export function registerGenerateTools(server) {
|
|
11
|
+
// ─── generate_action ───────────────────────────────────────────────────────
|
|
12
|
+
server.registerTool("generate_action", {
|
|
13
|
+
title: "Generar Server Action",
|
|
14
|
+
description: `Genera una Server Action siguiendo los patrones del proyecto:
|
|
15
|
+
- "use server" al inicio
|
|
16
|
+
- Validación con Zod 4 usando safeParse
|
|
17
|
+
- Autenticación con auth() de NextAuth si se requiere
|
|
18
|
+
- Tipos de retorno explícitos
|
|
19
|
+
- Revalidación de cache si aplica
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
- entity: nombre de la entidad (ej: "user", "post", "invoice")
|
|
23
|
+
- operation: tipo de operación CRUD
|
|
24
|
+
- with_auth: si requiere sesión autenticada (default: true)
|
|
25
|
+
- prisma_schema: en qué schema de Prisma está la entidad
|
|
26
|
+
|
|
27
|
+
Returns: código TypeScript listo para copiar a server/actions/[entity].ts`,
|
|
28
|
+
inputSchema: z.object({
|
|
29
|
+
entity: z.string().min(1).describe("Nombre de la entidad en singular (ej: 'user')"),
|
|
30
|
+
operation: z.enum(["create", "update", "delete", "get", "list"]),
|
|
31
|
+
with_auth: z.boolean().default(true),
|
|
32
|
+
prisma_schema: z.enum(["auth", "rbac", "audit", "base"]).default("base")
|
|
33
|
+
}).strict(),
|
|
34
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
35
|
+
}, async ({ entity, operation, with_auth, prisma_schema }) => {
|
|
36
|
+
const pascal = toPascalCase(entity);
|
|
37
|
+
const camel = toCamelCase(entity);
|
|
38
|
+
// Buscar el modelo en Prisma para conocer los campos
|
|
39
|
+
const models = await scanPrismaSchemas();
|
|
40
|
+
const model = models.find(m => m.name.toLowerCase() === entity.toLowerCase());
|
|
41
|
+
// Campos de datos (no relaciones, no id, no timestamps)
|
|
42
|
+
const dataFields = model?.fields.filter(f => !f.isRelation && f.name !== "id" &&
|
|
43
|
+
f.name !== "createdAt" && f.name !== "updatedAt") ?? [];
|
|
44
|
+
const zodFields = dataFields.length > 0
|
|
45
|
+
? dataFields.map(f => {
|
|
46
|
+
const base = f.type === "String" ? "z.string().min(1)" :
|
|
47
|
+
f.type === "Int" ? "z.number().int()" :
|
|
48
|
+
f.type === "Boolean" ? "z.boolean()" :
|
|
49
|
+
f.type === "DateTime" ? "z.coerce.date()" : "z.string()";
|
|
50
|
+
return ` ${f.name}: ${f.isOptional ? base + ".optional()" : base}`;
|
|
51
|
+
}).join(",\n")
|
|
52
|
+
: ` // Agregá los campos de ${pascal} acá`;
|
|
53
|
+
const schemaImport = prisma_schema === "base"
|
|
54
|
+
? `import { prismaPostgres } from "@/lib/db/postgres"`
|
|
55
|
+
: `import { prismaPostgres } from "@/lib/db/postgres"`;
|
|
56
|
+
const authBlock = with_auth ? `
|
|
57
|
+
const session = await auth()
|
|
58
|
+
if (!session?.user) return { success: false, error: "No autenticado" }
|
|
59
|
+
` : "";
|
|
60
|
+
const authImport = with_auth ? `\nimport { auth } from "@/lib/auth"` : "";
|
|
61
|
+
let body;
|
|
62
|
+
switch (operation) {
|
|
63
|
+
case "create":
|
|
64
|
+
body = `
|
|
65
|
+
const parsed = ${pascal}Schema.safeParse({
|
|
66
|
+
${dataFields.map(f => ` ${f.name}: formData.get("${f.name}")`).join(",\n") || ` // extraer campos de formData`}
|
|
67
|
+
})
|
|
68
|
+
if (!parsed.success) return { success: false, error: parsed.error.flatten().fieldErrors }
|
|
69
|
+
|
|
70
|
+
const ${camel} = await prismaPostgres.${camel}.create({ data: parsed.data })
|
|
71
|
+
revalidateTag("${camel}s")
|
|
72
|
+
return { success: true, data: ${camel} }`;
|
|
73
|
+
break;
|
|
74
|
+
case "update":
|
|
75
|
+
body = `
|
|
76
|
+
const parsed = ${pascal}Schema.partial().safeParse({
|
|
77
|
+
${dataFields.map(f => ` ${f.name}: formData.get("${f.name}")`).join(",\n") || ` // extraer campos de formData`}
|
|
78
|
+
})
|
|
79
|
+
if (!parsed.success) return { success: false, error: parsed.error.flatten().fieldErrors }
|
|
80
|
+
|
|
81
|
+
const ${camel} = await prismaPostgres.${camel}.update({
|
|
82
|
+
where: { id },
|
|
83
|
+
data: parsed.data
|
|
84
|
+
})
|
|
85
|
+
revalidateTag("${camel}s")
|
|
86
|
+
return { success: true, data: ${camel} }`;
|
|
87
|
+
break;
|
|
88
|
+
case "delete":
|
|
89
|
+
body = `
|
|
90
|
+
await prismaPostgres.${camel}.delete({ where: { id } })
|
|
91
|
+
revalidateTag("${camel}s")
|
|
92
|
+
return { success: true }`;
|
|
93
|
+
break;
|
|
94
|
+
case "get":
|
|
95
|
+
body = `
|
|
96
|
+
const ${camel} = await prismaPostgres.${camel}.findUnique({
|
|
97
|
+
where: { id },
|
|
98
|
+
select: {
|
|
99
|
+
id: true,
|
|
100
|
+
${dataFields.map(f => ` ${f.name}: true`).join(",\n") || " // seleccionar campos necesarios"}
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
if (!${camel}) return { success: false, error: "${pascal} no encontrado" }
|
|
104
|
+
return { success: true, data: ${camel} }`;
|
|
105
|
+
break;
|
|
106
|
+
case "list":
|
|
107
|
+
body = `
|
|
108
|
+
const ${camel}s = await prismaPostgres.${camel}.findMany({
|
|
109
|
+
select: {
|
|
110
|
+
id: true,
|
|
111
|
+
${dataFields.slice(0, 4).map(f => ` ${f.name}: true`).join(",\n") || " // seleccionar campos necesarios"}
|
|
112
|
+
},
|
|
113
|
+
orderBy: { ${model?.hasTimestamps ? "createdAt" : "id"}: "desc" },
|
|
114
|
+
take: 50
|
|
115
|
+
})
|
|
116
|
+
return { success: true, data: ${camel}s }`;
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
body = ` // implementar lógica acá`;
|
|
120
|
+
}
|
|
121
|
+
const params = operation === "update" || operation === "delete" || operation === "get"
|
|
122
|
+
? `id: string${operation === "update" ? ", formData: FormData" : ""}`
|
|
123
|
+
: operation === "create" ? "formData: FormData" : "";
|
|
124
|
+
const code = `"use server"
|
|
125
|
+
|
|
126
|
+
import { z } from "zod"
|
|
127
|
+
import { revalidateTag } from "next/cache"${authImport}
|
|
128
|
+
${schemaImport}
|
|
129
|
+
|
|
130
|
+
const ${pascal}Schema = z.object({
|
|
131
|
+
${zodFields}
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
type ActionResult<T = void> =
|
|
135
|
+
| { success: true; data?: T }
|
|
136
|
+
| { success: false; error: Record<string, string[]> | string }
|
|
137
|
+
|
|
138
|
+
export async function ${operation}${pascal}(${params}): Promise<ActionResult> {${authBlock}${body}
|
|
139
|
+
}`;
|
|
140
|
+
return {
|
|
141
|
+
content: [{ type: "text", text: code }],
|
|
142
|
+
structuredContent: { entity, operation, file: `server/actions/${entity}s.ts` }
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
// ─── generate_page ─────────────────────────────────────────────────────────
|
|
146
|
+
server.registerTool("generate_page", {
|
|
147
|
+
title: "Generar página Next.js",
|
|
148
|
+
description: `Genera una página Next.js 16 siguiendo el patrón del proyecto:
|
|
149
|
+
- RSC por defecto
|
|
150
|
+
- Metadata dinámica si necesita SEO
|
|
151
|
+
- Layout con estructura del dashboard si es una ruta protegida
|
|
152
|
+
- Suspense boundaries y loading state
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
- path: ruta de la página (ej: "/dashboard/users/[id]")
|
|
156
|
+
- type: tipo de página
|
|
157
|
+
- with_auth: si requiere sesión (agrega redirect si no hay sesión)
|
|
158
|
+
|
|
159
|
+
Returns: código de la página listo para src/app/[ruta]/page.tsx`,
|
|
160
|
+
inputSchema: z.object({
|
|
161
|
+
path: z.string().describe("Ruta de la página (ej: /dashboard/users/[id])"),
|
|
162
|
+
type: z.enum(["list", "detail", "form", "dashboard"]),
|
|
163
|
+
with_auth: z.boolean().default(true),
|
|
164
|
+
with_metadata: z.boolean().default(false)
|
|
165
|
+
}).strict(),
|
|
166
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
167
|
+
}, async ({ path: routePath, type, with_auth, with_metadata }) => {
|
|
168
|
+
const segments = routePath.split("/").filter(Boolean);
|
|
169
|
+
const dynamicParams = segments.filter(s => s.startsWith("[") && s.endsWith("]"))
|
|
170
|
+
.map(s => s.slice(1, -1));
|
|
171
|
+
const entity = segments.find(s => !s.startsWith("[") && !s.startsWith("(")) ?? "entity";
|
|
172
|
+
const pascal = toPascalCase(entity.replace(/s$/, "")); // plurals → singular
|
|
173
|
+
const paramsType = dynamicParams.length > 0
|
|
174
|
+
? `{ params: { ${dynamicParams.map(p => `${p}: string`).join("; ")} } }`
|
|
175
|
+
: "";
|
|
176
|
+
const authBlock = with_auth ? `
|
|
177
|
+
const session = await auth()
|
|
178
|
+
if (!session) redirect("/login")
|
|
179
|
+
` : "";
|
|
180
|
+
const authImports = with_auth
|
|
181
|
+
? `import { auth } from "@/lib/auth"\nimport { redirect } from "next/navigation"\n`
|
|
182
|
+
: "";
|
|
183
|
+
const metadataBlock = with_metadata ? `
|
|
184
|
+
export async function generateMetadata({ params }: ${paramsType || "{}"}): Promise<Metadata> {
|
|
185
|
+
// const item = await get${pascal}(params.id)
|
|
186
|
+
return { title: "${pascal}" }
|
|
187
|
+
}
|
|
188
|
+
` : "";
|
|
189
|
+
const metadataImport = with_metadata ? `import type { Metadata } from "next"\n` : "";
|
|
190
|
+
let body;
|
|
191
|
+
switch (type) {
|
|
192
|
+
case "list":
|
|
193
|
+
body = ` // const items = await prismaPostgres.${entity.toLowerCase()}.findMany({ take: 50 })
|
|
194
|
+
|
|
195
|
+
return (
|
|
196
|
+
<div className="space-y-6">
|
|
197
|
+
<div className="flex items-center justify-between">
|
|
198
|
+
<h1 className="text-2xl font-semibold">${pascal}s</h1>
|
|
199
|
+
{/* <CreateButton /> */}
|
|
200
|
+
</div>
|
|
201
|
+
{/* <${pascal}List items={items} /> */}
|
|
202
|
+
</div>
|
|
203
|
+
)`;
|
|
204
|
+
break;
|
|
205
|
+
case "detail":
|
|
206
|
+
body = ` // const item = await prismaPostgres.${entity.toLowerCase()}.findUnique({
|
|
207
|
+
// where: { id: params.${dynamicParams[0] ?? "id"} }
|
|
208
|
+
// })
|
|
209
|
+
// if (!item) notFound()
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<div className="space-y-6">
|
|
213
|
+
<h1 className="text-2xl font-semibold">${pascal}</h1>
|
|
214
|
+
{/* <${pascal}Detail item={item} /> */}
|
|
215
|
+
</div>
|
|
216
|
+
)`;
|
|
217
|
+
break;
|
|
218
|
+
case "form":
|
|
219
|
+
body = ` return (
|
|
220
|
+
<div className="max-w-2xl space-y-6">
|
|
221
|
+
<h1 className="text-2xl font-semibold">Nuevo ${pascal}</h1>
|
|
222
|
+
{/* <Create${pascal}Form /> */}
|
|
223
|
+
</div>
|
|
224
|
+
)`;
|
|
225
|
+
break;
|
|
226
|
+
default:
|
|
227
|
+
body = ` return (
|
|
228
|
+
<div className="space-y-6">
|
|
229
|
+
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
|
230
|
+
</div>
|
|
231
|
+
)`;
|
|
232
|
+
}
|
|
233
|
+
const code = `${metadataImport}${authImports}
|
|
234
|
+
export default async function ${pascal}Page(${paramsType ? `props: ${paramsType}` : ""}) {${authBlock}
|
|
235
|
+
${body}
|
|
236
|
+
}
|
|
237
|
+
${metadataBlock}`;
|
|
238
|
+
const fsPath = `src/app${routePath}/page.tsx`;
|
|
239
|
+
return {
|
|
240
|
+
content: [{ type: "text", text: code.trim() }],
|
|
241
|
+
structuredContent: { path: routePath, fsPath, dynamicParams }
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
// ─── generate_component ────────────────────────────────────────────────────
|
|
245
|
+
server.registerTool("generate_component", {
|
|
246
|
+
title: "Generar componente React",
|
|
247
|
+
description: `Genera un componente React siguiendo las convenciones del proyecto:
|
|
248
|
+
- RSC por defecto, "use client" solo si se especifica
|
|
249
|
+
- Tipado con TypeScript estricto
|
|
250
|
+
- Usa cn() para merge de clases Tailwind
|
|
251
|
+
- Props interface explícita
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
- name: nombre del componente en PascalCase
|
|
255
|
+
- feature: feature a la que pertenece (carpeta en components/)
|
|
256
|
+
- type: tipo de componente`,
|
|
257
|
+
inputSchema: z.object({
|
|
258
|
+
name: z.string().describe("Nombre en PascalCase (ej: 'UserCard', 'InvoiceTable')"),
|
|
259
|
+
feature: z.string().describe("Feature a la que pertenece (ej: 'users', 'dashboard')"),
|
|
260
|
+
type: z.enum(["display", "form", "layout", "interactive"]),
|
|
261
|
+
is_client: z.boolean().default(false)
|
|
262
|
+
.describe("Si necesita 'use client' (hooks, eventos)")
|
|
263
|
+
}).strict(),
|
|
264
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
265
|
+
}, async ({ name, feature, type, is_client }) => {
|
|
266
|
+
const clientDirective = is_client ? `"use client"\n\n` : "";
|
|
267
|
+
const propsExample = type === "display"
|
|
268
|
+
? ` // data: YourDataType`
|
|
269
|
+
: type === "form"
|
|
270
|
+
? ` // onSubmit?: (data: FormData) => void`
|
|
271
|
+
: type === "interactive"
|
|
272
|
+
? ` // defaultOpen?: boolean`
|
|
273
|
+
: ` // children: React.ReactNode`;
|
|
274
|
+
const bodyExample = type === "display"
|
|
275
|
+
? ` <div className={cn("rounded-lg border p-4", className)}>
|
|
276
|
+
{/* contenido */}
|
|
277
|
+
</div>`
|
|
278
|
+
: type === "form"
|
|
279
|
+
? ` <form className={cn("space-y-4", className)}>
|
|
280
|
+
{/* campos */}
|
|
281
|
+
<Button type="submit">Guardar</Button>
|
|
282
|
+
</form>`
|
|
283
|
+
: type === "interactive"
|
|
284
|
+
? ` <div className={cn("", className)}>
|
|
285
|
+
{/* estado: {open ? "abierto" : "cerrado"} */}
|
|
286
|
+
</div>`
|
|
287
|
+
: ` <div className={cn("", className)}>
|
|
288
|
+
{children}
|
|
289
|
+
</div>`;
|
|
290
|
+
const imports = type === "form"
|
|
291
|
+
? `import { Button } from "@/components/ui/button"\n`
|
|
292
|
+
: "";
|
|
293
|
+
const stateExample = (is_client && type === "interactive")
|
|
294
|
+
? ` const [open, setOpen] = React.useState(false)\n`
|
|
295
|
+
: "";
|
|
296
|
+
const reactImport = (is_client && type === "interactive")
|
|
297
|
+
? `import * as React from "react"\n`
|
|
298
|
+
: "";
|
|
299
|
+
const code = `${clientDirective}${reactImport}import { cn } from "@/lib/utils"
|
|
300
|
+
${imports}
|
|
301
|
+
interface ${name}Props {
|
|
302
|
+
${propsExample}
|
|
303
|
+
className?: string
|
|
304
|
+
${type === "layout" ? " children: React.ReactNode\n" : ""}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export function ${name}({ ${type === "layout" ? "children, " : ""}className }: ${name}Props) {
|
|
308
|
+
${stateExample}
|
|
309
|
+
return (
|
|
310
|
+
${bodyExample}
|
|
311
|
+
)
|
|
312
|
+
}`;
|
|
313
|
+
const fsPath = `src/components/${feature}/${name.replace(/([A-Z])/g, (_, l, i) => i > 0 ? `-${l.toLowerCase()}` : l.toLowerCase())}.tsx`;
|
|
314
|
+
return {
|
|
315
|
+
content: [{ type: "text", text: code }],
|
|
316
|
+
structuredContent: { name, feature, fsPath, isClient: is_client }
|
|
317
|
+
};
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/generate/index.ts"],"names":[],"mappings":"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"}
|