#!/usr/bin/env node /** * Factory Router — V2 Protocol Stack → Full-stack Factory Bridge * * Routes a structured PRD to the appropriate factory chain. * No factory logic lives here — only routing decisions. * * Current factories: * - fullstack → SF-01 (project-intake) + SF-02 (architecture) + SF-03~06 (fullstack-composer) * * Future factories (routing placeholder): * - research → 科研工厂 * - writing → 写作工厂 * - analysis → 分析工厂 * * @module factory-router */ /** * Route a PRD to the appropriate factory. * Currently only "fullstack" is implemented. * * @param {object} prd — Structured PRD from SF-01 * @param {object} opts * @param {object} opts.arch — Architecture from SF-02 (optional, auto-generated if missing) * @param {string} opts.factory — Force a factory ("fullstack" | "research" | "writing" | "analysis") * @returns {{ factory: string, factoryFn: string, needsArch: boolean }} */ export function route(prd, opts = {}) { const domain = prd.domain || "generic"; // Resolve factory name let factory = opts.factory || _inferFactory(domain, prd); // All factories need architecture → default to fullstack pipeline for now if (factory === "fullstack") { return { factory: "fullstack", factoryFn: "./fullstack-composer-agent.mjs", needsArch: !opts.arch, }; } // Unknown or future factory → default to fullstack return { factory: "fullstack", factoryFn: "./fullstack-composer-agent.mjs", needsArch: !opts.arch, }; } /** * Infer factory type from domain and PRD content. * * @param {string} domain * @param {object} prd * @returns {string} factory name */ function _inferFactory(domain, prd) { // Research domains → research factory (future) const researchDomains = ["research", "academic", "scientific", "paper", "thesis"]; if (researchDomains.includes(domain)) return "research"; // Writing domains → writing factory (future) const writingDomains = ["writing", "blog", "article", "news"]; if (writingDomains.includes(domain)) return "writing"; // Analysis domains → analysis factory (future) const analysisDomains = ["analytics", "dashboard", "report"]; if (analysisDomains.includes(domain)) return "analysis"; // Default: fullstack factory return "fullstack"; } /** * Load a factory module. Keeps dynamic import lazy. * * @param {string} factoryFn — Path to factory script (relative to scripts/) * @returns {Promise} factory module */ export async function loadFactory(factoryFn) { return await import(factoryFn); }