mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-05 23:02:10 +03:00
feat(agent-skills): add POST /generate with management auth + dryRun default
Implements POST /api/agent-skills/generate (F4): - Requires management auth via requireManagementAuth (same pattern as usage/combo-health-dashboard and other management routes) - Validates body via GenerateBodySchema (dryRun defaults true, prune defaults false — safe preview mode) - Dynamic import of @/lib/agentSkills/generator so the route coexists before F3 (generator.ts) is merged; returns 503 if module unavailable - Hard Rule #12: all error paths use buildErrorBody (400/401/403/503/500) - Hard Rule #7: Zod validates both JSON parse and schema shape
This commit is contained in:
68
src/app/api/agent-skills/generate/route.ts
Normal file
68
src/app/api/agent-skills/generate/route.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* POST /api/agent-skills/generate
|
||||
*
|
||||
* Triggers the Agent Skills generator. Requires management auth.
|
||||
* Default: dryRun=true, prune=false (safe preview mode).
|
||||
*
|
||||
* Body (all optional):
|
||||
* - dryRun?: boolean (default true)
|
||||
* - prune?: boolean (default false)
|
||||
* - onlyIds?: string[] (only regenerate these skill IDs)
|
||||
*
|
||||
* Response: GeneratorReport
|
||||
* 401 if unauthenticated.
|
||||
* 400 if body is malformed.
|
||||
* 503 if generator module is not yet available (F3 not merged).
|
||||
* 500 on internal error.
|
||||
*/
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { buildErrorBody } from "@omniroute/open-sse/utils/error.ts";
|
||||
import { requireManagementAuth } from "@/lib/api/requireManagementAuth";
|
||||
import { GenerateBodySchema } from "@/lib/agentSkills/schemas";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
// Management auth — returns null if OK, error Response if not
|
||||
const authError = await requireManagementAuth(request);
|
||||
if (authError) return authError;
|
||||
|
||||
// Parse + validate request body
|
||||
let rawBody: unknown;
|
||||
try {
|
||||
rawBody = await request.json();
|
||||
} catch {
|
||||
return NextResponse.json(buildErrorBody(400, "Request body must be valid JSON"), {
|
||||
status: 400,
|
||||
});
|
||||
}
|
||||
|
||||
const parsed = GenerateBodySchema.safeParse(rawBody ?? {});
|
||||
if (!parsed.success) {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(400, parsed.error.issues[0]?.message ?? "Invalid request body"),
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
// Dynamic import — F3 (generator.ts) may not be merged yet
|
||||
let generateAgentSkills: (opts: typeof parsed.data) => Promise<unknown>;
|
||||
try {
|
||||
const mod = await import("@/lib/agentSkills/generator");
|
||||
generateAgentSkills = mod.generateAgentSkills;
|
||||
} catch {
|
||||
return NextResponse.json(
|
||||
buildErrorBody(503, "Generator module is not yet available"),
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const report = await generateAgentSkills(parsed.data);
|
||||
return NextResponse.json(report);
|
||||
} catch (error) {
|
||||
console.error("[API] POST /api/agent-skills/generate error:", error);
|
||||
return NextResponse.json(buildErrorBody(500, "Generator failed"), { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user