feat: migrate npm registry from Verdaccio to Gitea Packages
Some checks failed
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 1s
Monorepo Pipeline / 🧹 Lint (push) Failing after 35s
Monorepo Pipeline / 🧪 Test (push) Failing after 35s
Monorepo Pipeline / 🏗️ Build (push) Failing after 12s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Image Processor (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
Some checks failed
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 1s
Monorepo Pipeline / 🧹 Lint (push) Failing after 35s
Monorepo Pipeline / 🧪 Test (push) Failing after 35s
Monorepo Pipeline / 🏗️ Build (push) Failing after 12s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Image Processor (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
This commit is contained in:
110
packages/concept-engine/src/steps/02-audit.ts
Normal file
110
packages/concept-engine/src/steps/02-audit.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
// ============================================================================
|
||||
// Step 02: Audit — Feature Auditor + Skeptical Review (Gemini Flash)
|
||||
// ============================================================================
|
||||
|
||||
import { llmJsonRequest } from "../llm-client.js";
|
||||
import type { ConceptState, StepResult, PipelineConfig } from "../types.js";
|
||||
import { DEFAULT_MODELS } from "../types.js";
|
||||
|
||||
export async function executeAudit(
|
||||
state: ConceptState,
|
||||
config: PipelineConfig,
|
||||
): Promise<StepResult> {
|
||||
const models = { ...DEFAULT_MODELS, ...config.modelsOverride };
|
||||
const startTime = Date.now();
|
||||
|
||||
if (!state.facts) {
|
||||
return { success: false, error: "No facts from Step 01 available." };
|
||||
}
|
||||
|
||||
const systemPrompt = `
|
||||
You are a "Strict Cost Controller". Your mission is to prevent over-billing.
|
||||
Review the extracted FEATURES against the BRIEFING and the EXISTING SITE ANALYSIS.
|
||||
|
||||
### RULE OF THUMB:
|
||||
- A "Feature" (1.500 €) is ONLY justified for complex, dynamic systems (logic, database, CMS-driven management, advanced filtering).
|
||||
- Simple lists, information sections, or static descriptions (e.g., "Messen", "Team", "Historie", "Jobs" as mere text) are ALWAYS "Pages" (600 €).
|
||||
- If the briefing doesn't explicitly mention "Management System", "Filterable Database", or "Client Login", it is a PAGE.
|
||||
|
||||
### ADDITIONAL CHECKS:
|
||||
1. If any feature maps to an entity that has its own external website (listed in EXTERNAL_DOMAINS), remove it entirely — it's out of scope.
|
||||
2. Videos are ASSETS not pages. Remove any video-related entries from pages.
|
||||
3. If the existing site has features (search, forms, etc.), ensure they are in the functions list.
|
||||
|
||||
### MISSION:
|
||||
Return the corrected 'features', 'otherPages', and 'functions' arrays.
|
||||
|
||||
### OUTPUT FORMAT:
|
||||
{
|
||||
"features": string[],
|
||||
"otherPages": string[],
|
||||
"functions": string[],
|
||||
"removedItems": [{ "item": string, "reason": string }],
|
||||
"addedItems": [{ "item": string, "reason": string }]
|
||||
}
|
||||
`;
|
||||
|
||||
const userPrompt = `
|
||||
EXTRACTED FACTS:
|
||||
${JSON.stringify(state.facts, null, 2)}
|
||||
|
||||
BRIEFING:
|
||||
${state.briefing}
|
||||
|
||||
EXTERNAL DOMAINS (have own websites, OUT OF SCOPE):
|
||||
${state.siteProfile?.externalDomains?.join(", ") || "none"}
|
||||
|
||||
EXISTING FEATURES ON CURRENT SITE:
|
||||
${state.siteProfile?.existingFeatures?.join(", ") || "none"}
|
||||
`;
|
||||
|
||||
try {
|
||||
const { data, usage } = await llmJsonRequest({
|
||||
model: models.flash,
|
||||
systemPrompt,
|
||||
userPrompt,
|
||||
apiKey: config.openrouterKey,
|
||||
});
|
||||
|
||||
// Apply audit results to facts
|
||||
const auditedFacts = { ...state.facts };
|
||||
auditedFacts.features = data.features || [];
|
||||
auditedFacts.otherPages = [
|
||||
...new Set([...(auditedFacts.otherPages || []), ...(data.otherPages || [])]),
|
||||
];
|
||||
if (data.functions) {
|
||||
auditedFacts.functions = [
|
||||
...new Set([...(auditedFacts.functions || []), ...data.functions]),
|
||||
];
|
||||
}
|
||||
|
||||
// Log changes
|
||||
if (data.removedItems?.length) {
|
||||
console.log(" 📉 Audit removed:");
|
||||
for (const item of data.removedItems) {
|
||||
console.log(` - ${item.item}: ${item.reason}`);
|
||||
}
|
||||
}
|
||||
if (data.addedItems?.length) {
|
||||
console.log(" 📈 Audit added:");
|
||||
for (const item of data.addedItems) {
|
||||
console.log(` + ${item.item}: ${item.reason}`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: auditedFacts,
|
||||
usage: {
|
||||
step: "02-audit",
|
||||
model: models.flash,
|
||||
promptTokens: usage.promptTokens,
|
||||
completionTokens: usage.completionTokens,
|
||||
cost: usage.cost,
|
||||
durationMs: Date.now() - startTime,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
return { success: false, error: `Audit step failed: ${(err as Error).message}` };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user