UNPKG

@autobe/agent

Version:

AI backend server code generator

195 lines 8.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fillTocDeterministic = fillTocDeterministic; const uuid_1 = require("uuid"); const FixedAnalyzeTemplate_1 = require("./structures/FixedAnalyzeTemplate"); // ─── Helpers ─── function slugify(text) { return text .toLowerCase() .trim() .replace(/[^\p{L}\p{N} -]/gu, "") .replace(/\s+/g, "-") .replace(/-+/g, "-") .replace(/^-|-$/g, ""); } // ─── Zero-cost metric/token stubs ─── const ZERO_TOKEN_USAGE = { total: 0, input: { total: 0, cached: 0 }, output: { total: 0, reasoning: 0, accepted_prediction: 0, rejected_prediction: 0, }, }; const ZERO_METRIC = { attempt: 0, success: 0, consent: 0, validationFailure: 0, invalidJson: 0, }; const EMPTY_ACQUISITION = { previousAnalysisSections: [] }; // ─── Main ─── /** * Fill the TOC file (00-toc.md) deterministically — no LLM calls. * * Must be called AFTER all other files (01-05) have completed Stage 2/3 so that * their module/unit/section titles are available for navigation. * * Returns the final markdown content directly (no module/unit hierarchy). Also * sets minimal `unitResults` and `sectionResults` so that * `convertToSectionEntries()` for preloading still works. */ function fillTocDeterministic(ctx, props) { var _a, _b; const { scenario, tocFileState, otherFileStates, expandedTemplate } = props; const step = ((_b = (_a = ctx.state().analyze) === null || _a === void 0 ? void 0 : _a.step) !== null && _b !== void 0 ? _b : -1) + 1; // Build flat markdown content — no # / ## / ### hierarchy const content = buildTocContent(scenario, expandedTemplate, otherFileStates); // Minimal unit/section events for convertToSectionEntries() preloading const unitEvent = { type: "analyzeWriteUnit", id: (0, uuid_1.v7)(), moduleIndex: 0, unitSections: [ { title: "Table of Contents", purpose: "Project summary, document navigation, glossary, and assumptions.", content: "Project summary, document navigation, glossary, and assumptions.", keywords: ["project-summary", "document-map", "glossary", "navigation"], }, ], step, retry: 0, total: 1, completed: 1, tokenUsage: Object.assign({}, ZERO_TOKEN_USAGE), metric: Object.assign({}, ZERO_METRIC), acquisition: Object.assign({}, EMPTY_ACQUISITION), created_at: new Date().toISOString(), }; const sectionEvent = { type: "analyzeWriteSection", id: (0, uuid_1.v7)(), moduleIndex: 0, unitIndex: 0, sectionSections: [{ title: "Table of Contents", content }], step, retry: 0, total: 1, completed: 1, tokenUsage: Object.assign({}, ZERO_TOKEN_USAGE), metric: Object.assign({}, ZERO_METRIC), acquisition: Object.assign({}, EMPTY_ACQUISITION), created_at: new Date().toISOString(), }; tocFileState.moduleResult = Object.assign(Object.assign({}, tocFileState.moduleResult), { moduleSections: [ { title: "Table of Contents", purpose: "Project summary, document navigation, glossary, and assumptions.", content: "", }, ] }); tocFileState.unitResults = [unitEvent]; tocFileState.sectionResults = [[sectionEvent]]; return content; } // ─── Content builder ─── /** * Build the entire TOC content as a single markdown string. * * Combines project vision, scope, document map, canonical sources, glossary, * and assumptions into one flat section. */ function buildTocContent(scenario, expandedTemplate, otherFileStates) { const lines = []; lines.push("### Table of Contents", ""); // ── Project Vision ── const actors = scenario.actors.map((a) => a.name).join(", "); const entities = scenario.entities.map((e) => e.name).join(", "); lines.push(`**${scenario.prefix}** is a backend service with the following actors and domain entities.`, "", `**Actors**: ${actors}`, `**Entities**: ${entities}`); // ── Scope ── lines.push("", "---", "", "**Scope**", ""); for (const e of scenario.entities) { const rels = e.relationships && e.relationships.length > 0 ? ` — ${e.relationships.join(", ")}` : ""; lines.push(`- **${e.name}**${rels}`); } lines.push(""); for (const a of scenario.actors) { lines.push(`- **${a.name}** (${a.kind})`); } // ── Document Map ── lines.push("", "---", "", "**Document Map**", ""); lines.push((0, FixedAnalyzeTemplate_1.buildFixedAnalyzeDocumentMapContent)(expandedTemplate)); // ── Section Navigation ── lines.push("", "**Section Navigation**"); lines.push("", '<!-- Load sections by ID: `process({ request: { type: "getAnalysisSections", sectionIds: [ID, ...] } })` -->'); // TOC itself occupies section ID 0, so remaining files start from ID 1 let sectionId = 1; for (const state of otherFileStates) { if (!state.moduleResult || !state.unitResults) continue; const filename = state.file.filename; lines.push("", `**[${filename}](./${filename})**`); // Per-file anchor counter for GFM duplicate heading resolution const anchorCounts = new Map(); const resolveAnchor = (title) => { var _a; const base = slugify(title); const count = (_a = anchorCounts.get(base)) !== null && _a !== void 0 ? _a : 0; anchorCounts.set(base, count + 1); return count === 0 ? base : `${base}-${count}`; }; // Same traversal order as assembleModule / convertToSectionEntries: // moduleIndex ascending, then unitIndex ascending for (let moduleIndex = 0; moduleIndex < state.moduleResult.moduleSections.length; moduleIndex++) { const moduleSection = state.moduleResult.moduleSections[moduleIndex]; const unitEvent = state.unitResults[moduleIndex]; if (!moduleSection || !unitEvent) continue; lines.push(`- [${moduleSection.title}](./${filename}#${resolveAnchor(moduleSection.title)})`); for (const unitSection of unitEvent.unitSections) { const purpose = unitSection.purpose ? ` — ${unitSection.purpose}` : ""; lines.push(` - [${sectionId}] [${unitSection.title}](./${filename}#${resolveAnchor(unitSection.title)})${purpose}`); sectionId++; } } } // ── Canonical Sources ── lines.push("", "---", "", "**Canonical Sources**", ""); lines.push((0, FixedAnalyzeTemplate_1.buildFixedAnalyzeCanonicalSourceContent)()); // ── Glossary ── lines.push("", "---", "", "**Glossary**", ""); for (const e of scenario.entities) { const rels = e.relationships && e.relationships.length > 0 ? ` — ${e.relationships.join(", ")}` : ""; lines.push(`- **${e.name}**${rels}`); } // ── Constraints & Features ── const constraintLines = []; for (const file of scenario.files) { if (file.constraints && file.constraints.length > 0) { for (const c of file.constraints) { constraintLines.push(`- ${c}`); } } } if (constraintLines.length > 0) { lines.push("", "---", "", "**Constraints**", ""); lines.push(...constraintLines); } const features = scenario.features.length > 0 ? scenario.features.map((f) => `- ${f.id}`).join("\n") : null; if (features) { lines.push("", "**Active Features**", "", features); } return lines.join("\n"); } //# sourceMappingURL=fillTocDeterministic.js.map