opencroc 1.8.4 → 1.8.5
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/README.ja.md +383 -386
- package/README.zh-CN.md +383 -414
- package/dist/cli/index.js +24 -8
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../node_modules/tsup/assets/esm_shims.js","../../src/cli/commands/init.ts","../../src/cli/load-config.ts","../../src/parsers/model-parser.ts","../../src/parsers/controller-parser.ts","../../src/parsers/association-parser.ts","../../src/analyzers/api-chain-analyzer.ts","../../src/generators/er-diagram-generator.ts","../../src/generators/test-code-generator.ts","../../src/validators/schema-validator.ts","../../src/validators/semantic-validator.ts","../../src/validators/dryrun-validator.ts","../../src/validators/config-validator.ts","../../src/pipeline/index.ts","../../src/cli/commands/generate.ts","../../src/cli/commands/test.ts","../../src/cli/commands/validate.ts","../../src/llm/openai.ts","../../src/llm/ollama.ts","../../src/llm/index.ts","../../src/self-healing/dialog-loop-runner.ts","../../src/self-healing/controlled-fixer.ts","../../src/self-healing/auto-fix-generator.ts","../../src/self-healing/index.ts","../../src/cli/commands/heal.ts","../../src/ci/index.ts","../../src/cli/commands/ci.ts","../../src/reporters/checklist-reporter.ts","../../src/reporters/workorder-reporter.ts","../../src/reporters/token-reporter.ts","../../src/reporters/index.ts","../../src/cli/commands/report.ts","../../src/dashboard/index.ts","../../src/cli/commands/dashboard.ts","../../src/runtime/playwright-config-generator.ts","../../src/runtime/global-setup-generator.ts","../../src/runtime/global-teardown-generator.ts","../../src/runtime/auth-setup-generator.ts","../../src/cli/commands/init-runtime.ts","../../src/orchestrator/index.ts","../../src/orchestrator/reporter.ts","../../src/cli/commands/run.ts","../../src/server/routes/project.ts","../../src/server/routes/agents.ts","../../src/scanner/language-detector.ts","../../src/scanner/project-scanner.ts","../../src/scanner/github-cloner.ts","../../src/graph/index.ts","../../src/insight/index.ts","../../src/server/studio-store.ts","../../src/agents/role-registry.ts","../../src/server/routes/studio.ts","../../src/agents/task-router.ts","../../src/execution/coordinator.ts","../../src/runtime/resilient-fetch.ts","../../src/execution/backend-manager.ts","../../src/execution/runtime-bootstrap.ts","../../src/execution/auth-provisioner.ts","../../src/execution/quality-gate.ts","../../src/server/croc-office.ts","../../src/server/index.ts","../../src/cli/commands/serve.ts","../../src/cli/commands/scan.ts","../../src/cli/commands/analyze.ts","../../src/cli/index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import chalk from 'chalk';\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { createInterface } from 'node:readline/promises';\r\nimport { stdin, stdout } from 'node:process';\r\n\r\nconst ADAPTERS = ['sequelize', 'typeorm', 'prisma'] as const;\r\nconst LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'none'] as const;\r\n\r\nexport interface InitAnswers {\r\n backendRoot: string;\r\n adapter: string;\r\n llmProvider: string;\r\n outDir: string;\r\n}\r\n\r\nconst DEFAULTS: InitAnswers = {\r\n backendRoot: './backend',\r\n adapter: 'sequelize',\r\n llmProvider: 'openai',\r\n outDir: './opencroc-output',\r\n};\r\n\r\nexport function buildConfigContent(answers: InitAnswers): string {\r\n const llmBlock =\r\n answers.llmProvider === 'none'\r\n ? ''\r\n : `\r\n llm: {\r\n provider: '${answers.llmProvider}',${answers.llmProvider === 'ollama' ? '' : \"\\n // apiKey: process.env.OPENCROC_LLM_API_KEY,\"}\r\n model: '${answers.llmProvider === 'zhipu' ? 'glm-4' : answers.llmProvider === 'ollama' ? 'llama3' : 'gpt-4o-mini'}',\r\n },`;\r\n\r\n return `import { defineConfig } from 'opencroc';\r\n\r\nexport default defineConfig({\r\n backendRoot: '${answers.backendRoot}',\r\n adapter: '${answers.adapter}',${llmBlock}\r\n outDir: '${answers.outDir}',\r\n selfHealing: {\r\n enabled: true,\r\n maxIterations: 3,\r\n },\r\n});\r\n`;\r\n}\r\n\r\nasync function prompt(\r\n rl: ReturnType<typeof createInterface>,\r\n question: string,\r\n defaultValue: string,\r\n): Promise<string> {\r\n const answer = await rl.question(` ${question} ${chalk.gray(`(${defaultValue})`)}: `);\r\n return answer.trim() || defaultValue;\r\n}\r\n\r\nasync function promptChoice(\r\n rl: ReturnType<typeof createInterface>,\r\n question: string,\r\n choices: readonly string[],\r\n defaultValue: string,\r\n): Promise<string> {\r\n const list = choices\r\n .map((c) => (c === defaultValue ? chalk.underline(c) : c))\r\n .join(' / ');\r\n const answer = await rl.question(` ${question} [${list}]: `);\r\n const trimmed = answer.trim().toLowerCase();\r\n if (!trimmed) return defaultValue;\r\n return choices.find((c) => c.toLowerCase() === trimmed) || defaultValue;\r\n}\r\n\r\nasync function collectAnswers(): Promise<InitAnswers> {\r\n const rl = createInterface({ input: stdin, output: stdout });\r\n try {\r\n const backendRoot = await prompt(rl, 'Backend source root', DEFAULTS.backendRoot);\r\n const adapter = await promptChoice(rl, 'ORM adapter', ADAPTERS, DEFAULTS.adapter);\r\n const llmProvider = await promptChoice(rl, 'LLM provider', LLM_PROVIDERS, DEFAULTS.llmProvider);\r\n const outDir = await prompt(rl, 'Test output directory', DEFAULTS.outDir);\r\n return { backendRoot, adapter, llmProvider, outDir };\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nfunction writeProject(cwd: string, answers: InitAnswers): void {\r\n const configPath = join(cwd, 'opencroc.config.ts');\r\n writeFileSync(configPath, buildConfigContent(answers), 'utf-8');\r\n console.log(chalk.green(' ✓ Created opencroc.config.ts'));\r\n\r\n const outputDir = join(cwd, answers.outDir);\r\n if (!existsSync(outputDir)) {\r\n mkdirSync(outputDir, { recursive: true });\r\n console.log(chalk.green(` ✓ Created ${answers.outDir}/`));\r\n }\r\n}\r\n\r\nfunction printNextSteps(answers: InitAnswers): void {\r\n const needsKey = answers.llmProvider !== 'none' && answers.llmProvider !== 'ollama';\r\n console.log('');\r\n console.log(chalk.cyan(' Next steps:'));\r\n let step = 1;\r\n console.log(` ${step++}. Review opencroc.config.ts`);\r\n if (needsKey) {\r\n console.log(` ${step++}. Set OPENCROC_LLM_API_KEY environment variable`);\r\n }\r\n console.log(` ${step++}. npx opencroc generate --all`);\r\n console.log(` ${step}. npx opencroc test`);\r\n}\r\n\r\nexport async function initProject(opts?: { yes?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const configPath = join(cwd, 'opencroc.config.ts');\r\n\r\n if (existsSync(configPath)) {\r\n console.log(chalk.yellow('\\n ⚠ opencroc.config.ts already exists. Skipping.\\n'));\r\n return;\r\n }\r\n\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Project Setup\\n'));\r\n\r\n const answers = opts?.yes ? { ...DEFAULTS } : await collectAnswers();\r\n\r\n console.log('');\r\n writeProject(cwd, answers);\r\n printNextSteps(answers);\r\n console.log('');\r\n}\r\n","import { cosmiconfig } from 'cosmiconfig';\r\nimport type { OpenCrocConfig } from '../types.js';\r\n\r\nconst MODULE_NAME = 'opencroc';\r\n\r\nconst SEARCH_PLACES = [\r\n 'opencroc.config.ts',\r\n 'opencroc.config.js',\r\n 'opencroc.config.json',\r\n '.opencrocrc.json',\r\n 'package.json',\r\n];\r\n\r\nexport interface LoadConfigResult {\r\n config: OpenCrocConfig;\r\n filepath: string;\r\n}\r\n\r\nexport async function loadConfig(cwd?: string): Promise<LoadConfigResult> {\r\n const explorer = cosmiconfig(MODULE_NAME, {\r\n searchPlaces: SEARCH_PLACES,\r\n ...(cwd ? { stopDir: cwd } : {}),\r\n });\r\n\r\n const result = cwd ? await explorer.search(cwd) : await explorer.search();\r\n\r\n if (!result || result.isEmpty) {\r\n throw new Error(\r\n 'No opencroc config found. Run `opencroc init` to create one.',\r\n );\r\n }\r\n\r\n const config: OpenCrocConfig =\r\n result.config?.default ?? result.config;\r\n\r\n if (!config.backendRoot) {\r\n throw new Error(\r\n `Invalid config in ${result.filepath}: \"backendRoot\" is required.`,\r\n );\r\n }\r\n\r\n return { config, filepath: result.filepath };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type Node,\r\n} from 'ts-morph';\r\nimport type { TableSchema, FieldSchema, IndexSchema } from '../types.js';\r\n\r\nexport interface ModelParser {\r\n parseFile(filePath: string): Promise<TableSchema | null>;\r\n parseDirectory(dirPath: string): Promise<TableSchema[]>;\r\n}\r\n\r\n/**\r\n * Parse a single Sequelize Model file and extract TableSchema.\r\n */\r\nexport function parseModelFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const initCall = findInitCall(sourceFile);\r\n if (!initCall) return null;\r\n\r\n const args = initCall.getArguments();\r\n if (args.length < 2) return null;\r\n\r\n const fields = parseFieldDefinitions(args[0]);\r\n const { tableName, indexes } = parseOptions(args[1]);\r\n\r\n if (!tableName) return null;\r\n\r\n return { tableName, fields, indexes };\r\n}\r\n\r\n/**\r\n * Batch parse all Model files in a directory.\r\n */\r\nexport function parseModuleModels(modelDir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // skip unparseable files\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nfunction findInitCall(sourceFile: Node): CallExpression | null {\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n if (propAccess.getName() === 'init') return call;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\r\n\r\n const objLiteral = fieldsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const initializer = propAssign.getInitializer();\r\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n fields.push(parseFieldObject(propAssign.getName(), initializer as ObjectLiteralExpression));\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\r\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\r\n\r\n for (const prop of fieldObj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n switch (key) {\r\n case 'type': field.type = extractDataType(init); break;\r\n case 'allowNull': field.allowNull = init.getText().trim() === 'true'; break;\r\n case 'primaryKey': field.primaryKey = init.getText().trim() === 'true'; break;\r\n case 'defaultValue': field.defaultValue = extractDefaultValue(init); break;\r\n }\r\n }\r\n return field;\r\n}\r\n\r\nfunction extractDataType(node: Node): string {\r\n const text = node.getText().trim();\r\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\r\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\r\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\r\n if (propMatch) return propMatch[1];\r\n return text;\r\n}\r\n\r\nfunction extractDefaultValue(node: Node): unknown {\r\n const text = node.getText().trim();\r\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\r\n if (text === 'true') return true;\r\n if (text === 'false') return false;\r\n if (text === 'null') return null;\r\n return text;\r\n}\r\n\r\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\r\n let tableName: string | null = null;\r\n let indexes: IndexSchema[] = [];\r\n\r\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\r\n\r\n const objLiteral = optionsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'tableName') tableName = extractStringValue(init);\r\n if (key === 'indexes') indexes = parseIndexes(init);\r\n }\r\n return { tableName, indexes };\r\n}\r\n\r\nfunction extractStringValue(node: Node): string | null {\r\n const text = node.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction parseIndexes(node: Node): IndexSchema[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n const indexes: IndexSchema[] = [];\r\n for (const el of arr.getElements()) {\r\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n const idx = parseIndexObject(el as ObjectLiteralExpression);\r\n if (idx) indexes.push(idx);\r\n }\r\n return indexes;\r\n}\r\n\r\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\r\n let name = '';\r\n let fields: string[] = [];\r\n let unique = false;\r\n\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n switch (pa.getName()) {\r\n case 'name': name = extractStringValue(init) || ''; break;\r\n case 'fields': fields = extractStringArray(init); break;\r\n case 'unique': unique = init.getText().trim() === 'true'; break;\r\n }\r\n }\r\n if (!name || fields.length === 0) return null;\r\n return { name, fields, unique };\r\n}\r\n\r\nfunction extractStringArray(node: Node): string[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n return arr.getElements()\r\n .map((el) => el.getText().trim())\r\n .filter((t) => (t.startsWith(\"'\") || t.startsWith('\"')))\r\n .map((t) => t.slice(1, -1));\r\n}\r\n\r\nexport function createModelParser(): ModelParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseModelFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseModuleModels(dirPath);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type SourceFile,\r\n Node,\r\n type PropertyAccessExpression,\r\n type Decorator,\r\n type MethodDeclaration,\r\n type ObjectLiteralExpression,\r\n} from 'ts-morph';\r\nimport type { ApiEndpoint } from '../types.js';\r\n\r\nexport interface ControllerParser {\r\n parseFile(filePath: string): Promise<ApiEndpoint[]>;\r\n parseDirectory(dirPath: string): Promise<ApiEndpoint[]>;\r\n}\r\n\r\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\nconst METHOD_MAP: Record<string, string> = {\r\n get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH',\r\n};\r\n\r\nconst NEST_HTTP_DECORATORS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\n/**\r\n * Parse a single Controller file and extract API endpoints.\r\n */\r\nexport function parseControllerFile(filePath: string): ApiEndpoint[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n try {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n endpoints.push(...extractRouterCalls(sourceFile));\r\n endpoints.push(...extractBaseCrudRoutes(sourceFile));\r\n endpoints.push(...extractNestControllerRoutes(sourceFile));\r\n\r\n return deduplicateEndpoints(endpoints);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Parse all Controller files in a directory.\r\n */\r\nexport function parseControllerDirectory(dirPath: string): ApiEndpoint[] {\r\n const absoluteDir = path.resolve(dirPath);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n for (const file of files) {\r\n endpoints.push(...parseControllerFile(path.join(absoluteDir, file)));\r\n }\r\n return deduplicateEndpoints(endpoints);\r\n}\r\n\r\nfunction extractRouterCalls(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (!isRouterLike(objectText)) continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length === 0) continue;\r\n\r\n const routePath = resolveRoutePath(args[0], sourceFile);\r\n if (!routePath) continue;\r\n\r\n endpoints.push({\r\n method: METHOD_MAP[methodName],\r\n path: routePath,\r\n pathParams: extractPathParams(routePath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractDescription(call),\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction isRouterLike(text: string): boolean {\r\n return text === 'router' || text === 'this.router';\r\n}\r\n\r\nfunction extractBaseCrudRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n let isBaseCrud = false;\r\n for (const cls of sourceFile.getClasses()) {\r\n const heritage = cls.getExtends();\r\n if (heritage?.getText().includes('BaseCrudController')) {\r\n isBaseCrud = true;\r\n break;\r\n }\r\n }\r\n if (!isBaseCrud) return endpoints;\r\n\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n let resourcePath: string | null = null;\r\n\r\n for (const call of calls) {\r\n const exprText = call.getExpression().getText();\r\n if (\r\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\r\n !exprText.includes('Custom')\r\n ) {\r\n const args = call.getArguments();\r\n if (args.length >= 2) resourcePath = extractStringLiteral(args[1]);\r\n }\r\n }\r\n if (!resourcePath) return endpoints;\r\n\r\n const basePath = `/v1/:tenantId/${resourcePath}`;\r\n const crudRoutes: Array<{ method: string; path: string; desc: string }> = [\r\n { method: 'GET', path: basePath, desc: `List ${resourcePath}` },\r\n { method: 'GET', path: `${basePath}/:id`, desc: `Get ${resourcePath} by ID` },\r\n { method: 'POST', path: basePath, desc: `Create ${resourcePath}` },\r\n { method: 'PUT', path: `${basePath}/:id`, desc: `Update ${resourcePath}` },\r\n { method: 'DELETE', path: `${basePath}/:id`, desc: `Delete ${resourcePath}` },\r\n { method: 'POST', path: `${basePath}/batch-delete`, desc: `Batch delete ${resourcePath}` },\r\n ];\r\n\r\n for (const route of crudRoutes) {\r\n endpoints.push({\r\n method: route.method,\r\n path: route.path,\r\n pathParams: extractPathParams(route.path),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: route.desc,\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction extractNestControllerRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n for (const cls of sourceFile.getClasses()) {\r\n const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === 'controller');\r\n if (!controllerDecorator) continue;\r\n\r\n const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? '');\r\n\r\n for (const methodDecl of cls.getMethods()) {\r\n const requestMapping = extractRequestMapping(methodDecl, sourceFile);\r\n if (requestMapping) {\r\n const fullPath = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));\r\n endpoints.push({\r\n method: requestMapping.method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n continue;\r\n }\r\n\r\n const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));\r\n if (!httpDecorator) continue;\r\n\r\n const methodName = httpDecorator.getName().toLowerCase();\r\n const method = METHOD_MAP[methodName];\r\n if (!method) continue;\r\n\r\n const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? '');\r\n const fullPath = joinRoutePath(controllerBasePath, methodPath);\r\n\r\n endpoints.push({\r\n method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n }\r\n }\r\n\r\n return endpoints;\r\n}\r\n\r\n/**\r\n * Infer related database table names from Service file imports.\r\n */\r\nexport function inferRelatedTables(servicePaths: string[]): string[] {\r\n const tables = new Set<string>();\r\n for (const sp of servicePaths) {\r\n const absolutePath = path.resolve(sp);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n try {\r\n const content = fs.readFileSync(absolutePath, 'utf-8');\r\n const importRegex = /import\\s*\\{([^}]+)\\}\\s*from\\s*['\"][^'\"]*models[^'\"]*['\"]/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const names = match[1].split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n const cleanName = name.replace(/\\s+as\\s+\\w+/, '').trim();\r\n if (cleanName) tables.add(pascalToSnake(cleanName));\r\n }\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return Array.from(tables);\r\n}\r\n\r\nfunction resolveRoutePath(node: Node, sourceFile: SourceFile): string | null {\r\n const kind = node.getKind();\r\n if (kind === SyntaxKind.StringLiteral) return node.getText().slice(1, -1);\r\n if (kind === SyntaxKind.TemplateExpression || kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\r\n return resolveTemplateLiteral(node, sourceFile);\r\n }\r\n if (kind === SyntaxKind.Identifier) {\r\n return resolveVariableValue(sourceFile, node.getText().trim());\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractDecoratorPath(decorator: Decorator, sourceFile: SourceFile): string | null {\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return '';\r\n\r\n const firstArg = args[0];\r\n if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n return extractPathFromObjectLiteral(firstArg as ObjectLiteralExpression, sourceFile);\r\n }\r\n\r\n return resolveRoutePath(firstArg, sourceFile);\r\n}\r\n\r\nfunction extractPathFromObjectLiteral(node: ObjectLiteralExpression, sourceFile: SourceFile): string | null {\r\n const pathProp = node.getProperty('path');\r\n if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;\r\n const initializer = pathProp.getInitializer();\r\n if (!initializer) return null;\r\n return resolveRoutePath(initializer, sourceFile);\r\n}\r\n\r\nfunction extractRequestMapping(\r\n methodDecl: MethodDeclaration,\r\n sourceFile: SourceFile,\r\n): { method: string; path: string } | null {\r\n const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === 'requestmapping');\r\n if (!decorator) return null;\r\n\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return null;\r\n const firstArg = args[0];\r\n if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return null;\r\n\r\n const obj = firstArg as ObjectLiteralExpression;\r\n const methodProp = obj.getProperty('method');\r\n let method = 'GET';\r\n if (methodProp && Node.isPropertyAssignment(methodProp)) {\r\n const init = methodProp.getInitializer();\r\n const methodText = init?.getText() || '';\r\n const normalized = methodText\r\n .replace(/['\"`]/g, '')\r\n .split('.')\r\n .pop()\r\n ?.toUpperCase();\r\n if (normalized && ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) {\r\n method = normalized;\r\n }\r\n }\r\n\r\n const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? '';\r\n return { method, path: pathValue };\r\n}\r\n\r\nfunction normalizeRoutePath(routePath: string): string {\r\n const cleaned = routePath.trim();\r\n if (!cleaned || cleaned === '/') return '';\r\n return `/${cleaned.replace(/^\\/+|\\/+$/g, '')}`;\r\n}\r\n\r\nfunction joinRoutePath(basePath: string, childPath: string): string {\r\n const joined = `${basePath}${childPath}`.replace(/\\/+/g, '/');\r\n return joined || '/';\r\n}\r\n\r\nfunction extractMethodDescription(methodDecl: MethodDeclaration): string {\r\n const docs = methodDecl.getJsDocs();\r\n if (docs.length > 0) {\r\n const desc = docs[0].getDescription().trim();\r\n if (desc) return desc;\r\n }\r\n return '';\r\n}\r\n\r\nfunction resolveTemplateLiteral(node: Node, sourceFile: SourceFile): string {\r\n let result = node.getText().slice(1, -1);\r\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\r\n const resolved = resolveVariableValue(sourceFile, expr.trim());\r\n return resolved || `{${expr.trim()}}`;\r\n });\r\n return result;\r\n}\r\n\r\nfunction resolveVariableValue(sourceFile: SourceFile, varName: string): string | null {\r\n for (const decl of sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\r\n if (decl.getName() === varName) {\r\n const init = decl.getInitializer();\r\n if (!init) continue;\r\n const t = init.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n if (t.startsWith('`') && t.endsWith('`'))\r\n return resolveTemplateLiteral(init, sourceFile);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction extractDescription(call: CallExpression): string {\r\n let current: Node = call;\r\n while (\r\n current.getParent() &&\r\n current.getParent()!.getKind() !== SyntaxKind.SourceFile &&\r\n current.getParent()!.getKind() !== SyntaxKind.Block\r\n ) {\r\n current = current.getParent()!;\r\n }\r\n const fullText = current.getFullText();\r\n const leadingText = fullText.substring(0, fullText.indexOf(current.getText()));\r\n const jsdocMatch = leadingText.match(/\\/\\*\\*[\\s\\S]*?\\*\\s+(.+?)(?:\\n|\\*\\/)/);\r\n if (jsdocMatch) return jsdocMatch[1].replace(/^\\*\\s*/, '').trim();\r\n const lineMatch = leadingText.match(/\\/\\/\\s*(.+)/);\r\n if (lineMatch) return lineMatch[1].trim();\r\n return '';\r\n}\r\n\r\nfunction extractStringLiteral(node: Node): string | null {\r\n const t = node.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction pascalToSnake(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction deduplicateEndpoints(endpoints: ApiEndpoint[]): ApiEndpoint[] {\r\n const seen = new Map<string, ApiEndpoint>();\r\n for (const ep of endpoints) {\r\n const key = `${ep.method}:${ep.path}`;\r\n if (!seen.has(key)) {\r\n seen.set(key, ep);\r\n } else {\r\n const existing = seen.get(key)!;\r\n const merged = new Set([...existing.relatedTables, ...ep.relatedTables]);\r\n existing.relatedTables = Array.from(merged);\r\n if (!existing.description && ep.description) existing.description = ep.description;\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createControllerParser(): ControllerParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseControllerFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseControllerDirectory(dirPath);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type SourceFile,\r\n} from 'ts-morph';\r\nimport type { ForeignKeyRelation } from '../types.js';\r\nimport { parseModelFile } from './model-parser.js';\r\n\r\nexport interface AssociationParser {\r\n parseFile(filePath: string): Promise<ForeignKeyRelation[]>;\r\n}\r\n\r\ninterface RawAssociation {\r\n sourceClass: string;\r\n targetClass: string;\r\n foreignKey: string;\r\n type: 'hasMany' | 'belongsTo' | 'hasOne';\r\n importPath?: string;\r\n}\r\n\r\n/**\r\n * Parse an associations.ts file to extract all foreign key relations.\r\n */\r\nexport function parseAssociationFile(\r\n filePath: string,\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const importPathMap = collectImportPaths(sourceFile);\r\n const rawAssociations = extractAssociationCalls(sourceFile, importPathMap);\r\n if (rawAssociations.length === 0) return [];\r\n\r\n return deduplicateRelations(rawAssociations, classToTableMap, moduleTablePrefix);\r\n}\r\n\r\n/**\r\n * Build className → tableName map from Model files in a directory.\r\n */\r\nexport function buildClassToTableMap(modelDir: string): Map<string, string> {\r\n const map = new Map<string, string>();\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return map;\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) {\r\n const className = file.replace('.ts', '');\r\n map.set(className, schema.tableName);\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction collectImportPaths(sourceFile: SourceFile): Map<string, string> {\r\n const map = new Map<string, string>();\r\n for (const decl of sourceFile.getImportDeclarations()) {\r\n const moduleSpecifier = decl.getModuleSpecifierValue();\r\n for (const named of decl.getNamedImports()) {\r\n map.set(named.getName(), moduleSpecifier);\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction extractAssociationCalls(\r\n sourceFile: SourceFile,\r\n importPathMap: Map<string, string>,\r\n): RawAssociation[] {\r\n const associations: RawAssociation[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n const methodName = propAccess.getName();\r\n if (methodName !== 'hasMany' && methodName !== 'belongsTo' && methodName !== 'hasOne') continue;\r\n\r\n const sourceClass = propAccess.getExpression().getText().trim();\r\n const args = call.getArguments();\r\n if (args.length < 1) continue;\r\n\r\n const targetClass = args[0].getText().trim();\r\n let foreignKey = '';\r\n\r\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n foreignKey = extractStringProperty(args[1] as ObjectLiteralExpression, 'foreignKey');\r\n }\r\n\r\n associations.push({\r\n sourceClass,\r\n targetClass,\r\n foreignKey,\r\n type: methodName as RawAssociation['type'],\r\n importPath: importPathMap.get(targetClass),\r\n });\r\n }\r\n return associations;\r\n}\r\n\r\nfunction extractStringProperty(obj: ObjectLiteralExpression, propertyName: string): string {\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n if (pa.getName() !== propertyName) continue;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return text;\r\n }\r\n return '';\r\n}\r\n\r\nexport function classNameToTableName(className: string): string {\r\n return className.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction resolveTableName(className: string, classToTableMap?: Map<string, string>): string {\r\n if (classToTableMap?.has(className)) return classToTableMap.get(className)!;\r\n return classNameToTableName(className);\r\n}\r\n\r\nfunction isCrossModuleRef(\r\n targetTableName: string,\r\n importPath: string | undefined,\r\n moduleTablePrefix?: string,\r\n): boolean {\r\n if (moduleTablePrefix) return !targetTableName.startsWith(moduleTablePrefix);\r\n if (importPath) {\r\n const upLevels = (importPath.match(/\\.\\.\\//g) || []).length;\r\n return upLevels >= 2;\r\n }\r\n return false;\r\n}\r\n\r\nfunction deduplicateRelations(\r\n rawAssociations: RawAssociation[],\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const seen = new Map<string, ForeignKeyRelation>();\r\n\r\n for (const raw of rawAssociations) {\r\n const sourceTable = resolveTableName(raw.sourceClass, classToTableMap);\r\n const targetTable = resolveTableName(raw.targetClass, classToTableMap);\r\n const crossModule = isCrossModuleRef(targetTable, raw.importPath, moduleTablePrefix);\r\n\r\n let parentTable: string;\r\n let childTable: string;\r\n let cardinality: ForeignKeyRelation['cardinality'];\r\n\r\n switch (raw.type) {\r\n case 'hasMany':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:N'; break;\r\n case 'belongsTo':\r\n parentTable = targetTable; childTable = sourceTable; cardinality = 'N:1'; break;\r\n case 'hasOne':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:1'; break;\r\n }\r\n\r\n const dedupeKey = `${parentTable}|${childTable}|${raw.foreignKey}`;\r\n if (seen.has(dedupeKey)) {\r\n const existing = seen.get(dedupeKey)!;\r\n if (existing.cardinality === 'N:1' && (cardinality === '1:N' || cardinality === '1:1')) {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule || existing.isCrossModule,\r\n });\r\n }\r\n } else {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule,\r\n });\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createAssociationParser(): AssociationParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseAssociationFile(filePath);\r\n },\r\n };\r\n}\r\n","import type {\r\n ApiEndpoint,\r\n ApiDependency,\r\n ApiChainAnalysisResult,\r\n DirectedAcyclicGraph,\r\n} from '../types.js';\r\n\r\nconst EXCLUDED_PARAMS = new Set(['tenantId']);\r\n\r\nconst enum Color { WHITE = 0, GRAY = 1, BLACK = 2 }\r\n\r\nfunction toNodeKey(endpoint: ApiEndpoint): string {\r\n return `${endpoint.method} ${endpoint.path}`;\r\n}\r\n\r\nfunction paramToResourceHint(param: string): string {\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n return stripped.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\r\n}\r\n\r\nfunction postProducesResource(postEndpoint: ApiEndpoint, resourceHint: string): boolean {\r\n const segments = postEndpoint.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n if (segments.length === 0) return false;\r\n\r\n const lastSegment = segments[segments.length - 1].toLowerCase();\r\n if (lastSegment.includes(resourceHint)) return true;\r\n\r\n const parts = lastSegment.split('-');\r\n if (parts.some((p) => p === resourceHint || p.startsWith(resourceHint))) return true;\r\n\r\n if (resourceHint.length <= 4) {\r\n const abbreviation = parts.map((p) => p[0]).join('');\r\n if (abbreviation.startsWith(resourceHint)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Infer API dependencies via path parameter matching.\r\n * POST endpoints produce IDs; GET/PUT/DELETE endpoints consume them.\r\n */\r\nexport function inferDependencies(endpoints: ApiEndpoint[]): ApiDependency[] {\r\n const dependencies: ApiDependency[] = [];\r\n const postEndpoints = endpoints.filter((ep) => ep.method === 'POST');\r\n\r\n for (const consumer of endpoints) {\r\n const consumedParams = consumer.pathParams.filter((p) => !EXCLUDED_PARAMS.has(p));\r\n if (consumedParams.length === 0) continue;\r\n\r\n for (const param of consumedParams) {\r\n if (param === 'id') {\r\n const basePath = consumer.path.replace(/\\/:id(\\/.*)?$/, '');\r\n const producer = postEndpoints.find((ep) => ep.path === basePath);\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n continue;\r\n }\r\n\r\n const resourceHint = paramToResourceHint(param);\r\n if (!resourceHint) continue;\r\n\r\n const producer = postEndpoints.find((ep) => postProducesResource(ep, resourceHint));\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n }\r\n }\r\n return deduplicateDependencies(dependencies);\r\n}\r\n\r\nfunction deduplicateDependencies(deps: ApiDependency[]): ApiDependency[] {\r\n const map = new Map<string, ApiDependency>();\r\n for (const dep of deps) {\r\n const key = `${toNodeKey(dep.from)}→${toNodeKey(dep.to)}`;\r\n if (map.has(key)) {\r\n Object.assign(map.get(key)!.paramMapping, dep.paramMapping);\r\n } else {\r\n map.set(key, { ...dep, paramMapping: { ...dep.paramMapping } });\r\n }\r\n }\r\n return Array.from(map.values());\r\n}\r\n\r\n/**\r\n * Build a directed graph from endpoints and their dependencies.\r\n */\r\nexport function buildGraph(\r\n endpoints: ApiEndpoint[],\r\n dependencies: ApiDependency[],\r\n): DirectedAcyclicGraph {\r\n const nodeSet = new Set<string>();\r\n for (const ep of endpoints) nodeSet.add(toNodeKey(ep));\r\n\r\n const edges: Array<{ from: string; to: string; label?: string }> = [];\r\n for (const dep of dependencies) {\r\n edges.push({\r\n from: toNodeKey(dep.from),\r\n to: toNodeKey(dep.to),\r\n label: Object.keys(dep.paramMapping).join(', ') || undefined,\r\n });\r\n }\r\n return { nodes: Array.from(nodeSet), edges };\r\n}\r\n\r\n/**\r\n * Detect cycles in a directed graph using DFS coloring.\r\n */\r\nexport function detectCycles(dag: DirectedAcyclicGraph): string[] {\r\n const adjacency = new Map<string, string[]>();\r\n for (const node of dag.nodes) adjacency.set(node, []);\r\n for (const edge of dag.edges) adjacency.get(edge.from)?.push(edge.to);\r\n\r\n const color = new Map<string, Color>();\r\n for (const node of dag.nodes) color.set(node, Color.WHITE);\r\n\r\n const warnings: string[] = [];\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n color.set(node, Color.GRAY);\r\n path.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nc = color.get(neighbor);\r\n if (nc === Color.GRAY) {\r\n const cycleStart = path.indexOf(neighbor);\r\n warnings.push(`Cycle detected: ${path.slice(cycleStart).concat(neighbor).join(' → ')}`);\r\n } else if (nc === Color.WHITE) {\r\n dfs(neighbor);\r\n }\r\n }\r\n path.pop();\r\n color.set(node, Color.BLACK);\r\n }\r\n\r\n for (const node of dag.nodes) {\r\n if (color.get(node) === Color.WHITE) dfs(node);\r\n }\r\n return warnings;\r\n}\r\n\r\n/**\r\n * Topological sort using Kahn's algorithm.\r\n */\r\nexport function topologicalSort(dag: DirectedAcyclicGraph): string[] {\r\n const inDegree = new Map<string, number>();\r\n const adjacency = new Map<string, string[]>();\r\n\r\n for (const node of dag.nodes) { inDegree.set(node, 0); adjacency.set(node, []); }\r\n for (const edge of dag.edges) {\r\n adjacency.get(edge.from)?.push(edge.to);\r\n inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);\r\n }\r\n\r\n const queue: string[] = [];\r\n for (const [node, degree] of inDegree) {\r\n if (degree === 0) queue.push(node);\r\n }\r\n\r\n const sorted: string[] = [];\r\n while (queue.length > 0) {\r\n const node = queue.shift()!;\r\n sorted.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nd = (inDegree.get(neighbor) || 1) - 1;\r\n inDegree.set(neighbor, nd);\r\n if (nd === 0) queue.push(neighbor);\r\n }\r\n }\r\n return sorted;\r\n}\r\n\r\nexport interface ApiChainAnalyzer {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult;\r\n}\r\n\r\n/**\r\n * Analyze API endpoints: infer dependencies, build DAG, detect cycles, topological sort.\r\n */\r\nexport function createApiChainAnalyzer(): ApiChainAnalyzer {\r\n return {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult {\r\n const dependencies = inferDependencies(endpoints);\r\n const dag = buildGraph(endpoints, dependencies);\r\n const cycleWarnings = detectCycles(dag);\r\n\r\n return {\r\n moduleName: '',\r\n endpoints,\r\n dependencies,\r\n dag,\r\n hasCycles: cycleWarnings.length > 0,\r\n cycleWarnings,\r\n };\r\n },\r\n };\r\n}\r\n","import type { ERDiagramResult, TableSchema, ForeignKeyRelation } from '../types.js';\r\n\r\nexport interface ERDiagramGenerator {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult;\r\n}\r\n\r\n/**\r\n * Map field type string to a short Mermaid ER type label.\r\n */\r\nfunction toMermaidType(fieldType: string): string {\r\n const upper = fieldType.toUpperCase();\r\n if (upper.startsWith('STRING')) return 'string';\r\n if (upper === 'BIGINT' || upper === 'INTEGER') return 'bigint';\r\n if (upper === 'BOOLEAN') return 'boolean';\r\n if (upper.startsWith('DATE') || upper === 'NOW') return 'datetime';\r\n if (upper === 'JSON' || upper === 'JSONB') return 'json';\r\n if (upper === 'TEXT') return 'text';\r\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return 'float';\r\n if (upper === 'UUID') return 'uuid';\r\n if (upper.startsWith('ENUM')) return 'enum';\r\n return 'string';\r\n}\r\n\r\n/**\r\n * Mermaid requires entity names without special characters.\r\n */\r\nfunction sanitizeEntityName(name: string): string {\r\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n\r\n/**\r\n * Generate Mermaid ER diagram syntax from parsed schemas and relations.\r\n */\r\nfunction generateMermaidER(tables: TableSchema[], relations: ForeignKeyRelation[]): string {\r\n const lines: string[] = ['erDiagram'];\r\n\r\n // Entity blocks\r\n for (const table of tables) {\r\n const entityName = sanitizeEntityName(table.tableName);\r\n lines.push(` ${entityName} {`);\r\n for (const field of table.fields) {\r\n const mType = toMermaidType(field.type);\r\n const pk = field.primaryKey ? 'PK' : '';\r\n const comment = field.comment ? ` \"${field.comment}\"` : '';\r\n lines.push(` ${mType} ${field.name}${pk ? ' ' + pk : ''}${comment}`);\r\n }\r\n lines.push(' }');\r\n }\r\n\r\n // Relationships\r\n const tableNames = new Set(tables.map((t) => t.tableName));\r\n for (const rel of relations) {\r\n if (!tableNames.has(rel.sourceTable) || !tableNames.has(rel.targetTable)) continue;\r\n\r\n const src = sanitizeEntityName(rel.sourceTable);\r\n const tgt = sanitizeEntityName(rel.targetTable);\r\n const linkStyle = rel.isCrossModule ? '..' : '--';\r\n\r\n let cardinality: string;\r\n switch (rel.cardinality) {\r\n case '1:N': cardinality = `||${linkStyle}o{`; break;\r\n case 'N:1': cardinality = `}o${linkStyle}||`; break;\r\n case '1:1': cardinality = `||${linkStyle}||`; break;\r\n default: cardinality = `||${linkStyle}o{`;\r\n }\r\n\r\n lines.push(` ${src} ${cardinality} ${tgt} : \"${rel.targetField}\"`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createERDiagramGenerator(): ERDiagramGenerator {\r\n return {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult {\r\n const mermaidText = generateMermaidER(tables, relations);\r\n return { tables, relations, mermaidText };\r\n },\r\n };\r\n}\r\n","import type { GeneratedTestFile, TestChain, TestStep } from '../types.js';\r\n\r\nexport interface TestCodeGenerator {\r\n generate(chains: TestChain[]): GeneratedTestFile[];\r\n}\r\n\r\n/**\r\n * Resolve a path parameter from the available createdIds.\r\n */\r\nfunction resolvePathParam(param: string, ids: string[]): string {\r\n // Try direct match (e.g., 'kbId' → look for 'kbId' in ids)\r\n if (ids.includes(param)) return `createdIds['${param}']`;\r\n // Try with 'Id' suffix stripped\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n if (ids.includes(stripped)) return `createdIds['${stripped}']`;\r\n // Generic id\r\n if (param === 'id') return `createdIds['id']`;\r\n return `createdIds['${param}'] || '1'`;\r\n}\r\n\r\n/**\r\n * Generate URL building code for a test step.\r\n */\r\nfunction buildUrlCode(step: TestStep): string {\r\n const pathParams = step.endpoint.pathParams;\r\n if (pathParams.length === 0) return `const url = '${step.endpoint.path}';`;\r\n\r\n let urlTemplate = step.endpoint.path;\r\n const replacements: string[] = [];\r\n for (const param of pathParams) {\r\n urlTemplate = urlTemplate.replace(`:${param}`, `\\${${resolvePathParam(param, pathParams)}}`);\r\n replacements.push(param);\r\n }\r\n return `const url = \\`${urlTemplate}\\`;`;\r\n}\r\n\r\n/**\r\n * Generate assertion code for a test step.\r\n */\r\nfunction generateAssertions(step: TestStep): string[] {\r\n const lines: string[] = [];\r\n if (step.assertions.length > 0) {\r\n for (const assertion of step.assertions) {\r\n lines.push(` expect(${assertion}).toBeTruthy();`);\r\n }\r\n } else {\r\n // Default assertions\r\n if (step.endpoint.method === 'POST') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n lines.push(' const body = await response.json();');\r\n lines.push(\" if (body.data?.id) createdIds['id'] = body.data.id;\");\r\n } else if (step.endpoint.method === 'GET') {\r\n lines.push(' expect(response.ok()).toBeTruthy();');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n } else {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n }\r\n }\r\n return lines;\r\n}\r\n\r\n/**\r\n * Generate a single Playwright test file from a test chain.\r\n */\r\nfunction generateTestFile(chain: TestChain): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test, expect } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push(`test.describe('${chain.name}', () => {`);\r\n lines.push(\" const createdIds: Record<string, string> = {};\");\r\n lines.push('');\r\n\r\n for (const step of chain.steps) {\r\n lines.push(` test('Step ${step.order}: ${step.description}', async ({ request }) => {`);\r\n lines.push(` // ${step.action}: ${step.endpoint.method} ${step.endpoint.path}`);\r\n lines.push(` ${buildUrlCode(step)}`);\r\n lines.push('');\r\n\r\n if (step.endpoint.method === 'GET') {\r\n lines.push(' const response = await request.get(url);');\r\n } else if (step.endpoint.method === 'POST') {\r\n lines.push(' const response = await request.post(url, { data: {} });');\r\n } else if (step.endpoint.method === 'PUT') {\r\n lines.push(' const response = await request.put(url, { data: {} });');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' const response = await request.delete(url);');\r\n } else if (step.endpoint.method === 'PATCH') {\r\n lines.push(' const response = await request.patch(url, { data: {} });');\r\n }\r\n\r\n lines.push('');\r\n lines.push(...generateAssertions(step));\r\n lines.push(' });');\r\n lines.push('');\r\n }\r\n\r\n lines.push('});');\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createTestCodeGenerator(): TestCodeGenerator {\r\n return {\r\n generate(chains: TestChain[]): GeneratedTestFile[] {\r\n return chains.map((chain) => ({\r\n filePath: `${chain.module}/${chain.name.replace(/\\s+/g, '-').toLowerCase()}.spec.ts`,\r\n content: generateTestFile(chain),\r\n module: chain.module,\r\n chain: chain.name,\r\n }));\r\n },\r\n };\r\n}\r\n","/**\r\n * Schema Validator — Layer 1 of three-layer module config validation.\r\n * Checks structural integrity, field types, format conventions.\r\n */\r\n\r\nimport type {\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;\r\n\r\nexport function validateSchema(config: unknown): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n if (config === null || config === undefined || typeof config !== 'object') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: '', message: 'Config must be a non-null object' });\r\n return { passed: false, layer: 'schema', errors, warnings };\r\n }\r\n\r\n const cfg = config as Record<string, unknown>;\r\n\r\n // Required top-level fields\r\n const required: Array<{ name: string; type: string }> = [\r\n { name: 'moduleName', type: 'string' },\r\n { name: 'version', type: 'string' },\r\n { name: 'generatedAt', type: 'string' },\r\n { name: 'bodyTemplates', type: 'object' },\r\n { name: 'paramRewrites', type: 'object' },\r\n { name: 'idAliases', type: 'array' },\r\n { name: 'seed', type: 'array' },\r\n ];\r\n\r\n for (const f of required) {\r\n if (cfg[f.name] === undefined || cfg[f.name] === null) {\r\n errors.push({\r\n layer: 'schema', type: 'missing-field', path: f.name,\r\n message: `Required field '${f.name}' is missing`,\r\n suggestion: `Add '${f.name}' field of type ${f.type}`,\r\n });\r\n }\r\n }\r\n\r\n // Field type checks\r\n validateFieldTypes(cfg, errors);\r\n\r\n // bodyTemplates structure\r\n if (cfg.bodyTemplates && typeof cfg.bodyTemplates === 'object' && !Array.isArray(cfg.bodyTemplates)) {\r\n validateBodyTemplates(cfg.bodyTemplates as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // paramRewrites structure\r\n if (cfg.paramRewrites && typeof cfg.paramRewrites === 'object' && !Array.isArray(cfg.paramRewrites)) {\r\n validateParamRewrites(cfg.paramRewrites as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // idAliases structure\r\n if (Array.isArray(cfg.idAliases)) {\r\n validateIdAliases(cfg.idAliases, errors);\r\n }\r\n\r\n // seed array\r\n if (Array.isArray(cfg.seed)) {\r\n validateSeedArray(cfg.seed, errors, warnings);\r\n }\r\n\r\n // version format\r\n if (typeof cfg.version === 'string' && !/^\\d+\\.\\d+(\\.\\d+)?$/.test(cfg.version)) {\r\n warnings.push({ layer: 'schema', path: 'version', message: `Version '${cfg.version}' does not follow semver format` });\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'schema', errors, warnings };\r\n}\r\n\r\nfunction validateFieldTypes(cfg: Record<string, unknown>, errors: ModuleConfigValidationError[]): void {\r\n if (cfg.moduleName !== undefined && typeof cfg.moduleName !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'moduleName', message: `'moduleName' must be a string` });\r\n } else if (typeof cfg.moduleName === 'string' && cfg.moduleName.trim() === '') {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: 'moduleName', message: \"'moduleName' must not be empty\" });\r\n }\r\n\r\n if (cfg.bodyTemplates !== undefined && (typeof cfg.bodyTemplates !== 'object' || Array.isArray(cfg.bodyTemplates))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'bodyTemplates', message: \"'bodyTemplates' must be a plain object\" });\r\n }\r\n if (cfg.paramRewrites !== undefined && (typeof cfg.paramRewrites !== 'object' || Array.isArray(cfg.paramRewrites))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'paramRewrites', message: \"'paramRewrites' must be a plain object\" });\r\n }\r\n if (cfg.idAliases !== undefined && !Array.isArray(cfg.idAliases)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'idAliases', message: \"'idAliases' must be an array\" });\r\n }\r\n if (cfg.seed !== undefined && !Array.isArray(cfg.seed)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'seed', message: \"'seed' must be an array\" });\r\n }\r\n}\r\n\r\nfunction validateBodyTemplates(\r\n templates: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(templates)) {\r\n const p = `bodyTemplates.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Body template '${key}' must be a plain object` });\r\n continue;\r\n }\r\n if (!/^(GET|POST|PUT|PATCH|DELETE)\\s+\\//.test(key)) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template key '${key}' should follow format 'METHOD /path'` });\r\n }\r\n if (Object.keys(value).length === 0) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template '${key}' is empty` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewrites(\r\n rewrites: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n _warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(rewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Param rewrite '${key}' must be a plain object` });\r\n continue;\r\n }\r\n for (const [paramName, paramValue] of Object.entries(value as Record<string, unknown>)) {\r\n if (typeof paramValue !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.${paramName}`, message: `Param rewrite value for '${paramName}' must be a string` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliases(aliases: unknown[], errors: ModuleConfigValidationError[]): void {\r\n for (let i = 0; i < aliases.length; i++) {\r\n const alias = aliases[i] as Record<string, unknown> | null;\r\n const p = `idAliases[${i}]`;\r\n if (typeof alias !== 'object' || alias === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `idAlias at index ${i} must be an object` });\r\n continue;\r\n }\r\n if (typeof alias.pathPattern !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.pathPattern`, message: `idAlias at index ${i} must have a string 'pathPattern'` });\r\n }\r\n if (typeof alias.alias !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.alias`, message: `idAlias at index ${i} must have a string 'alias'` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedArray(\r\n seed: unknown[],\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (seed.length === 0) {\r\n warnings.push({ layer: 'schema', path: 'seed', message: 'Seed array is empty, no setup steps will be executed' });\r\n return;\r\n }\r\n\r\n const capturedVars = new Set<string>();\r\n const stepNumbers = new Set<number>();\r\n\r\n for (let i = 0; i < seed.length; i++) {\r\n const step = seed[i] as Record<string, unknown> | null;\r\n const p = `seed[${i}]`;\r\n if (typeof step !== 'object' || step === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Seed step at index ${i} must be an object` });\r\n continue;\r\n }\r\n\r\n // step number\r\n if (step.step === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.step`, message: `Seed step at index ${i} is missing 'step' number` });\r\n } else if (typeof step.step !== 'number' || !Number.isInteger(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.step`, message: `'step' must be an integer` });\r\n } else {\r\n if (stepNumbers.has(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.step`, message: `Duplicate step number ${step.step}` });\r\n }\r\n stepNumbers.add(step.step);\r\n }\r\n\r\n // method\r\n if (step.method === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.method`, message: `Seed step at index ${i} is missing 'method'` });\r\n } else if (typeof step.method !== 'string' || !(VALID_HTTP_METHODS as readonly string[]).includes(step.method)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.method`, message: `'method' must be one of ${VALID_HTTP_METHODS.join(', ')}` });\r\n }\r\n\r\n // path\r\n if (step.path === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.path`, message: `Seed step at index ${i} is missing 'path'` });\r\n } else if (typeof step.path !== 'string' || !(step.path as string).startsWith('/')) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.path`, message: `'path' must start with '/'` });\r\n }\r\n\r\n // required\r\n if (step.required === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.required`, message: `Seed step at index ${i} is missing 'required'` });\r\n }\r\n\r\n // body\r\n if (step.body !== undefined && (typeof step.body !== 'object' || step.body === null || Array.isArray(step.body))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.body`, message: `'body' must be a plain object` });\r\n } else if (step.body === undefined && typeof step.method === 'string' && ['POST', 'PUT', 'PATCH'].includes(step.method)) {\r\n warnings.push({ layer: 'schema', path: `${p}.body`, message: `${step.method} step at index ${i} has no body template` });\r\n }\r\n\r\n // captureAs uniqueness\r\n if (typeof step.captureAs === 'string') {\r\n if (capturedVars.has(step.captureAs)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.captureAs`, message: `Duplicate captureAs variable '${step.captureAs}'` });\r\n }\r\n capturedVars.add(step.captureAs);\r\n }\r\n\r\n // dependsOn reference check\r\n if (Array.isArray(step.dependsOn)) {\r\n for (const dep of step.dependsOn) {\r\n if (typeof dep === 'string' && !capturedVars.has(dep)) {\r\n errors.push({\r\n layer: 'schema', type: 'dependency-missing', path: `${p}.dependsOn`,\r\n message: `Seed step ${step.step ?? i} depends on '${dep}' not captured by any preceding step`,\r\n suggestion: `Ensure a preceding step has captureAs: '${dep}'`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Semantic Validator — Layer 2 of three-layer module config validation.\r\n * Checks that config matches actual source code (routes, DTO fields, dependencies).\r\n */\r\n\r\nimport type {\r\n ModuleTestConfig,\r\n SeedStep,\r\n ApiEndpoint,\r\n DTOInfo,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateSemantic(\r\n config: ModuleTestConfig,\r\n context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n validateBodyTemplatesSemantic(config, context, errors, warnings);\r\n validateParamRewritesSemantic(config, context, errors, warnings);\r\n validateIdAliasesSemantic(config, context, warnings);\r\n validateSeedRoutesSemantic(config, context, errors);\r\n validateSeedDependenciesSemantic(config, errors, warnings);\r\n\r\n return { passed: errors.length === 0, layer: 'semantic', errors, warnings };\r\n}\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction normalizePath(p: string): string {\r\n return p.replace(/\\/+$/, '').replace(/\\/+/g, '/');\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction findMatchingEndpoint(\r\n method: string, configPath: string, endpoints: ApiEndpoint[],\r\n): ApiEndpoint | undefined {\r\n const normalized = normalizePath(configPath);\r\n return endpoints.find((ep) => {\r\n if (ep.method !== method.toUpperCase()) return false;\r\n const epNorm = normalizePath(ep.path);\r\n if (epNorm === normalized) return true;\r\n const cSegs = normalized.split('/');\r\n const eSegs = epNorm.split('/');\r\n if (cSegs.length !== eSegs.length) return false;\r\n return cSegs.every((seg, idx) => seg === eSegs[idx] || seg.startsWith(':') || eSegs[idx].startsWith(':'));\r\n });\r\n}\r\n\r\nfunction findMatchingDTO(method: string, dtos: DTOInfo[]): DTOInfo | undefined {\r\n if (dtos.length === 0) return undefined;\r\n if (['POST'].includes(method)) return dtos.find((d) => /Create|Input|Request/.test(d.name));\r\n if (['PUT', 'PATCH'].includes(method)) return dtos.find((d) => /Update/.test(d.name)) || dtos.find((d) => /Create|Input/.test(d.name));\r\n if (['GET'].includes(method)) return dtos.find((d) => /Query|List|Params/.test(d.name));\r\n return undefined;\r\n}\r\n\r\n// ============================================================\r\n// Validators\r\n// ============================================================\r\n\r\nfunction validateBodyTemplatesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const p = `bodyTemplates.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: p,\r\n message: `Route '${method} ${routePath}' in bodyTemplates does not match any parsed API endpoint`,\r\n suggestion: `Check that the controller defines ${method} ${routePath}`,\r\n });\r\n continue;\r\n }\r\n\r\n const bodyFields = Object.keys(body);\r\n if (bodyFields.length === 0) continue;\r\n\r\n const dto = findMatchingDTO(method, ctx.dtos);\r\n if (!dto) {\r\n warnings.push({ layer: 'semantic', path: p, message: `No matching DTO found for '${method} ${routePath}', cannot verify field completeness` });\r\n continue;\r\n }\r\n\r\n const dtoFieldNames = new Set(dto.fields.map((f) => f.name));\r\n for (const fieldName of bodyFields) {\r\n if (!dtoFieldNames.has(fieldName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${fieldName}`, message: `Field '${fieldName}' in body template not found in DTO '${dto.name}'` });\r\n }\r\n }\r\n\r\n const bodyFieldSet = new Set(bodyFields);\r\n for (const field of dto.fields) {\r\n if (field.required && !field.isSystemField && !bodyFieldSet.has(field.name)) {\r\n warnings.push({ layer: 'semantic', path: p, message: `Required DTO field '${field.name}' (from ${dto.name}) not present in body template` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewritesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, mapping] of Object.entries(config.paramRewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({ layer: 'semantic', type: 'param-mapping-invalid', path: p, message: `Route '${method} ${routePath}' in paramRewrites does not match any parsed API endpoint` });\r\n continue;\r\n }\r\n\r\n const actualParams = new Set(extractPathParams(endpoint.path));\r\n for (const paramName of Object.keys(mapping)) {\r\n if (!actualParams.has(paramName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${paramName}`, message: `Param '${paramName}' in paramRewrites not found in route path params [${[...actualParams].join(', ')}]` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliasesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (let i = 0; i < config.idAliases.length; i++) {\r\n const alias = config.idAliases[i];\r\n const matched = ctx.endpoints.some((ep) => {\r\n try { return new RegExp(alias.pathPattern).test(ep.path); } catch { return ep.path.includes(alias.pathPattern); }\r\n });\r\n if (!matched) {\r\n warnings.push({ layer: 'semantic', path: `idAliases[${i}].pathPattern`, message: `idAlias pathPattern '${alias.pathPattern}' does not match any known API route` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedRoutesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n): void {\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n const endpoint = findMatchingEndpoint(step.method, step.path, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: `seed[${i}].path`,\r\n message: `Seed step ${step.step}: route '${step.method} ${step.path}' does not match any parsed API endpoint`,\r\n suggestion: `Verify that '${step.method} ${step.path}' exists in the module controllers`,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedDependenciesSemantic(\r\n config: ModuleTestConfig,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (config.seed.length === 0) return;\r\n\r\n const capturedSet = new Set<string>();\r\n const variablePattern = /\\{\\{(\\w+)\\}\\}|\\$\\{(\\w+)\\}/g;\r\n\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n\r\n // Check body variable references\r\n if (step.body) {\r\n const bodyStr = JSON.stringify(step.body);\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(bodyStr)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].body`, message: `Body references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n // Check path variable references\r\n if (step.path) {\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(step.path)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].path`, message: `Path references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n if (step.captureAs) capturedSet.add(step.captureAs);\r\n }\r\n\r\n // Cycle detection via DFS\r\n detectDependencyCycle(config.seed, errors);\r\n}\r\n\r\nfunction detectDependencyCycle(seed: SeedStep[], errors: ModuleConfigValidationError[]): void {\r\n const graph = new Map<string, string[]>();\r\n for (const step of seed) {\r\n if (step.captureAs) {\r\n graph.set(step.captureAs, step.dependsOn || []);\r\n }\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n\r\n function dfs(node: string): boolean {\r\n if (inStack.has(node)) return true;\r\n if (visited.has(node)) return false;\r\n visited.add(node);\r\n inStack.add(node);\r\n for (const neighbor of graph.get(node) || []) {\r\n if (dfs(neighbor)) {\r\n errors.push({ layer: 'semantic', type: 'dependency-cycle', path: 'seed', message: `Circular dependency detected involving '${node}' → '${neighbor}'` });\r\n return true;\r\n }\r\n }\r\n inStack.delete(node);\r\n return false;\r\n }\r\n\r\n for (const node of graph.keys()) {\r\n if (!visited.has(node)) dfs(node);\r\n }\r\n}\r\n","/**\r\n * Dry-run Validator — Layer 3 of three-layer module config validation.\r\n * Generates temporary TypeScript code from config and runs ts-morph compile check.\r\n */\r\n\r\nimport { Project, DiagnosticCategory } from 'ts-morph';\r\nimport type {\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateDryrun(\r\n config: ModuleTestConfig,\r\n _context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n const project = new Project({\r\n compilerOptions: {\r\n strict: false,\r\n noEmit: true,\r\n target: 2, // ES2015\r\n module: 1, // CommonJS\r\n esModuleInterop: true,\r\n skipLibCheck: true,\r\n },\r\n useInMemoryFileSystem: true,\r\n });\r\n\r\n // Add helper type declarations\r\n project.createSourceFile(\r\n '__helpers.d.ts',\r\n `\r\ndeclare function apiRequest(\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',\r\n path: string,\r\n body?: Record<string, any>,\r\n params?: Record<string, string>\r\n): Promise<{ status: number; data: any }>;\r\ndeclare function captureId(response: { data: any }, field?: string): string;\r\ndeclare const tenantId: string;\r\ndeclare const captured: Record<string, string>;\r\n`,\r\n );\r\n\r\n // Generate and check bodyTemplates test code\r\n const bodyCode = generateBodyTemplateTestCode(config);\r\n if (bodyCode) {\r\n const bodyFile = project.createSourceFile('__dryrun_body_test.ts', bodyCode);\r\n for (const diag of bodyFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `bodyTemplates (line ${line})` : 'bodyTemplates';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the body template that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n // Generate and check seed test code\r\n const seedCode = generateSeedTestCode(config);\r\n if (seedCode) {\r\n const seedFile = project.createSourceFile('__dryrun_seed_test.ts', seedCode);\r\n for (const diag of seedFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `seed (line ${line})` : 'seed';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the seed step that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'dryrun', errors, warnings };\r\n}\r\n\r\nfunction generateBodyTemplateTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.bodyTemplates || Object.keys(config.bodyTemplates).length === 0) return null;\r\n\r\n const lines = ['async function testBodyTemplates() {'];\r\n let idx = 0;\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n const method = key.substring(0, spaceIdx);\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n lines.push(` const body_${idx} = ${JSON.stringify(body, null, 2)};`);\r\n lines.push(` const result_${idx} = await apiRequest('${method}', '${routePath}', body_${idx});`);\r\n lines.push(` if (result_${idx}.status !== 200 && result_${idx}.status !== 201) {`);\r\n lines.push(` throw new Error('Unexpected status: ' + result_${idx}.status);`);\r\n lines.push(' }');\r\n idx++;\r\n }\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction generateSeedTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.seed || config.seed.length === 0) return null;\r\n\r\n const lines = [\r\n 'async function testSeedSteps() {',\r\n ' const captured: Record<string, string> = {};',\r\n '',\r\n ];\r\n\r\n for (const step of config.seed) {\r\n if (step.body) {\r\n lines.push(` const body_step${step.step} = ${JSON.stringify(step.body, null, 2)};`);\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}', body_step${step.step});`);\r\n } else {\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}');`);\r\n }\r\n\r\n if (step.captureAs) {\r\n lines.push(` captured['${step.captureAs}'] = captureId(result_step${step.step});`);\r\n }\r\n\r\n if (step.required) {\r\n lines.push(` if (result_step${step.step}.status >= 400) {`);\r\n lines.push(` throw new Error('${step.failureMessage || `Required step ${step.step} failed`}');`);\r\n lines.push(' }');\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n","import type {\r\n ValidationError,\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n ModuleConfigValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\nimport { validateSchema } from './schema-validator.js';\r\nimport { validateSemantic } from './semantic-validator.js';\r\nimport { validateDryrun } from './dryrun-validator.js';\r\n\r\nconst REQUIRED_FIELDS = ['backendRoot'];\r\n\r\nconst VALID_ADAPTERS = ['sequelize', 'typeorm', 'prisma', 'drizzle'];\r\nconst VALID_STEPS = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\nconst VALID_LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'custom'];\r\nconst VALID_REPORT_FORMATS = ['html', 'json', 'markdown'];\r\nconst VALID_HEAL_MODES = ['config-only', 'config-and-source'];\r\n\r\n/**\r\n * Validate an OpenCroc configuration object.\r\n * Returns an array of ValidationErrors (empty = valid).\r\n */\r\nexport function validateConfig(config: Record<string, unknown>): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n\r\n // Required fields\r\n for (const field of REQUIRED_FIELDS) {\r\n if (!config[field]) {\r\n errors.push({\r\n module: 'config',\r\n field,\r\n message: `Missing required field: ${field}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // backendRoot must be a string\r\n if (config.backendRoot && typeof config.backendRoot !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: 'backendRoot',\r\n message: 'backendRoot must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n // adapter validation\r\n if (config.adapter && typeof config.adapter === 'string') {\r\n if (!VALID_ADAPTERS.includes(config.adapter)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'adapter',\r\n message: `Invalid adapter: ${config.adapter}. Must be one of: ${VALID_ADAPTERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // steps validation\r\n if (config.steps && Array.isArray(config.steps)) {\r\n for (const step of config.steps) {\r\n if (!VALID_STEPS.includes(step as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'steps',\r\n message: `Invalid pipeline step: ${step}. Must be one of: ${VALID_STEPS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // LLM config validation\r\n if (config.llm && typeof config.llm === 'object') {\r\n const llm = config.llm as Record<string, unknown>;\r\n if (llm.provider && !VALID_LLM_PROVIDERS.includes(llm.provider as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.provider',\r\n message: `Invalid LLM provider: ${llm.provider}. Must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (llm.provider && llm.provider !== 'ollama' && !llm.apiKey) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.apiKey',\r\n message: 'LLM apiKey is required for cloud providers',\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n\r\n // Report config validation\r\n if (config.report && typeof config.report === 'object') {\r\n const report = config.report as Record<string, unknown>;\r\n if (report.format && Array.isArray(report.format)) {\r\n for (const fmt of report.format) {\r\n if (!VALID_REPORT_FORMATS.includes(fmt as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'report.format',\r\n message: `Invalid report format: ${fmt}. Must be one of: ${VALID_REPORT_FORMATS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Self-healing config validation\r\n if (config.selfHealing && typeof config.selfHealing === 'object') {\r\n const sh = config.selfHealing as Record<string, unknown>;\r\n if (sh.mode && !VALID_HEAL_MODES.includes(sh.mode as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.mode',\r\n message: `Invalid self-healing mode: ${sh.mode}. Must be one of: ${VALID_HEAL_MODES.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (sh.maxIterations && (typeof sh.maxIterations !== 'number' || sh.maxIterations < 1)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.maxIterations',\r\n message: 'maxIterations must be a positive number',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // Execution hooks validation\r\n if (config.execution && typeof config.execution === 'object') {\r\n const execution = config.execution as Record<string, unknown>;\r\n const hookFields = ['setupHook', 'authHook', 'teardownHook'];\r\n\r\n for (const hookField of hookFields) {\r\n const hook = execution[hookField];\r\n if (hook === undefined) continue;\r\n\r\n if (typeof hook === 'string') continue;\r\n\r\n if (typeof hook !== 'object' || hook === null) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}`,\r\n message: `${hookField} must be a string command or an object { command, args?, cwd? }`,\r\n severity: 'error',\r\n });\r\n continue;\r\n }\r\n\r\n const hookObj = hook as Record<string, unknown>;\r\n if (typeof hookObj.command !== 'string' || hookObj.command.trim() === '') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.command`,\r\n message: 'command is required and must be a non-empty string',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.args !== undefined && (!Array.isArray(hookObj.args) || hookObj.args.some((a) => typeof a !== 'string'))) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.args`,\r\n message: 'args must be an array of strings',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.cwd !== undefined && typeof hookObj.cwd !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.cwd`,\r\n message: 'cwd must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n// ============================================================\r\n// Three-Layer Module Config Validator\r\n// ============================================================\r\n\r\nexport interface ValidateModuleConfigOptions {\r\n stopOnFailure?: boolean;\r\n skipLayers?: Array<'schema' | 'semantic' | 'dryrun'>;\r\n}\r\n\r\nexport function validateModuleConfig(\r\n config: unknown,\r\n context?: ModuleConfigValidationContext,\r\n options?: ValidateModuleConfigOptions,\r\n): ModuleConfigValidationResult {\r\n const stopOnFailure = options?.stopOnFailure ?? true;\r\n const skipLayers = new Set(options?.skipLayers ?? []);\r\n\r\n const allErrors: ModuleConfigValidationError[] = [];\r\n const allWarnings: ModuleConfigValidationWarning[] = [];\r\n const result: ModuleConfigValidationResult = {\r\n passed: false,\r\n errors: allErrors,\r\n warnings: allWarnings,\r\n };\r\n\r\n if (!skipLayers.has('schema')) {\r\n const schemaResult = validateSchema(config);\r\n result.schemaResult = schemaResult;\r\n allErrors.push(...schemaResult.errors);\r\n allWarnings.push(...schemaResult.warnings);\r\n\r\n if (!schemaResult.passed) {\r\n result.failedAtLayer = 'schema';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'schema';\r\n }\r\n }\r\n\r\n const validConfig = config as ModuleTestConfig;\r\n\r\n if (!skipLayers.has('semantic')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'semantic', path: '', message: 'ValidationContext not provided, skipping semantic validation' });\r\n } else {\r\n const semanticResult = validateSemantic(validConfig, context);\r\n result.semanticResult = semanticResult;\r\n allErrors.push(...semanticResult.errors);\r\n allWarnings.push(...semanticResult.warnings);\r\n\r\n if (!semanticResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'semantic';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'semantic';\r\n }\r\n }\r\n }\r\n\r\n if (!skipLayers.has('dryrun')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'dryrun', path: '', message: 'ValidationContext not provided, skipping dry-run validation' });\r\n } else {\r\n const dryrunResult = validateDryrun(validConfig, context);\r\n result.dryrunResult = dryrunResult;\r\n allErrors.push(...dryrunResult.errors);\r\n allWarnings.push(...dryrunResult.warnings);\r\n\r\n if (!dryrunResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'dryrun';\r\n } else {\r\n result.lastPassedLayer = 'dryrun';\r\n }\r\n }\r\n }\r\n\r\n result.passed = allErrors.length === 0;\r\n return result;\r\n}\r\n\r\nexport function formatValidationResult(result: ModuleConfigValidationResult): string {\r\n const lines: string[] = [];\r\n lines.push(result.passed ? '\\u2705 Validation PASSED' : '\\u274c Validation FAILED');\r\n if (result.failedAtLayer) lines.push(` Failed at layer: ${result.failedAtLayer}`);\r\n if (result.lastPassedLayer) lines.push(` Last passed layer: ${result.lastPassedLayer}`);\r\n\r\n if (result.errors.length > 0) {\r\n lines.push('', `Errors (${result.errors.length}):`);\r\n for (const err of result.errors) {\r\n lines.push(` [${err.layer}] ${err.path}: ${err.message}`);\r\n if (err.suggestion) lines.push(` \\ud83d\\udca1 ${err.suggestion}`);\r\n }\r\n }\r\n\r\n if (result.warnings.length > 0) {\r\n lines.push('', `Warnings (${result.warnings.length}):`);\r\n for (const warn of result.warnings) {\r\n lines.push(` [${warn.layer}] ${warn.path}: ${warn.message}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n PipelineStep,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n} from '../types.js';\r\nimport { parseModuleModels } from '../parsers/model-parser.js';\r\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\r\nimport { parseAssociationFile } from '../parsers/association-parser.js';\r\nimport { createApiChainAnalyzer, topologicalSort } from '../analyzers/api-chain-analyzer.js';\r\nimport { createERDiagramGenerator } from '../generators/er-diagram-generator.js';\r\nimport { createTestCodeGenerator } from '../generators/test-code-generator.js';\r\nimport { validateConfig } from '../validators/config-validator.js';\r\n\r\nexport interface Pipeline {\r\n run(steps?: PipelineStep[]): Promise<PipelineRunResult>;\r\n}\r\n\r\nconst ALL_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\n\r\nexport function createPipeline(config: OpenCrocConfig): Pipeline {\r\n return {\r\n async run(steps) {\r\n const startTime = Date.now();\r\n const activeSteps = steps || config.steps || ALL_STEPS;\r\n\r\n const result: PipelineRunResult = {\r\n modules: [],\r\n erDiagrams: new Map(),\r\n chainPlans: new Map(),\r\n generatedFiles: [],\r\n validationErrors: [],\r\n duration: 0,\r\n };\r\n\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n // Smart discovery: find models/ and controllers/ in common locations\r\n const findDir = (name: string): string | null => {\r\n const candidates = [\r\n path.join(backendRoot, name), // ./models\r\n path.join(backendRoot, 'src', name), // ./src/models\r\n path.join(backendRoot, 'backend', 'src', name), // ./backend/src/models\r\n path.join(backendRoot, 'backend', name), // ./backend/models\r\n path.join(backendRoot, 'server', 'src', name), // ./server/src/models\r\n path.join(backendRoot, 'app', name), // ./app/models\r\n ];\r\n for (const c of candidates) {\r\n if (fs.existsSync(c)) return c;\r\n }\r\n return null;\r\n };\r\n\r\n const modelsRoot = findDir('models');\r\n const controllersRoot = findDir('controllers');\r\n\r\n // Step 1: Scan — discover modules\r\n if (activeSteps.includes('scan')) {\r\n if (modelsRoot) {\r\n // Discover modules from subdirectories\r\n const dirs = fs.readdirSync(modelsRoot, { withFileTypes: true })\r\n .filter((d) => d.isDirectory())\r\n .map((d) => d.name);\r\n\r\n const moduleFilter = config.modules;\r\n for (const dir of dirs) {\r\n if (moduleFilter && !moduleFilter.includes(dir)) continue;\r\n result.modules.push(dir);\r\n }\r\n\r\n // If no subdirectories, treat root as single \"default\" module\r\n if (result.modules.length === 0) {\r\n result.modules.push('default');\r\n } else {\r\n // Also include root-level model files as \"default\" module\r\n const rootFiles = fs.readdirSync(modelsRoot)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts');\r\n if (rootFiles.length > 0) {\r\n result.modules.unshift('default');\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Helper: resolve model dir for a module\r\n const resolveModelDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (modelsRoot || path.join(backendRoot, 'models'))\r\n : path.join(modelsRoot || path.join(backendRoot, 'models'), mod);\r\n\r\n // Helper: resolve controller dir for a module\r\n const resolveControllerDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (controllersRoot || path.join(backendRoot, 'controllers'))\r\n : path.join(controllersRoot || path.join(backendRoot, 'controllers'), mod);\r\n\r\n // Step 2: ER Diagram — parse models and generate relationship graphs\r\n if (activeSteps.includes('er-diagram')) {\r\n const erGen = createERDiagramGenerator();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const modelDir = resolveModelDir(backendRoot, mod);\r\n\r\n // For flat layouts, scan all model files for embedded associations\r\n const tables = fs.existsSync(modelDir) ? parseModuleModels(modelDir) : [];\r\n const relations: import('../types.js').ForeignKeyRelation[] = [];\r\n\r\n // Check for dedicated associations.ts first\r\n const assocFile = path.join(modelDir, 'associations.ts');\r\n if (fs.existsSync(assocFile)) {\r\n relations.push(...parseAssociationFile(assocFile));\r\n }\r\n\r\n // Also scan model files for embedded associations (belongsTo/hasMany at end of file)\r\n if (fs.existsSync(modelDir)) {\r\n const modelFiles = fs.readdirSync(modelDir)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts');\r\n for (const file of modelFiles) {\r\n try {\r\n const embedded = parseAssociationFile(path.join(modelDir, file));\r\n relations.push(...embedded);\r\n } catch {\r\n // skip files that fail to parse\r\n }\r\n }\r\n }\r\n\r\n const erResult: ERDiagramResult = erGen.generate(tables, relations);\r\n result.erDiagrams.set(mod, erResult);\r\n }\r\n }\r\n\r\n // Step 3: API Chain — analyze controller routes and build dependency DAG\r\n if (activeSteps.includes('api-chain')) {\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n analysis.moduleName = mod;\r\n\r\n if (analysis.hasCycles) {\r\n for (const warning of analysis.cycleWarnings) {\r\n result.validationErrors.push({\r\n module: mod,\r\n field: 'api-chain',\r\n message: warning,\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Step 4: Plan — generate test chains from dependency analysis\r\n if (activeSteps.includes('plan')) {\r\n const backendRoot = path.resolve(config.backendRoot);\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n const topoOrder = topologicalSort(analysis.dag);\r\n\r\n // Group by resource to create chains\r\n const chains = generateChainPlan(mod, endpoints, topoOrder);\r\n result.chainPlans.set(mod, chains);\r\n }\r\n }\r\n\r\n // Step 5: Codegen — emit Playwright test files from chain plans\r\n if (activeSteps.includes('codegen')) {\r\n const testGen = createTestCodeGenerator();\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n for (const [_mod, plan] of result.chainPlans) {\r\n const files = testGen.generate(plan.chains);\r\n for (const file of files) {\r\n file.filePath = path.join(outDir, file.filePath);\r\n }\r\n result.generatedFiles.push(...files);\r\n }\r\n }\r\n\r\n // Step 6: Validate — run validation on generated configs\r\n if (activeSteps.includes('validate')) {\r\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\r\n result.validationErrors.push(...configErrors);\r\n }\r\n\r\n result.duration = Date.now() - startTime;\r\n return result;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate a basic chain plan from endpoints and topological order.\r\n */\r\nfunction generateChainPlan(\r\n moduleName: string,\r\n endpoints: import('../types.js').ApiEndpoint[],\r\n _topoOrder: string[],\r\n): ChainPlanResult {\r\n // Group endpoints by resource (first non-param path segment)\r\n const groups = new Map<string, import('../types.js').ApiEndpoint[]>();\r\n\r\n for (const ep of endpoints) {\r\n const segments = ep.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n const resource = segments[segments.length - 1] || 'default';\r\n if (!groups.has(resource)) groups.set(resource, []);\r\n groups.get(resource)!.push(ep);\r\n }\r\n\r\n const chains: import('../types.js').TestChain[] = [];\r\n let totalSteps = 0;\r\n\r\n for (const [resource, eps] of groups) {\r\n const steps: import('../types.js').TestStep[] = eps.map((ep, i) => ({\r\n order: i + 1,\r\n action: ep.method,\r\n endpoint: ep,\r\n description: ep.description || `${ep.method} ${ep.path}`,\r\n assertions: [],\r\n }));\r\n\r\n chains.push({ name: `${resource} CRUD chain`, module: moduleName, steps });\r\n totalSteps += steps.length;\r\n }\r\n\r\n return { chains, totalSteps };\r\n}\r\n","import chalk from 'chalk';\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport type { PipelineStep, PipelineRunResult } from '../../types.js';\r\n\r\nconst VALID_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\n\r\nexport interface GenerateOptions {\r\n module?: string;\r\n all?: boolean;\r\n steps?: string;\r\n dryRun?: boolean;\r\n}\r\n\r\nfunction parseSteps(raw?: string): PipelineStep[] | undefined {\r\n if (!raw) return undefined;\r\n const names = raw.split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n if (!VALID_STEPS.includes(name as PipelineStep)) {\r\n throw new Error(`Unknown pipeline step \"${name}\". Valid steps: ${VALID_STEPS.join(', ')}`);\r\n }\r\n }\r\n return names as PipelineStep[];\r\n}\r\n\r\nfunction writeGeneratedFiles(result: PipelineRunResult): number {\r\n let written = 0;\r\n for (const file of result.generatedFiles) {\r\n const dir = dirname(file.filePath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n writeFileSync(file.filePath, file.content, 'utf-8');\r\n written++;\r\n console.log(chalk.green(` ✓ ${file.filePath}`));\r\n }\r\n return written;\r\n}\r\n\r\nfunction printSummary(result: PipelineRunResult, dryRun: boolean): void {\r\n console.log('');\r\n console.log(chalk.cyan.bold(' Summary'));\r\n console.log(` Modules discovered : ${result.modules.length}`);\r\n console.log(` ER diagrams : ${result.erDiagrams.size}`);\r\n console.log(` Chain plans : ${result.chainPlans.size}`);\r\n console.log(` Generated files : ${result.generatedFiles.length}${dryRun ? ' (dry-run, not written)' : ''}`);\r\n\r\n if (result.validationErrors.length > 0) {\r\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\r\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\r\n if (errors.length > 0) console.log(chalk.red(` Errors : ${errors.length}`));\r\n if (warnings.length > 0) console.log(chalk.yellow(` Warnings : ${warnings.length}`));\r\n\r\n for (const err of result.validationErrors) {\r\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\r\n console.log(` ${icon} [${err.module}] ${err.message}`);\r\n }\r\n }\r\n\r\n console.log(chalk.gray(` Duration : ${result.duration}ms`));\r\n console.log('');\r\n}\r\n\r\nexport async function generate(opts: GenerateOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Generate E2E Tests\\n'));\r\n\r\n // Load config\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n // Apply --module filter\r\n if (opts.module) {\r\n config.modules = [opts.module];\r\n }\r\n\r\n // Parse --steps\r\n const steps = parseSteps(opts.steps);\r\n\r\n // Create and run pipeline\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run(steps);\r\n\r\n // Write files (unless dry-run)\r\n if (!opts.dryRun && result.generatedFiles.length > 0) {\r\n console.log('');\r\n console.log(chalk.cyan(' Generated files:'));\r\n writeGeneratedFiles(result);\r\n } else if (opts.dryRun && result.generatedFiles.length > 0) {\r\n console.log('');\r\n console.log(chalk.yellow(' Dry-run — files that would be generated:'));\r\n for (const file of result.generatedFiles) {\r\n console.log(chalk.gray(` ${file.filePath}`));\r\n }\r\n }\r\n\r\n printSummary(result, !!opts.dryRun);\r\n}\r\n","import chalk from 'chalk';\r\nimport { readdirSync, existsSync } from 'node:fs';\r\nimport { join, resolve } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport { loadConfig } from '../load-config.js';\r\nimport type { ExecutionConfig, HookConfig } from '../../types.js';\r\n\r\nexport interface TestOptions {\r\n module?: string;\r\n headed?: boolean;\r\n setupHook?: string;\r\n authHook?: string;\r\n teardownHook?: string;\r\n}\r\n\r\nfunction normalizeHook(hook: HookConfig | undefined): HookConfig | undefined {\r\n if (!hook) return undefined;\r\n if (typeof hook === 'string') return hook.trim() ? hook : undefined;\r\n return hook.command.trim() ? hook : undefined;\r\n}\r\n\r\nfunction runShellCommand(command: string): void {\r\n if (process.platform === 'win32') {\r\n execFileSync('cmd.exe', ['/d', '/s', '/c', command], {\r\n stdio: 'inherit',\r\n cwd: process.cwd(),\r\n });\r\n return;\r\n }\r\n\r\n execFileSync('sh', ['-lc', command], {\r\n stdio: 'inherit',\r\n cwd: process.cwd(),\r\n });\r\n}\r\n\r\nfunction runHook(name: string, hook: HookConfig | undefined): void {\r\n const normalized = normalizeHook(hook);\r\n if (!normalized) return;\r\n\r\n console.log(chalk.cyan(` Running ${name} hook...`));\r\n\r\n if (typeof normalized === 'string') {\r\n runShellCommand(normalized);\r\n console.log(chalk.green(` ✓ ${name} hook passed`));\r\n return;\r\n }\r\n\r\n execFileSync(normalized.command, normalized.args ?? [], {\r\n stdio: 'inherit',\r\n cwd: normalized.cwd ? resolve(normalized.cwd) : process.cwd(),\r\n });\r\n console.log(chalk.green(` ✓ ${name} hook passed`));\r\n}\r\n\r\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\r\n const absDir = resolve(outDir);\r\n if (!existsSync(absDir)) return [];\r\n\r\n const files: string[] = [];\r\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\r\n for (const entry of entries) {\r\n if (!entry.isFile()) continue;\r\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\r\n const fullPath = join(entry.parentPath || (entry as unknown as { path: string }).path || absDir, entry.name);\r\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\r\n files.push(fullPath);\r\n }\r\n return files;\r\n}\r\n\r\nexport async function runTests(opts: TestOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Run E2E Tests\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const execution: ExecutionConfig = {\r\n ...(config.execution || {}),\r\n ...(opts.setupHook ? { setupHook: opts.setupHook } : {}),\r\n ...(opts.authHook ? { authHook: opts.authHook } : {}),\r\n ...(opts.teardownHook ? { teardownHook: opts.teardownHook } : {}),\r\n };\r\n\r\n try {\r\n runHook('setup', execution.setupHook);\r\n runHook('auth', execution.authHook);\r\n } catch {\r\n console.log(chalk.red(' ✗ setup/auth hook failed. Abort test run.\\n'));\r\n process.exitCode = 1;\r\n try {\r\n runHook('teardown', execution.teardownHook);\r\n } catch {\r\n console.log(chalk.red(' ✗ teardown hook also failed.\\n'));\r\n }\r\n return;\r\n }\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const testFiles = discoverTestFiles(outDir, opts.module);\r\n\r\n if (testFiles.length === 0) {\r\n console.log(chalk.yellow(' No test files found. Run `opencroc generate` first.\\n'));\r\n return;\r\n }\r\n\r\n console.log(` Found ${testFiles.length} test file(s)`);\r\n for (const f of testFiles) {\r\n console.log(chalk.gray(` ${f}`));\r\n }\r\n console.log('');\r\n\r\n // Build Playwright args\r\n const args = ['test', ...testFiles];\r\n if (!opts.headed) {\r\n args.push('--reporter=list');\r\n } else {\r\n args.push('--headed');\r\n }\r\n\r\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\r\n\r\n try {\r\n console.log(chalk.cyan(' Running Playwright...\\n'));\r\n execFileSync(npxCmd, ['playwright', ...args], {\r\n stdio: 'inherit',\r\n cwd: process.cwd(),\r\n });\r\n console.log(chalk.green('\\n ✓ All tests passed.\\n'));\r\n } catch {\r\n console.log(chalk.red('\\n ✗ Some tests failed.\\n'));\r\n process.exitCode = 1;\r\n } finally {\r\n try {\r\n runHook('teardown', execution.teardownHook);\r\n } catch {\r\n console.log(chalk.red(' ✗ teardown hook failed.\\n'));\r\n process.exitCode = 1;\r\n }\r\n }\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { validateConfig } from '../../validators/config-validator.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport type { ValidationError } from '../../types.js';\r\n\r\nexport interface ValidateOptions {\r\n module?: string;\r\n}\r\n\r\nfunction printErrors(errors: ValidationError[]): void {\r\n for (const err of errors) {\r\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\r\n const scope = err.module === 'config' ? '' : ` [${err.module}]`;\r\n console.log(` ${icon}${scope} ${err.field}: ${err.message}`);\r\n }\r\n}\r\n\r\nexport async function validate(opts: ValidateOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Validate\\n'));\r\n\r\n // Load and validate config\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\r\n\r\n // Apply module filter\r\n if (opts.module) {\r\n config.modules = [opts.module];\r\n }\r\n\r\n // Run pipeline in scan + validate mode to discover module-level issues\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run(['scan', 'validate']);\r\n\r\n const allErrors = [...configErrors, ...result.validationErrors];\r\n const errors = allErrors.filter((e) => e.severity === 'error');\r\n const warnings = allErrors.filter((e) => e.severity === 'warning');\r\n\r\n if (allErrors.length === 0) {\r\n console.log(chalk.green(' ✓ Configuration is valid.'));\r\n console.log(chalk.gray(` Modules: ${result.modules.join(', ') || '(none)'}\\n`));\r\n return;\r\n }\r\n\r\n if (errors.length > 0) {\r\n console.log(chalk.red(` ${errors.length} error(s):`));\r\n printErrors(errors);\r\n }\r\n if (warnings.length > 0) {\r\n console.log(chalk.yellow(` ${warnings.length} warning(s):`));\r\n printErrors(warnings);\r\n }\r\n\r\n console.log('');\r\n\r\n if (errors.length > 0) {\r\n process.exitCode = 1;\r\n }\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant';\r\n content: string;\r\n}\r\n\r\ninterface OpenAIResponse {\r\n choices: Array<{ message: { content: string } }>;\r\n usage?: { total_tokens: number };\r\n}\r\n\r\nconst DEFAULT_MODELS: Record<string, string> = {\r\n openai: 'gpt-4o-mini',\r\n zhipu: 'glm-4',\r\n};\r\n\r\nconst DEFAULT_BASE_URLS: Record<string, string> = {\r\n openai: 'https://api.openai.com/v1',\r\n zhipu: 'https://open.bigmodel.cn/api/paas/v4',\r\n};\r\n\r\n/**\r\n * Create an OpenAI-compatible LLM provider.\r\n * Works with OpenAI, Zhipu (GLM), and any OpenAI-compatible API.\r\n */\r\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\r\n const provider = config.provider === 'zhipu' ? 'zhipu' : 'openai';\r\n const baseUrl = config.baseUrl || DEFAULT_BASE_URLS[provider];\r\n const model = config.model || DEFAULT_MODELS[provider];\r\n const maxTokens = config.maxTokens || 2048;\r\n const temperature = config.temperature ?? 0.3;\r\n\r\n if (!config.apiKey) {\r\n throw new Error(\r\n `API key is required for ${provider}. Set it in config or via OPENCROC_LLM_API_KEY env variable.`,\r\n );\r\n }\r\n\r\n return {\r\n name: provider,\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/chat/completions`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: maxTokens,\r\n temperature,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`LLM API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OpenAIResponse;\r\n const content = data.choices?.[0]?.message?.content;\r\n if (!content) {\r\n throw new Error('LLM returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Rough estimate: ~4 chars per token for English, ~2 for CJK\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\ninterface OllamaResponse {\r\n message: { content: string };\r\n}\r\n\r\n/**\r\n * Create an Ollama LLM provider for local model inference.\r\n */\r\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'http://localhost:11434';\r\n const model = config.model || 'llama3';\r\n\r\n return {\r\n name: 'ollama',\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/api/chat`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n stream: false,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OllamaResponse;\r\n const content = data.message?.content;\r\n if (!content) {\r\n throw new Error('Ollama returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Same rough estimate as OpenAI provider\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\nimport { createOpenAIProvider } from './openai.js';\r\nimport { createOllamaProvider } from './ollama.js';\r\n\r\nexport { createOpenAIProvider } from './openai.js';\r\nexport { createOllamaProvider } from './ollama.js';\r\n\r\n/**\r\n * Create an LLM provider from config.\r\n * Resolves apiKey from config or OPENCROC_LLM_API_KEY env variable.\r\n */\r\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\r\n const resolved: LlmConfig = {\r\n ...config,\r\n apiKey: config.apiKey || process.env.OPENCROC_LLM_API_KEY,\r\n };\r\n\r\n switch (config.provider) {\r\n case 'openai':\r\n case 'zhipu':\r\n return createOpenAIProvider(resolved);\r\n case 'ollama':\r\n return createOllamaProvider(resolved);\r\n default:\r\n throw new Error(\r\n `Unknown LLM provider: \"${config.provider}\". Available: openai, zhipu, ollama`,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Token usage tracker — accumulates tokens across multiple LLM calls.\r\n */\r\nexport interface TokenTracker {\r\n track(text: string): void;\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string): void;\r\n total: number;\r\n reset(): void;\r\n}\r\n\r\nexport function createTokenTracker(provider: LlmProvider): TokenTracker {\r\n let total = 0;\r\n\r\n return {\r\n track(text: string) {\r\n total += provider.estimateTokens(text);\r\n },\r\n\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string) {\r\n for (const msg of messages) {\r\n total += provider.estimateTokens(msg.content);\r\n }\r\n total += provider.estimateTokens(response);\r\n },\r\n\r\n get total() {\r\n return total;\r\n },\r\n\r\n reset() {\r\n total = 0;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * System prompts for different LLM use cases in OpenCroc.\r\n */\r\nexport const SYSTEM_PROMPTS = {\r\n failureAnalysis: `You are an expert test failure analyst for an E2E testing framework.\r\nGiven a test failure error message and its context, analyze the root cause and suggest a fix.\r\nRespond in JSON format: { \"rootCause\": string, \"category\": string, \"suggestedFix\": string, \"confidence\": number }\r\nCategories: backend-5xx, timeout, endpoint-not-found, data-constraint, network, frontend-render, test-script, unknown.`,\r\n\r\n chainPlanning: `You are an API test chain planner.\r\nGiven a list of API endpoints and their dependencies, generate an optimal test execution order.\r\nConsider data dependencies, authentication requirements, and cleanup steps.\r\nRespond in JSON format: { \"chains\": [{ \"name\": string, \"steps\": [{ \"endpoint\": string, \"method\": string, \"description\": string }] }] }`,\r\n} as const;\r\n","/**\r\n * Dialog Loop Runner — multi-iteration self-healing loop.\r\n *\r\n * Runs tests, parses results, applies controlled fixes, and reruns\r\n * until all tests pass or the maximum iteration count is reached.\r\n * Tracks error history to avoid infinite loops on recurring failures.\r\n */\r\n\r\nimport type {\r\n DialogLoopConfig,\r\n TestFailureInfo,\r\n IterationResult,\r\n DialogLoopSummary,\r\n ControlledFixOutcome,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface TestRunner {\r\n run(): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface ResultParser {\r\n parse(stdout: string): TestFailureInfo[];\r\n countTotal(stdout: string): number;\r\n}\r\n\r\nexport interface FixApplier {\r\n apply(failure: TestFailureInfo): Promise<ControlledFixOutcome>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULTS: Required<DialogLoopConfig> = {\r\n maxIterations: 3,\r\n pollIntervalMs: 10_000,\r\n sameErrorThreshold: 2,\r\n autoRerunOnFix: true,\r\n};\r\n\r\n// ===== JSON result parser (reads Playwright JSON output) =====\r\n\r\nexport function createJsonResultParser(): ResultParser {\r\n return {\r\n parse(stdout: string): TestFailureInfo[] {\r\n const failures: TestFailureInfo[] = [];\r\n // Match pass/fail summary from Playwright output\r\n const lines = stdout.split('\\n');\r\n for (const line of lines) {\r\n // Playwright format: \" ✘ [chromium] › test.spec.ts:10:5 › suite › title\"\r\n // or stderr lines with \"Error:\" prefix\r\n const failMatch = line.match(/[✘✗×]\\s+.*?›\\s+(.+)/);\r\n if (failMatch) {\r\n failures.push({\r\n title: failMatch[1].trim(),\r\n error: failMatch[1].trim(),\r\n });\r\n }\r\n }\r\n return failures;\r\n },\r\n countTotal(stdout: string): number {\r\n // Match \"X passed\" or \"X failed\" from Playwright summary\r\n let total = 0;\r\n const passMatch = stdout.match(/(\\d+)\\s+passed/);\r\n const failMatch = stdout.match(/(\\d+)\\s+failed/);\r\n if (passMatch) total += parseInt(passMatch[1], 10);\r\n if (failMatch) total += parseInt(failMatch[1], 10);\r\n return total || 1; // at least 1 to avoid division by zero\r\n },\r\n };\r\n}\r\n\r\n// ===== Dialog Loop =====\r\n\r\nexport interface DialogLoopOptions {\r\n runner: TestRunner;\r\n parser: ResultParser;\r\n fixer: FixApplier;\r\n config?: DialogLoopConfig;\r\n onIteration?: (result: IterationResult) => void;\r\n}\r\n\r\nexport async function runDialogLoop(options: DialogLoopOptions): Promise<DialogLoopSummary> {\r\n const cfg = { ...DEFAULTS, ...options.config };\r\n const { runner, parser, fixer } = options;\r\n\r\n const history: IterationResult[] = [];\r\n const errorTracker = new Map<string, number>();\r\n\r\n for (let iteration = 1; iteration <= cfg.maxIterations + 1; iteration++) {\r\n const iterStart = Date.now();\r\n\r\n // Step 1: Run tests\r\n const { stdout } = await runner.run();\r\n\r\n // Step 2: Parse results\r\n const failures = parser.parse(stdout);\r\n const totalTests = parser.countTotal(stdout);\r\n const passed = totalTests - failures.length;\r\n\r\n const iterResult: IterationResult = {\r\n iteration,\r\n totalTests,\r\n passed,\r\n failed: failures.length,\r\n failedTests: failures.map(f => f.title),\r\n fixesApplied: [],\r\n durationMs: 0,\r\n };\r\n\r\n // Step 3: All passed → success\r\n if (failures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 4: Max iterations exceeded\r\n if (iteration > cfg.maxIterations) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 5: Filter out repeated errors beyond threshold\r\n const newFailures = failures.filter(f => {\r\n const key = `${f.title}::${f.error}`;\r\n const count = (errorTracker.get(key) ?? 0) + 1;\r\n errorTracker.set(key, count);\r\n return count <= cfg.sameErrorThreshold;\r\n });\r\n\r\n if (newFailures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 6: Apply controlled fixes\r\n for (const failure of newFailures) {\r\n const outcome = await fixer.apply(failure);\r\n if (outcome.success) {\r\n iterResult.fixesApplied.push(failure.title);\r\n }\r\n }\r\n\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n\r\n // Step 7: If any fixes applied and autoRerun, continue loop\r\n if (iterResult.fixesApplied.length === 0 || !cfg.autoRerunOnFix) {\r\n break;\r\n }\r\n }\r\n\r\n const final = history[history.length - 1];\r\n const totalFixesApplied = history.reduce((sum, h) => sum + h.fixesApplied.length, 0);\r\n\r\n return {\r\n iterations: history,\r\n finalPassed: final?.passed ?? 0,\r\n finalFailed: final?.failed ?? 0,\r\n totalFixesApplied,\r\n success: (final?.failed ?? 1) === 0,\r\n };\r\n}\r\n","/**\r\n * Controlled Fixer — two-phase fix engine with safety guarantees.\r\n *\r\n * Phase A (config-only): backup → validate → fix → dry-run → write → verify → cleanup.\r\n * Phase B (config-and-source): generates a draft PR with the AI-suggested code patch.\r\n *\r\n * All mutations are reversible — failures trigger automatic rollback.\r\n */\r\n\r\nimport { existsSync, copyFileSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type {\r\n FixScope,\r\n ControlledFixOptions,\r\n ControlledFixOutcome,\r\n AIAttributionResult,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface ConfigValidator {\r\n validate(configContent: string): { passed: boolean; errors: string[] };\r\n}\r\n\r\nexport interface ConfigFixer {\r\n fix(configContent: string, errors: string[]): { success: boolean; fixedContent: string; fixedItems: string[]; remainingErrors: string[] };\r\n}\r\n\r\nexport interface PRGenerator {\r\n generate(attribution: AIAttributionResult): Promise<string>;\r\n}\r\n\r\n// ===== FS abstraction (injectable for tests) =====\r\n\r\nexport interface FsOps {\r\n exists(path: string): boolean;\r\n read(path: string): string;\r\n write(path: string, content: string): void;\r\n copy(src: string, dest: string): void;\r\n remove(path: string): void;\r\n mkdirp(dir: string): void;\r\n}\r\n\r\nconst defaultFs: FsOps = {\r\n exists: existsSync,\r\n read: (p) => readFileSync(p, 'utf-8'),\r\n write: (p, c) => { mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, c, 'utf-8'); },\r\n copy: copyFileSync,\r\n remove: unlinkSync,\r\n mkdirp: (d) => mkdirSync(d, { recursive: true }),\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport interface ControlledFixerOptions {\r\n configPath: string;\r\n validator: ConfigValidator;\r\n fixer: ConfigFixer;\r\n prGenerator?: PRGenerator;\r\n attribution?: AIAttributionResult;\r\n fs?: FsOps;\r\n options?: ControlledFixOptions;\r\n}\r\n\r\nexport async function applyControlledFix(opts: ControlledFixerOptions): Promise<ControlledFixOutcome> {\r\n const fs = opts.fs ?? defaultFs;\r\n const scope: FixScope = opts.options?.scope ?? 'config-only';\r\n const dryRun = opts.options?.dryRun ?? true;\r\n const verify = opts.options?.verify ?? true;\r\n const configPath = opts.configPath;\r\n const backupPath = configPath + '.backup';\r\n\r\n // --- Phase A: Config-only fix ---\r\n\r\n // Load config\r\n if (!fs.exists(configPath)) {\r\n return { success: false, scope, fixedItems: [], rolledBack: false, error: `Config file not found: ${configPath}` };\r\n }\r\n\r\n const originalContent = fs.read(configPath);\r\n\r\n // Backup before mutation\r\n fs.write(backupPath, originalContent);\r\n\r\n // Validate current config\r\n const validation = opts.validator.validate(originalContent);\r\n\r\n if (validation.passed) {\r\n // No errors to fix\r\n cleanup(fs, backupPath);\r\n return { success: true, scope, fixedItems: [], rolledBack: false };\r\n }\r\n\r\n // Attempt fix\r\n let fixResult: ReturnType<ConfigFixer['fix']>;\r\n try {\r\n fixResult = opts.fixer.fix(originalContent, validation.errors);\r\n } catch (err) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: [], rolledBack: true, error: `Fix threw: ${err instanceof Error ? err.message : String(err)}` };\r\n }\r\n\r\n if (!fixResult.success) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Remaining errors: ${fixResult.remainingErrors.join('; ')}` };\r\n }\r\n\r\n // Dry-run: validate fixed content before writing\r\n if (dryRun) {\r\n const dryValidation = opts.validator.validate(fixResult.fixedContent);\r\n if (!dryValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Dry-run validation failed: ${dryValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Write fixed content\r\n fs.write(configPath, fixResult.fixedContent);\r\n\r\n // Verify after write\r\n if (verify) {\r\n const reloaded = fs.read(configPath);\r\n const postValidation = opts.validator.validate(reloaded);\r\n if (!postValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Post-write verification failed: ${postValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Phase A success — clean up backup\r\n cleanup(fs, backupPath);\r\n\r\n // --- Phase B: Config-and-source (optional) ---\r\n let prUrl: string | undefined;\r\n if (scope === 'config-and-source' && opts.attribution && opts.prGenerator) {\r\n try {\r\n prUrl = await opts.prGenerator.generate(opts.attribution);\r\n } catch {\r\n // PR generation failure is non-fatal; config fix already succeeded\r\n }\r\n }\r\n\r\n return { success: true, scope, fixedItems: fixResult.fixedItems, rolledBack: false, prUrl };\r\n}\r\n\r\nfunction rollback(fs: FsOps, backupPath: string, configPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n const backup = fs.read(backupPath);\r\n fs.write(configPath, backup);\r\n fs.remove(backupPath);\r\n }\r\n}\r\n\r\nfunction cleanup(fs: FsOps, backupPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n fs.remove(backupPath);\r\n }\r\n}\r\n","/**\r\n * Auto-Fix PR Generator — creates draft PRs from AI attribution results.\r\n *\r\n * Flow: create branch → write patch → git apply → commit → push → gh pr create --draft.\r\n * All PRs are draft-only as a safety invariant.\r\n */\r\n\r\nimport type { AIAttributionResult, AutoFixPROptions, AutoFixPRResult } from '../types.js';\r\n\r\n// ===== Executor abstraction (injectable for tests) =====\r\n\r\nexport interface GitExecutor {\r\n exec(command: string, args: string[]): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface PatchWriter {\r\n write(path: string, content: string): Promise<void>;\r\n mkdir(dir: string): Promise<void>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULT_OPTIONS: Required<AutoFixPROptions> = {\r\n branchPrefix: 'autofix/',\r\n baseBranch: 'main',\r\n draftOnly: true,\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport async function generateFixPR(\r\n attribution: AIAttributionResult,\r\n git: GitExecutor,\r\n patchWriter: PatchWriter,\r\n options?: AutoFixPROptions,\r\n): Promise<AutoFixPRResult> {\r\n const opts = { ...DEFAULT_OPTIONS, ...options };\r\n const ts = new Date().toISOString().replace(/[:.]/g, '-');\r\n const branch = `${opts.branchPrefix}${ts}`;\r\n const patchFile = `report/patch-${ts}.patch`;\r\n\r\n // Create branch\r\n await git.exec('git', ['checkout', '-b', branch]);\r\n\r\n // Write patch\r\n await patchWriter.mkdir('report');\r\n await patchWriter.write(patchFile, attribution.fixSuggestion.codePatch);\r\n\r\n // Apply patch (non-fatal if fails)\r\n try {\r\n await git.exec('git', ['apply', patchFile]);\r\n } catch {\r\n // Patch may not apply cleanly — continue anyway\r\n }\r\n\r\n // Stage, commit, push\r\n await git.exec('git', ['add', '.']);\r\n await git.exec('git', ['commit', '-m', `fix: AI auto-patch for \"${attribution.testName}\"`]);\r\n await git.exec('git', ['push', 'origin', branch]);\r\n\r\n // Create draft PR (always draft for safety)\r\n const prArgs = [\r\n 'pr', 'create', '--draft',\r\n '--title', `[AI Fix] ${attribution.testName}`,\r\n '--body', buildPRBody(attribution),\r\n ];\r\n const { stdout: prUrl } = await git.exec('gh', prArgs);\r\n\r\n // Return to base branch\r\n await git.exec('git', ['checkout', opts.baseBranch]);\r\n\r\n return { prUrl: prUrl.trim(), branch, patchFile };\r\n}\r\n\r\nfunction buildPRBody(a: AIAttributionResult): string {\r\n return [\r\n '## AI Auto-Fix PR',\r\n '',\r\n `**Test:** ${a.testName}`,\r\n `**Category:** ${a.category} | **Severity:** ${a.severity} | **Confidence:** ${(a.confidence * 100).toFixed(0)}%`,\r\n '',\r\n '### Root Cause',\r\n a.rootCause,\r\n '',\r\n '### Fix',\r\n a.fixSuggestion.description,\r\n '',\r\n '---',\r\n '> This PR was auto-generated by AI and **must be reviewed before merging**.',\r\n ].join('\\n');\r\n}\r\n","import type { SelfHealingConfig, SelfHealingResult, FixOutcome, LlmProvider } from '../types.js';\r\nimport { SYSTEM_PROMPTS } from '../llm/index.js';\r\n\r\nexport type { SelfHealingResult, FixOutcome };\r\n\r\n// Advanced Self-Healing (v1.1)\r\nexport { runDialogLoop, createJsonResultParser } from './dialog-loop-runner.js';\r\nexport type { TestRunner, ResultParser, FixApplier, DialogLoopOptions } from './dialog-loop-runner.js';\r\nexport { applyControlledFix } from './controlled-fixer.js';\r\nexport type { ConfigValidator, ConfigFixer, PRGenerator, FsOps, ControlledFixerOptions } from './controlled-fixer.js';\r\nexport { generateFixPR } from './auto-fix-generator.js';\r\nexport type { GitExecutor, PatchWriter } from './auto-fix-generator.js';\r\n\r\nexport interface SelfHealingLoop {\r\n run(testResultsDir: string): Promise<SelfHealingResult>;\r\n}\r\n\r\nexport interface SelfHealingOptions {\r\n config: SelfHealingConfig;\r\n llm?: LlmProvider;\r\n}\r\n\r\n/**\r\n * Categorize a test failure by heuristic rules.\r\n */\r\nexport function categorizeFailure(errorMessage: string): {\r\n category: string;\r\n confidence: number;\r\n} {\r\n const msg = errorMessage.toLowerCase();\r\n\r\n if (/5\\d{2}|internal server error/.test(msg))\r\n return { category: 'backend-5xx', confidence: 0.9 };\r\n if (/timeout|timed?\\s*out/.test(msg))\r\n return { category: 'timeout', confidence: 0.8 };\r\n if (/404|not found/.test(msg))\r\n return { category: 'endpoint-not-found', confidence: 0.85 };\r\n if (/4[0-2]\\d|validation|constraint/.test(msg))\r\n return { category: 'data-constraint', confidence: 0.75 };\r\n if (/econnrefused|enotfound|network/.test(msg))\r\n return { category: 'network', confidence: 0.9 };\r\n if (/selector|locator|element/.test(msg))\r\n return { category: 'frontend-render', confidence: 0.7 };\r\n if (/storage\\s*state|auth|login/.test(msg))\r\n return { category: 'test-script', confidence: 0.8 };\r\n\r\n return { category: 'unknown', confidence: 0.5 };\r\n}\r\n\r\n/**\r\n * LLM-enhanced failure analysis with heuristic fallback.\r\n */\r\nexport async function analyzeFailureWithLLM(\r\n errorMessage: string,\r\n llm?: LlmProvider,\r\n): Promise<{ rootCause: string; category: string; suggestedFix: string; confidence: number }> {\r\n // Always get heuristic result as fallback\r\n const heuristic = categorizeFailure(errorMessage);\r\n\r\n if (!llm) {\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n\r\n try {\r\n const response = await llm.chat([\r\n { role: 'system', content: SYSTEM_PROMPTS.failureAnalysis },\r\n { role: 'user', content: `Analyze this test failure:\\n\\n${errorMessage}` },\r\n ]);\r\n\r\n const parsed = JSON.parse(response) as {\r\n rootCause?: string;\r\n category?: string;\r\n suggestedFix?: string;\r\n confidence?: number;\r\n };\r\n\r\n return {\r\n rootCause: parsed.rootCause || errorMessage,\r\n category: parsed.category || heuristic.category,\r\n suggestedFix: parsed.suggestedFix || '',\r\n confidence: parsed.confidence || heuristic.confidence,\r\n };\r\n } catch {\r\n // LLM failed — fall back to heuristic\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Attempt a config-only fix: validate and write corrected config JSON.\r\n */\r\nasync function attemptConfigFix(\r\n _testResultsDir: string,\r\n _mode: SelfHealingConfig['mode'],\r\n _llm?: LlmProvider,\r\n): Promise<FixOutcome> {\r\n // TODO: Load module config → run autoFix validation → write corrected JSON\r\n // For now, return a no-op outcome\r\n return {\r\n success: false,\r\n scope: 'config-only',\r\n fixedItems: [],\r\n rolledBack: false,\r\n };\r\n}\r\n\r\n/**\r\n * Create a self-healing loop. Accepts an optional LLM provider for AI-enhanced analysis.\r\n */\r\nexport function createSelfHealingLoop(config: SelfHealingConfig, llm?: LlmProvider): SelfHealingLoop {\r\n return {\r\n async run(testResultsDir: string): Promise<SelfHealingResult> {\r\n const maxIterations = config.maxIterations || 3;\r\n const mode = config.mode || 'config-only';\r\n const fixed: string[] = [];\r\n const remaining: string[] = [];\r\n let iterations = 0;\r\n let totalTokensUsed = 0;\r\n\r\n for (let i = 0; i < maxIterations; i++) {\r\n iterations = i + 1;\r\n\r\n const outcome = await attemptConfigFix(testResultsDir, mode, llm);\r\n if (outcome.success) {\r\n fixed.push(...outcome.fixedItems);\r\n } else {\r\n remaining.push(`iteration-${i + 1}: no fix applied`);\r\n }\r\n\r\n // Track token usage if LLM is available\r\n if (llm) {\r\n totalTokensUsed += llm.estimateTokens(`iteration-${i + 1}`);\r\n }\r\n\r\n // If all fixed, stop early\r\n if (outcome.success && outcome.fixedItems.length > 0) break;\r\n }\r\n\r\n return {\r\n iterations,\r\n fixed,\r\n remaining,\r\n totalTokensUsed,\r\n };\r\n },\r\n };\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createSelfHealingLoop } from '../../self-healing/index.js';\r\nimport type { SelfHealingConfig } from '../../types.js';\r\n\r\nexport interface HealOptions {\r\n module?: string;\r\n maxIterations?: string;\r\n}\r\n\r\nexport async function heal(opts: HealOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Self-Healing\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const maxIterations = opts.maxIterations ? parseInt(opts.maxIterations, 10) : 3;\r\n\r\n const healingConfig: SelfHealingConfig = {\r\n enabled: true,\r\n maxIterations,\r\n mode: config.selfHealing?.mode || 'config-only',\r\n };\r\n\r\n console.log(chalk.gray(` Mode: ${healingConfig.mode}`));\r\n console.log(chalk.gray(` Max iterations: ${maxIterations}`));\r\n\r\n if (opts.module) {\r\n console.log(chalk.gray(` Module: ${opts.module}`));\r\n }\r\n console.log('');\r\n\r\n const loop = createSelfHealingLoop(healingConfig);\r\n const result = await loop.run(outDir);\r\n\r\n // Report results\r\n console.log(chalk.cyan(' Results:'));\r\n console.log(` Iterations : ${result.iterations}`);\r\n console.log(` Fixed : ${result.fixed.length > 0 ? chalk.green(result.fixed.join(', ')) : chalk.gray('(none)')}`);\r\n console.log(` Remaining : ${result.remaining.length > 0 ? chalk.yellow(result.remaining.join(', ')) : chalk.gray('(none)')}`);\r\n if (result.totalTokensUsed > 0) {\r\n console.log(` Tokens used : ${result.totalTokensUsed}`);\r\n }\r\n\r\n console.log('');\r\n\r\n if (result.remaining.length > 0) {\r\n console.log(chalk.yellow(' Some issues could not be auto-fixed. Manual review needed.\\n'));\r\n } else if (result.fixed.length > 0) {\r\n console.log(chalk.green(' ✓ All issues resolved.\\n'));\r\n } else {\r\n console.log(chalk.gray(' No issues detected.\\n'));\r\n }\r\n}\r\n","/**\r\n * CI template generators for popular CI/CD platforms.\r\n *\r\n * Usage:\r\n * npx opencroc ci --platform=github\r\n * npx opencroc ci --platform=gitlab\r\n */\r\n\r\nexport interface CiTemplateOptions {\r\n /** Node.js version(s). Default: ['20.x'] */\r\n nodeVersions?: string[];\r\n /** Install command. Default: 'npm ci' */\r\n installCommand?: string;\r\n /** Whether to run self-healing. Default: false */\r\n selfHeal?: boolean;\r\n /** Custom opencroc generate args */\r\n generateArgs?: string;\r\n /** Custom opencroc test args */\r\n testArgs?: string;\r\n}\r\n\r\nexport function generateGitHubActionsTemplate(opts: CiTemplateOptions = {}): string {\r\n const nodeVersions = opts.nodeVersions ?? ['20.x'];\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const healStep = opts.selfHeal\r\n ? `\r\n - name: Self-heal failures\r\n if: failure()\r\n run: npx opencroc heal --max-iterations 3`\r\n : '';\r\n\r\n const matrix =\r\n nodeVersions.length > 1\r\n ? `\r\n strategy:\r\n matrix:\r\n node-version: [${nodeVersions.join(', ')}]`\r\n : '';\r\n\r\n const nodeSetup =\r\n nodeVersions.length > 1\r\n ? '${{ matrix.node-version }}'\r\n : nodeVersions[0];\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nname: OpenCroc E2E\r\n\r\non:\r\n push:\r\n branches: [main]\r\n pull_request:\r\n branches: [main]\r\n\r\njobs:\r\n e2e:\r\n runs-on: ubuntu-latest${matrix}\r\n steps:\r\n - uses: actions/checkout@v4\r\n\r\n - uses: actions/setup-node@v4\r\n with:\r\n node-version: '${nodeSetup}'\r\n\r\n - name: Install dependencies\r\n run: ${install}\r\n\r\n - name: Install Playwright browsers\r\n run: npx playwright install --with-deps chromium\r\n\r\n - name: Generate E2E tests\r\n run: npx opencroc generate ${genArgs}\r\n\r\n - name: Run E2E tests\r\n run: npx opencroc test ${testArgs}\r\n${healStep}\r\n - name: Upload test report\r\n if: always()\r\n uses: actions/upload-artifact@v4\r\n with:\r\n name: opencroc-report\r\n path: opencroc-output/\r\n retention-days: 14\r\n`;\r\n}\r\n\r\nexport function generateGitLabCITemplate(opts: CiTemplateOptions = {}): string {\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const nodeVersion = opts.nodeVersions?.[0] ?? '20';\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nimage: node:${nodeVersion}\r\n\r\nstages:\r\n - generate\r\n - test\r\n\r\nvariables:\r\n PLAYWRIGHT_BROWSERS_PATH: \\${CI_PROJECT_DIR}/.cache/ms-playwright\r\n\r\ncache:\r\n key: \\${CI_COMMIT_REF_SLUG}\r\n paths:\r\n - node_modules/\r\n - .cache/ms-playwright/\r\n\r\ngenerate:\r\n stage: generate\r\n script:\r\n - ${install}\r\n - npx opencroc generate ${genArgs}\r\n artifacts:\r\n paths:\r\n - opencroc-output/\r\n expire_in: 1 day\r\n\r\ne2e:\r\n stage: test\r\n needs: [generate]\r\n before_script:\r\n - ${install}\r\n - npx playwright install --with-deps chromium\r\n script:\r\n - npx opencroc test ${testArgs}\r\n artifacts:\r\n when: always\r\n paths:\r\n - opencroc-output/\r\n expire_in: 14 days\r\n`;\r\n}\r\n\r\nconst TEMPLATES: Record<string, (opts: CiTemplateOptions) => string> = {\r\n github: generateGitHubActionsTemplate,\r\n gitlab: generateGitLabCITemplate,\r\n};\r\n\r\n/**\r\n * Get available CI platform names.\r\n */\r\nexport function listCiPlatforms(): string[] {\r\n return Object.keys(TEMPLATES);\r\n}\r\n\r\n/**\r\n * Generate a CI template for the given platform.\r\n */\r\nexport function generateCiTemplate(\r\n platform: string,\r\n opts: CiTemplateOptions = {},\r\n): string {\r\n const generator = TEMPLATES[platform];\r\n if (!generator) {\r\n throw new Error(\r\n `Unknown CI platform: \"${platform}\". Available: ${Object.keys(TEMPLATES).join(', ')}`,\r\n );\r\n }\r\n return generator(opts);\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport chalk from 'chalk';\r\nimport { generateCiTemplate, listCiPlatforms } from '../../ci/index.js';\r\nimport type { CiTemplateOptions } from '../../ci/index.js';\r\n\r\nexport interface CiCommandOptions {\r\n platform?: string;\r\n selfHeal?: boolean;\r\n node?: string;\r\n}\r\n\r\nexport async function ci(opts: CiCommandOptions): Promise<void> {\r\n const platform = opts.platform ?? 'github';\r\n const available = listCiPlatforms();\r\n\r\n if (!available.includes(platform)) {\r\n console.error(chalk.red(`Unknown platform: \"${platform}\". Available: ${available.join(', ')}`));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const templateOpts: CiTemplateOptions = {\r\n selfHeal: opts.selfHeal ?? false,\r\n };\r\n if (opts.node) {\r\n templateOpts.nodeVersions = opts.node.split(',').map((s) => s.trim());\r\n }\r\n\r\n const content = generateCiTemplate(platform, templateOpts);\r\n\r\n let outputPath: string;\r\n if (platform === 'github') {\r\n outputPath = path.join('.github', 'workflows', 'opencroc.yml');\r\n } else if (platform === 'gitlab') {\r\n outputPath = '.gitlab-ci.yml';\r\n } else {\r\n outputPath = `opencroc-ci-${platform}.yml`;\r\n }\r\n\r\n const dir = path.dirname(outputPath);\r\n if (dir !== '.' && !fs.existsSync(dir)) {\r\n fs.mkdirSync(dir, { recursive: true });\r\n }\r\n\r\n fs.writeFileSync(outputPath, content, 'utf-8');\r\n console.log(chalk.green(`✔ CI template written to ${outputPath}`));\r\n console.log(chalk.dim(` Platform: ${platform}`));\r\n}\r\n","/**\r\n * Checklist Reporter — generates backend fix checklists from test results.\r\n *\r\n * Groups failures by API domain, lists affected tests and endpoints,\r\n * and produces both structured data and Markdown output.\r\n */\r\n\r\nimport type {\r\n TestResultRecord,\r\n FailureCategory,\r\n FailureSummary,\r\n BackendDomainItem,\r\n LogCompletionSummary,\r\n} from '../types.js';\r\n\r\n// ===== Failure classification =====\r\n\r\nexport function classifyFailure(error?: string): FailureCategory {\r\n if (!error) return 'other';\r\n if (error.includes('[BACKEND_5XX]')) return 'backend-5xx';\r\n if (error.includes('[MIXED_5XX]')) return 'mixed-5xx';\r\n if (error.includes('[SLOW_API_FATAL]')) return 'slow-api';\r\n if (error.includes('[LOG_COMPLETION_FAIL]')) return 'log-fail';\r\n if (error.includes('[LOG_COMPLETION_TIMEOUT]')) return 'log-timeout';\r\n if (/waitForSelector|toHaveURL|Timeout/i.test(error)) return 'frontend-load';\r\n return 'other';\r\n}\r\n\r\n// ===== Failure summary =====\r\n\r\nexport function buildFailureSummary(records: TestResultRecord[]): FailureSummary {\r\n const failed = records.filter(r => r.status === 'failed');\r\n const cats = failed.map(r => classifyFailure(r.error));\r\n return {\r\n totalFailed: failed.length,\r\n backend5xx: cats.filter(c => c === 'backend-5xx').length,\r\n mixed5xx: cats.filter(c => c === 'mixed-5xx').length,\r\n slowApi: cats.filter(c => c === 'slow-api').length,\r\n logFail: cats.filter(c => c === 'log-fail').length,\r\n logTimeout: cats.filter(c => c === 'log-timeout').length,\r\n frontendLoad: cats.filter(c => c === 'frontend-load').length,\r\n other: cats.filter(c => c === 'other').length,\r\n };\r\n}\r\n\r\n// ===== Log completion aggregation =====\r\n\r\nexport function aggregateLogCompletion(records: TestResultRecord[]): LogCompletionSummary {\r\n let totalCandidates = 0;\r\n let succeeded = 0;\r\n let failed = 0;\r\n let timedOut = 0;\r\n const timedOutFreq = new Map<string, { method: string; path: string; count: number }>();\r\n\r\n for (const r of records) {\r\n const lc = r.logCompletion;\r\n if (!lc || lc.candidateCount === 0) continue;\r\n\r\n totalCandidates += lc.candidateCount;\r\n succeeded += lc.succeeded.length;\r\n failed += lc.failed.length;\r\n timedOut += lc.timedOut.length;\r\n\r\n for (const item of lc.timedOut) {\r\n const key = `${item.method}:${item.path}`;\r\n const existing = timedOutFreq.get(key);\r\n if (existing) existing.count += 1;\r\n else timedOutFreq.set(key, { method: item.method, path: item.path, count: 1 });\r\n }\r\n }\r\n\r\n const timedOutTop5 = Array.from(timedOutFreq.values())\r\n .sort((a, b) => b.count - a.count)\r\n .slice(0, 5)\r\n .map(t => ({ method: t.method, path: t.path, occurrences: t.count }));\r\n\r\n const matchRate = totalCandidates > 0 ? (succeeded + failed) / totalCandidates * 100 : 0;\r\n const effectiveRate = totalCandidates > 0 ? succeeded / totalCandidates * 100 : 0;\r\n\r\n return { totalCandidates, succeeded, failed, timedOut, matchRate, effectiveRate, timedOutTop5 };\r\n}\r\n\r\n// ===== URL extraction helpers =====\r\n\r\nfunction extractUrls(error?: string): string[] {\r\n if (!error) return [];\r\n const matched = error.match(/https?:\\/\\/[^\\s\\n]+/g);\r\n return matched ? Array.from(new Set(matched)) : [];\r\n}\r\n\r\nexport function parseApiDomain(urlStr: string): string | null {\r\n try {\r\n const u = new URL(urlStr);\r\n const segments = u.pathname.split('/').filter(Boolean);\r\n const v1Index = segments.findIndex(s => s === 'v1');\r\n if (v1Index === -1 || v1Index + 1 >= segments.length) return segments[0] || null;\r\n const afterV1 = segments.slice(v1Index + 1);\r\n if (afterV1.length === 0) return null;\r\n const first = afterV1[0];\r\n if (/^\\d+$/.test(first) && afterV1.length > 1) return afterV1[1];\r\n return first;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ===== Backend checklist =====\r\n\r\nexport function buildBackendChecklist(records: TestResultRecord[]): BackendDomainItem[] {\r\n const domainMap = new Map<string, { tests: Set<string>; endpoints: Set<string> }>();\r\n const failed = records.filter(r => r.status === 'failed');\r\n\r\n for (const item of failed) {\r\n const cat = classifyFailure(item.error);\r\n if (cat !== 'backend-5xx' && cat !== 'mixed-5xx') continue;\r\n const urls = extractUrls(item.error);\r\n for (const url of urls) {\r\n const domain = parseApiDomain(url);\r\n if (!domain) continue;\r\n const current = domainMap.get(domain) ?? { tests: new Set<string>(), endpoints: new Set<string>() };\r\n current.tests.add(item.title);\r\n current.endpoints.add(url);\r\n domainMap.set(domain, current);\r\n }\r\n }\r\n\r\n return Array.from(domainMap.entries())\r\n .map(([domain, v]) => ({\r\n domain,\r\n tests: Array.from(v.tests).sort(),\r\n endpoints: Array.from(v.endpoints).sort(),\r\n }))\r\n .sort((a, b) => b.tests.length - a.tests.length || a.domain.localeCompare(b.domain));\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderChecklistMarkdown(\r\n items: BackendDomainItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Fix Checklist',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}% (candidates=${logSummary.totalCandidates}, succeeded=${logSummary.succeeded}, failed=${logSummary.failed}, timedOut=${logSummary.timedOut})`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (logSummary && logSummary.timedOutTop5.length > 0) {\r\n lines.push('### Timed-out APIs Top 5', '', '| # | Method | Path | Occurrences |', '|---|--------|------|-------------|');\r\n logSummary.timedOutTop5.forEach((t, i) => {\r\n lines.push(`| ${i + 1} | ${t.method} | ${t.path} | ${t.occurrences} |`);\r\n });\r\n lines.push('');\r\n }\r\n\r\n if (items.length === 0) {\r\n lines.push('No backend 5xx failures this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const item of items) {\r\n lines.push(\r\n `## ${item.domain}`,\r\n '',\r\n `- Failed tests: ${item.tests.length}`,\r\n '- Affected tests:',\r\n );\r\n for (const t of item.tests) lines.push(` - ${t}`);\r\n lines.push('- Failed endpoints:');\r\n for (const e of item.endpoints) lines.push(` - ${e}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Workorder Reporter — auto-generates prioritized backend work orders.\r\n *\r\n * Priority rules:\r\n * - P0: ≥3 affected tests OR log completion rate < 90%\r\n * - P1: 2 affected tests\r\n * - P2: 1 affected test\r\n *\r\n * Each workorder includes objective, affected scope, and acceptance criteria.\r\n */\r\n\r\nimport type {\r\n BackendDomainItem,\r\n FailureSummary,\r\n LogCompletionSummary,\r\n WorkorderItem,\r\n} from '../types.js';\r\n\r\n// ===== Priority assignment =====\r\n\r\nfunction assignPriority(item: BackendDomainItem, isLogRate: boolean): 'P0' | 'P1' | 'P2' {\r\n if (isLogRate) return 'P0';\r\n if (item.tests.length >= 3) return 'P0';\r\n if (item.tests.length === 2) return 'P1';\r\n return 'P2';\r\n}\r\n\r\n// ===== Workorder builder =====\r\n\r\nexport interface BuildWorkordersOptions {\r\n checklist: BackendDomainItem[];\r\n summary: FailureSummary;\r\n logSummary?: LogCompletionSummary;\r\n logRateThreshold?: number;\r\n}\r\n\r\nexport function buildWorkorders(opts: BuildWorkordersOptions): WorkorderItem[] {\r\n const { checklist, logSummary, logRateThreshold = 90 } = opts;\r\n const result: WorkorderItem[] = [];\r\n let idx = 1;\r\n\r\n // Auto P0 workorder if log completion rate is below threshold\r\n if (logSummary && logSummary.totalCandidates > 0 && logSummary.matchRate < logRateThreshold) {\r\n const logItem: BackendDomainItem = {\r\n domain: 'Log Completion Standards',\r\n tests: logSummary.timedOutTop5.map(t => `${t.method} ${t.path} (×${t.occurrences})`),\r\n endpoints: logSummary.timedOutTop5.map(t => t.path),\r\n };\r\n result.push({\r\n index: idx++,\r\n domain: logItem.domain,\r\n priority: 'P0',\r\n tests: logItem.tests,\r\n endpoints: logItem.endpoints,\r\n objective: 'Add missing end-phase structured logs for timed-out APIs',\r\n acceptanceCriteria: [\r\n `Log completion match rate ≥ ${logRateThreshold}%`,\r\n 'TimedOut API count drops to 0 or only SSE/long-polling endpoints remain',\r\n ],\r\n });\r\n }\r\n\r\n // Standard workorders from checklist\r\n for (const item of checklist) {\r\n const priority = assignPriority(item, false);\r\n result.push({\r\n index: idx++,\r\n domain: item.domain,\r\n priority,\r\n tests: item.tests,\r\n endpoints: item.endpoints,\r\n objective: 'Fix 500 errors and return a valid business response',\r\n acceptanceCriteria: [\r\n 'HTTP status returns 2xx for affected endpoints',\r\n 'No [BACKEND_5XX] errors in corresponding page traversal',\r\n 'All covered tests pass',\r\n ],\r\n });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderWorkordersMarkdown(\r\n workorders: WorkorderItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Work Orders',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}%`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Total failed: ${summary.totalFailed}`,\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (workorders.length === 0) {\r\n lines.push('No backend work orders this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const wo of workorders) {\r\n lines.push(\r\n `## Workorder ${wo.index} - ${wo.domain}`,\r\n '',\r\n `- Priority: ${wo.priority}`,\r\n `- Affected tests: ${wo.tests.length}`,\r\n '- Scope:',\r\n );\r\n for (const t of wo.tests) lines.push(` - ${t}`);\r\n if (wo.endpoints.length > 0) {\r\n lines.push('- Endpoints:');\r\n for (const e of wo.endpoints) lines.push(` - ${e}`);\r\n }\r\n lines.push(`- Objective: ${wo.objective}`);\r\n lines.push('- Acceptance criteria:');\r\n for (const c of wo.acceptanceCriteria) lines.push(` - ${c}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Token Usage Reporter — tracks and reports LLM token consumption.\r\n *\r\n * Aggregates usage entries by category and model, computes costs,\r\n * tracks budget utilization, and renders both structured data and Markdown.\r\n */\r\n\r\nimport type { TokenUsageEntry, TokenUsageSummary } from '../types.js';\r\n\r\n// ===== Token Tracker =====\r\n\r\nexport class TokenTracker {\r\n private entries: TokenUsageEntry[] = [];\r\n private budget: number | null = null;\r\n\r\n setBudget(maxTokens: number): void {\r\n this.budget = maxTokens;\r\n }\r\n\r\n record(entry: TokenUsageEntry): void {\r\n this.entries.push(entry);\r\n }\r\n\r\n reset(): void {\r\n this.entries = [];\r\n }\r\n\r\n getSummary(): TokenUsageSummary {\r\n const totalRequests = this.entries.length;\r\n let totalPromptTokens = 0;\r\n let totalCompletionTokens = 0;\r\n let totalEstimatedCost = 0;\r\n let totalLatency = 0;\r\n\r\n const byCategory: TokenUsageSummary['byCategory'] = {};\r\n const byModel: TokenUsageSummary['byModel'] = {};\r\n\r\n for (const e of this.entries) {\r\n totalPromptTokens += e.promptTokens;\r\n totalCompletionTokens += e.completionTokens;\r\n totalEstimatedCost += e.estimatedCost;\r\n totalLatency += e.latencyMs;\r\n\r\n // By category\r\n if (!byCategory[e.category]) {\r\n byCategory[e.category] = { requests: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const cat = byCategory[e.category];\r\n cat.requests++;\r\n cat.promptTokens += e.promptTokens;\r\n cat.completionTokens += e.completionTokens;\r\n cat.totalTokens += e.promptTokens + e.completionTokens;\r\n cat.estimatedCost += e.estimatedCost;\r\n\r\n // By model\r\n if (!byModel[e.model]) {\r\n byModel[e.model] = { requests: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const mod = byModel[e.model];\r\n mod.requests++;\r\n mod.totalTokens += e.promptTokens + e.completionTokens;\r\n mod.estimatedCost += e.estimatedCost;\r\n }\r\n\r\n const totalTokens = totalPromptTokens + totalCompletionTokens;\r\n const budgetUsedPercent = this.budget && this.budget > 0\r\n ? Math.round(totalTokens / this.budget * 10000) / 100\r\n : null;\r\n\r\n return {\r\n totalRequests,\r\n totalTokens,\r\n totalPromptTokens,\r\n totalCompletionTokens,\r\n totalEstimatedCost,\r\n avgLatencyMs: totalRequests > 0 ? Math.round(totalLatency / totalRequests) : 0,\r\n byCategory,\r\n byModel,\r\n budgetUsedPercent,\r\n budgetExceeded: budgetUsedPercent !== null && budgetUsedPercent > 100,\r\n };\r\n }\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderTokenReportMarkdown(summary: TokenUsageSummary): string {\r\n const lines: string[] = [\r\n '# AI Token Usage Report',\r\n '',\r\n `- Total requests: ${summary.totalRequests}`,\r\n `- Total tokens: ${summary.totalTokens.toLocaleString()}`,\r\n `- Prompt tokens: ${summary.totalPromptTokens.toLocaleString()}`,\r\n `- Completion tokens: ${summary.totalCompletionTokens.toLocaleString()}`,\r\n `- Estimated cost: ¥${summary.totalEstimatedCost.toFixed(4)}`,\r\n `- Average latency: ${summary.avgLatencyMs}ms`,\r\n ];\r\n\r\n if (summary.budgetUsedPercent !== null) {\r\n lines.push(`- Budget used: ${summary.budgetUsedPercent}%${summary.budgetExceeded ? ' **EXCEEDED**' : ''}`);\r\n }\r\n lines.push('');\r\n\r\n // By category\r\n const cats = Object.entries(summary.byCategory).sort((a, b) => b[1].totalTokens - a[1].totalTokens);\r\n if (cats.length > 0) {\r\n lines.push(\r\n '## By Category',\r\n '',\r\n '| Category | Requests | Prompt | Completion | Total | Cost |',\r\n '|----------|----------|--------|------------|-------|------|',\r\n );\r\n for (const [cat, d] of cats) {\r\n lines.push(`| ${cat} | ${d.requests} | ${d.promptTokens.toLocaleString()} | ${d.completionTokens.toLocaleString()} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // By model\r\n const models = Object.entries(summary.byModel);\r\n if (models.length > 0) {\r\n lines.push(\r\n '## By Model',\r\n '',\r\n '| Model | Requests | Total Tokens | Cost |',\r\n '|-------|----------|-------------|------|',\r\n );\r\n for (const [model, d] of models) {\r\n lines.push(`| ${model} | ${d.requests} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","import type {\r\n PipelineRunResult,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n GeneratedTestFile,\r\n ValidationError,\r\n ExecutionMetrics,\r\n} from '../types.js';\r\nimport type { ExecutionQualityGateResult } from '../execution/types.js';\r\n\r\n// ===== Reporter Types =====\r\n\r\nexport interface ReportOutput {\r\n format: 'html' | 'json' | 'markdown';\r\n content: string;\r\n filename: string;\r\n}\r\n\r\nexport interface ReportExecutionContext {\r\n metrics?: ExecutionMetrics | null;\r\n quality?: ExecutionQualityGateResult | null;\r\n}\r\n\r\n// ===== JSON Reporter =====\r\n\r\nexport function generateJsonReport(\r\n result: PipelineRunResult,\r\n context?: ReportExecutionContext,\r\n): ReportOutput {\r\n const serializable = {\r\n modules: result.modules,\r\n erDiagrams: Object.fromEntries(\r\n Array.from(result.erDiagrams.entries()).map(([k, v]) => [\r\n k,\r\n { tables: v.tables.length, relations: v.relations.length, mermaidText: v.mermaidText },\r\n ]),\r\n ),\r\n chainPlans: Object.fromEntries(\r\n Array.from(result.chainPlans.entries()).map(([k, v]) => [\r\n k,\r\n { chains: v.chains.length, totalSteps: v.totalSteps },\r\n ]),\r\n ),\r\n generatedFiles: result.generatedFiles.map((f) => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n })),\r\n execution: context\r\n ? {\r\n metrics: context.metrics ?? null,\r\n quality: context.quality ?? null,\r\n }\r\n : undefined,\r\n validationErrors: result.validationErrors,\r\n duration: result.duration,\r\n };\r\n\r\n return {\r\n format: 'json',\r\n content: JSON.stringify(serializable, null, 2),\r\n filename: 'opencroc-report.json',\r\n };\r\n}\r\n\r\n// ===== Markdown Reporter =====\r\n\r\nexport function generateMarkdownReport(\r\n result: PipelineRunResult,\r\n context?: ReportExecutionContext,\r\n): ReportOutput {\r\n const lines: string[] = [\r\n '# OpenCroc Report',\r\n '',\r\n `**Duration**: ${result.duration}ms`,\r\n `**Modules**: ${result.modules.length} (${result.modules.join(', ')})`,\r\n '',\r\n '## ER Diagrams',\r\n '',\r\n ];\r\n\r\n for (const [mod, er] of result.erDiagrams) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Tables: ${er.tables.length}`);\r\n lines.push(`- Relations: ${er.relations.length}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push('## Chain Plans', '');\r\n for (const [mod, plan] of result.chainPlans) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Chains: ${plan.chains.length}`);\r\n lines.push(`- Total Steps: ${plan.totalSteps}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(`## Generated Files (${result.generatedFiles.length})`, '');\r\n for (const f of result.generatedFiles) {\r\n lines.push(`- \\`${f.filePath}\\` (${f.module} / ${f.chain})`);\r\n }\r\n\r\n if (result.validationErrors.length > 0) {\r\n lines.push('', '## Validation Issues', '');\r\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\r\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\r\n if (errors.length > 0) {\r\n lines.push(`### Errors (${errors.length})`, '');\r\n for (const e of errors) {\r\n lines.push(`- **[${e.module}]** ${e.field}: ${e.message}`);\r\n }\r\n }\r\n if (warnings.length > 0) {\r\n lines.push(`### Warnings (${warnings.length})`, '');\r\n for (const w of warnings) {\r\n lines.push(`- **[${w.module}]** ${w.field}: ${w.message}`);\r\n }\r\n }\r\n }\r\n\r\n if (context?.metrics || context?.quality) {\r\n lines.push('', '## Execution Quality', '');\r\n if (context.metrics) {\r\n lines.push(\r\n `- Passed: ${context.metrics.passed}`,\r\n `- Failed: ${context.metrics.failed}`,\r\n `- Skipped: ${context.metrics.skipped}`,\r\n `- TimedOut: ${context.metrics.timedOut}`,\r\n );\r\n }\r\n if (context.quality) {\r\n lines.push(\r\n `- Gate Level: ${context.quality.level}`,\r\n `- Setup Fail: ${context.quality.setupFail}`,\r\n `- Skip Ratio: ${(context.quality.skipRatio * 100).toFixed(2)}%`,\r\n `- Auth Fail Ratio: ${(context.quality.authFailRatio * 100).toFixed(2)}%`,\r\n `- Effective Execution Rate: ${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%`,\r\n `- Auth Status: ${context.quality.authStatus}`,\r\n `- Backend Status: ${context.quality.backendStatus}`,\r\n );\r\n if (context.quality.reasons.length > 0) {\r\n lines.push(`- Reasons: ${context.quality.reasons.join(', ')}`);\r\n }\r\n }\r\n }\r\n\r\n lines.push('', '---', '*Generated by [OpenCroc](https://github.com/opencroc/opencroc)*');\r\n\r\n return {\r\n format: 'markdown',\r\n content: lines.join('\\n'),\r\n filename: 'opencroc-report.md',\r\n };\r\n}\r\n\r\n// ===== HTML Reporter =====\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n\r\nfunction erSummaryRows(erDiagrams: Map<string, ERDiagramResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, er] of erDiagrams) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${er.tables.length}</td><td>${er.relations.length}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction chainSummaryRows(chainPlans: Map<string, ChainPlanResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, plan] of chainPlans) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${plan.chains.length}</td><td>${plan.totalSteps}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction fileListRows(files: GeneratedTestFile[]): string {\r\n return files\r\n .map((f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`)\r\n .join('\\n');\r\n}\r\n\r\nfunction validationRows(errors: ValidationError[]): string {\r\n return errors\r\n .map(\r\n (e) =>\r\n `<tr class=\"${e.severity}\"><td><span class=\"badge ${e.severity}\">${e.severity}</span></td><td>${escapeHtml(e.module)}</td><td>${escapeHtml(e.field)}</td><td>${escapeHtml(e.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n}\r\n\r\nexport function generateHtmlReport(\r\n result: PipelineRunResult,\r\n context?: ReportExecutionContext,\r\n): ReportOutput {\r\n const totalTables = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.tables.length, 0);\r\n const totalRelations = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.relations.length, 0);\r\n const totalChains = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.chains.length, 0);\r\n const totalSteps = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.totalSteps, 0);\r\n const errorCount = result.validationErrors.filter((e) => e.severity === 'error').length;\r\n const warnCount = result.validationErrors.filter((e) => e.severity === 'warning').length;\r\n\r\n const html = `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\" />\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n<title>OpenCroc Report</title>\r\n<style>\r\n :root { --bg: #0d1117; --fg: #c9d1d9; --card: #161b22; --border: #30363d; --accent: #58a6ff; --green: #3fb950; --yellow: #d29922; --red: #f85149; }\r\n * { box-sizing: border-box; margin: 0; padding: 0; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--fg); padding: 2rem; }\r\n h1 { color: var(--accent); margin-bottom: 0.25rem; }\r\n .subtitle { color: #8b949e; margin-bottom: 2rem; }\r\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\r\n .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }\r\n .card .label { font-size: 0.85rem; color: #8b949e; }\r\n .card .value { font-size: 2rem; font-weight: 700; color: var(--accent); }\r\n .card .value.green { color: var(--green); }\r\n .card .value.yellow { color: var(--yellow); }\r\n .card .value.red { color: var(--red); }\r\n section { margin-bottom: 2rem; }\r\n h2 { color: var(--fg); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }\r\n table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 8px; overflow: hidden; }\r\n th, td { text-align: left; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }\r\n th { background: #21262d; color: #8b949e; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; }\r\n tr:last-child td { border-bottom: none; }\r\n code { background: #21262d; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; }\r\n .badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }\r\n .badge.error { background: rgba(248,81,73,0.15); color: var(--red); }\r\n .badge.warning { background: rgba(210,153,34,0.15); color: var(--yellow); }\r\n footer { margin-top: 3rem; text-align: center; color: #484f58; font-size: 0.85rem; }\r\n footer a { color: var(--accent); text-decoration: none; }\r\n</style>\r\n</head>\r\n<body>\r\n<h1>OpenCroc Report</h1>\r\n<p class=\"subtitle\">Generated in ${result.duration}ms · ${result.modules.length} module(s)</p>\r\n\r\n<div class=\"grid\">\r\n <div class=\"card\"><div class=\"label\">Modules</div><div class=\"value\">${result.modules.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Tables</div><div class=\"value\">${totalTables}</div></div>\r\n <div class=\"card\"><div class=\"label\">Relations</div><div class=\"value\">${totalRelations}</div></div>\r\n <div class=\"card\"><div class=\"label\">Chains</div><div class=\"value\">${totalChains}</div></div>\r\n <div class=\"card\"><div class=\"label\">Steps</div><div class=\"value\">${totalSteps}</div></div>\r\n <div class=\"card\"><div class=\"label\">Files</div><div class=\"value green\">${result.generatedFiles.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Errors</div><div class=\"value${errorCount > 0 ? ' red' : ''}\">${errorCount}</div></div>\r\n <div class=\"card\"><div class=\"label\">Warnings</div><div class=\"value${warnCount > 0 ? ' yellow' : ''}\">${warnCount}</div></div>\r\n</div>\r\n\r\n<section>\r\n<h2>ER Diagrams</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Tables</th><th>Relations</th></tr></thead>\r\n<tbody>${erSummaryRows(result.erDiagrams)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Chain Plans</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Chains</th><th>Steps</th></tr></thead>\r\n<tbody>${chainSummaryRows(result.chainPlans)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Generated Files (${result.generatedFiles.length})</h2>\r\n<table>\r\n<thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n<tbody>${fileListRows(result.generatedFiles)}</tbody>\r\n</table>\r\n</section>\r\n\r\n${\r\n context?.quality || context?.metrics\r\n ? `<section>\r\n<h2>Execution Quality</h2>\r\n<table>\r\n<thead><tr><th>Item</th><th>Value</th></tr></thead>\r\n<tbody>\r\n${context.metrics ? `<tr><td>Passed</td><td>${context.metrics.passed}</td></tr><tr><td>Failed</td><td>${context.metrics.failed}</td></tr><tr><td>Skipped</td><td>${context.metrics.skipped}</td></tr><tr><td>TimedOut</td><td>${context.metrics.timedOut}</td></tr>` : ''}\r\n${context.quality ? `<tr><td>Gate Level</td><td>${escapeHtml(context.quality.level)}</td></tr><tr><td>Setup Fail</td><td>${String(context.quality.setupFail)}</td></tr><tr><td>Skip Ratio</td><td>${(context.quality.skipRatio * 100).toFixed(2)}%</td></tr><tr><td>Auth Fail Ratio</td><td>${(context.quality.authFailRatio * 100).toFixed(2)}%</td></tr><tr><td>Effective Execution Rate</td><td>${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%</td></tr><tr><td>Auth Status</td><td>${escapeHtml(context.quality.authStatus)}</td></tr><tr><td>Backend Status</td><td>${escapeHtml(context.quality.backendStatus)}</td></tr><tr><td>Reasons</td><td>${escapeHtml(context.quality.reasons.join(', ') || '-')}</td></tr>` : ''}\r\n</tbody>\r\n</table>\r\n</section>`\r\n : ''\r\n}\r\n\r\n${\r\n result.validationErrors.length > 0\r\n ? `<section>\r\n<h2>Validation Issues (${result.validationErrors.length})</h2>\r\n<table>\r\n<thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n<tbody>${validationRows(result.validationErrors)}</tbody>\r\n</table>\r\n</section>`\r\n : ''\r\n}\r\n\r\n<footer>\r\n Generated by <a href=\"https://github.com/opencroc/opencroc\">OpenCroc</a>\r\n</footer>\r\n</body>\r\n</html>`;\r\n\r\n return {\r\n format: 'html',\r\n content: html,\r\n filename: 'opencroc-report.html',\r\n };\r\n}\r\n\r\n// ===== Report Orchestrator =====\r\n\r\nconst REPORTERS: Record<string, (result: PipelineRunResult, context?: ReportExecutionContext) => ReportOutput> = {\r\n html: generateHtmlReport,\r\n json: generateJsonReport,\r\n markdown: generateMarkdownReport,\r\n};\r\n\r\n/**\r\n * Generate reports in the specified formats.\r\n */\r\nexport function generateReports(\r\n result: PipelineRunResult,\r\n formats: ('html' | 'json' | 'markdown')[] = ['html'],\r\n context?: ReportExecutionContext,\r\n): ReportOutput[] {\r\n return formats.map((fmt) => {\r\n const gen = REPORTERS[fmt];\r\n if (!gen) throw new Error(`Unknown report format: \"${fmt}\". Available: ${Object.keys(REPORTERS).join(', ')}`);\r\n return gen(result, context);\r\n });\r\n}\r\n\r\n// ===== Advanced Reporters (v1.2) =====\r\nexport {\r\n classifyFailure,\r\n buildFailureSummary,\r\n aggregateLogCompletion,\r\n parseApiDomain,\r\n buildBackendChecklist,\r\n renderChecklistMarkdown,\r\n} from './checklist-reporter.js';\r\n\r\nexport {\r\n buildWorkorders,\r\n renderWorkordersMarkdown,\r\n} from './workorder-reporter.js';\r\nexport type { BuildWorkordersOptions } from './workorder-reporter.js';\r\n\r\nexport {\r\n TokenTracker,\r\n renderTokenReportMarkdown,\r\n} from './token-reporter.js';\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport { generateReports } from '../../reporters/index.js';\r\n\r\nexport interface ReportCommandOptions {\r\n format?: string;\r\n output?: string;\r\n}\r\n\r\nexport async function report(opts: ReportCommandOptions): Promise<void> {\r\n let loaded;\r\n try {\r\n loaded = await loadConfig();\r\n } catch {\r\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const { config } = loaded;\r\n\r\n console.log(chalk.cyan('Running pipeline to generate report...'));\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run();\r\n\r\n const formats = (opts.format ?? 'html').split(',').map((s) => s.trim()) as ('html' | 'json' | 'markdown')[];\r\n const reports = generateReports(result, formats);\r\n\r\n const outDir = opts.output ?? config.outDir ?? './opencroc-output';\r\n if (!fs.existsSync(outDir)) {\r\n fs.mkdirSync(outDir, { recursive: true });\r\n }\r\n\r\n for (const r of reports) {\r\n const filePath = path.join(outDir, r.filename);\r\n fs.writeFileSync(filePath, r.content, 'utf-8');\r\n console.log(chalk.green(`✔ ${r.format} report → ${filePath}`));\r\n }\r\n\r\n console.log(chalk.dim(` ${result.modules.length} modules, ${result.generatedFiles.length} files, ${result.duration}ms`));\r\n}\r\n","import type { PipelineRunResult } from '../types.js';\r\n\r\nexport interface DashboardData {\r\n generatedAt: string;\r\n durationMs: number;\r\n modules: string[];\r\n totals: {\r\n modules: number;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n files: number;\r\n errors: number;\r\n warnings: number;\r\n };\r\n moduleCards: Array<{\r\n module: string;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n }>;\r\n files: Array<{ filePath: string; module: string; chain: string }>;\r\n issues: Array<{ severity: string; module: string; field: string; message: string }>;\r\n}\r\n\r\nexport interface DashboardOutput {\r\n filename: string;\r\n content: string;\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction number(v: unknown): number {\r\n return typeof v === 'number' && Number.isFinite(v) ? v : 0;\r\n}\r\n\r\nexport function buildDashboardDataFromPipeline(result: PipelineRunResult): DashboardData {\r\n const moduleCards = result.modules.map((mod) => {\r\n const er = result.erDiagrams.get(mod);\r\n const plan = result.chainPlans.get(mod);\r\n return {\r\n module: mod,\r\n tables: er?.tables.length ?? 0,\r\n relations: er?.relations.length ?? 0,\r\n chains: plan?.chains.length ?? 0,\r\n steps: plan?.totalSteps ?? 0,\r\n };\r\n });\r\n\r\n const totals = {\r\n modules: result.modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: result.generatedFiles.length,\r\n errors: result.validationErrors.filter((e) => e.severity === 'error').length,\r\n warnings: result.validationErrors.filter((e) => e.severity === 'warning').length,\r\n };\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: result.duration,\r\n modules: [...result.modules],\r\n totals,\r\n moduleCards,\r\n files: result.generatedFiles.map((f) => ({ filePath: f.filePath, module: f.module, chain: f.chain })),\r\n issues: result.validationErrors.map((e) => ({\r\n severity: e.severity,\r\n module: e.module,\r\n field: e.field,\r\n message: e.message,\r\n })),\r\n };\r\n}\r\n\r\nexport function buildDashboardDataFromReportJson(input: unknown): DashboardData {\r\n const src = (input ?? {}) as Record<string, unknown>;\r\n const modules = Array.isArray(src.modules) ? src.modules.map((m) => String(m)) : [];\r\n const er = (src.erDiagrams ?? {}) as Record<string, { tables?: unknown; relations?: unknown }>;\r\n const plans = (src.chainPlans ?? {}) as Record<string, { chains?: unknown; totalSteps?: unknown }>;\r\n const files = Array.isArray(src.generatedFiles)\r\n ? src.generatedFiles.map((f) => {\r\n const row = f as Record<string, unknown>;\r\n return {\r\n filePath: String(row.filePath ?? ''),\r\n module: String(row.module ?? ''),\r\n chain: String(row.chain ?? ''),\r\n };\r\n })\r\n : [];\r\n\r\n const rawIssues = Array.isArray(src.validationErrors) ? src.validationErrors : [];\r\n const issues = rawIssues.map((item) => {\r\n const row = item as Record<string, unknown>;\r\n return {\r\n severity: String(row.severity ?? 'warning'),\r\n module: String(row.module ?? 'unknown'),\r\n field: String(row.field ?? 'unknown'),\r\n message: String(row.message ?? ''),\r\n };\r\n });\r\n\r\n const moduleCards = modules.map((mod) => ({\r\n module: mod,\r\n tables: number(er[mod]?.tables),\r\n relations: number(er[mod]?.relations),\r\n chains: number(plans[mod]?.chains),\r\n steps: number(plans[mod]?.totalSteps),\r\n }));\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: number(src.duration),\r\n modules,\r\n totals: {\r\n modules: modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: files.length,\r\n errors: issues.filter((i) => i.severity === 'error').length,\r\n warnings: issues.filter((i) => i.severity === 'warning').length,\r\n },\r\n moduleCards,\r\n files,\r\n issues,\r\n };\r\n}\r\n\r\nexport function generateVisualDashboardHtml(data: DashboardData): string {\r\n const moduleCardHtml = data.moduleCards\r\n .map(\r\n (m) => `<article class=\"module-card reveal\">\r\n <h3>${escapeHtml(m.module)}</h3>\r\n <div class=\"meta\">${m.tables} tables · ${m.relations} relations</div>\r\n <div class=\"bars\">\r\n <div class=\"bar\"><span>Chains</span><strong>${m.chains}</strong></div>\r\n <div class=\"bar\"><span>Steps</span><strong>${m.steps}</strong></div>\r\n </div>\r\n</article>`,\r\n )\r\n .join('\\n');\r\n\r\n const fileRows = data.files\r\n .slice(0, 20)\r\n .map(\r\n (f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n const issueRows = data.issues\r\n .map(\r\n (i) => `<tr class=\"${escapeHtml(i.severity)}\"><td>${escapeHtml(i.severity)}</td><td>${escapeHtml(i.module)}</td><td>${escapeHtml(i.field)}</td><td>${escapeHtml(i.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n <title>OpenCroc Visual Dashboard</title>\r\n <style>\r\n @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');\r\n :root {\r\n --bg: #f4efe6;\r\n --ink: #18222c;\r\n --card: #fff8ef;\r\n --line: #d8c7b4;\r\n --accent: #0b7a75;\r\n --accent-2: #f26a2e;\r\n --ok: #2f7d32;\r\n --warn: #b7791f;\r\n --err: #c0392b;\r\n }\r\n * { box-sizing: border-box; }\r\n body {\r\n margin: 0;\r\n font-family: 'Space Grotesk', 'Segoe UI', sans-serif;\r\n color: var(--ink);\r\n background:\r\n radial-gradient(circle at 15% 10%, #f9e2c5 0%, transparent 32%),\r\n radial-gradient(circle at 85% 0%, #d3efe4 0%, transparent 28%),\r\n var(--bg);\r\n min-height: 100vh;\r\n }\r\n .wrap { max-width: 1160px; margin: 0 auto; padding: 24px 18px 40px; }\r\n .hero {\r\n border: 2px solid var(--line);\r\n border-radius: 18px;\r\n background: linear-gradient(130deg, #fff8ef 0%, #f8f2ea 45%, #f3ece3 100%);\r\n padding: 22px;\r\n box-shadow: 0 12px 24px rgba(24, 34, 44, 0.08);\r\n position: relative;\r\n overflow: hidden;\r\n }\r\n .hero::after {\r\n content: '';\r\n position: absolute;\r\n right: -42px;\r\n top: -38px;\r\n width: 160px;\r\n height: 160px;\r\n border-radius: 50%;\r\n background: conic-gradient(from 50deg, #f26a2e 0deg, #f7a35a 90deg, #0b7a75 220deg, #f26a2e 360deg);\r\n opacity: 0.14;\r\n }\r\n h1 { margin: 0; font-size: clamp(1.6rem, 3vw, 2.5rem); letter-spacing: -0.03em; }\r\n .subtitle { margin-top: 8px; font-size: 0.95rem; opacity: 0.82; }\r\n .kpi-grid {\r\n margin-top: 16px;\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\r\n gap: 10px;\r\n }\r\n .kpi {\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n padding: 10px 12px;\r\n background: #fffdf9;\r\n }\r\n .kpi .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }\r\n .kpi .value { font-size: 1.45rem; font-weight: 700; margin-top: 4px; }\r\n .kpi.error .value { color: var(--err); }\r\n .kpi.warning .value { color: var(--warn); }\r\n .kpi.files .value { color: var(--accent); }\r\n\r\n .section-title {\r\n margin: 24px 0 10px;\r\n font-size: 1rem;\r\n text-transform: uppercase;\r\n letter-spacing: 0.08em;\r\n color: #344250;\r\n }\r\n\r\n .module-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\r\n gap: 12px;\r\n }\r\n .module-card {\r\n border: 1px solid var(--line);\r\n border-radius: 14px;\r\n padding: 14px;\r\n background: var(--card);\r\n box-shadow: 0 8px 16px rgba(24, 34, 44, 0.06);\r\n }\r\n .module-card h3 { margin: 0 0 6px; font-size: 1.05rem; }\r\n .module-card .meta { font-size: 0.85rem; opacity: 0.78; }\r\n .bars { margin-top: 10px; display: grid; gap: 8px; }\r\n .bar { display: flex; justify-content: space-between; border-top: 1px dashed var(--line); padding-top: 7px; }\r\n\r\n table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n overflow: hidden;\r\n background: #fffdf9;\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n font-size: 0.82rem;\r\n }\r\n thead { background: #efe5d8; }\r\n th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eadfce; }\r\n tbody tr:last-child td { border-bottom: none; }\r\n tr.error td:first-child { color: var(--err); font-weight: 700; }\r\n tr.warning td:first-child { color: var(--warn); font-weight: 700; }\r\n\r\n code {\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n background: #f5ece0;\r\n border: 1px solid #eadfce;\r\n border-radius: 6px;\r\n padding: 1px 5px;\r\n }\r\n\r\n .reveal { opacity: 0; transform: translateY(12px); animation: rise .55s ease forwards; }\r\n .module-card.reveal:nth-child(2) { animation-delay: .06s; }\r\n .module-card.reveal:nth-child(3) { animation-delay: .12s; }\r\n .module-card.reveal:nth-child(4) { animation-delay: .18s; }\r\n .module-card.reveal:nth-child(5) { animation-delay: .24s; }\r\n @keyframes rise {\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n\r\n @media (max-width: 700px) {\r\n .wrap { padding: 14px 12px 28px; }\r\n .hero { padding: 16px; }\r\n table { font-size: 0.76rem; }\r\n th, td { padding: 7px 8px; }\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <main class=\"wrap\">\r\n <section class=\"hero reveal\">\r\n <h1>OpenCroc Visual Dashboard</h1>\r\n <p class=\"subtitle\">Pipeline finished in ${data.durationMs}ms · Generated ${escapeHtml(data.generatedAt)}</p>\r\n <div class=\"kpi-grid\">\r\n <div class=\"kpi\"><div class=\"label\">Modules</div><div class=\"value\">${data.totals.modules}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Tables</div><div class=\"value\">${data.totals.tables}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Relations</div><div class=\"value\">${data.totals.relations}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Chains</div><div class=\"value\">${data.totals.chains}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Steps</div><div class=\"value\">${data.totals.steps}</div></div>\r\n <div class=\"kpi files\"><div class=\"label\">Files</div><div class=\"value\">${data.totals.files}</div></div>\r\n <div class=\"kpi error\"><div class=\"label\">Errors</div><div class=\"value\">${data.totals.errors}</div></div>\r\n <div class=\"kpi warning\"><div class=\"label\">Warnings</div><div class=\"value\">${data.totals.warnings}</div></div>\r\n </div>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Module Health</h2>\r\n <section class=\"module-grid\">\r\n ${moduleCardHtml || '<article class=\"module-card\">No module data</article>'}\r\n </section>\r\n\r\n <h2 class=\"section-title\">Generated Files (Top 20)</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n <tbody>${fileRows || '<tr><td colspan=\"3\">No files generated</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Validation Issues</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n <tbody>${issueRows || '<tr><td colspan=\"4\">No validation issues</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n </main>\r\n</body>\r\n</html>`;\r\n}\r\n\r\nexport function generateVisualDashboard(result: PipelineRunResult): DashboardOutput {\r\n const data = buildDashboardDataFromPipeline(result);\r\n return {\r\n filename: 'opencroc-dashboard.html',\r\n content: generateVisualDashboardHtml(data),\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport {\r\n buildDashboardDataFromReportJson,\r\n buildDashboardDataFromPipeline,\r\n generateVisualDashboardHtml,\r\n} from '../../dashboard/index.js';\r\n\r\nexport interface DashboardCommandOptions {\r\n output?: string;\r\n input?: string;\r\n}\r\n\r\nexport async function dashboard(opts: DashboardCommandOptions): Promise<void> {\r\n let dashboardHtml: string;\r\n\r\n if (opts.input) {\r\n const inputPath = path.resolve(opts.input);\r\n if (!fs.existsSync(inputPath)) {\r\n console.error(chalk.red(`Input report not found: ${inputPath}`));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const raw = fs.readFileSync(inputPath, 'utf-8');\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n console.error(chalk.red('Invalid JSON input. Please provide opencroc-report.json output.'));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const data = buildDashboardDataFromReportJson(parsed);\r\n dashboardHtml = generateVisualDashboardHtml(data);\r\n console.log(chalk.cyan(`Building visual dashboard from ${inputPath}...`));\r\n } else {\r\n let loaded;\r\n try {\r\n loaded = await loadConfig();\r\n } catch {\r\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const { config } = loaded;\r\n console.log(chalk.cyan('Running pipeline to build visual dashboard...'));\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run();\r\n\r\n const data = buildDashboardDataFromPipeline(result);\r\n dashboardHtml = generateVisualDashboardHtml(data);\r\n }\r\n\r\n const outDir = opts.output ? path.resolve(opts.output) : path.resolve('./opencroc-output');\r\n if (!fs.existsSync(outDir)) {\r\n fs.mkdirSync(outDir, { recursive: true });\r\n }\r\n\r\n const outPath = path.join(outDir, 'opencroc-dashboard.html');\r\n fs.writeFileSync(outPath, dashboardHtml, 'utf-8');\r\n console.log(chalk.green(`✔ visual dashboard → ${outPath}`));\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate playwright.config.ts content based on OpenCroc config.\r\n */\r\nexport function generatePlaywrightConfig(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n const baseURL = pw.baseURL ? `'${pw.baseURL}'` : \"process.env.BASE_URL || 'http://localhost:3000'\";\r\n const timeout = pw.timeout ?? 30_000;\r\n const workers = pw.workers ?? (null as number | null); // null → use expression\r\n const retries = pw.retries ?? (null as number | null);\r\n const actionTimeout = pw.actionTimeout ?? 10_000;\r\n const navigationTimeout = pw.navigationTimeout ?? timeout;\r\n const storageState = rt.auth?.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const hasAuth = !!(rt.auth?.loginUrl);\r\n\r\n const lines: string[] = [];\r\n lines.push(`import { defineConfig, devices } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push('export default defineConfig({');\r\n lines.push(` testDir: '${outDir}',`);\r\n lines.push(` testMatch: ['**/*.spec.ts', '**/*.test.ts'],`);\r\n lines.push(` fullyParallel: false,`);\r\n lines.push(` forbidOnly: !!process.env.CI,`);\r\n lines.push(` retries: ${retries !== null ? retries : 'process.env.CI ? 1 : 0'},`);\r\n lines.push(` workers: ${workers !== null ? workers : 'process.env.CI ? 4 : 2'},`);\r\n lines.push(` timeout: ${timeout},`);\r\n lines.push(` globalSetup: './global-setup.ts',`);\r\n lines.push(` globalTeardown: './global-teardown.ts',`);\r\n lines.push(` reporter: [['list'], ['html', { open: 'never' }]],`);\r\n lines.push(` use: {`);\r\n lines.push(` baseURL: ${baseURL},`);\r\n lines.push(` trace: 'retain-on-failure',`);\r\n lines.push(` screenshot: 'only-on-failure',`);\r\n lines.push(` video: 'retain-on-failure',`);\r\n lines.push(` actionTimeout: ${actionTimeout},`);\r\n lines.push(` navigationTimeout: ${navigationTimeout},`);\r\n lines.push(` },`);\r\n\r\n // Projects\r\n lines.push(` projects: [`);\r\n\r\n if (hasAuth) {\r\n lines.push(` {`);\r\n lines.push(` name: 'setup',`);\r\n lines.push(` testMatch: '**/auth.setup.ts',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` dependencies: ['setup'],`);\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium-no-auth',`);\r\n lines.push(` testMatch: '**/login-flow.test.ts',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n }\r\n\r\n // Extra projects from config\r\n if (rt.extraProjects) {\r\n for (const proj of rt.extraProjects) {\r\n lines.push(` {`);\r\n lines.push(` name: '${proj.name}',`);\r\n lines.push(` testMatch: '${proj.testMatch}',`);\r\n if (proj.dependencies?.length) {\r\n lines.push(` dependencies: [${proj.dependencies.map((d) => `'${d}'`).join(', ')}],`);\r\n }\r\n if (proj.useAuth !== false && hasAuth) {\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n }\r\n lines.push(` },`);\r\n }\r\n }\r\n\r\n lines.push(` ],`);\r\n lines.push('});');\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-setup.ts content for Playwright.\r\n * Handles backend readiness probe, seed endpoint call, and log cleanup.\r\n */\r\nexport function generateGlobalSetup(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasSeedEndpoint = !!rt.db?.seedEndpoint;\r\n const hasLogEndpoint = !!rt.logEndpoint;\r\n const hasSeedFile = !!rt.db?.seedFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global setup — generated by OpenCroc.`);\r\n lines.push(` * Runs once before all test projects.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n // fetchWithRetry helper\r\n lines.push(`async function fetchWithRetry(`);\r\n lines.push(` url: string,`);\r\n lines.push(` options: RequestInit,`);\r\n lines.push(` retries = 3,`);\r\n lines.push(`): Promise<Response | null> {`);\r\n lines.push(` for (let i = 0; i < retries; i++) {`);\r\n lines.push(` try {`);\r\n lines.push(` const resp = await fetch(url, { ...options, signal: AbortSignal.timeout(10_000) });`);\r\n lines.push(` if (resp.ok) return resp;`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} → \\${resp.status} (\\${i + 1}/\\${retries})\\`);`);\r\n lines.push(` } catch (err: unknown) {`);\r\n lines.push(` const msg = err instanceof Error ? err.message : String(err);`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} error (\\${i + 1}/\\${retries}): \\${msg}\\`);`);\r\n lines.push(` }`);\r\n lines.push(` if (i < retries - 1) await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, i)));`);\r\n lines.push(` }`);\r\n lines.push(` return null;`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // waitForBackend helper\r\n lines.push(`async function waitForBackend(origin: string, timeoutMs = 30_000): Promise<void> {`);\r\n lines.push(` const start = Date.now();`);\r\n lines.push(` while (Date.now() - start < timeoutMs) {`);\r\n lines.push(` try {`);\r\n lines.push(` const res = await fetch(\\`\\${origin}/health\\`, { signal: AbortSignal.timeout(3_000) });`);\r\n lines.push(` if (res.ok) return;`);\r\n lines.push(` } catch {`);\r\n lines.push(` // not ready yet`);\r\n lines.push(` }`);\r\n lines.push(` await new Promise((r) => setTimeout(r, 1_000));`);\r\n lines.push(` }`);\r\n lines.push(` throw new Error(\\`Backend not ready after \\${timeoutMs}ms\\`);`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // Main function\r\n lines.push(`export default async function globalSetup(): Promise<void> {`);\r\n lines.push(` console.log('[global-setup] Starting...');`);\r\n lines.push('');\r\n lines.push(` // Backend readiness probe`);\r\n lines.push(` try {`);\r\n lines.push(` await waitForBackend(BASE_URL, 30_000);`);\r\n lines.push(` console.log('[global-setup] Backend is ready.');`);\r\n lines.push(` } catch (e: unknown) {`);\r\n lines.push(` console.warn(\\`[global-setup] \\${e instanceof Error ? e.message : String(e)}\\`);`);\r\n lines.push(` }`);\r\n lines.push('');\r\n\r\n if (hasSeedEndpoint) {\r\n lines.push(` // Seed data via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(`);\r\n lines.push(` \\`\\${BASE_URL}${rt.db!.seedEndpoint}\\`,`);\r\n lines.push(` { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' },`);\r\n lines.push(` );`);\r\n lines.push(` console.log('[global-setup] Seed endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Seed endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasLogEndpoint) {\r\n lines.push(` // Clear test logs`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(\\`\\${BASE_URL}${rt.logEndpoint}\\`, { method: 'DELETE' });`);\r\n lines.push(` console.log('[global-setup] Test logs cleared.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Failed to clear test logs.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasSeedFile) {\r\n lines.push(` // SQL seed file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.seedFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-setup] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-teardown.ts content for Playwright.\r\n * Handles cleanup endpoint call and optional SQL cleanup.\r\n */\r\nexport function generateGlobalTeardown(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasCleanupEndpoint = !!rt.db?.cleanupEndpoint;\r\n const hasCleanupFile = !!rt.db?.cleanupFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global teardown — generated by OpenCroc.`);\r\n lines.push(` * Runs once after all test projects complete.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n lines.push(`export default async function globalTeardown(): Promise<void> {`);\r\n lines.push(` console.log('[global-teardown] Starting...');`);\r\n lines.push('');\r\n\r\n if (hasCleanupEndpoint) {\r\n lines.push(` // Cleanup via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetch(\\`\\${BASE_URL}${rt.db!.cleanupEndpoint}\\`, { method: 'POST' });`);\r\n lines.push(` console.log('[global-teardown] Cleanup endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-teardown] Cleanup endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasCleanupFile) {\r\n lines.push(` // SQL cleanup file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.cleanupFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-teardown] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate auth.setup.ts content for Playwright.\r\n * Creates an authentication setup project that stores state for reuse.\r\n */\r\nexport function generateAuthSetup(config: OpenCrocConfig): string {\r\n const rt = config.runtime ?? {};\r\n const pw = config.playwright ?? {};\r\n const auth = rt.auth ?? {};\r\n const baseURL = pw.baseURL || '';\r\n const storageStatePath = auth.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test as setup, expect } from '@playwright/test';`);\r\n lines.push(`import * as fs from 'fs/promises';`);\r\n lines.push(`import * as path from 'path';`);\r\n lines.push('');\r\n\r\n lines.push(`const authFile = '${storageStatePath}';`);\r\n lines.push('');\r\n\r\n if (auth.loginUrl) {\r\n // API-based authentication\r\n lines.push(`setup('authenticate', async ({ request }) => {`);\r\n lines.push(` const loginUrl = process.env.AUTH_LOGIN_URL || '${auth.loginUrl}';`);\r\n lines.push(` const username = process.env.AUTH_USERNAME || '${auth.username || 'admin'}';`);\r\n lines.push(` const password = process.env.AUTH_PASSWORD || '${auth.password || ''}';`);\r\n lines.push('');\r\n lines.push(` // API login`);\r\n lines.push(` const response = await request.post(loginUrl, {`);\r\n lines.push(` data: { username, password },`);\r\n lines.push(` });`);\r\n lines.push(` expect(response.ok()).toBeTruthy();`);\r\n lines.push('');\r\n lines.push(` const body = await response.json();`);\r\n lines.push(` const token = body.data?.token || body.token || '';`);\r\n lines.push(` console.log('[auth.setup] Login successful, token obtained:', !!token);`);\r\n lines.push('');\r\n lines.push(` // Save storage state with auth cookie/localStorage`);\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push('');\r\n lines.push(` // Build storage state JSON`);\r\n lines.push(` const baseURL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push(` const origin = new URL(baseURL).origin;`);\r\n lines.push(` const storageState = {`);\r\n lines.push(` cookies: [],`);\r\n lines.push(` origins: [`);\r\n lines.push(` {`);\r\n lines.push(` origin,`);\r\n lines.push(` localStorage: [`);\r\n lines.push(` { name: 'token', value: token },`);\r\n lines.push(` ],`);\r\n lines.push(` },`);\r\n lines.push(` ],`);\r\n lines.push(` };`);\r\n lines.push('');\r\n lines.push(` await fs.writeFile(authFile, JSON.stringify(storageState, null, 2));`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push(`});`);\r\n } else {\r\n // Browser-based authentication (placeholder)\r\n lines.push(`setup('authenticate', async ({ browser }) => {`);\r\n lines.push(` const context = await browser.newContext();`);\r\n lines.push(` const page = await context.newPage();`);\r\n lines.push('');\r\n lines.push(` // TODO: Implement your login flow here`);\r\n lines.push(` // await page.goto('/login');`);\r\n lines.push(` // await page.fill('[name=username]', 'admin');`);\r\n lines.push(` // await page.fill('[name=password]', 'password');`);\r\n lines.push(` // await page.click('button[type=submit]');`);\r\n lines.push(` // await page.waitForURL('/dashboard');`);\r\n lines.push('');\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push(` await context.storageState({ path: authFile });`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push('');\r\n lines.push(` await context.close();`);\r\n lines.push(`});`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import chalk from 'chalk';\r\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { join, resolve } from 'node:path';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { generatePlaywrightConfig } from '../../runtime/playwright-config-generator.js';\r\nimport { generateGlobalSetup } from '../../runtime/global-setup-generator.js';\r\nimport { generateGlobalTeardown } from '../../runtime/global-teardown-generator.js';\r\nimport { generateAuthSetup } from '../../runtime/auth-setup-generator.js';\r\n\r\nexport interface InitRuntimeOptions {\r\n output?: string;\r\n force?: boolean;\r\n}\r\n\r\nfunction writeIfNotExists(filePath: string, content: string, force: boolean): boolean {\r\n if (existsSync(filePath) && !force) {\r\n console.log(chalk.yellow(` ⊘ ${filePath} already exists (use --force to overwrite)`));\r\n return false;\r\n }\r\n const dir = resolve(filePath, '..');\r\n mkdirSync(dir, { recursive: true });\r\n writeFileSync(filePath, content, 'utf-8');\r\n console.log(chalk.green(` ✓ ${filePath}`));\r\n return true;\r\n}\r\n\r\nexport async function initRuntime(opts: InitRuntimeOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Initialize Playwright Runtime\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const outDir = resolve(opts.output || '.');\r\n const force = opts.force ?? false;\r\n const hasAuth = !!config.runtime?.auth?.loginUrl;\r\n\r\n let written = 0;\r\n\r\n console.log(chalk.cyan('\\n Generating runtime files...\\n'));\r\n\r\n if (writeIfNotExists(join(outDir, 'playwright.config.ts'), generatePlaywrightConfig(config), force)) written++;\r\n if (writeIfNotExists(join(outDir, 'global-setup.ts'), generateGlobalSetup(config), force)) written++;\r\n if (writeIfNotExists(join(outDir, 'global-teardown.ts'), generateGlobalTeardown(config), force)) written++;\r\n\r\n if (hasAuth) {\r\n if (writeIfNotExists(join(outDir, 'auth.setup.ts'), generateAuthSetup(config), force)) written++;\r\n }\r\n\r\n console.log('');\r\n if (written > 0) {\r\n console.log(chalk.green(` ✓ Generated ${written} runtime file(s) in ${outDir}\\n`));\r\n } else {\r\n console.log(chalk.yellow(` No files written. Use --force to overwrite existing files.\\n`));\r\n }\r\n}\r\n","/**\r\n * Full orchestration engine: generate → execute → analyze → heal → report.\r\n *\r\n * Runs a multi-phase pipeline with per-phase tracking, failure detection,\r\n * token budget management, and structured result reporting.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, readdirSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n SelfHealingConfig,\r\n SelfHealingResult,\r\n} from '../types.js';\r\nimport { createPipeline } from '../pipeline/index.js';\r\nimport { createSelfHealingLoop } from '../self-healing/index.js';\r\nimport { generateReports } from '../reporters/index.js';\r\nimport type { ReportOutput } from '../reporters/index.js';\r\n\r\n// ===== Types =====\r\n\r\nexport type PhaseStatus = 'success' | 'warn' | 'error' | 'skipped';\r\n\r\nexport interface PhaseResult<T = unknown> {\r\n phase: string;\r\n status: PhaseStatus;\r\n output?: T;\r\n error?: string;\r\n durationMs: number;\r\n}\r\n\r\nexport interface OrchestrationOptions {\r\n /** Which phases to run (default: all) */\r\n phases?: OrchestrationPhase[];\r\n /** Enable self-healing phase (default: false) */\r\n selfHeal?: boolean;\r\n /** Max self-healing iterations */\r\n maxHealIterations?: number;\r\n /** Report formats to generate */\r\n reportFormats?: ('html' | 'json' | 'markdown')[];\r\n /** Run Playwright in headed mode */\r\n headed?: boolean;\r\n /** Module filter */\r\n module?: string;\r\n /** LLM token budget (0 = unlimited) */\r\n tokenBudget?: number;\r\n /** Abort on phase error (default: false — continue where possible) */\r\n abortOnError?: boolean;\r\n}\r\n\r\nexport type OrchestrationPhase = 'generate' | 'execute' | 'analyze' | 'heal' | 'report';\r\n\r\nexport interface ExecutionMetrics {\r\n passed: number;\r\n failed: number;\r\n skipped: number;\r\n timedOut: number;\r\n}\r\n\r\nexport interface OrchestrationSummary {\r\n overallStatus: 'success' | 'partial-fail' | 'fatal-fail';\r\n phases: PhaseResult[];\r\n totalDurationMs: number;\r\n modules: string[];\r\n executionMetrics?: ExecutionMetrics;\r\n reports?: ReportOutput[];\r\n healingResult?: SelfHealingResult;\r\n recommendation?: string;\r\n}\r\n\r\nconst ALL_PHASES: OrchestrationPhase[] = ['generate', 'execute', 'analyze', 'heal', 'report'];\r\n\r\n// ===== Helpers =====\r\n\r\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\r\n const absDir = join(process.cwd(), outDir);\r\n if (!existsSync(absDir)) return [];\r\n\r\n const files: string[] = [];\r\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\r\n for (const entry of entries) {\r\n if (!entry.isFile()) continue;\r\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\r\n const fullPath = join(\r\n entry.parentPath || (entry as unknown as { path: string }).path || absDir,\r\n entry.name,\r\n );\r\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\r\n files.push(fullPath);\r\n }\r\n return files;\r\n}\r\n\r\nfunction parsePlaywrightOutput(stderr: string): ExecutionMetrics {\r\n const metrics: ExecutionMetrics = { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n\r\n // Playwright summary line: \"X passed\", \"Y failed\", \"Z skipped\"\r\n const passedMatch = stderr.match(/(\\d+)\\s+passed/);\r\n const failedMatch = stderr.match(/(\\d+)\\s+failed/);\r\n const skippedMatch = stderr.match(/(\\d+)\\s+skipped/);\r\n const timedOutMatch = stderr.match(/(\\d+)\\s+timed?\\s*out/i);\r\n\r\n if (passedMatch) metrics.passed = parseInt(passedMatch[1], 10);\r\n if (failedMatch) metrics.failed = parseInt(failedMatch[1], 10);\r\n if (skippedMatch) metrics.skipped = parseInt(skippedMatch[1], 10);\r\n if (timedOutMatch) metrics.timedOut = parseInt(timedOutMatch[1], 10);\r\n\r\n return metrics;\r\n}\r\n\r\n// ===== Orchestrator =====\r\n\r\nexport function createOrchestrator(config: OpenCrocConfig, options: OrchestrationOptions = {}) {\r\n const {\r\n phases = ALL_PHASES,\r\n selfHeal = false,\r\n maxHealIterations = 3,\r\n reportFormats = ['html', 'json'],\r\n headed = false,\r\n module: moduleFilter,\r\n tokenBudget = 0,\r\n abortOnError = false,\r\n } = options;\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const phaseResults: PhaseResult[] = [];\r\n let pipelineResult: PipelineRunResult | undefined;\r\n let executionMetrics: ExecutionMetrics | undefined;\r\n let healingResult: SelfHealingResult | undefined;\r\n let reports: ReportOutput[] | undefined;\r\n let tokensUsed = 0;\r\n\r\n function isBudgetExceeded(): boolean {\r\n return tokenBudget > 0 && tokensUsed >= tokenBudget;\r\n }\r\n\r\n function shouldRun(phase: OrchestrationPhase): boolean {\r\n if (phase === 'heal' && !selfHeal) return false;\r\n return phases.includes(phase);\r\n }\r\n\r\n async function runPhase<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n ): Promise<PhaseResult<T>> {\r\n const start = Date.now();\r\n try {\r\n const output = await fn();\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'success',\r\n output,\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n } catch (err) {\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'error',\r\n error: err instanceof Error ? err.message : String(err),\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n }\r\n\r\n function skipPhase(name: string, reason: string): PhaseResult {\r\n const result: PhaseResult = {\r\n phase: name,\r\n status: 'skipped',\r\n error: reason,\r\n durationMs: 0,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n\r\n return {\r\n async run(): Promise<OrchestrationSummary> {\r\n const orchestrationStart = Date.now();\r\n\r\n // ── Phase 1: Generate ──\r\n if (shouldRun('generate')) {\r\n const genResult = await runPhase('generate', async () => {\r\n if (moduleFilter) config.modules = [moduleFilter];\r\n const pipeline = createPipeline(config);\r\n pipelineResult = await pipeline.run();\r\n\r\n // Write generated files\r\n for (const file of pipelineResult.generatedFiles) {\r\n const dir = dirname(file.filePath);\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n writeFileSync(file.filePath, file.content, 'utf-8');\r\n }\r\n\r\n return pipelineResult;\r\n });\r\n\r\n if (genResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n\r\n // ── Phase 2: Execute ──\r\n if (shouldRun('execute')) {\r\n const testFiles = discoverTestFiles(outDir, moduleFilter);\r\n\r\n if (testFiles.length === 0) {\r\n skipPhase('execute', 'No test files found');\r\n } else {\r\n const execResult = await runPhase('execute', async () => {\r\n const args = ['test', ...testFiles];\r\n if (!headed) args.push('--reporter=list');\r\n else args.push('--headed');\r\n\r\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\r\n\r\n try {\r\n execFileSync(npxCmd, ['playwright', ...args], {\r\n cwd: process.cwd(),\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n timeout: 300_000,\r\n });\r\n return { passed: testFiles.length, failed: 0, skipped: 0, timedOut: 0 } as ExecutionMetrics;\r\n } catch (err) {\r\n const stderr = (err as { stderr?: Buffer })?.stderr?.toString() ?? '';\r\n const metrics = parsePlaywrightOutput(stderr);\r\n if (metrics.passed === 0 && metrics.failed === 0) {\r\n metrics.failed = testFiles.length;\r\n }\r\n executionMetrics = metrics;\r\n if (metrics.failed > 0) {\r\n throw new Error(`${metrics.failed} test(s) failed, ${metrics.passed} passed`, { cause: err });\r\n }\r\n return metrics;\r\n }\r\n });\r\n\r\n if (!executionMetrics && execResult.output) {\r\n executionMetrics = execResult.output as ExecutionMetrics;\r\n }\r\n\r\n if (execResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 3: Analyze ──\r\n if (shouldRun('analyze')) {\r\n if (!pipelineResult || !executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('analyze', 'No failures to analyze');\r\n } else {\r\n await runPhase('analyze', async () => {\r\n // Re-run pipeline validation for failure context\r\n const pipeline = createPipeline(config);\r\n const validationResult = await pipeline.run(['validate']);\r\n return {\r\n validationErrors: validationResult.validationErrors,\r\n failedTestCount: executionMetrics!.failed,\r\n };\r\n });\r\n }\r\n }\r\n\r\n // ── Phase 4: Heal ──\r\n if (shouldRun('heal')) {\r\n if (isBudgetExceeded()) {\r\n skipPhase('heal', 'Token budget exceeded');\r\n } else if (!executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('heal', 'No failures to heal');\r\n } else {\r\n const healResult = await runPhase('heal', async () => {\r\n const healConfig: SelfHealingConfig = {\r\n enabled: true,\r\n maxIterations: maxHealIterations,\r\n mode: config.selfHealing?.mode || 'config-only',\r\n };\r\n\r\n const loop = createSelfHealingLoop(healConfig);\r\n const result = await loop.run(outDir);\r\n tokensUsed += result.totalTokensUsed;\r\n healingResult = result;\r\n return result;\r\n });\r\n\r\n if (healResult.status === 'success' && healingResult && healingResult.remaining.length > 0) {\r\n healResult.status = 'warn';\r\n phaseResults[phaseResults.length - 1] = healResult;\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 5: Report ──\r\n if (shouldRun('report')) {\r\n if (!pipelineResult) {\r\n skipPhase('report', 'No pipeline results to report');\r\n } else {\r\n await runPhase('report', async () => {\r\n reports = generateReports(pipelineResult!, reportFormats);\r\n\r\n if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });\r\n for (const r of reports) {\r\n writeFileSync(join(outDir, r.filename), r.content, 'utf-8');\r\n }\r\n\r\n return reports;\r\n });\r\n }\r\n }\r\n\r\n return buildSummary(orchestrationStart);\r\n },\r\n };\r\n\r\n function buildSummary(startTime: number): OrchestrationSummary {\r\n const errorCount = phaseResults.filter((p) => p.status === 'error').length;\r\n const allSuccess = phaseResults.every((p) => p.status === 'success' || p.status === 'skipped');\r\n\r\n let overallStatus: OrchestrationSummary['overallStatus'];\r\n if (allSuccess) overallStatus = 'success';\r\n else if (errorCount > 1) overallStatus = 'fatal-fail';\r\n else overallStatus = 'partial-fail';\r\n\r\n let recommendation: string | undefined;\r\n if (executionMetrics && executionMetrics.failed > 0 && !selfHeal) {\r\n recommendation = 'Test failures detected. Consider running with --self-heal to attempt automated fixes.';\r\n } else if (healingResult && healingResult.remaining.length > 0) {\r\n recommendation = `${healingResult.remaining.length} issue(s) could not be auto-fixed. Manual review needed.`;\r\n }\r\n\r\n return {\r\n overallStatus,\r\n phases: phaseResults,\r\n totalDurationMs: Date.now() - startTime,\r\n modules: pipelineResult?.modules ?? [],\r\n executionMetrics,\r\n reports,\r\n healingResult,\r\n recommendation,\r\n };\r\n }\r\n}\r\n","/**\r\n * Orchestration summary reporter.\r\n * Writes phase-by-phase JSON and a human-readable console summary.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { OrchestrationSummary, PhaseResult } from './index.js';\r\n\r\nexport interface OrchestrationReportOptions {\r\n outputDir: string;\r\n module?: string;\r\n}\r\n\r\n/**\r\n * Write the orchestration summary to a JSON file.\r\n * Returns the written file path.\r\n */\r\nexport function writeOrchestrationSummary(\r\n summary: OrchestrationSummary,\r\n options: OrchestrationReportOptions,\r\n): string {\r\n const { outputDir, module: mod } = options;\r\n if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const moduleName = mod ?? 'all';\r\n const filename = `orchestration-${moduleName}-${timestamp}.json`;\r\n const filePath = join(outputDir, filename);\r\n\r\n const serializable = {\r\n ...summary,\r\n phases: summary.phases.map((p) => ({\r\n phase: p.phase,\r\n status: p.status,\r\n error: p.error,\r\n durationMs: p.durationMs,\r\n })),\r\n // Strip report content to avoid massive JSON\r\n reports: summary.reports?.map((r) => ({\r\n format: r.format,\r\n filename: r.filename,\r\n })),\r\n };\r\n\r\n writeFileSync(filePath, JSON.stringify(serializable, null, 2), 'utf-8');\r\n return filePath;\r\n}\r\n\r\n/**\r\n * Format a phase result as a single console line.\r\n */\r\nfunction formatPhase(p: PhaseResult): string {\r\n const icons: Record<string, string> = {\r\n success: '✓',\r\n warn: '⚠',\r\n error: '✗',\r\n skipped: '○',\r\n };\r\n const icon = icons[p.status] ?? '?';\r\n const dur = p.durationMs > 0 ? ` (${p.durationMs}ms)` : '';\r\n const err = p.error ? ` — ${p.error}` : '';\r\n return ` ${icon} ${p.phase}${dur}${err}`;\r\n}\r\n\r\n/**\r\n * Print a human-readable console summary.\r\n */\r\nexport function printOrchestrationSummary(summary: OrchestrationSummary): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push('');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push(' Orchestration Summary');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push('');\r\n\r\n for (const p of summary.phases) {\r\n lines.push(formatPhase(p));\r\n }\r\n\r\n lines.push('');\r\n lines.push(` Overall : ${summary.overallStatus}`);\r\n lines.push(` Modules : ${summary.modules.join(', ') || '(none)'}`);\r\n lines.push(` Duration : ${summary.totalDurationMs}ms`);\r\n\r\n if (summary.executionMetrics) {\r\n const m = summary.executionMetrics;\r\n lines.push(` Tests : ${m.passed} passed, ${m.failed} failed, ${m.skipped} skipped`);\r\n }\r\n\r\n if (summary.healingResult) {\r\n const h = summary.healingResult;\r\n lines.push(` Healing : ${h.fixed.length} fixed, ${h.remaining.length} remaining (${h.iterations} iterations)`);\r\n }\r\n\r\n if (summary.reports) {\r\n lines.push(` Reports : ${summary.reports.map((r) => r.format).join(', ')}`);\r\n }\r\n\r\n if (summary.recommendation) {\r\n lines.push('');\r\n lines.push(` → ${summary.recommendation}`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createOrchestrator } from '../../orchestrator/index.js';\r\nimport { writeOrchestrationSummary, printOrchestrationSummary } from '../../orchestrator/reporter.js';\r\nimport type { OrchestrationPhase } from '../../orchestrator/index.js';\r\n\r\nexport interface RunOptions {\r\n module?: string;\r\n phases?: string;\r\n selfHeal?: boolean;\r\n headed?: boolean;\r\n report?: string;\r\n tokenBudget?: string;\r\n abortOnError?: boolean;\r\n}\r\n\r\nconst VALID_PHASES: OrchestrationPhase[] = ['generate', 'execute', 'analyze', 'heal', 'report'];\r\n\r\nfunction parsePhases(raw?: string): OrchestrationPhase[] | undefined {\r\n if (!raw) return undefined;\r\n const names = raw.split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n if (!VALID_PHASES.includes(name as OrchestrationPhase)) {\r\n console.log(chalk.red(` Unknown phase \"${name}\". Valid: ${VALID_PHASES.join(', ')}`));\r\n process.exitCode = 1;\r\n return undefined;\r\n }\r\n }\r\n return names as OrchestrationPhase[];\r\n}\r\n\r\nexport async function run(opts: RunOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Full Orchestration\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const phases = parsePhases(opts.phases);\r\n if (phases === undefined && opts.phases) return;\r\n\r\n const reportFormats = (opts.report ?? 'html,json').split(',').map((s) => s.trim()) as ('html' | 'json' | 'markdown')[];\r\n\r\n const orchestrator = createOrchestrator(config, {\r\n phases,\r\n selfHeal: opts.selfHeal ?? false,\r\n headed: opts.headed ?? false,\r\n module: opts.module,\r\n reportFormats,\r\n tokenBudget: opts.tokenBudget ? parseInt(opts.tokenBudget, 10) : 0,\r\n abortOnError: opts.abortOnError ?? false,\r\n });\r\n\r\n console.log(chalk.gray(` Phases: ${(phases ?? VALID_PHASES).join(' → ')}`));\r\n if (opts.selfHeal) console.log(chalk.gray(' Self-heal: enabled'));\r\n console.log('');\r\n\r\n const summary = await orchestrator.run();\r\n\r\n // Print console summary\r\n const lines = printOrchestrationSummary(summary);\r\n for (const line of lines) {\r\n const color =\r\n summary.overallStatus === 'success' ? chalk.green :\r\n summary.overallStatus === 'partial-fail' ? chalk.yellow :\r\n chalk.red;\r\n console.log(color(line));\r\n }\r\n\r\n // Write JSON summary\r\n const outDir = config.outDir || './opencroc-output';\r\n const summaryPath = writeOrchestrationSummary(summary, { outputDir: outDir, module: opts.module });\r\n console.log(chalk.gray(` Summary: ${summaryPath}\\n`));\r\n\r\n if (summary.overallStatus !== 'success') {\r\n process.exitCode = 1;\r\n }\r\n}\r\n","import type { FastifyInstance } from 'fastify';\r\nimport type { CrocOffice } from '../croc-office.js';\r\n\r\nexport function registerProjectRoutes(app: FastifyInstance, office: CrocOffice): void {\r\n // GET /api/project — full project info + knowledge graph\r\n app.get('/api/project', async () => {\r\n return office.getProjectInfo();\r\n });\r\n\r\n // GET /api/project/graph — knowledge graph only\r\n app.get('/api/project/graph', async () => {\r\n return office.buildKnowledgeGraph();\r\n });\r\n\r\n // POST /api/project/refresh — invalidate cache and re-scan\r\n app.post('/api/project/refresh', async () => {\r\n office.invalidateCache();\r\n const graph = await office.buildKnowledgeGraph();\r\n office.broadcast('graph:update', graph);\r\n return { ok: true, nodes: graph.nodes.length, edges: graph.edges.length };\r\n });\r\n}\r\n","import type { FastifyInstance } from 'fastify';\r\nimport type { CrocOffice } from '../croc-office.js';\r\nimport type { ExecutionRunMode } from '../../execution/types.js';\r\n\r\nexport function registerAgentRoutes(app: FastifyInstance, office: CrocOffice): void {\r\n // GET /api/agents — list all croc agents\r\n app.get('/api/agents', async () => {\r\n return office.getAgents();\r\n });\r\n\r\n // GET /api/agents/:id — get specific agent\r\n app.get<{ Params: { id: string } }>('/api/agents/:id', async (req, reply) => {\r\n const agent = office.getAgent(req.params.id);\r\n if (!agent) {\r\n reply.code(404).send({ error: 'Agent not found' });\r\n return;\r\n }\r\n return agent;\r\n });\r\n\r\n // POST /api/scan — trigger project scan (parser croc)\r\n app.post('/api/scan', async (_req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n // Run async — don't await, respond immediately\r\n office.runScan().catch(() => { /* errors handled in runScan */ });\r\n return { ok: true, message: 'Scan started' };\r\n });\r\n\r\n // POST /api/pipeline — trigger full pipeline (all crocs)\r\n app.post('/api/pipeline', async (_req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n office.runPipeline().catch(() => { /* errors handled in runPipeline */ });\r\n return { ok: true, message: 'Pipeline started' };\r\n });\r\n\r\n // POST /api/reset — reset all agents to idle\r\n app.post('/api/reset', async () => {\r\n office.resetAgents();\r\n return { ok: true };\r\n });\r\n\r\n // GET /api/status — overall status\r\n app.get('/api/status', async () => {\r\n return {\r\n running: office.isRunning(),\r\n agents: office.getAgents(),\r\n };\r\n });\r\n\r\n // GET /api/files — generated test files from last pipeline run\r\n app.get('/api/files', async () => {\r\n const files = office.getGeneratedFiles();\r\n return files.map(f => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n lines: f.content.split('\\n').length,\r\n size: f.content.length,\r\n }));\r\n });\r\n\r\n // GET /api/files/:index — get content of a specific generated file\r\n app.get<{ Params: { index: string } }>('/api/files/:index', async (req, reply) => {\r\n const files = office.getGeneratedFiles();\r\n const idx = parseInt(req.params.index, 10);\r\n if (isNaN(idx) || idx < 0 || idx >= files.length) {\r\n reply.code(404).send({ error: 'File not found' });\r\n return;\r\n }\r\n return files[idx];\r\n });\r\n\r\n // GET /api/pipeline/result — last pipeline result summary\r\n app.get('/api/pipeline/result', async () => {\r\n const result = office.getLastPipelineResult();\r\n if (!result) return { ok: false, message: 'No pipeline has been run yet' };\r\n return {\r\n ok: true,\r\n modules: result.modules,\r\n erDiagramCount: result.erDiagrams.size,\r\n chainCount: [...result.chainPlans.values()].reduce((s, p) => s + p.chains.length, 0),\r\n totalSteps: [...result.chainPlans.values()].reduce((s, p) => s + p.totalSteps, 0),\r\n filesGenerated: result.generatedFiles.length,\r\n validationErrors: result.validationErrors.length,\r\n duration: result.duration,\r\n };\r\n });\r\n\r\n // POST /api/run-tests — execute generated tests with Playwright\r\n app.post<{ Body: { mode?: ExecutionRunMode } }>('/api/run-tests', async (req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n const mode = req.body?.mode;\r\n if (mode && !['auto', 'reuse', 'managed'].includes(mode)) {\r\n reply.code(400).send({ error: 'Invalid mode. Valid values: auto, reuse, managed' });\r\n return;\r\n }\r\n office.runTests({ mode }).catch(() => { /* errors handled internally */ });\r\n return { ok: true, message: 'Test execution started' };\r\n });\r\n\r\n // GET /api/test-results — last test execution metrics\r\n app.get('/api/test-results', async () => {\r\n const metrics = office.getLastExecutionMetrics();\r\n const quality = office.getLastExecutionQuality();\r\n if (!metrics && !quality) return { ok: false, message: 'No tests have been run yet' };\r\n if (!metrics) {\r\n return { ok: true, metrics: null, total: 0, quality };\r\n }\r\n const total = metrics.passed + metrics.failed + metrics.skipped + metrics.timedOut;\r\n return { ok: true, metrics, total, quality };\r\n });\r\n\r\n // POST /api/reports/generate — generate reports from last pipeline result\r\n app.post('/api/reports/generate', async (_req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n office.generateReport().catch(() => { /* errors handled internally */ });\r\n return { ok: true, message: 'Report generation started' };\r\n });\r\n\r\n // GET /api/reports — list last generated reports\r\n app.get('/api/reports', async () => {\r\n const reports = office.getLastReports();\r\n if (reports.length === 0) return { ok: false, message: 'No reports generated yet' };\r\n return {\r\n ok: true,\r\n reports: reports.map(r => ({\r\n format: r.format,\r\n filename: r.filename,\r\n size: r.content.length,\r\n })),\r\n };\r\n });\r\n\r\n // GET /api/reports/:format — get report content by format (html|json|markdown)\r\n app.get<{ Params: { format: string } }>('/api/reports/:format', async (req, reply) => {\r\n const reports = office.getLastReports();\r\n const report = reports.find(r => r.format === req.params.format);\r\n if (!report) {\r\n reply.code(404).send({ error: `No ${req.params.format} report found` });\r\n return;\r\n }\r\n const contentType = req.params.format === 'html' ? 'text/html'\r\n : req.params.format === 'json' ? 'application/json'\r\n : 'text/markdown';\r\n reply.type(contentType).send(report.content);\r\n });\r\n\r\n // GET /api/ci/template — generate CI config template\r\n app.get<{ Querystring: { provider?: string } }>('/api/ci/template', async (req) => {\r\n const provider = req.query.provider || 'github';\r\n const { generateGitHubActionsTemplate, generateGitLabCITemplate } = await import('../../ci/index.js');\r\n if (provider === 'gitlab') {\r\n return { ok: true, provider: 'gitlab', template: generateGitLabCITemplate() };\r\n }\r\n return { ok: true, provider: 'github', template: generateGitHubActionsTemplate() };\r\n });\r\n}\r\n","/**\r\n * Language Detector\r\n *\r\n * Detects programming languages, frameworks, and project type\r\n * from a project directory without reading source code ASTs.\r\n * Uses file extensions, config files, and package manifests.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type { ProjectType, FrameworkDetection } from '../graph/types.js';\r\n\r\n// ===== Language Detection by File Extension =====\r\n\r\nconst EXTENSION_MAP: Record<string, string> = {\r\n '.ts': 'typescript', '.tsx': 'typescript', '.mts': 'typescript', '.cts': 'typescript',\r\n '.js': 'javascript', '.jsx': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript',\r\n '.py': 'python', '.pyw': 'python', '.pyi': 'python',\r\n '.go': 'go',\r\n '.java': 'java', '.kt': 'kotlin', '.kts': 'kotlin',\r\n '.rs': 'rust',\r\n '.rb': 'ruby',\r\n '.php': 'php',\r\n '.cs': 'csharp',\r\n '.cpp': 'cpp', '.cc': 'cpp', '.cxx': 'cpp', '.c': 'c', '.h': 'c',\r\n '.swift': 'swift',\r\n '.dart': 'dart',\r\n '.vue': 'vue',\r\n '.svelte': 'svelte',\r\n '.astro': 'astro',\r\n '.sql': 'sql',\r\n '.graphql': 'graphql', '.gql': 'graphql',\r\n '.proto': 'protobuf',\r\n '.yaml': 'yaml', '.yml': 'yaml',\r\n '.json': 'json',\r\n '.toml': 'toml',\r\n '.md': 'markdown',\r\n '.html': 'html', '.htm': 'html',\r\n '.css': 'css', '.scss': 'scss', '.less': 'less', '.sass': 'sass',\r\n '.sh': 'shell', '.bash': 'shell', '.zsh': 'shell',\r\n '.ps1': 'powershell',\r\n '.dockerfile': 'docker',\r\n '.tf': 'terraform',\r\n '.lua': 'lua',\r\n '.r': 'r', '.R': 'r',\r\n '.scala': 'scala',\r\n '.ex': 'elixir', '.exs': 'elixir',\r\n '.erl': 'erlang',\r\n '.zig': 'zig',\r\n};\r\n\r\n/** Directories to skip during scanning */\r\nconst SKIP_DIRS = new Set([\r\n 'node_modules', '.git', '.svn', '.hg', 'dist', 'build', 'out', 'target',\r\n '__pycache__', '.cache', '.next', '.nuxt', '.output', 'vendor', 'venv',\r\n '.venv', 'env', '.env', 'coverage', '.idea', '.vscode', '.vs',\r\n '.turbo', '.nx', 'bower_components', 'jspm_packages',\r\n]);\r\n\r\n/** Max depth to scan */\r\nconst MAX_DEPTH = 8;\r\n\r\n/** Max files to scan for detection (avoid huge repos) */\r\nconst MAX_FILES = 10000;\r\n\r\nexport interface LanguageDetectionResult {\r\n /** Language → file count */\r\n languages: Record<string, number>;\r\n /** Language → total line count */\r\n linesByLanguage: Record<string, number>;\r\n /** Total files found */\r\n totalFiles: number;\r\n /** Total lines of code */\r\n totalLines: number;\r\n /** Primary language */\r\n primaryLanguage: string;\r\n /** Detected frameworks */\r\n frameworks: FrameworkDetection[];\r\n /** Detected project type */\r\n projectType: ProjectType;\r\n /** Package manager */\r\n packageManager?: string;\r\n /** All discovered source files */\r\n files: Array<{ path: string; language: string; lines: number; size: number }>;\r\n}\r\n\r\n/**\r\n * Detect languages, frameworks, and project type from a directory.\r\n */\r\nexport function detectProject(rootDir: string): LanguageDetectionResult {\r\n const absRoot = path.resolve(rootDir);\r\n const languages: Record<string, number> = {};\r\n const linesByLanguage: Record<string, number> = {};\r\n const files: Array<{ path: string; language: string; lines: number; size: number }> = [];\r\n let totalFiles = 0;\r\n let totalLines = 0;\r\n\r\n // Recursive file scan\r\n function walk(dir: string, depth: number): void {\r\n if (depth > MAX_DEPTH || totalFiles > MAX_FILES) return;\r\n let entries: fs.Dirent[];\r\n try {\r\n entries = fs.readdirSync(dir, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n for (const entry of entries) {\r\n if (totalFiles > MAX_FILES) break;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) {\r\n walk(fullPath, depth + 1);\r\n }\r\n continue;\r\n }\r\n\r\n if (!entry.isFile()) continue;\r\n\r\n const ext = path.extname(entry.name).toLowerCase();\r\n // Special file name detection\r\n const lang = detectLanguageByFile(entry.name, ext);\r\n if (!lang) continue;\r\n\r\n let lineCount = 0;\r\n let fileSize = 0;\r\n try {\r\n const stat = fs.statSync(fullPath);\r\n fileSize = stat.size;\r\n // Only count lines for reasonable files (< 1MB)\r\n if (fileSize < 1_048_576) {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n lineCount = content.split('\\n').length;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n\r\n languages[lang] = (languages[lang] || 0) + 1;\r\n linesByLanguage[lang] = (linesByLanguage[lang] || 0) + lineCount;\r\n totalFiles++;\r\n totalLines += lineCount;\r\n\r\n const relPath = path.relative(absRoot, fullPath).replace(/\\\\/g, '/');\r\n files.push({ path: relPath, language: lang, lines: lineCount, size: fileSize });\r\n }\r\n }\r\n\r\n walk(absRoot, 0);\r\n\r\n // Determine primary language (by file count, ignoring config-only languages)\r\n const codeLangs = Object.entries(languages)\r\n .filter(([k]) => !['json', 'yaml', 'toml', 'markdown', 'html', 'css', 'scss', 'less', 'sass'].includes(k))\r\n .sort((a, b) => b[1] - a[1]);\r\n const primaryLanguage = codeLangs[0]?.[0] || 'unknown';\r\n\r\n // Detect frameworks\r\n const frameworks = detectFrameworks(absRoot, languages, files);\r\n\r\n // Detect project type\r\n const projectType = detectProjectType(absRoot, languages, frameworks);\r\n\r\n // Detect package manager\r\n const packageManager = detectPackageManager(absRoot);\r\n\r\n return {\r\n languages,\r\n linesByLanguage,\r\n totalFiles,\r\n totalLines,\r\n primaryLanguage,\r\n frameworks,\r\n projectType,\r\n packageManager,\r\n files,\r\n };\r\n}\r\n\r\nfunction detectLanguageByFile(fileName: string, ext: string): string | null {\r\n // Special file names\r\n if (fileName === 'Dockerfile' || fileName.startsWith('Dockerfile.')) return 'docker';\r\n if (fileName === 'Makefile') return 'makefile';\r\n if (fileName === 'CMakeLists.txt') return 'cmake';\r\n if (fileName === 'Vagrantfile') return 'ruby';\r\n if (fileName === 'Gemfile') return 'ruby';\r\n if (fileName === 'Rakefile') return 'ruby';\r\n if (fileName === 'Cargo.toml') return 'rust';\r\n if (fileName === 'go.mod' || fileName === 'go.sum') return 'go';\r\n\r\n return EXTENSION_MAP[ext] || null;\r\n}\r\n\r\n// ===== Framework Detection =====\r\n\r\ninterface FrameworkRule {\r\n name: string;\r\n detect: (root: string, langs: Record<string, number>, files: Array<{ path: string }>) => FrameworkDetection | null;\r\n}\r\n\r\nconst FRAMEWORK_RULES: FrameworkRule[] = [\r\n // --- Node.js / JavaScript ---\r\n {\r\n name: 'express',\r\n detect: (root) => detectFromPackageJson(root, 'express', 'Express'),\r\n },\r\n {\r\n name: 'nestjs',\r\n detect: (root) => detectFromPackageJson(root, '@nestjs/core', 'NestJS'),\r\n },\r\n {\r\n name: 'fastify',\r\n detect: (root) => detectFromPackageJson(root, 'fastify', 'Fastify'),\r\n },\r\n {\r\n name: 'koa',\r\n detect: (root) => detectFromPackageJson(root, 'koa', 'Koa'),\r\n },\r\n {\r\n name: 'hapi',\r\n detect: (root) => detectFromPackageJson(root, '@hapi/hapi', 'Hapi'),\r\n },\r\n {\r\n name: 'nextjs',\r\n detect: (root) => detectFromPackageJson(root, 'next', 'Next.js'),\r\n },\r\n {\r\n name: 'nuxtjs',\r\n detect: (root) => detectFromPackageJson(root, 'nuxt', 'Nuxt.js'),\r\n },\r\n {\r\n name: 'react',\r\n detect: (root) => detectFromPackageJson(root, 'react', 'React'),\r\n },\r\n {\r\n name: 'vue',\r\n detect: (root) => detectFromPackageJson(root, 'vue', 'Vue'),\r\n },\r\n {\r\n name: 'angular',\r\n detect: (root) => detectFromPackageJson(root, '@angular/core', 'Angular'),\r\n },\r\n {\r\n name: 'svelte',\r\n detect: (root) => detectFromPackageJson(root, 'svelte', 'Svelte'),\r\n },\r\n {\r\n name: 'electron',\r\n detect: (root) => detectFromPackageJson(root, 'electron', 'Electron'),\r\n },\r\n {\r\n name: 'sequelize',\r\n detect: (root) => detectFromPackageJson(root, 'sequelize', 'Sequelize'),\r\n },\r\n {\r\n name: 'typeorm',\r\n detect: (root) => detectFromPackageJson(root, 'typeorm', 'TypeORM'),\r\n },\r\n {\r\n name: 'prisma',\r\n detect: (root) => detectFromPackageJson(root, 'prisma', 'Prisma') || detectFromPackageJson(root, '@prisma/client', 'Prisma'),\r\n },\r\n {\r\n name: 'mongoose',\r\n detect: (root) => detectFromPackageJson(root, 'mongoose', 'Mongoose'),\r\n },\r\n {\r\n name: 'playwright',\r\n detect: (root) => detectFromPackageJson(root, '@playwright/test', 'Playwright'),\r\n },\r\n // --- Python ---\r\n {\r\n name: 'django',\r\n detect: (root) => detectFromRequirements(root, 'django', 'Django') || detectFromFile(root, 'manage.py', 'Django'),\r\n },\r\n {\r\n name: 'flask',\r\n detect: (root) => detectFromRequirements(root, 'flask', 'Flask'),\r\n },\r\n {\r\n name: 'fastapi',\r\n detect: (root) => detectFromRequirements(root, 'fastapi', 'FastAPI'),\r\n },\r\n {\r\n name: 'pytorch',\r\n detect: (root) => detectFromRequirements(root, 'torch', 'PyTorch'),\r\n },\r\n {\r\n name: 'tensorflow',\r\n detect: (root) => detectFromRequirements(root, 'tensorflow', 'TensorFlow'),\r\n },\r\n // --- Go ---\r\n {\r\n name: 'gin',\r\n detect: (root) => detectFromGoMod(root, 'github.com/gin-gonic/gin', 'Gin'),\r\n },\r\n {\r\n name: 'echo',\r\n detect: (root) => detectFromGoMod(root, 'github.com/labstack/echo', 'Echo'),\r\n },\r\n {\r\n name: 'fiber',\r\n detect: (root) => detectFromGoMod(root, 'github.com/gofiber/fiber', 'Fiber'),\r\n },\r\n // --- Java ---\r\n {\r\n name: 'spring-boot',\r\n detect: (root) => detectFromFile(root, 'pom.xml', 'Spring Boot', 'spring-boot') || detectFromFile(root, 'build.gradle', 'Spring Boot', 'spring-boot'),\r\n },\r\n // --- Rust ---\r\n {\r\n name: 'actix-web',\r\n detect: (root) => detectFromCargoToml(root, 'actix-web', 'Actix Web'),\r\n },\r\n {\r\n name: 'axum',\r\n detect: (root) => detectFromCargoToml(root, 'axum', 'Axum'),\r\n },\r\n // --- Ruby ---\r\n {\r\n name: 'rails',\r\n detect: (root) => detectFromFile(root, 'Gemfile', 'Ruby on Rails', 'rails'),\r\n },\r\n // --- PHP ---\r\n {\r\n name: 'laravel',\r\n detect: (root) => detectFromFile(root, 'artisan', 'Laravel'),\r\n },\r\n];\r\n\r\nfunction detectFromPackageJson(root: string, dep: string, name: string): FrameworkDetection | null {\r\n // Search in root and common subdirs\r\n const candidates = [\r\n path.join(root, 'package.json'),\r\n path.join(root, 'backend', 'package.json'),\r\n path.join(root, 'server', 'package.json'),\r\n path.join(root, 'api', 'package.json'),\r\n path.join(root, 'frontend', 'package.json'),\r\n path.join(root, 'web', 'package.json'),\r\n path.join(root, 'client', 'package.json'),\r\n ];\r\n\r\n for (const pkgPath of candidates) {\r\n try {\r\n if (!fs.existsSync(pkgPath)) continue;\r\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\r\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies };\r\n if (dep in allDeps) {\r\n return {\r\n name,\r\n version: allDeps[dep]?.replace(/[\\^~>=<]*/g, ''),\r\n confidence: 0.95,\r\n evidence: `Found \"${dep}\" in ${path.relative(root, pkgPath)}`,\r\n };\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromRequirements(root: string, dep: string, name: string): FrameworkDetection | null {\r\n const candidates = [\r\n path.join(root, 'requirements.txt'),\r\n path.join(root, 'Pipfile'),\r\n path.join(root, 'pyproject.toml'),\r\n path.join(root, 'setup.py'),\r\n path.join(root, 'setup.cfg'),\r\n ];\r\n\r\n for (const filePath of candidates) {\r\n try {\r\n if (!fs.existsSync(filePath)) continue;\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n const pattern = new RegExp(`^${dep}([>=<~!\\\\s]|$)`, 'im');\r\n if (pattern.test(content)) {\r\n return {\r\n name,\r\n confidence: 0.9,\r\n evidence: `Found \"${dep}\" in ${path.basename(filePath)}`,\r\n };\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromGoMod(root: string, module: string, name: string): FrameworkDetection | null {\r\n const goModPath = path.join(root, 'go.mod');\r\n try {\r\n if (!fs.existsSync(goModPath)) return null;\r\n const content = fs.readFileSync(goModPath, 'utf-8');\r\n if (content.includes(module)) {\r\n return {\r\n name,\r\n confidence: 0.95,\r\n evidence: `Found \"${module}\" in go.mod`,\r\n };\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromCargoToml(root: string, crate: string, name: string): FrameworkDetection | null {\r\n const cargoPath = path.join(root, 'Cargo.toml');\r\n try {\r\n if (!fs.existsSync(cargoPath)) return null;\r\n const content = fs.readFileSync(cargoPath, 'utf-8');\r\n if (content.includes(crate)) {\r\n return {\r\n name,\r\n confidence: 0.9,\r\n evidence: `Found \"${crate}\" in Cargo.toml`,\r\n };\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromFile(root: string, fileName: string, name: string, searchTerm?: string): FrameworkDetection | null {\r\n const filePath = path.join(root, fileName);\r\n try {\r\n if (!fs.existsSync(filePath)) return null;\r\n if (searchTerm) {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n if (!content.toLowerCase().includes(searchTerm.toLowerCase())) return null;\r\n }\r\n return {\r\n name,\r\n confidence: 0.8,\r\n evidence: `Found ${fileName}${searchTerm ? ` containing \"${searchTerm}\"` : ''}`,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction detectFrameworks(root: string, langs: Record<string, number>, files: Array<{ path: string }>): FrameworkDetection[] {\r\n const detected: FrameworkDetection[] = [];\r\n for (const rule of FRAMEWORK_RULES) {\r\n const result = rule.detect(root, langs, files);\r\n if (result) detected.push(result);\r\n }\r\n return detected;\r\n}\r\n\r\n// ===== Project Type Detection =====\r\n\r\nfunction detectProjectType(root: string, langs: Record<string, number>, frameworks: FrameworkDetection[]): ProjectType {\r\n const frameworkNames = new Set(frameworks.map(f => f.name.toLowerCase()));\r\n\r\n // Monorepo detection\r\n const hasLerna = fs.existsSync(path.join(root, 'lerna.json'));\r\n const hasPnpmWorkspace = fs.existsSync(path.join(root, 'pnpm-workspace.yaml'));\r\n const hasNxJson = fs.existsSync(path.join(root, 'nx.json'));\r\n const hasTurboJson = fs.existsSync(path.join(root, 'turbo.json'));\r\n let hasWorkspaces = false;\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));\r\n hasWorkspaces = Array.isArray(pkg.workspaces) || typeof pkg.workspaces === 'object';\r\n } catch {\r\n // ignore\r\n }\r\n if (hasLerna || hasPnpmWorkspace || hasNxJson || hasTurboJson || hasWorkspaces) {\r\n return 'monorepo';\r\n }\r\n\r\n // Library detection\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));\r\n if (pkg.main || pkg.exports || pkg.module) {\r\n const hasNoServer = !frameworkNames.has('express') && !frameworkNames.has('fastify') &&\r\n !frameworkNames.has('koa') && !frameworkNames.has('nestjs');\r\n const hasNoFrontend = !frameworkNames.has('react') && !frameworkNames.has('vue') &&\r\n !frameworkNames.has('angular') && !frameworkNames.has('svelte');\r\n if (hasNoServer && hasNoFrontend && pkg.keywords) return 'library';\r\n }\r\n if (pkg.bin) return 'cli-tool';\r\n } catch {\r\n // ignore\r\n }\r\n\r\n // SSR frameworks\r\n if (frameworkNames.has('next.js') || frameworkNames.has('nuxt.js')) return 'frontend-ssr';\r\n\r\n // Mobile\r\n if (frameworkNames.has('electron')) return 'fullstack';\r\n if (langs['dart']) return 'mobile';\r\n if (langs['swift'] && !langs['typescript'] && !langs['python']) return 'mobile';\r\n\r\n // Fullstack detection (has both frontend and backend frameworks)\r\n const hasBackend = frameworkNames.has('express') || frameworkNames.has('fastify') ||\r\n frameworkNames.has('nestjs') || frameworkNames.has('koa') ||\r\n frameworkNames.has('django') || frameworkNames.has('flask') ||\r\n frameworkNames.has('fastapi') || frameworkNames.has('gin') ||\r\n frameworkNames.has('spring boot') || frameworkNames.has('rails') ||\r\n frameworkNames.has('laravel');\r\n const hasFrontend = frameworkNames.has('react') || frameworkNames.has('vue') ||\r\n frameworkNames.has('angular') || frameworkNames.has('svelte');\r\n\r\n if (hasBackend && hasFrontend) return 'fullstack';\r\n if (hasBackend) return 'backend-api';\r\n if (hasFrontend) return 'frontend-spa';\r\n\r\n // Rust/Go API\r\n if (frameworkNames.has('actix web') || frameworkNames.has('axum') ||\r\n frameworkNames.has('gin') || frameworkNames.has('echo') || frameworkNames.has('fiber')) {\r\n return 'backend-api';\r\n }\r\n\r\n return 'unknown';\r\n}\r\n\r\n// ===== Package Manager Detection =====\r\n\r\nfunction detectPackageManager(root: string): string | undefined {\r\n if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';\r\n if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';\r\n if (fs.existsSync(path.join(root, 'bun.lockb'))) return 'bun';\r\n if (fs.existsSync(path.join(root, 'package-lock.json'))) return 'npm';\r\n if (fs.existsSync(path.join(root, 'Pipfile.lock'))) return 'pipenv';\r\n if (fs.existsSync(path.join(root, 'poetry.lock'))) return 'poetry';\r\n if (fs.existsSync(path.join(root, 'go.sum'))) return 'go-modules';\r\n if (fs.existsSync(path.join(root, 'Cargo.lock'))) return 'cargo';\r\n if (fs.existsSync(path.join(root, 'Gemfile.lock'))) return 'bundler';\r\n if (fs.existsSync(path.join(root, 'composer.lock'))) return 'composer';\r\n return undefined;\r\n}\r\n","/**\r\n * Universal Project Scanner\r\n *\r\n * Scans any project directory and extracts entities (modules, classes,\r\n * functions, APIs, models) and relationships. Works with any language\r\n * by combining:\r\n * 1. Static analysis (ts-morph for TS/JS)\r\n * 2. Pattern matching (regex for Python/Go/Java/etc.)\r\n * 3. Config file parsing (package.json, OpenAPI, etc.)\r\n * 4. LLM fallback (for unknown patterns)\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type {\r\n ScanResult,\r\n ExtractedEntity,\r\n ExtractedRelationship,\r\n GraphNodeType,\r\n GraphEdgeRelation,\r\n DiscoveredFile,\r\n} from '../graph/types.js';\r\nimport { detectProject, type LanguageDetectionResult } from './language-detector.js';\r\n\r\nexport interface ScanOptions {\r\n /** Project root directory */\r\n rootDir: string;\r\n /** Max files to deeply analyze (default: 500) */\r\n maxDeepScan?: number;\r\n /** Enable LLM fallback for unknown patterns */\r\n useLlm?: boolean;\r\n /** Progress callback */\r\n onProgress?: (phase: string, percent: number, detail?: string) => void;\r\n}\r\n\r\n/**\r\n * Scan a project and extract all entities and relationships.\r\n */\r\nexport async function scanProject(options: ScanOptions): Promise<ScanResult> {\r\n const { rootDir, maxDeepScan = 500, onProgress } = options;\r\n const startTime = Date.now();\r\n\r\n onProgress?.('detecting', 0, 'Detecting languages and frameworks...');\r\n\r\n // Phase 1: Language detection\r\n const detection = detectProject(rootDir);\r\n\r\n onProgress?.('detecting', 100, `Found ${detection.totalFiles} files, primary: ${detection.primaryLanguage}`);\r\n\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Phase 2: Extract entities by language\r\n const sourceFiles = detection.files.filter(f => {\r\n const lang = f.language;\r\n return !['json', 'yaml', 'toml', 'markdown', 'html', 'css', 'scss', 'less', 'sass', 'docker', 'shell', 'powershell'].includes(lang);\r\n });\r\n\r\n const filesToAnalyze = sourceFiles.slice(0, maxDeepScan);\r\n\r\n for (let i = 0; i < filesToAnalyze.length; i++) {\r\n const file = filesToAnalyze[i]!;\r\n const percent = Math.round((i / filesToAnalyze.length) * 100);\r\n if (i % 20 === 0) {\r\n onProgress?.('scanning', percent, `Scanning ${file.path}...`);\r\n }\r\n\r\n const fullPath = path.join(rootDir, file.path);\r\n try {\r\n const extracted = extractEntitiesFromFile(fullPath, file.path, file.language);\r\n entities.push(...extracted.entities);\r\n relationships.push(...extracted.relationships);\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n\r\n onProgress?.('scanning', 100, `Extracted ${entities.length} entities`);\r\n\r\n // Phase 3: Extract from config files\r\n onProgress?.('configs', 0, 'Parsing config files...');\r\n const configEntities = extractFromConfigs(rootDir, detection);\r\n entities.push(...configEntities.entities);\r\n relationships.push(...configEntities.relationships);\r\n onProgress?.('configs', 100, 'Config parsing complete');\r\n\r\n // Phase 4: Infer cross-file relationships\r\n onProgress?.('relations', 0, 'Building relationships...');\r\n const inferredRelations = inferRelationships(entities, rootDir);\r\n relationships.push(...inferredRelations);\r\n onProgress?.('relations', 100, `${relationships.length} total relationships`);\r\n\r\n // Convert detection files to DiscoveredFile format\r\n const discoveredFiles: DiscoveredFile[] = detection.files.map(f => ({\r\n path: f.path,\r\n language: f.language,\r\n category: categorizeFile(f.path, f.language),\r\n lines: f.lines,\r\n size: f.size,\r\n }));\r\n\r\n return {\r\n languages: detection.languages,\r\n frameworks: detection.frameworks,\r\n files: discoveredFiles,\r\n entities,\r\n relationships,\r\n duration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n// ===== File Entity Extraction =====\r\n\r\ninterface ExtractionResult {\r\n entities: ExtractedEntity[];\r\n relationships: ExtractedRelationship[];\r\n}\r\n\r\nfunction extractEntitiesFromFile(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n switch (language) {\r\n case 'typescript':\r\n case 'javascript':\r\n return extractFromTsJs(fullPath, relPath, language);\r\n case 'python':\r\n return extractFromPython(fullPath, relPath);\r\n case 'go':\r\n return extractFromGo(fullPath, relPath);\r\n case 'java':\r\n case 'kotlin':\r\n return extractFromJavaKotlin(fullPath, relPath, language);\r\n case 'rust':\r\n return extractFromRust(fullPath, relPath);\r\n case 'ruby':\r\n return extractFromRuby(fullPath, relPath);\r\n case 'php':\r\n return extractFromPHP(fullPath, relPath);\r\n case 'vue':\r\n case 'svelte':\r\n return extractFromTsJs(fullPath, relPath, 'typescript'); // Extract script section\r\n default:\r\n return { entities: [], relationships: [] };\r\n }\r\n}\r\n\r\n// ===== TypeScript / JavaScript Extraction =====\r\n\r\nfunction extractFromTsJs(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({\r\n id: fileId,\r\n name: path.basename(relPath),\r\n type: 'file',\r\n filePath: relPath,\r\n language,\r\n metadata: {},\r\n });\r\n\r\n // Extract classes\r\n const classRegex = /(?:export\\s+)?(?:abstract\\s+)?class\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?(?:\\s+implements\\s+([\\w,\\s]+))?\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const extendsClass = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n\r\n entities.push({\r\n id: classId,\r\n name: className,\r\n type: detectClassType(className, content),\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { extends: extendsClass },\r\n });\r\n\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n\r\n if (extendsClass) {\r\n relationships.push({\r\n sourceId: classId,\r\n targetId: `class:*:${extendsClass}`,\r\n relation: 'extends',\r\n });\r\n }\r\n }\r\n\r\n // Extract functions (top-level and exported)\r\n const funcRegex = /(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId,\r\n name: funcName,\r\n type: 'function',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract arrow function exports\r\n const arrowFuncRegex = /export\\s+(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?\\(/g;\r\n while ((match = arrowFuncRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId,\r\n name: funcName,\r\n type: 'function',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { arrow: true },\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract Express/Fastify routes\r\n const routeRegex = /(?:router|app)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/gi;\r\n while ((match = routeRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId,\r\n name: `${method} ${routePath}`,\r\n type: 'api',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract imports\r\n const importRegex = /(?:import\\s+.*from\\s+['\"`]([^'\"`]+)['\"`]|require\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*\\))/g;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const importPath = match[1] || match[2]!;\r\n if (importPath.startsWith('.')) {\r\n // Relative import → file dependency\r\n const resolved = resolveRelativeImport(relPath, importPath);\r\n relationships.push({\r\n sourceId: fileId,\r\n targetId: `file:${resolved}`,\r\n relation: 'imports',\r\n });\r\n } else {\r\n // External dependency\r\n const depName = importPath.startsWith('@') ? importPath.split('/').slice(0, 2).join('/') : importPath.split('/')[0]!;\r\n const depId = `dep:${depName}`;\r\n entities.push({\r\n id: depId,\r\n name: depName,\r\n type: 'dependency',\r\n filePath: '',\r\n language: 'external',\r\n metadata: { external: true },\r\n });\r\n relationships.push({ sourceId: fileId, targetId: depId, relation: 'depends-on' });\r\n }\r\n }\r\n\r\n // Extract Sequelize/TypeORM model definitions\r\n if (content.includes('.init(') || content.includes('Model.init') || content.includes('@Entity') || content.includes('defineModel')) {\r\n const tableMatch = content.match(/tableName:\\s*['\"`](\\w+)['\"`]/);\r\n if (tableMatch) {\r\n const tableName = tableMatch[1]!;\r\n const modelId = `model:${tableName}`;\r\n entities.push({\r\n id: modelId,\r\n name: tableName,\r\n type: 'model',\r\n filePath: relPath,\r\n language,\r\n metadata: { orm: 'sequelize' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Python Extraction =====\r\n\r\nfunction extractFromPython(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'python', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /^class\\s+(\\w+)(?:\\(([^)]*)\\))?\\s*:/gm;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const bases = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n entities.push({\r\n id: classId, name: className,\r\n type: detectPythonClassType(className, bases || '', content),\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { bases },\r\n });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /^(?:async\\s+)?def\\s+(\\w+)\\s*\\(/gm;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName.startsWith('_') && funcName !== '__init__') continue;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId, name: funcName, type: 'function',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // FastAPI/Flask routes\r\n const routeRegex = /@(?:app|router)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"]([^'\"]+)['\"]/gi;\r\n while ((match = routeRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId, name: `${method} ${routePath}`, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Django URL patterns\r\n const djangoUrlRegex = /path\\s*\\(\\s*['\"]([^'\"]+)['\"],\\s*(\\w+)/g;\r\n while ((match = djangoUrlRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'route',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { handler: match[2] },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Django models\r\n const djangoModelRegex = /class\\s+(\\w+)\\((?:models\\.)?Model\\)/g;\r\n while ((match = djangoModelRegex.exec(content)) !== null) {\r\n const modelName = match[1]!;\r\n const modelId = `model:${modelName}`;\r\n entities.push({\r\n id: modelId, name: modelName, type: 'model',\r\n filePath: relPath, language: 'python', metadata: { orm: 'django' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // SQLAlchemy models\r\n const sqlalchemyRegex = /class\\s+(\\w+)\\(.*(?:Base|DeclarativeBase|db\\.Model)\\)/g;\r\n while ((match = sqlalchemyRegex.exec(content)) !== null) {\r\n const modelName = match[1]!;\r\n const modelId = `model:${modelName}`;\r\n entities.push({\r\n id: modelId, name: modelName, type: 'model',\r\n filePath: relPath, language: 'python', metadata: { orm: 'sqlalchemy' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Imports\r\n const importRegex = /^(?:from\\s+([\\w.]+)\\s+import|import\\s+([\\w.]+))/gm;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const mod = match[1] || match[2]!;\r\n if (mod.startsWith('.')) {\r\n relationships.push({ sourceId: fileId, targetId: `file:${mod}`, relation: 'imports' });\r\n } else {\r\n const depName = mod.split('.')[0]!;\r\n entities.push({ id: `dep:${depName}`, name: depName, type: 'dependency', filePath: '', language: 'external', metadata: { external: true } });\r\n relationships.push({ sourceId: fileId, targetId: `dep:${depName}`, relation: 'depends-on' });\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Go Extraction =====\r\n\r\nfunction extractFromGo(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'go', metadata: {} });\r\n\r\n // Structs\r\n const structRegex = /type\\s+(\\w+)\\s+struct\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = structRegex.exec(content)) !== null) {\r\n const structName = match[1]!;\r\n const structId = `class:${relPath}:${structName}`;\r\n entities.push({\r\n id: structId, name: structName,\r\n type: structName.endsWith('Model') || structName.endsWith('Entity') ? 'model' : 'class',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: {},\r\n });\r\n relationships.push({ sourceId: structId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /func\\s+(?:\\(\\w+\\s+\\*?\\w+\\)\\s+)?(\\w+)\\s*\\(/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName[0] !== funcName[0]!.toUpperCase()) continue; // Skip unexported\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId, name: funcName, type: 'function',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Gin/Echo routes\r\n const ginRouteRegex = /\\.(GET|POST|PUT|PATCH|DELETE)\\s*\\(\\s*\"([^\"]+)\"/gi;\r\n while ((match = ginRouteRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId, name: `${method} ${routePath}`, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Java/Kotlin Extraction =====\r\n\r\nfunction extractFromJavaKotlin(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language, metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /(?:public\\s+)?(?:abstract\\s+)?(?:class|interface|enum)\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const classId = `class:${relPath}:${className}`;\r\n entities.push({\r\n id: classId, name: className,\r\n type: content.includes('@Entity') || content.includes('@Table') ? 'model' : 'class',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language, metadata: {},\r\n });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Spring Boot endpoints\r\n const springRegex = /@(?:Get|Post|Put|Patch|Delete|Request)Mapping\\s*\\(\\s*(?:value\\s*=\\s*)?[\"']([^\"']+)[\"']/g;\r\n while ((match = springRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language, metadata: { path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Rust Extraction =====\r\n\r\nfunction extractFromRust(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'rust', metadata: {} });\r\n\r\n // Structs\r\n const structRegex = /pub\\s+struct\\s+(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = structRegex.exec(content)) !== null) {\r\n const structName = match[1]!;\r\n const structId = `class:${relPath}:${structName}`;\r\n entities.push({ id: structId, name: structName, type: 'class', filePath: relPath, line: getLineNumber(content, match.index), language: 'rust', metadata: {} });\r\n relationships.push({ sourceId: structId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /pub\\s+(?:async\\s+)?fn\\s+(\\w+)/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({ id: funcId, name: funcName, type: 'function', filePath: relPath, line: getLineNumber(content, match.index), language: 'rust', metadata: {} });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Ruby Extraction =====\r\n\r\nfunction extractFromRuby(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'ruby', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /class\\s+(\\w+)(?:\\s*<\\s*(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const base = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n const type: GraphNodeType = base === 'ApplicationRecord' || base === 'ActiveRecord::Base' ? 'model' : 'class';\r\n entities.push({ id: classId, name: className, type, filePath: relPath, line: getLineNumber(content, match.index), language: 'ruby', metadata: { extends: base } });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Methods\r\n const defRegex = /def\\s+(?:self\\.)?(\\w+)/g;\r\n while ((match = defRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName.startsWith('_')) continue;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({ id: funcId, name: funcName, type: 'function', filePath: relPath, line: getLineNumber(content, match.index), language: 'ruby', metadata: {} });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== PHP Extraction =====\r\n\r\nfunction extractFromPHP(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'php', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /(?:abstract\\s+)?class\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const base = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n const type: GraphNodeType = base === 'Model' || base === 'Eloquent' ? 'model' : 'class';\r\n entities.push({ id: classId, name: className, type, filePath: relPath, line: getLineNumber(content, match.index), language: 'php', metadata: {} });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Laravel routes\r\n const laravelRouteRegex = /Route::(get|post|put|patch|delete)\\s*\\(\\s*['\"]([^'\"]+)['\"]/gi;\r\n while ((match = laravelRouteRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({ id: apiId, name: `${method} ${routePath}`, type: 'api', filePath: relPath, line: getLineNumber(content, match.index), language: 'php', metadata: { method, path: routePath } });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Config File Extraction =====\r\n\r\nfunction extractFromConfigs(rootDir: string, _detection: LanguageDetectionResult): ExtractionResult {\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Extract dependencies from package.json\r\n const pkgPath = path.join(rootDir, 'package.json');\r\n if (fs.existsSync(pkgPath)) {\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\r\n const allDeps = { ...pkg.dependencies };\r\n for (const [name, version] of Object.entries(allDeps)) {\r\n const depId = `dep:${name}`;\r\n entities.push({\r\n id: depId, name, type: 'dependency',\r\n filePath: 'package.json', language: 'external',\r\n metadata: { version, source: 'npm', external: true },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Extract from OpenAPI/Swagger spec\r\n const openAPIFiles = ['openapi.json', 'openapi.yaml', 'openapi.yml', 'swagger.json', 'swagger.yaml'];\r\n for (const apiFile of openAPIFiles) {\r\n const apiPath = path.join(rootDir, apiFile);\r\n if (fs.existsSync(apiPath)) {\r\n try {\r\n const content = fs.readFileSync(apiPath, 'utf-8');\r\n // Simple path extraction from OpenAPI\r\n const pathRegex = /\"(\\/[^\"]+)\":\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = pathRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'api',\r\n filePath: apiFile, language: 'openapi',\r\n metadata: { source: 'openapi' },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n }\r\n\r\n // Extract Docker services\r\n const composeFiles = ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml'];\r\n for (const composeFile of composeFiles) {\r\n const composePath = path.join(rootDir, composeFile);\r\n if (fs.existsSync(composePath)) {\r\n try {\r\n const content = fs.readFileSync(composePath, 'utf-8');\r\n // Simple service extraction\r\n const serviceRegex = /^\\s{2}(\\w[\\w-]*):\\s*$/gm;\r\n let match: RegExpExecArray | null;\r\n while ((match = serviceRegex.exec(content)) !== null) {\r\n const serviceName = match[1]!;\r\n if (serviceName === 'services' || serviceName === 'volumes' || serviceName === 'networks') continue;\r\n entities.push({\r\n id: `service:${serviceName}`, name: serviceName,\r\n type: detectServiceType(serviceName),\r\n filePath: composeFile, language: 'docker',\r\n metadata: { source: 'docker-compose' },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Relationship Inference =====\r\n\r\nfunction inferRelationships(entities: ExtractedEntity[], _rootDir: string): ExtractedRelationship[] {\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Group entities by type\r\n const models = entities.filter(e => e.type === 'model');\r\n const apis = entities.filter(e => e.type === 'api');\r\n // const classes = entities.filter(e => e.type === 'class' || e.type === 'service');\r\n\r\n // Infer API → Model relationships by path patterns\r\n for (const api of apis) {\r\n const apiPath = (api.metadata.path as string) || api.name;\r\n for (const model of models) {\r\n const modelName = model.name.toLowerCase().replace(/_/g, '');\r\n const pathLower = apiPath.toLowerCase().replace(/[/-]/g, '');\r\n if (pathLower.includes(modelName) || modelName.includes(pathLower.split('/').pop() || '')) {\r\n const method = (api.metadata.method as string) || 'ANY';\r\n const relation: GraphEdgeRelation = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method) ? 'writes' : 'reads';\r\n relationships.push({ sourceId: api.id, targetId: model.id, relation });\r\n }\r\n }\r\n }\r\n\r\n // Infer module groupings from directory structure\r\n const fileEntities = entities.filter(e => e.type === 'file');\r\n for (const file of fileEntities) {\r\n const dir = path.dirname(file.filePath).split('/')[0];\r\n if (dir && dir !== '.') {\r\n const moduleId = `module:${dir}`;\r\n // Only add module entity if not already exists\r\n if (!entities.some(e => e.id === moduleId)) {\r\n entities.push({\r\n id: moduleId, name: dir, type: 'module',\r\n filePath: dir, language: 'directory',\r\n metadata: {},\r\n });\r\n }\r\n relationships.push({ sourceId: file.id, targetId: moduleId, relation: 'belongs-to' });\r\n }\r\n }\r\n\r\n return relationships;\r\n}\r\n\r\n// ===== Helpers =====\r\n\r\nfunction getLineNumber(content: string, index: number): number {\r\n return content.slice(0, index).split('\\n').length;\r\n}\r\n\r\nfunction resolveRelativeImport(currentFile: string, importPath: string): string {\r\n const dir = path.dirname(currentFile);\r\n let resolved = path.posix.join(dir, importPath);\r\n // Normalize: add .ts extension if missing\r\n if (!path.extname(resolved)) {\r\n resolved += '.ts';\r\n }\r\n return resolved;\r\n}\r\n\r\nfunction categorizeFile(filePath: string, language: string): 'source' | 'config' | 'test' | 'docs' | 'build' | 'asset' | 'other' {\r\n const lower = filePath.toLowerCase();\r\n if (lower.includes('.test.') || lower.includes('.spec.') || lower.includes('__tests__') || lower.includes('/test/') || lower.includes('/tests/')) return 'test';\r\n if (['json', 'yaml', 'toml'].includes(language) || lower.includes('config') || lower.includes('.env')) return 'config';\r\n if (language === 'markdown' || lower.includes('/docs/') || lower.includes('/doc/')) return 'docs';\r\n if (language === 'docker' || lower.includes('makefile') || lower.includes('webpack') || lower.includes('rollup') || lower.includes('vite')) return 'build';\r\n if (['html', 'css', 'scss', 'less'].includes(language)) return 'asset';\r\n return 'source';\r\n}\r\n\r\nfunction detectClassType(name: string, content: string): GraphNodeType {\r\n if (content.includes('.init(') || content.includes('@Entity') || content.includes('tableName')) return 'model';\r\n if (name.includes('Controller') || name.includes('Handler')) return 'service';\r\n if (name.includes('Service') || name.includes('Provider')) return 'service';\r\n if (name.includes('Middleware')) return 'middleware';\r\n if (name.includes('Component') || name.includes('Widget')) return 'component';\r\n return 'class';\r\n}\r\n\r\nfunction detectPythonClassType(name: string, bases: string, _content: string): GraphNodeType {\r\n if (bases.includes('Model') || bases.includes('Base') || bases.includes('db.Model')) return 'model';\r\n if (name.includes('View') || name.includes('ViewSet') || bases.includes('APIView')) return 'service';\r\n if (name.includes('Serializer')) return 'class';\r\n return 'class';\r\n}\r\n\r\nfunction detectServiceType(name: string): GraphNodeType {\r\n const lower = name.toLowerCase();\r\n if (lower.includes('redis') || lower.includes('memcache')) return 'cache';\r\n if (lower.includes('rabbit') || lower.includes('kafka') || lower.includes('nats')) return 'queue';\r\n if (lower.includes('postgres') || lower.includes('mysql') || lower.includes('mongo') || lower.includes('db')) return 'database';\r\n return 'external-api';\r\n}\r\n","/**\r\n * GitHub Cloner\r\n *\r\n * Clone a GitHub/GitLab/any git repository and scan it.\r\n * Supports: HTTPS URLs, shorthand (user/repo), and local paths.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as os from 'node:os';\r\nimport * as path from 'node:path';\r\nimport { execSync } from 'node:child_process';\r\nimport { scanProject, type ScanOptions } from './project-scanner.js';\r\nimport type { ScanResult } from '../graph/types.js';\r\n\r\nexport interface CloneOptions extends Omit<ScanOptions, 'rootDir'> {\r\n /** GitHub URL, shorthand (user/repo), or local path */\r\n target: string;\r\n /** Where to clone into (default: os temp dir) */\r\n cloneDir?: string;\r\n /** Branch/tag to clone (default: default branch) */\r\n branch?: string;\r\n /** Shallow clone depth (default: 1) */\r\n depth?: number;\r\n /** Keep cloned repo after scan (default: false for remote, true for local) */\r\n keepClone?: boolean;\r\n}\r\n\r\ninterface ResolvedTarget {\r\n type: 'local' | 'git';\r\n path: string;\r\n url?: string;\r\n repoName: string;\r\n}\r\n\r\n/**\r\n * Clone (if needed) and scan a project.\r\n */\r\nexport async function cloneAndScan(options: CloneOptions): Promise<ScanResult & { clonedPath?: string }> {\r\n const { target, cloneDir, branch, depth = 1, keepClone, onProgress, ...scanOpts } = options;\r\n\r\n const resolved = resolveTarget(target);\r\n\r\n let projectDir: string;\r\n\r\n if (resolved.type === 'local') {\r\n // Local path — scan directly\r\n projectDir = resolved.path;\r\n onProgress?.('clone', 100, `Using local directory: ${projectDir}`);\r\n } else {\r\n // Git URL — clone first\r\n const tempBase = cloneDir || path.join(os.tmpdir(), 'opencroc-scan');\r\n fs.mkdirSync(tempBase, { recursive: true });\r\n projectDir = path.join(tempBase, resolved.repoName);\r\n\r\n // Clean previous clone\r\n if (fs.existsSync(projectDir)) {\r\n fs.rmSync(projectDir, { recursive: true, force: true });\r\n }\r\n\r\n onProgress?.('clone', 10, `Cloning ${resolved.url}...`);\r\n\r\n const branchArg = branch ? `--branch ${branch}` : '';\r\n const depthArg = depth > 0 ? `--depth ${depth}` : '';\r\n const cmd = `git clone ${branchArg} ${depthArg} --single-branch ${resolved.url} \"${projectDir}\"`;\r\n\r\n try {\r\n execSync(cmd, {\r\n stdio: 'pipe',\r\n timeout: 120_000, // 2 minutes max\r\n });\r\n } catch (err) {\r\n throw new Error(`Failed to clone repository: ${(err as Error).message}`);\r\n }\r\n\r\n onProgress?.('clone', 100, `Cloned to ${projectDir}`);\r\n }\r\n\r\n // Scan the project\r\n const scanResult = await scanProject({\r\n rootDir: projectDir,\r\n ...scanOpts,\r\n onProgress,\r\n });\r\n\r\n // Cleanup if remote and not keeping\r\n if (resolved.type === 'git' && !keepClone) {\r\n try {\r\n fs.rmSync(projectDir, { recursive: true, force: true });\r\n } catch {\r\n // Best effort cleanup\r\n }\r\n }\r\n\r\n return {\r\n ...scanResult,\r\n clonedPath: resolved.type === 'git' ? projectDir : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Resolve a target string into a local path or git URL.\r\n */\r\nfunction resolveTarget(target: string): ResolvedTarget {\r\n // Local path — resolve first so relative paths work correctly\r\n const resolved = path.resolve(target);\r\n if (fs.existsSync(resolved)) {\r\n return {\r\n type: 'local',\r\n path: resolved,\r\n repoName: path.basename(resolved),\r\n };\r\n }\r\n\r\n // Full git URL (https://github.com/user/repo, git@github.com:user/repo.git)\r\n if (target.startsWith('https://') || target.startsWith('http://') || target.startsWith('git@')) {\r\n let url = target;\r\n // Ensure .git suffix\r\n if (!url.endsWith('.git')) url += '.git';\r\n const repoName = path.basename(url, '.git');\r\n return { type: 'git', path: '', url, repoName };\r\n }\r\n\r\n // Shorthand: user/repo → https://github.com/user/repo.git\r\n if (/^[\\w.-]+\\/[\\w.-]+$/.test(target)) {\r\n const url = `https://github.com/${target}.git`;\r\n const repoName = target.split('/')[1]!;\r\n return { type: 'git', path: '', url, repoName };\r\n }\r\n\r\n throw new Error(\r\n `Cannot resolve target \"${target}\". Expected: local path, GitHub URL, or shorthand (user/repo).`\r\n );\r\n}\r\n","/**\r\n * Knowledge Graph Builder\r\n *\r\n * Transforms raw ScanResult entities and relationships into a\r\n * fully connected KnowledgeGraph with deduplication, wildcard\r\n * resolution, module grouping, and statistics.\r\n */\r\n\r\nimport type {\r\n KnowledgeGraph,\r\n GraphNode,\r\n GraphEdge,\r\n ProjectMetadata,\r\n ProjectStats,\r\n ScanResult,\r\n ExtractedEntity,\r\n} from './types.js';\r\n\r\nexport interface GraphBuildOptions {\r\n /** Project name (from package.json or dir name) */\r\n projectName: string;\r\n /** Source type */\r\n source: 'local' | 'github' | 'gitlab' | 'url';\r\n sourceUrl?: string;\r\n /** Project root path */\r\n rootPath: string;\r\n}\r\n\r\n/**\r\n * Build a KnowledgeGraph from scan results.\r\n */\r\nexport function buildKnowledgeGraph(scanResult: ScanResult, options: GraphBuildOptions): KnowledgeGraph {\r\n const startTime = Date.now();\r\n\r\n // Deduplicate entities by ID\r\n const entityMap = new Map<string, ExtractedEntity>();\r\n for (const entity of scanResult.entities) {\r\n if (!entityMap.has(entity.id)) {\r\n entityMap.set(entity.id, entity);\r\n }\r\n }\r\n\r\n // Convert entities to graph nodes\r\n const nodes: GraphNode[] = [];\r\n for (const entity of entityMap.values()) {\r\n nodes.push({\r\n id: entity.id,\r\n label: entity.name,\r\n type: entity.type,\r\n filePath: entity.filePath || undefined,\r\n line: entity.line,\r\n module: inferModule(entity),\r\n language: entity.language,\r\n metadata: entity.metadata,\r\n status: 'idle',\r\n });\r\n }\r\n\r\n // Resolve wildcard references and build edges\r\n const edges: GraphEdge[] = [];\r\n const edgeSet = new Set<string>();\r\n\r\n for (const rel of scanResult.relationships) {\r\n let targetId = rel.targetId;\r\n\r\n // Resolve wildcard references (e.g., class:*:ClassName)\r\n if (targetId.includes(':*:')) {\r\n const suffix = targetId.split(':*:')[1]!;\r\n const resolved = findMatchingEntity(entityMap, targetId.split(':')[0]!, suffix);\r\n if (resolved) {\r\n targetId = resolved;\r\n } else {\r\n continue; // Can't resolve — skip\r\n }\r\n }\r\n\r\n // Skip self-references\r\n if (rel.sourceId === targetId) continue;\r\n\r\n // Skip if either node doesn't exist\r\n if (!entityMap.has(rel.sourceId) && !entityMap.has(targetId)) continue;\r\n\r\n // Deduplicate edges\r\n const edgeKey = `${rel.sourceId}->${targetId}:${rel.relation}`;\r\n if (edgeSet.has(edgeKey)) continue;\r\n edgeSet.add(edgeKey);\r\n\r\n edges.push({\r\n id: `edge-${edges.length}`,\r\n source: rel.sourceId,\r\n target: targetId,\r\n relation: rel.relation,\r\n metadata: rel.metadata,\r\n });\r\n }\r\n\r\n // Build project metadata\r\n const projectInfo = buildProjectMetadata(scanResult, options, nodes);\r\n\r\n return {\r\n nodes,\r\n edges,\r\n projectInfo,\r\n builtAt: new Date().toISOString(),\r\n buildDuration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n/**\r\n * Query the knowledge graph for nodes matching criteria.\r\n */\r\nexport function queryNodes(graph: KnowledgeGraph, filter: Partial<Pick<GraphNode, 'type' | 'language' | 'module'>>): GraphNode[] {\r\n return graph.nodes.filter(n => {\r\n if (filter.type && n.type !== filter.type) return false;\r\n if (filter.language && n.language !== filter.language) return false;\r\n if (filter.module && n.module !== filter.module) return false;\r\n return true;\r\n });\r\n}\r\n\r\n/**\r\n * Get all neighbors of a node (incoming + outgoing).\r\n */\r\nexport function getNeighbors(graph: KnowledgeGraph, nodeId: string): { incoming: GraphEdge[]; outgoing: GraphEdge[] } {\r\n return {\r\n incoming: graph.edges.filter(e => e.target === nodeId),\r\n outgoing: graph.edges.filter(e => e.source === nodeId),\r\n };\r\n}\r\n\r\n/**\r\n * BFS traversal from a node, returning all reachable nodes within maxDepth.\r\n */\r\nexport function bfsTraversal(graph: KnowledgeGraph, startNodeId: string, maxDepth = 3): string[] {\r\n const visited = new Set<string>();\r\n const queue: Array<{ id: string; depth: number }> = [{ id: startNodeId, depth: 0 }];\r\n visited.add(startNodeId);\r\n\r\n // Build adjacency list\r\n const adjacency = new Map<string, string[]>();\r\n for (const edge of graph.edges) {\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n // Bidirectional for impact analysis\r\n if (!adjacency.has(edge.target)) adjacency.set(edge.target, []);\r\n adjacency.get(edge.target)!.push(edge.source);\r\n }\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n if (current.depth >= maxDepth) continue;\r\n\r\n const neighbors = adjacency.get(current.id) || [];\r\n for (const neighbor of neighbors) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n queue.push({ id: neighbor, depth: current.depth + 1 });\r\n }\r\n }\r\n }\r\n\r\n visited.delete(startNodeId);\r\n return [...visited];\r\n}\r\n\r\n/**\r\n * Find all paths between two nodes (up to maxPaths).\r\n */\r\nexport function findPaths(\r\n graph: KnowledgeGraph,\r\n fromId: string,\r\n toId: string,\r\n maxPaths = 5,\r\n maxDepth = 6,\r\n): string[][] {\r\n const paths: string[][] = [];\r\n\r\n // Build directed adjacency\r\n const adjacency = new Map<string, string[]>();\r\n for (const edge of graph.edges) {\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n }\r\n\r\n function dfs(current: string, target: string, path: string[], visited: Set<string>): void {\r\n if (paths.length >= maxPaths) return;\r\n if (path.length > maxDepth) return;\r\n\r\n if (current === target) {\r\n paths.push([...path]);\r\n return;\r\n }\r\n\r\n const neighbors = adjacency.get(current) || [];\r\n for (const neighbor of neighbors) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n path.push(neighbor);\r\n dfs(neighbor, target, path, visited);\r\n path.pop();\r\n visited.delete(neighbor);\r\n }\r\n }\r\n }\r\n\r\n const visited = new Set([fromId]);\r\n dfs(fromId, toId, [fromId], visited);\r\n return paths;\r\n}\r\n\r\n/**\r\n * Generate a Mermaid diagram from the knowledge graph.\r\n */\r\nexport function toMermaid(graph: KnowledgeGraph, options?: { maxNodes?: number; nodeTypes?: string[] }): string {\r\n const maxNodes = options?.maxNodes || 50;\r\n const nodeTypes = options?.nodeTypes;\r\n\r\n let filteredNodes = graph.nodes;\r\n if (nodeTypes) {\r\n filteredNodes = filteredNodes.filter(n => nodeTypes.includes(n.type));\r\n }\r\n filteredNodes = filteredNodes.slice(0, maxNodes);\r\n\r\n const nodeIds = new Set(filteredNodes.map(n => n.id));\r\n const filteredEdges = graph.edges.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target));\r\n\r\n const lines: string[] = ['graph TD'];\r\n\r\n // Style definitions\r\n lines.push(' classDef model fill:#4ecca3,color:#000,stroke:#2d9970');\r\n lines.push(' classDef api fill:#e94560,color:#fff,stroke:#c23049');\r\n lines.push(' classDef service fill:#3498db,color:#fff,stroke:#2378b8');\r\n lines.push(' classDef module fill:#f39c12,color:#000,stroke:#c27d0e');\r\n lines.push(' classDef component fill:#9b59b6,color:#fff,stroke:#7d3c98');\r\n lines.push(' classDef file fill:#555,color:#fff,stroke:#333');\r\n\r\n // Nodes\r\n for (const node of filteredNodes) {\r\n const safeId = sanitizeMermaidId(node.id);\r\n const safeLabel = node.label.replace(/\"/g, \"'\");\r\n lines.push(` ${safeId}[\"${safeLabel}\"]:::${node.type}`);\r\n }\r\n\r\n // Edges\r\n for (const edge of filteredEdges) {\r\n const safeSource = sanitizeMermaidId(edge.source);\r\n const safeTarget = sanitizeMermaidId(edge.target);\r\n const label = edge.relation;\r\n lines.push(` ${safeSource} -->|${label}| ${safeTarget}`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Get graph statistics summary.\r\n */\r\nexport function getGraphStats(graph: KnowledgeGraph): Record<string, number> {\r\n const stats: Record<string, number> = {\r\n totalNodes: graph.nodes.length,\r\n totalEdges: graph.edges.length,\r\n };\r\n\r\n // Count by node type\r\n for (const node of graph.nodes) {\r\n const key = `${node.type}Count`;\r\n stats[key] = (stats[key] || 0) + 1;\r\n }\r\n\r\n // Count by edge relation\r\n for (const edge of graph.edges) {\r\n const key = `${edge.relation}Count`;\r\n stats[key] = (stats[key] || 0) + 1;\r\n }\r\n\r\n return stats;\r\n}\r\n\r\n// ===== Helpers =====\r\n\r\nfunction inferModule(entity: ExtractedEntity): string | undefined {\r\n if (!entity.filePath) return undefined;\r\n const parts = entity.filePath.split('/');\r\n if (parts.length > 1) {\r\n // Use first meaningful directory as module\r\n const dir = parts[0]!;\r\n if (dir === 'src' && parts.length > 2) return parts[1];\r\n return dir;\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction findMatchingEntity(entityMap: Map<string, ExtractedEntity>, typePrefix: string, nameSuffix: string): string | null {\r\n for (const [id, entity] of entityMap) {\r\n if (id.startsWith(`${typePrefix}:`) && entity.name === nameSuffix) {\r\n return id;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction buildProjectMetadata(scanResult: ScanResult, options: GraphBuildOptions, nodes: GraphNode[]): ProjectMetadata {\r\n const stats: ProjectStats = {\r\n totalFiles: scanResult.files.length,\r\n totalLines: scanResult.files.reduce((sum, f) => sum + f.lines, 0),\r\n modules: nodes.filter(n => n.type === 'module').length,\r\n classes: nodes.filter(n => n.type === 'class').length,\r\n functions: nodes.filter(n => n.type === 'function').length,\r\n apiEndpoints: nodes.filter(n => n.type === 'api').length,\r\n dataModels: nodes.filter(n => n.type === 'model').length,\r\n dependencies: nodes.filter(n => n.type === 'dependency').length,\r\n linesByLanguage: scanResult.languages,\r\n };\r\n\r\n return {\r\n name: options.projectName,\r\n source: options.source,\r\n sourceUrl: options.sourceUrl,\r\n rootPath: options.rootPath,\r\n languages: scanResult.languages,\r\n frameworks: scanResult.frameworks.map(f => f.name),\r\n packageManager: undefined,\r\n projectType: 'unknown',\r\n stats,\r\n };\r\n}\r\n\r\nfunction sanitizeMermaidId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n","/**\r\n * AI Insight Engine\r\n *\r\n * Multi-perspective analysis powered by LLM. Generates:\r\n * - Risk reports (security, performance, data integrity, logic)\r\n * - Impact analysis (change blast radius)\r\n * - Multi-role reports (developer, architect, tester, product, student, executive)\r\n * - Digital twin simulation (AI-predicted test outcomes)\r\n */\r\n\r\nimport type {\r\n KnowledgeGraph,\r\n RiskAnnotation,\r\n RiskCategory,\r\n RiskSeverity,\r\n ImpactAnalysis,\r\n PerspectiveReport,\r\n ReportPerspective,\r\n ReportSection,\r\n SimulationScenario,\r\n SimulationResult,\r\n} from '../graph/types.js';\r\nimport { bfsTraversal, getNeighbors, toMermaid } from '../graph/index.js';\r\nimport type { LlmProvider } from '../types.js';\r\n\r\nexport interface InsightOptions {\r\n /** LLM provider for AI-enhanced analysis */\r\n llm?: LlmProvider;\r\n /** Enable LLM-based analysis (requires llm provider) */\r\n useLlm?: boolean;\r\n /** Progress callback */\r\n onProgress?: (phase: string, percent: number, detail?: string) => void;\r\n}\r\n\r\n// ===================================================================\r\n// Risk Analysis\r\n// ===================================================================\r\n\r\n/**\r\n * Analyze a knowledge graph for risks across all categories.\r\n * Combines rule-based static analysis with optional LLM enhancement.\r\n */\r\nexport async function analyzeRisks(\r\n graph: KnowledgeGraph,\r\n options?: InsightOptions,\r\n): Promise<RiskAnnotation[]> {\r\n const risks: RiskAnnotation[] = [];\r\n let riskCounter = 0;\r\n\r\n options?.onProgress?.('risk-analysis', 0, 'Starting risk analysis...');\r\n\r\n // --- Rule-based risk detection ---\r\n\r\n // 1. Security: Unprotected API endpoints\r\n const apis = graph.nodes.filter(n => n.type === 'api');\r\n const middlewares = graph.nodes.filter(n => n.type === 'middleware');\r\n const hasAuthMiddleware = middlewares.some(m =>\r\n m.label.toLowerCase().includes('auth') || m.label.toLowerCase().includes('jwt') || m.label.toLowerCase().includes('session')\r\n );\r\n\r\n for (const api of apis) {\r\n const incoming = graph.edges.filter(e => e.target === api.id);\r\n const hasAuth = incoming.some(e => {\r\n const sourceNode = graph.nodes.find(n => n.id === e.source);\r\n return sourceNode?.type === 'middleware' &&\r\n (sourceNode.label.toLowerCase().includes('auth') || e.relation === 'middleware-of');\r\n });\r\n\r\n if (!hasAuth && !hasAuthMiddleware) {\r\n const apiPath = (api.metadata.path as string) || api.label;\r\n const isSensitive = /user|admin|password|token|secret|key|delete|payment/i.test(apiPath);\r\n if (isSensitive) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'security',\r\n severity: 'high',\r\n title: `Potentially unprotected sensitive endpoint: ${api.label}`,\r\n description: `The endpoint ${api.label} appears to handle sensitive data but no authentication middleware was detected in the graph.`,\r\n affectedNodes: [api.id],\r\n suggestion: 'Add authentication middleware to protect this endpoint.',\r\n confidence: 0.6,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 20, 'Checking data integrity...');\r\n\r\n // 2. Data Integrity: Models without validation\r\n const models = graph.nodes.filter(n => n.type === 'model');\r\n for (const model of models) {\r\n const writeEdges = graph.edges.filter(e => e.target === model.id && e.relation === 'writes');\r\n if (writeEdges.length > 3) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'data-integrity',\r\n severity: 'medium',\r\n title: `High write fan-in on model: ${model.label}`,\r\n description: `Model \"${model.label}\" is written to by ${writeEdges.length} different endpoints. This increases risk of data conflicts and race conditions.`,\r\n affectedNodes: [model.id, ...writeEdges.map(e => e.source)],\r\n suggestion: 'Consider adding transaction boundaries or an optimistic locking strategy.',\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n\r\n // 3. Data Integrity: Cascade delete risk\r\n const foreignKeyEdges = graph.edges.filter(e => e.relation === 'foreign-key' || e.relation === 'cascade-delete');\r\n for (const fk of foreignKeyEdges) {\r\n const sourceNode = graph.nodes.find(n => n.id === fk.source);\r\n const targetNode = graph.nodes.find(n => n.id === fk.target);\r\n if (sourceNode && targetNode) {\r\n // Check how many other tables reference the target\r\n const dependents = graph.edges.filter(e =>\r\n (e.relation === 'foreign-key' || e.relation === 'cascade-delete') && e.target === fk.target\r\n );\r\n if (dependents.length >= 3) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'data-integrity',\r\n severity: 'high',\r\n title: `Cascade risk: ${targetNode.label} has ${dependents.length} dependent tables`,\r\n description: `Deleting records from \"${targetNode.label}\" could cascade to ${dependents.length} other tables.`,\r\n affectedNodes: [fk.target, ...dependents.map(d => d.source)],\r\n suggestion: 'Implement soft deletes or add cascade protection.',\r\n confidence: 0.85,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 40, 'Checking performance...');\r\n\r\n // 4. Performance: Large modules (God-module smell)\r\n const moduleNodes = graph.nodes.filter(n => n.type === 'module');\r\n for (const mod of moduleNodes) {\r\n const children = graph.edges.filter(e => e.target === mod.id && e.relation === 'belongs-to');\r\n if (children.length > 50) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'maintainability',\r\n severity: 'medium',\r\n title: `Large module: ${mod.label} (${children.length} entities)`,\r\n description: `Module \"${mod.label}\" contains ${children.length} entities. Consider splitting for better maintainability.`,\r\n affectedNodes: [mod.id],\r\n suggestion: 'Split into smaller, focused sub-modules.',\r\n confidence: 0.75,\r\n });\r\n }\r\n }\r\n\r\n // 5. Reliability: Circular dependencies\r\n const cycles = detectCycles(graph);\r\n for (const cycle of cycles) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'logic',\r\n severity: 'high',\r\n title: `Circular dependency detected: ${cycle.map(id => graph.nodes.find(n => n.id === id)?.label || id).join(' → ')}`,\r\n description: `A circular dependency was found involving ${cycle.length} entities. This can cause initialization issues and makes testing harder.`,\r\n affectedNodes: cycle,\r\n suggestion: 'Break the cycle by introducing an interface or Event-based decoupling.',\r\n confidence: 0.9,\r\n });\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 60, 'Checking maintainability...');\r\n\r\n // 6. Maintainability: High coupling\r\n for (const node of graph.nodes) {\r\n if (node.type === 'file' || node.type === 'dependency') continue;\r\n const outgoing = graph.edges.filter(e => e.source === node.id);\r\n const incoming = graph.edges.filter(e => e.target === node.id);\r\n const coupling = outgoing.length + incoming.length;\r\n if (coupling > 15) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'maintainability',\r\n severity: 'medium',\r\n title: `High coupling: ${node.label} (${coupling} connections)`,\r\n description: `\"${node.label}\" has ${coupling} connections (${outgoing.length} outgoing, ${incoming.length} incoming). Changes here will have wide impact.`,\r\n affectedNodes: [node.id],\r\n suggestion: 'Consider extracting shared logic or adding an abstraction layer.',\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n\r\n // 7. Security: Potential injection points (APIs with dynamic path params)\r\n for (const api of apis) {\r\n const apiPath = (api.metadata.path as string) || api.label;\r\n if (apiPath.includes(':') || apiPath.includes('{')) {\r\n const method = (api.metadata.method as string) || '';\r\n if (['DELETE', 'PUT', 'PATCH'].includes(method)) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'security',\r\n severity: 'low',\r\n title: `Verify input validation: ${api.label}`,\r\n description: `Endpoint ${api.label} accepts path parameters. Ensure proper input validation and authorization checks.`,\r\n affectedNodes: [api.id],\r\n suggestion: 'Add input validation middleware and verify the user has permission to modify the specified resource.',\r\n confidence: 0.5,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 80, `Found ${risks.length} risks`);\r\n\r\n // --- LLM-enhanced risk detection (optional) ---\r\n if (options?.useLlm && options.llm) {\r\n try {\r\n const llmRisks = await getLlmRisks(graph, risks, options.llm);\r\n risks.push(...llmRisks);\r\n } catch {\r\n // LLM enhancement failed — rule-based results are still valid\r\n }\r\n }\r\n\r\n // Sort by severity\r\n const severityOrder: Record<RiskSeverity, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\r\n risks.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);\r\n\r\n options?.onProgress?.('risk-analysis', 100, `Analysis complete: ${risks.length} risks found`);\r\n\r\n return risks;\r\n}\r\n\r\n// ===================================================================\r\n// Impact Analysis\r\n// ===================================================================\r\n\r\n/**\r\n * Analyze the impact of changing a specific node.\r\n */\r\nexport function analyzeImpact(graph: KnowledgeGraph, nodeId: string): ImpactAnalysis {\r\n const node = graph.nodes.find(n => n.id === nodeId);\r\n if (!node) {\r\n return {\r\n sourceNode: nodeId,\r\n directImpact: [],\r\n transitiveImpact: [],\r\n riskLevel: 'low',\r\n summary: `Node \"${nodeId}\" not found in the graph.`,\r\n mermaidText: '',\r\n };\r\n }\r\n\r\n // Direct neighbors\r\n const { incoming, outgoing } = getNeighbors(graph, nodeId);\r\n const directNodes = new Set([\r\n ...incoming.map(e => e.source),\r\n ...outgoing.map(e => e.target),\r\n ]);\r\n directNodes.delete(nodeId);\r\n\r\n // Transitive impact (BFS depth 3)\r\n const transitiveNodes = bfsTraversal(graph, nodeId, 3);\r\n\r\n // Calculate risk level\r\n const totalImpact = transitiveNodes.length;\r\n let riskLevel: RiskSeverity;\r\n if (totalImpact > 20) riskLevel = 'critical';\r\n else if (totalImpact > 10) riskLevel = 'high';\r\n else if (totalImpact > 5) riskLevel = 'medium';\r\n else riskLevel = 'low';\r\n\r\n // Generate summary\r\n const summary = `Changing \"${node.label}\" directly affects ${directNodes.size} entities and transitively impacts ${transitiveNodes.length} entities (risk: ${riskLevel}).`;\r\n\r\n // Generate Mermaid diagram\r\n const impactNodeIds = new Set([nodeId, ...directNodes, ...transitiveNodes.slice(0, 20)]);\r\n const impactNodes = graph.nodes.filter(n => impactNodeIds.has(n.id));\r\n const impactEdges = graph.edges.filter(e => impactNodeIds.has(e.source) && impactNodeIds.has(e.target));\r\n\r\n let mermaidText = 'graph TD\\n';\r\n mermaidText += ` style ${sanitizeId(nodeId)} fill:#e94560,color:#fff\\n`;\r\n for (const dn of directNodes) {\r\n mermaidText += ` style ${sanitizeId(dn)} fill:#f39c12,color:#000\\n`;\r\n }\r\n for (const n of impactNodes) {\r\n mermaidText += ` ${sanitizeId(n.id)}[\"${n.label.replace(/\"/g, \"'\")}\"]\\n`;\r\n }\r\n for (const e of impactEdges) {\r\n mermaidText += ` ${sanitizeId(e.source)} -->|${e.relation}| ${sanitizeId(e.target)}\\n`;\r\n }\r\n\r\n return {\r\n sourceNode: nodeId,\r\n directImpact: [...directNodes],\r\n transitiveImpact: transitiveNodes,\r\n riskLevel,\r\n summary,\r\n mermaidText,\r\n };\r\n}\r\n\r\n// ===================================================================\r\n// Multi-Perspective Reports\r\n// ===================================================================\r\n\r\n/**\r\n * Generate a report from a specific perspective.\r\n */\r\nexport async function generateReport(\r\n graph: KnowledgeGraph,\r\n perspective: ReportPerspective,\r\n risks: RiskAnnotation[],\r\n options?: InsightOptions,\r\n): Promise<PerspectiveReport> {\r\n // If LLM available, use it for rich narrative\r\n if (options?.useLlm && options.llm) {\r\n return generateLlmReport(graph, perspective, risks, options.llm);\r\n }\r\n\r\n // Fallback: rule-based report generation\r\n switch (perspective) {\r\n case 'developer':\r\n return buildDeveloperReport(graph, risks);\r\n case 'architect':\r\n return buildArchitectReport(graph, risks);\r\n case 'tester':\r\n return buildTesterReport(graph, risks);\r\n case 'product':\r\n return buildProductReport(graph, risks);\r\n case 'student':\r\n return buildStudentReport(graph, risks);\r\n case 'executive':\r\n return buildExecutiveReport(graph, risks);\r\n default:\r\n return buildDeveloperReport(graph, risks);\r\n }\r\n}\r\n\r\nfunction buildDeveloperReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const stats = projectInfo.stats;\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Project Overview',\r\n content: `**${projectInfo.name}** is a ${projectInfo.projectType} project using ${projectInfo.frameworks.join(', ') || 'unknown frameworks'}.\\n\\n` +\r\n `- **Files**: ${stats.totalFiles} | **Lines**: ${stats.totalLines.toLocaleString()}\\n` +\r\n `- **Languages**: ${Object.entries(projectInfo.languages).map(([k, v]) => `${k}(${v})`).join(', ')}\\n` +\r\n `- **APIs**: ${stats.apiEndpoints} | **Models**: ${stats.dataModels} | **Functions**: ${stats.functions}`,\r\n },\r\n {\r\n heading: 'Architecture Map',\r\n content: 'Module-level dependency graph:',\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module', 'model', 'api'], maxNodes: 30 }),\r\n },\r\n },\r\n {\r\n heading: 'API Endpoints',\r\n content: graph.nodes\r\n .filter(n => n.type === 'api')\r\n .map(a => `- \\`${a.label}\\` (${a.filePath || 'unknown'})`)\r\n .join('\\n') || 'No API endpoints detected.',\r\n },\r\n {\r\n heading: 'Data Models',\r\n content: graph.nodes\r\n .filter(n => n.type === 'model')\r\n .map(m => `- **${m.label}** (${m.filePath || 'unknown'})`)\r\n .join('\\n') || 'No data models detected.',\r\n },\r\n {\r\n heading: 'Risk Report',\r\n content: risks.length === 0\r\n ? 'No significant risks detected.'\r\n : risks.slice(0, 10).map(r =>\r\n `- **[${r.severity.toUpperCase()}]** ${r.title}\\n ${r.description}`\r\n ).join('\\n\\n'),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'developer',\r\n title: `Developer Report: ${projectInfo.name}`,\r\n summary: `${projectInfo.name} — ${stats.apiEndpoints} APIs, ${stats.dataModels} models, ${risks.length} risks detected.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildArchitectReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const modules = graph.nodes.filter(n => n.type === 'module');\r\n const criticalRisks = risks.filter(r => r.severity === 'critical' || r.severity === 'high');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'System Architecture',\r\n content: `**Type**: ${projectInfo.projectType}\\n**Frameworks**: ${projectInfo.frameworks.join(', ')}\\n**Modules**: ${modules.length}\\n\\n` +\r\n `The system is organized into ${modules.length} modules with ${graph.edges.length} relationships.`,\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module'], maxNodes: 20 }),\r\n },\r\n },\r\n {\r\n heading: 'Module Coupling Analysis',\r\n content: modules.map(m => {\r\n const edges = graph.edges.filter(e => e.source === m.id || e.target === m.id);\r\n return `- **${m.label}**: ${edges.length} connections`;\r\n }).join('\\n'),\r\n },\r\n {\r\n heading: 'Technical Debt & Risk',\r\n content: criticalRisks.length === 0\r\n ? 'No critical or high-severity risks.'\r\n : criticalRisks.map(r => `- **[${r.severity}]** ${r.title}\\n _Suggestion_: ${r.suggestion || 'N/A'}`).join('\\n\\n'),\r\n },\r\n {\r\n heading: 'Recommendations',\r\n content: generateArchitectRecommendations(graph, risks),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'architect',\r\n title: `Architecture Report: ${projectInfo.name}`,\r\n summary: `${modules.length} modules, ${graph.edges.length} relationships, ${criticalRisks.length} critical/high risks.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildTesterReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const apis = graph.nodes.filter(n => n.type === 'api');\r\n const tests = graph.nodes.filter(n => n.type === 'test');\r\n const riskyApis = risks.filter(r => r.category === 'security' || r.category === 'data-integrity');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Test Coverage Overview',\r\n content: `- **API Endpoints**: ${apis.length}\\n- **Test Files Found**: ${tests.length}\\n- **Estimated Coverage**: ${tests.length > 0 ? Math.min(Math.round(tests.length / Math.max(apis.length, 1) * 100), 100) : 0}%`,\r\n },\r\n {\r\n heading: 'Priority Test Targets',\r\n content: 'Endpoints with highest risk that need testing first:\\n\\n' +\r\n riskyApis.slice(0, 10).map((r, i) => `${i + 1}. **${r.title}** (${r.severity})\\n ${r.description}`).join('\\n\\n'),\r\n },\r\n {\r\n heading: 'Edge Cases to Consider',\r\n content: apis.slice(0, 10).map(api => {\r\n const method = (api.metadata.method as string) || 'ANY';\r\n const suggestions: string[] = [];\r\n if (method === 'POST' || method === 'PUT') suggestions.push('Empty body', 'Invalid types', 'Missing required fields', 'Extremely long strings');\r\n if (method === 'DELETE') suggestions.push('Non-existent ID', 'Already deleted', 'ID with dependencies');\r\n if (method === 'GET') suggestions.push('Invalid query params', 'Large pagination', 'Non-existent ID');\r\n return `- **${api.label}**: ${suggestions.join(', ')}`;\r\n }).join('\\n'),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'tester',\r\n title: `Testing Report: ${graph.projectInfo.name}`,\r\n summary: `${apis.length} endpoints to test, ${riskyApis.length} high-risk areas identified.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildProductReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const modules = graph.nodes.filter(n => n.type === 'module');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'What Does This System Do?',\r\n content: `This is a **${projectInfo.projectType}** system built with ${projectInfo.frameworks.join(', ')}. ` +\r\n `It contains ${modules.length} functional modules and ${projectInfo.stats.apiEndpoints} service interfaces.`,\r\n },\r\n {\r\n heading: 'Feature Map',\r\n content: modules.map(m => {\r\n const children = graph.edges.filter(e => e.target === m.id).length;\r\n return `- **${m.label}** — ${children} components`;\r\n }).join('\\n'),\r\n },\r\n {\r\n heading: 'Health Status',\r\n content: (() => {\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n if (critical > 0) return `⚠️ **Needs Attention**: ${critical} critical issues found that could affect users.`;\r\n if (high > 3) return `⚡ **Minor Concerns**: ${high} areas that should be improved.`;\r\n return '✅ **Healthy**: No critical issues detected. System is in good shape.';\r\n })(),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'product',\r\n title: `Product Overview: ${projectInfo.name}`,\r\n summary: `${modules.length} feature modules, ${risks.filter(r => r.severity === 'critical').length} critical issues.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildStudentReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'What is this project?',\r\n content: `This is a **${projectInfo.projectType}** project. Let\\'s break it down step by step!\\n\\n` +\r\n `**Languages used**: ${Object.keys(projectInfo.languages).join(', ')}\\n` +\r\n `**Frameworks**: ${projectInfo.frameworks.join(', ') || 'None detected'}\\n\\n` +\r\n `Think of this project like a building:\\n` +\r\n `- The **frameworks** are the building\\'s foundation\\n` +\r\n `- The **modules** are different rooms\\n` +\r\n `- The **APIs** are the doors and windows (interfaces to the outside world)\\n` +\r\n `- The **models** are the furniture and storage (data structures)`,\r\n },\r\n {\r\n heading: 'How is it organized?',\r\n content: `The project has **${projectInfo.stats.modules}** modules (think: folders of related code).\\n\\n` +\r\n `Each module typically contains:\\n` +\r\n `1. **Controllers/Routes** — Handle incoming requests (like a receptionist)\\n` +\r\n `2. **Services** — Business logic (like the workers)\\n` +\r\n `3. **Models** — Data structures (like forms and documents)\\n\\n` +\r\n 'Here\\'s a simplified view:',\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module', 'model'], maxNodes: 15 }),\r\n },\r\n },\r\n {\r\n heading: 'Key Concepts to Learn',\r\n content: `Based on this project, you should study:\\n\\n` +\r\n (projectInfo.frameworks.includes('Express') ? '- **Express.js** — Node.js web framework for building APIs\\n' : '') +\r\n (projectInfo.frameworks.includes('React') ? '- **React** — Frontend UI library for building user interfaces\\n' : '') +\r\n (projectInfo.frameworks.includes('Sequelize') ? '- **Sequelize** — ORM for database operations\\n' : '') +\r\n `- **REST APIs** — How the frontend talks to the backend\\n` +\r\n `- **MVC Pattern** — Model-View-Controller architecture\\n` +\r\n `- **Authentication** — How users log in and stay logged in`,\r\n },\r\n {\r\n heading: 'Things to Watch Out For',\r\n content: risks.length > 0\r\n ? `Here are ${Math.min(risks.length, 5)} interesting issues found:\\n\\n` +\r\n risks.slice(0, 5).map((r, i) => `${i + 1}. **${r.title}**\\n _Why it matters_: ${r.description}\\n _How to fix_: ${r.suggestion || 'Research this topic!'}`).join('\\n\\n')\r\n : 'This project looks clean! No major issues found.',\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'student',\r\n title: `Learning Guide: ${projectInfo.name}`,\r\n summary: `A ${projectInfo.projectType} project — great for learning ${Object.keys(projectInfo.languages).join(', ')}!`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildExecutiveReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n\r\n // Health score: 100 - (critical * 20 + high * 10 + medium * 3)\r\n const medium = risks.filter(r => r.severity === 'medium').length;\r\n const healthScore = Math.max(0, 100 - (critical * 20 + high * 10 + medium * 3));\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Health Score',\r\n content: `# ${healthScore}/100\\n\\n` +\r\n (healthScore >= 80 ? '✅ System is healthy and well-maintained.' :\r\n healthScore >= 60 ? '⚡ System needs some attention. Address high-priority items.' :\r\n '⚠️ System has significant issues that need immediate attention.'),\r\n },\r\n {\r\n heading: 'Key Metrics',\r\n content: `| Metric | Value |\\n|--------|-------|\\n` +\r\n `| Codebase Size | ${projectInfo.stats.totalLines.toLocaleString()} lines |\\n` +\r\n `| Technologies | ${projectInfo.frameworks.length} frameworks |\\n` +\r\n `| API Surface | ${projectInfo.stats.apiEndpoints} endpoints |\\n` +\r\n `| Data Models | ${projectInfo.stats.dataModels} tables |\\n` +\r\n `| Critical Issues | ${critical} |\\n` +\r\n `| High Issues | ${high} |`,\r\n },\r\n {\r\n heading: 'Top 3 Risks Needing Action',\r\n content: risks.slice(0, 3).map((r, i) =>\r\n `${i + 1}. **${r.title}** (${r.severity})`\r\n ).join('\\n') || 'No significant risks.',\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'executive',\r\n title: `Executive Summary: ${projectInfo.name}`,\r\n summary: `Health: ${healthScore}/100 | ${critical} critical, ${high} high risks | ${projectInfo.stats.apiEndpoints} APIs`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\n// ===================================================================\r\n// Digital Twin Simulation\r\n// ===================================================================\r\n\r\n/**\r\n * Run AI-powered simulation on a scenario (requires LLM).\r\n */\r\nexport async function simulateScenario(\r\n graph: KnowledgeGraph,\r\n scenario: SimulationScenario,\r\n llm: LlmProvider,\r\n): Promise<SimulationResult> {\r\n // Build context from graph\r\n const relatedNodes = scenario.steps\r\n .map(s => s.endpoint)\r\n .filter(Boolean)\r\n .flatMap(endpoint => graph.nodes.filter(n => n.type === 'api' && n.label.includes(endpoint!)))\r\n .map(n => n.id);\r\n\r\n const context = relatedNodes.flatMap(nodeId => {\r\n const neighbors = getNeighbors(graph, nodeId);\r\n return [\r\n ...neighbors.outgoing.map(e => {\r\n const target = graph.nodes.find(n => n.id === e.target);\r\n return `${e.relation}: ${target?.label || e.target}`;\r\n }),\r\n ];\r\n });\r\n\r\n const prompt = `You are an expert software engineer analyzing a system.\r\n\r\nProject: ${graph.projectInfo.name}\r\nFrameworks: ${graph.projectInfo.frameworks.join(', ')}\r\n\r\nScenario: ${scenario.name}\r\nDescription: ${scenario.description}\r\n\r\nSteps:\r\n${scenario.steps.map((s, i) => `${i + 1}. ${s.action} — ${s.endpoint || 'N/A'}`).join('\\n')}\r\n\r\nRelated context from knowledge graph:\r\n${context.join('\\n')}\r\n\r\nPredict:\r\n1. What would happen when executing this scenario?\r\n2. What anomalies or edge cases could occur?\r\n3. Rate the risk (0-100) of this scenario failing in production.\r\n\r\nRespond in JSON: { \"prediction\": \"...\", \"anomalies\": [\"...\"], \"riskScore\": N, \"confidence\": 0.X }`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n return {\r\n scenario,\r\n prediction: parsed.prediction || 'Unable to predict.',\r\n anomalies: parsed.anomalies || [],\r\n riskScore: parsed.riskScore || 50,\r\n confidence: parsed.confidence || 0.5,\r\n };\r\n } catch {\r\n return {\r\n scenario,\r\n prediction: response,\r\n anomalies: [],\r\n riskScore: 50,\r\n confidence: 0.3,\r\n };\r\n }\r\n}\r\n\r\n// ===================================================================\r\n// Helpers\r\n// ===================================================================\r\n\r\nfunction detectCycles(graph: KnowledgeGraph): string[][] {\r\n const cycles: string[][] = [];\r\n const adjacency = new Map<string, string[]>();\r\n\r\n // Build adjacency (only import/depends-on edges for cycle detection)\r\n for (const edge of graph.edges) {\r\n if (edge.relation !== 'imports' && edge.relation !== 'depends-on' && edge.relation !== 'calls') continue;\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n if (cycles.length >= 5) return; // Limit cycle count\r\n visited.add(node);\r\n inStack.add(node);\r\n path.push(node);\r\n\r\n for (const neighbor of adjacency.get(node) || []) {\r\n if (!visited.has(neighbor)) {\r\n dfs(neighbor);\r\n } else if (inStack.has(neighbor)) {\r\n // Found cycle\r\n const cycleStart = path.indexOf(neighbor);\r\n if (cycleStart >= 0) {\r\n cycles.push([...path.slice(cycleStart), neighbor]);\r\n }\r\n }\r\n }\r\n\r\n path.pop();\r\n inStack.delete(node);\r\n }\r\n\r\n for (const node of adjacency.keys()) {\r\n if (!visited.has(node)) {\r\n dfs(node);\r\n }\r\n }\r\n\r\n return cycles;\r\n}\r\n\r\nfunction generateArchitectRecommendations(_graph: KnowledgeGraph, risks: RiskAnnotation[]): string {\r\n const items: string[] = [];\r\n\r\n const securityRisks = risks.filter(r => r.category === 'security');\r\n if (securityRisks.length > 0) {\r\n items.push(`1. **Security Hardening**: Address ${securityRisks.length} security findings before next release.`);\r\n }\r\n\r\n const couplingRisks = risks.filter(r => r.category === 'maintainability');\r\n if (couplingRisks.length > 2) {\r\n items.push(`2. **Reduce Coupling**: ${couplingRisks.length} modules show high coupling. Consider introducing service boundaries.`);\r\n }\r\n\r\n const dataRisks = risks.filter(r => r.category === 'data-integrity');\r\n if (dataRisks.length > 0) {\r\n items.push(`3. **Data Protection**: ${dataRisks.length} data integrity concerns. Add transaction boundaries and cascade protections.`);\r\n }\r\n\r\n if (items.length === 0) {\r\n items.push('Architecture looks solid. Continue monitoring coupling metrics as the system grows.');\r\n }\r\n\r\n return items.join('\\n\\n');\r\n}\r\n\r\nasync function getLlmRisks(graph: KnowledgeGraph, existingRisks: RiskAnnotation[], llm: LlmProvider): Promise<RiskAnnotation[]> {\r\n const prompt = `Analyze this project knowledge graph for additional risks not already identified.\r\n\r\nProject: ${graph.projectInfo.name}\r\nType: ${graph.projectInfo.projectType}\r\nFrameworks: ${graph.projectInfo.frameworks.join(', ')}\r\nStats: ${graph.projectInfo.stats.apiEndpoints} APIs, ${graph.projectInfo.stats.dataModels} models\r\n\r\nAlready identified risks (${existingRisks.length}):\r\n${existingRisks.slice(0, 5).map(r => `- [${r.severity}] ${r.title}`).join('\\n')}\r\n\r\nAPI Endpoints: ${graph.nodes.filter(n => n.type === 'api').slice(0, 20).map(n => n.label).join(', ')}\r\nModels: ${graph.nodes.filter(n => n.type === 'model').slice(0, 20).map(n => n.label).join(', ')}\r\n\r\nReturn up to 3 additional risks in JSON array format:\r\n[{ \"category\": \"security|performance|data-integrity|logic|maintainability|reliability\", \"severity\": \"critical|high|medium|low\", \"title\": \"...\", \"description\": \"...\", \"suggestion\": \"...\" }]`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n if (!Array.isArray(parsed)) return [];\r\n return parsed.slice(0, 3).map((r: Record<string, string>, i: number) => ({\r\n id: `risk-llm-${i}`,\r\n category: (r.category || 'logic') as RiskCategory,\r\n severity: (r.severity || 'medium') as RiskSeverity,\r\n title: r.title || 'LLM-detected risk',\r\n description: r.description || '',\r\n affectedNodes: [],\r\n suggestion: r.suggestion,\r\n confidence: 0.6,\r\n }));\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nasync function generateLlmReport(\r\n graph: KnowledgeGraph,\r\n perspective: ReportPerspective,\r\n risks: RiskAnnotation[],\r\n llm: LlmProvider,\r\n): Promise<PerspectiveReport> {\r\n const perspectiveDescriptions: Record<ReportPerspective, string> = {\r\n developer: 'a software developer who wants technical details, code patterns, and API documentation',\r\n architect: 'a software architect who cares about modularity, coupling, tech debt, and system design',\r\n tester: 'a QA engineer who wants to know what to test, edge cases, and risk areas',\r\n product: 'a product manager who wants to understand features in business terms, not code',\r\n student: 'a computer science student learning from this codebase, explain concepts step by step',\r\n executive: 'a CTO/VP who wants a one-page health summary with actionable insights',\r\n };\r\n\r\n const prompt = `Generate a project analysis report for ${graph.projectInfo.name} from the perspective of ${perspectiveDescriptions[perspective]}.\r\n\r\nProject Info:\r\n- Type: ${graph.projectInfo.projectType}\r\n- Frameworks: ${graph.projectInfo.frameworks.join(', ')}\r\n- Stats: ${graph.projectInfo.stats.totalFiles} files, ${graph.projectInfo.stats.apiEndpoints} APIs, ${graph.projectInfo.stats.dataModels} models\r\n- Languages: ${Object.entries(graph.projectInfo.languages).map(([k, v]) => `${k}(${v} files)`).join(', ')}\r\n\r\nTop risks:\r\n${risks.slice(0, 5).map(r => `- [${r.severity}] ${r.title}`).join('\\n')}\r\n\r\nGenerate 3-5 report sections with clear headings and content. Use markdown formatting.\r\nRespond in JSON: { \"title\": \"...\", \"summary\": \"...\", \"sections\": [{ \"heading\": \"...\", \"content\": \"...\" }] }`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n return {\r\n perspective,\r\n title: parsed.title || `${perspective} Report`,\r\n summary: parsed.summary || '',\r\n sections: (parsed.sections || []).map((s: Record<string, string>) => ({\r\n heading: s.heading || 'Section',\r\n content: s.content || '',\r\n })),\r\n generatedAt: new Date().toISOString(),\r\n };\r\n } catch {\r\n // Fallback to rule-based\r\n return buildDeveloperReport(graph, risks);\r\n }\r\n}\r\n\r\nfunction cleanJsonResponse(response: string): string {\r\n // Strip markdown code fences if present\r\n let cleaned = response.trim();\r\n if (cleaned.startsWith('```json')) cleaned = cleaned.slice(7);\r\n else if (cleaned.startsWith('```')) cleaned = cleaned.slice(3);\r\n if (cleaned.endsWith('```')) cleaned = cleaned.slice(0, -3);\r\n return cleaned.trim();\r\n}\r\n\r\nfunction sanitizeId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type { KnowledgeGraph, RiskAnnotation } from '../graph/types.js';\r\n\r\nfunction isSerializedSnapshotFile(value: SerializedSnapshotFile | StudioProjectStore): value is SerializedSnapshotFile {\r\n return 'snapshots' in value && Array.isArray(value.snapshots);\r\n}\r\n\r\nexport interface StudioProjectStore {\r\n graph: KnowledgeGraph | null;\r\n risks: RiskAnnotation[];\r\n scanTime: number;\r\n source: string;\r\n}\r\n\r\nexport interface StudioSnapshotStore {\r\n load(): StudioProjectStore | null;\r\n save(snapshot: StudioProjectStore): void;\r\n list(): StudioSnapshotSummary[];\r\n loadById(id: string): StudioProjectStore | null;\r\n rename(id: string, name: string): boolean;\r\n delete(id: string): boolean;\r\n pin(id: string, pinned: boolean): boolean;\r\n updateTags(id: string, tags: string[]): boolean;\r\n}\r\n\r\nexport interface StudioSnapshotRecord extends StudioProjectStore {\r\n id: string;\r\n name: string;\r\n pinned: boolean;\r\n tags: string[];\r\n}\r\n\r\nexport interface StudioSnapshotSummary {\r\n id: string;\r\n name: string;\r\n source: string;\r\n scanTime: number;\r\n nodeCount: number;\r\n riskCount: number;\r\n current: boolean;\r\n pinned: boolean;\r\n tags: string[];\r\n}\r\n\r\ninterface SerializedSnapshotFile {\r\n version: 2;\r\n currentSnapshotId: string | null;\r\n snapshots: StudioSnapshotRecord[];\r\n}\r\n\r\nexport const EMPTY_STUDIO_STORE: StudioProjectStore = {\r\n graph: null,\r\n risks: [],\r\n scanTime: 0,\r\n source: '',\r\n};\r\n\r\nexport class FileStudioSnapshotStore implements StudioSnapshotStore {\r\n private readonly filePath: string;\r\n private readonly maxSnapshots: number;\r\n\r\n constructor(filePath: string, maxSnapshots = 12) {\r\n this.filePath = filePath;\r\n this.maxSnapshots = maxSnapshots;\r\n }\r\n\r\n load(): StudioProjectStore | null {\r\n const data = this.readFile();\r\n if (!data || !data.currentSnapshotId) return null;\r\n const current = data.snapshots.find((snapshot) => snapshot.id === data.currentSnapshotId);\r\n return current ? this.toProjectStore(current) : null;\r\n }\r\n\r\n save(snapshot: StudioProjectStore): void {\r\n const data = this.readFile() ?? { version: 2, currentSnapshotId: null, snapshots: [] };\r\n const record = this.toSnapshotRecord(snapshot);\r\n data.currentSnapshotId = record.id;\r\n data.snapshots = [record, ...data.snapshots].slice(0, this.maxSnapshots);\r\n\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n }\r\n\r\n list(): StudioSnapshotSummary[] {\r\n const data = this.readFile();\r\n if (!data) return [];\r\n return data.snapshots.map((snapshot) => ({\r\n id: snapshot.id,\r\n name: snapshot.name,\r\n source: snapshot.source,\r\n scanTime: snapshot.scanTime,\r\n nodeCount: snapshot.graph?.nodes.length ?? 0,\r\n riskCount: snapshot.risks.length,\r\n current: snapshot.id === data.currentSnapshotId,\r\n pinned: Boolean(snapshot.pinned),\r\n tags: Array.isArray(snapshot.tags) ? snapshot.tags : [],\r\n })).sort((left, right) => {\r\n if (left.pinned !== right.pinned) return left.pinned ? -1 : 1;\r\n return right.scanTime - left.scanTime;\r\n });\r\n }\r\n\r\n loadById(id: string): StudioProjectStore | null {\r\n const data = this.readFile();\r\n if (!data) return null;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return null;\r\n\r\n data.currentSnapshotId = record.id;\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return this.toProjectStore(record);\r\n }\r\n\r\n rename(id: string, name: string): boolean {\r\n const nextName = name.trim();\r\n if (!nextName) return false;\r\n\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return false;\r\n\r\n record.name = nextName;\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n delete(id: string): boolean {\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const nextSnapshots = data.snapshots.filter((snapshot) => snapshot.id !== id);\r\n if (nextSnapshots.length === data.snapshots.length) return false;\r\n\r\n data.snapshots = nextSnapshots;\r\n if (data.currentSnapshotId === id) {\r\n data.currentSnapshotId = nextSnapshots[0]?.id ?? null;\r\n }\r\n\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n pin(id: string, pinned: boolean): boolean {\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return false;\r\n\r\n record.pinned = pinned;\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n updateTags(id: string, tags: string[]): boolean {\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return false;\r\n\r\n record.tags = this.normalizeTags(tags);\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n private readFile(): SerializedSnapshotFile | null {\r\n if (!existsSync(this.filePath)) return null;\r\n\r\n try {\r\n const raw = readFileSync(this.filePath, 'utf-8');\r\n const parsed = JSON.parse(raw) as SerializedSnapshotFile | StudioProjectStore;\r\n return this.normalize(parsed);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private normalize(parsed: SerializedSnapshotFile | StudioProjectStore): SerializedSnapshotFile {\r\n if (isSerializedSnapshotFile(parsed)) {\r\n return {\r\n version: 2,\r\n currentSnapshotId: typeof parsed.currentSnapshotId === 'string' ? parsed.currentSnapshotId : null,\r\n snapshots: parsed.snapshots.map((snapshot) => ({\r\n id: snapshot.id,\r\n name: snapshot.name,\r\n pinned: Boolean(snapshot.pinned),\r\n tags: this.normalizeTags(snapshot.tags),\r\n graph: snapshot.graph ?? null,\r\n risks: Array.isArray(snapshot.risks) ? snapshot.risks : [],\r\n scanTime: typeof snapshot.scanTime === 'number' ? snapshot.scanTime : 0,\r\n source: typeof snapshot.source === 'string' ? snapshot.source : '',\r\n })),\r\n };\r\n }\r\n\r\n const legacyStore = parsed as StudioProjectStore;\r\n const legacy = this.toSnapshotRecord({\r\n graph: legacyStore.graph ?? null,\r\n risks: Array.isArray(legacyStore.risks) ? legacyStore.risks : [],\r\n scanTime: typeof legacyStore.scanTime === 'number' ? legacyStore.scanTime : 0,\r\n source: typeof legacyStore.source === 'string' ? legacyStore.source : '',\r\n });\r\n\r\n return {\r\n version: 2,\r\n currentSnapshotId: legacy.id,\r\n snapshots: [legacy],\r\n };\r\n }\r\n\r\n private toSnapshotRecord(snapshot: StudioProjectStore): StudioSnapshotRecord {\r\n const name = snapshot.graph?.projectInfo?.name || this.deriveName(snapshot.source);\r\n return {\r\n id: `${snapshot.scanTime || Date.now()}-${Math.random().toString(16).slice(2, 8)}`,\r\n name,\r\n pinned: false,\r\n tags: [],\r\n graph: snapshot.graph ?? null,\r\n risks: Array.isArray(snapshot.risks) ? snapshot.risks : [],\r\n scanTime: typeof snapshot.scanTime === 'number' ? snapshot.scanTime : Date.now(),\r\n source: typeof snapshot.source === 'string' ? snapshot.source : '',\r\n };\r\n }\r\n\r\n private toProjectStore(snapshot: StudioSnapshotRecord): StudioProjectStore {\r\n return {\r\n graph: snapshot.graph ?? null,\r\n risks: Array.isArray(snapshot.risks) ? snapshot.risks : [],\r\n scanTime: typeof snapshot.scanTime === 'number' ? snapshot.scanTime : 0,\r\n source: typeof snapshot.source === 'string' ? snapshot.source : '',\r\n };\r\n }\r\n\r\n private deriveName(source: string): string {\r\n if (!source) return 'unknown-project';\r\n const parts = source.split(/[\\\\/]/).filter(Boolean);\r\n return parts[parts.length - 1] || source;\r\n }\r\n\r\n private normalizeTags(tags: unknown): string[] {\r\n if (!Array.isArray(tags)) return [];\r\n return [...new Set(tags\r\n .map((tag) => typeof tag === 'string' ? tag.trim() : '')\r\n .filter(Boolean)\r\n )];\r\n }\r\n}","/**\r\n * OpenCroc Dynamic Role Registry\r\n *\r\n * Manages an extensible pool of croc expert roles that can be\r\n * dynamically summoned based on project characteristics.\r\n *\r\n * Architecture:\r\n * RoleDefinition → what a croc CAN do (template)\r\n * CrocAgent → a live instance doing work (runtime)\r\n * TaskRouter → decides WHICH roles to summon for a project\r\n */\r\n\r\n// ─── Role Definition ─────────────────────────────────────────────────────────\r\n\r\nexport type RoleCategory =\r\n | 'core' // 官方核心角色 (always available)\r\n | 'language' // 语言专家鳄\r\n | 'framework' // 框架专家鳄\r\n | 'domain' // 领域专家鳄 (security, performance, etc.)\r\n | 'community'; // 社区贡献角色\r\n\r\nexport interface RoleTrigger {\r\n /** Match against detected languages (e.g. \"python\", \"typescript\") */\r\n languages?: string[];\r\n /** Match against detected frameworks (e.g. \"Express\", \"Django\", \"React\") */\r\n frameworks?: string[];\r\n /** Match against project type */\r\n projectTypes?: string[];\r\n /** Match against file patterns (glob-style) */\r\n filePatterns?: string[];\r\n /** Match against entity count thresholds */\r\n minEntities?: number;\r\n /** Match against risk categories found */\r\n riskCategories?: string[];\r\n /** Custom predicate for advanced matching */\r\n custom?: (ctx: MatchContext) => boolean;\r\n}\r\n\r\nexport interface MatchContext {\r\n languages: Record<string, number>;\r\n frameworks: string[];\r\n projectType: string;\r\n fileCount: number;\r\n entityCount: number;\r\n riskCategories: string[];\r\n hasModels: boolean;\r\n hasAPIs: boolean;\r\n hasFrontend: boolean;\r\n hasDocker: boolean;\r\n hasCI: boolean;\r\n}\r\n\r\nexport interface RoleDefinition {\r\n /** Unique identifier, e.g. \"security-auditor\" */\r\n id: string;\r\n /** Display name in Chinese, e.g. \"安全审计鳄\" */\r\n name: string;\r\n /** English name for international display */\r\n nameEn: string;\r\n /** Role category */\r\n category: RoleCategory;\r\n /** Short description of expertise */\r\n description: string;\r\n /** Icon/sprite identifier for 3D rendering */\r\n sprite: string;\r\n /** Color theme (hex) for the croc's glow */\r\n color: string;\r\n /** Priority: lower = summoned first when multiple match (0-100) */\r\n priority: number;\r\n /** When should this role be summoned? */\r\n triggers: RoleTrigger;\r\n /** System prompt template for LLM analysis */\r\n systemPrompt: string;\r\n /** What this role outputs */\r\n outputType: 'report' | 'analysis' | 'fix' | 'review' | 'diagram';\r\n /** Tags for search/filtering */\r\n tags: string[];\r\n /** Author info (for community roles) */\r\n author?: string;\r\n /** Version string */\r\n version?: string;\r\n}\r\n\r\n// ─── Built-in Core Roles ─────────────────────────────────────────────────────\r\n\r\nconst CORE_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'parser-croc',\r\n name: '解析鳄',\r\n nameEn: 'Parser Croc',\r\n category: 'core',\r\n description: '解析项目结构、提取实体和关系',\r\n sprite: 'parser',\r\n color: '#34d399',\r\n priority: 0,\r\n triggers: { custom: () => true }, // Always summoned\r\n systemPrompt: 'You are an expert code parser. Analyze the project structure, extract all entities (classes, functions, APIs, models) and their relationships.',\r\n outputType: 'analysis',\r\n tags: ['core', 'parser', 'structure'],\r\n },\r\n {\r\n id: 'analyzer-croc',\r\n name: '分析鳄',\r\n nameEn: 'Analyzer Croc',\r\n category: 'core',\r\n description: '构建知识图谱、分析依赖关系',\r\n sprite: 'analyzer',\r\n color: '#60a5fa',\r\n priority: 1,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert software architect. Build a knowledge graph of the project, analyze dependencies, coupling, and cohesion.',\r\n outputType: 'diagram',\r\n tags: ['core', 'graph', 'architecture'],\r\n },\r\n {\r\n id: 'tester-croc',\r\n name: '测试鳄',\r\n nameEn: 'Tester Croc',\r\n category: 'core',\r\n description: '生成和执行 E2E 测试',\r\n sprite: 'tester',\r\n color: '#a78bfa',\r\n priority: 2,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert test engineer. Generate comprehensive E2E test cases covering all critical paths, edge cases, and error scenarios.',\r\n outputType: 'analysis',\r\n tags: ['core', 'testing', 'e2e'],\r\n },\r\n {\r\n id: 'healer-croc',\r\n name: '修复鳄',\r\n nameEn: 'Healer Croc',\r\n category: 'core',\r\n description: '自动修复测试失败和代码问题',\r\n sprite: 'healer',\r\n color: '#f87171',\r\n priority: 3,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert debugger and code fixer. Analyze test failures, diagnose root causes, and propose minimal targeted fixes.',\r\n outputType: 'fix',\r\n tags: ['core', 'healing', 'debug'],\r\n },\r\n {\r\n id: 'planner-croc',\r\n name: '规划鳄',\r\n nameEn: 'Planner Croc',\r\n category: 'core',\r\n description: '制定测试策略和执行计划',\r\n sprite: 'planner',\r\n color: '#fbbf24',\r\n priority: 4,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert project planner. Create test strategies, prioritize test execution order, and optimize the testing pipeline.',\r\n outputType: 'analysis',\r\n tags: ['core', 'planning', 'strategy'],\r\n },\r\n {\r\n id: 'reporter-croc',\r\n name: '汇报鳄',\r\n nameEn: 'Reporter Croc',\r\n category: 'core',\r\n description: '生成多视角分析报告',\r\n sprite: 'reporter',\r\n color: '#22d3ee',\r\n priority: 5,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert technical writer. Generate clear, actionable reports from multiple perspectives (developer, architect, tester, product, executive).',\r\n outputType: 'report',\r\n tags: ['core', 'reporting', 'documentation'],\r\n },\r\n];\r\n\r\n// ─── Language Expert Roles ───────────────────────────────────────────────────\r\n\r\nconst LANGUAGE_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'python-croc',\r\n name: 'Python专家鳄',\r\n nameEn: 'Python Expert Croc',\r\n category: 'language',\r\n description: 'Python 生态专家:Django/Flask/FastAPI/SQLAlchemy',\r\n sprite: 'language',\r\n color: '#3776ab',\r\n priority: 10,\r\n triggers: { languages: ['python'] },\r\n systemPrompt: 'You are a Python ecosystem expert. Analyze Python code for best practices, type safety, async patterns, Django/Flask/FastAPI conventions, SQLAlchemy usage, and Python-specific security issues.',\r\n outputType: 'review',\r\n tags: ['language', 'python', 'django', 'flask', 'fastapi'],\r\n },\r\n {\r\n id: 'go-croc',\r\n name: 'Go专家鳄',\r\n nameEn: 'Go Expert Croc',\r\n category: 'language',\r\n description: 'Go 生态专家:goroutine/channel/接口设计',\r\n sprite: 'language',\r\n color: '#00add8',\r\n priority: 10,\r\n triggers: { languages: ['go'] },\r\n systemPrompt: 'You are a Go ecosystem expert. Analyze Go code for goroutine safety, channel patterns, interface design, error handling, and Go-specific performance concerns.',\r\n outputType: 'review',\r\n tags: ['language', 'go', 'golang', 'concurrency'],\r\n },\r\n {\r\n id: 'java-croc',\r\n name: 'Java专家鳄',\r\n nameEn: 'Java Expert Croc',\r\n category: 'language',\r\n description: 'Java/Kotlin 生态专家:Spring Boot/JPA/微服务',\r\n sprite: 'language',\r\n color: '#ed8b00',\r\n priority: 10,\r\n triggers: { languages: ['java', 'kotlin'] },\r\n systemPrompt: 'You are a Java/Kotlin ecosystem expert. Analyze Spring Boot applications for bean lifecycle issues, JPA N+1 queries, transaction management, and microservice patterns.',\r\n outputType: 'review',\r\n tags: ['language', 'java', 'kotlin', 'spring'],\r\n },\r\n {\r\n id: 'rust-croc',\r\n name: 'Rust专家鳄',\r\n nameEn: 'Rust Expert Croc',\r\n category: 'language',\r\n description: 'Rust 生态专家:所有权/生命周期/unsafe',\r\n sprite: 'language',\r\n color: '#dea584',\r\n priority: 10,\r\n triggers: { languages: ['rust'] },\r\n systemPrompt: 'You are a Rust ecosystem expert. Analyze Rust code for ownership patterns, lifetime issues, unsafe code safety, and performance optimization.',\r\n outputType: 'review',\r\n tags: ['language', 'rust', 'ownership', 'safety'],\r\n },\r\n];\r\n\r\n// ─── Framework Expert Roles ──────────────────────────────────────────────────\r\n\r\nconst FRAMEWORK_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'react-croc',\r\n name: 'React专家鳄',\r\n nameEn: 'React Expert Croc',\r\n category: 'framework',\r\n description: 'React/Next.js 前端性能和架构专家',\r\n sprite: 'framework',\r\n color: '#61dafb',\r\n priority: 15,\r\n triggers: { frameworks: ['React', 'Next.js'] },\r\n systemPrompt: 'You are a React/Next.js expert. Analyze component architecture, render performance, state management, SSR/SSG patterns, and React-specific anti-patterns.',\r\n outputType: 'review',\r\n tags: ['framework', 'react', 'nextjs', 'frontend'],\r\n },\r\n {\r\n id: 'vue-croc',\r\n name: 'Vue专家鳄',\r\n nameEn: 'Vue Expert Croc',\r\n category: 'framework',\r\n description: 'Vue/Nuxt 专家:组合式API/响应式/SSR',\r\n sprite: 'framework',\r\n color: '#42b883',\r\n priority: 15,\r\n triggers: { frameworks: ['Vue', 'Nuxt'] },\r\n systemPrompt: 'You are a Vue/Nuxt expert. Analyze Composition API usage, reactivity patterns, Pinia stores, SSR hydration, and Vue-specific best practices.',\r\n outputType: 'review',\r\n tags: ['framework', 'vue', 'nuxt', 'frontend'],\r\n },\r\n {\r\n id: 'express-croc',\r\n name: 'Express专家鳄',\r\n nameEn: 'Express Expert Croc',\r\n category: 'framework',\r\n description: 'Express/Koa/Fastify 路由和中间件专家',\r\n sprite: 'framework',\r\n color: '#68a063',\r\n priority: 15,\r\n triggers: { frameworks: ['Express', 'Koa', 'Fastify'] },\r\n systemPrompt: 'You are a Node.js backend expert. Analyze Express/Koa/Fastify middleware chains, route organization, error handling, authentication patterns, and performance.',\r\n outputType: 'review',\r\n tags: ['framework', 'express', 'koa', 'fastify', 'nodejs'],\r\n },\r\n {\r\n id: 'django-croc',\r\n name: 'Django专家鳄',\r\n nameEn: 'Django Expert Croc',\r\n category: 'framework',\r\n description: 'Django/DRF 专家:ORM/序列化/权限',\r\n sprite: 'framework',\r\n color: '#092e20',\r\n priority: 15,\r\n triggers: { frameworks: ['Django', 'DRF'] },\r\n systemPrompt: 'You are a Django/DRF expert. Analyze ORM query efficiency, serializer design, view permissions, middleware, and Django-specific security practices.',\r\n outputType: 'review',\r\n tags: ['framework', 'django', 'drf', 'python'],\r\n },\r\n {\r\n id: 'spring-croc',\r\n name: 'SpringBoot专家鳄',\r\n nameEn: 'Spring Boot Expert Croc',\r\n category: 'framework',\r\n description: 'Spring Boot/Cloud 微服务架构专家',\r\n sprite: 'framework',\r\n color: '#6db33f',\r\n priority: 15,\r\n triggers: { frameworks: ['Spring Boot', 'Spring Cloud'] },\r\n systemPrompt: 'You are a Spring Boot/Cloud expert. Analyze bean configurations, transaction management, service discovery, circuit breakers, and microservice communication patterns.',\r\n outputType: 'review',\r\n tags: ['framework', 'spring', 'springboot', 'microservice'],\r\n },\r\n];\r\n\r\n// ─── Domain Expert Roles ─────────────────────────────────────────────────────\r\n\r\nconst DOMAIN_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'security-croc',\r\n name: '安全审计鳄',\r\n nameEn: 'Security Auditor Croc',\r\n category: 'domain',\r\n description: '安全漏洞检测:注入/XSS/CSRF/认证/授权',\r\n sprite: 'security',\r\n color: '#ef4444',\r\n priority: 8,\r\n triggers: {\r\n riskCategories: ['security'],\r\n custom: (ctx) => ctx.hasAPIs,\r\n },\r\n systemPrompt: 'You are a security auditor. Scan for OWASP Top 10 vulnerabilities: SQL injection, XSS, CSRF, broken authentication, sensitive data exposure, insecure deserialization, and missing access controls.',\r\n outputType: 'report',\r\n tags: ['domain', 'security', 'owasp', 'audit'],\r\n },\r\n {\r\n id: 'performance-croc',\r\n name: '性能分析鳄',\r\n nameEn: 'Performance Analyst Croc',\r\n category: 'domain',\r\n description: '性能瓶颈检测:N+1查询/内存泄漏/慢接口',\r\n sprite: 'performance',\r\n color: '#f59e0b',\r\n priority: 9,\r\n triggers: {\r\n minEntities: 50,\r\n custom: (ctx) => ctx.hasModels && ctx.hasAPIs,\r\n },\r\n systemPrompt: 'You are a performance analyst. Detect N+1 queries, memory leaks, slow API endpoints, missing indexes, unnecessary data loading, and recommend caching strategies.',\r\n outputType: 'report',\r\n tags: ['domain', 'performance', 'optimization', 'n+1'],\r\n },\r\n {\r\n id: 'architecture-croc',\r\n name: '架构评审鳄',\r\n nameEn: 'Architecture Reviewer Croc',\r\n category: 'domain',\r\n description: '架构质量评审:耦合度/内聚性/分层/DDD',\r\n sprite: 'architecture',\r\n color: '#8b5cf6',\r\n priority: 7,\r\n triggers: {\r\n minEntities: 30,\r\n },\r\n systemPrompt: 'You are a software architect. Evaluate coupling, cohesion, layering, dependency injection, SOLID principles, DDD patterns, and recommend architectural improvements.',\r\n outputType: 'review',\r\n tags: ['domain', 'architecture', 'solid', 'ddd'],\r\n },\r\n {\r\n id: 'data-modeling-croc',\r\n name: '数据建模鳄',\r\n nameEn: 'Data Modeling Croc',\r\n category: 'domain',\r\n description: '数据模型评审:范式/索引/关联/迁移',\r\n sprite: 'database',\r\n color: '#06b6d4',\r\n priority: 9,\r\n triggers: {\r\n custom: (ctx) => ctx.hasModels,\r\n frameworks: ['Sequelize', 'Prisma', 'TypeORM', 'Drizzle', 'SQLAlchemy', 'Django'],\r\n },\r\n systemPrompt: 'You are a database expert. Review data models for normalization, index design, relationship integrity, migration safety, cascade delete risks, and query optimization.',\r\n outputType: 'review',\r\n tags: ['domain', 'database', 'modeling', 'orm'],\r\n },\r\n {\r\n id: 'devops-croc',\r\n name: '运维部署鳄',\r\n nameEn: 'DevOps Croc',\r\n category: 'domain',\r\n description: 'CI/CD、Docker、K8s 部署和运维专家',\r\n sprite: 'devops',\r\n color: '#2563eb',\r\n priority: 12,\r\n triggers: {\r\n custom: (ctx) => ctx.hasDocker || ctx.hasCI,\r\n filePatterns: ['Dockerfile', 'docker-compose*', '.github/workflows/*', '.gitlab-ci*', 'Jenkinsfile'],\r\n },\r\n systemPrompt: 'You are a DevOps expert. Analyze Dockerfile efficiency, compose orchestration, CI/CD pipeline design, secret management, health checks, and deployment strategies.',\r\n outputType: 'review',\r\n tags: ['domain', 'devops', 'docker', 'ci/cd', 'kubernetes'],\r\n },\r\n {\r\n id: 'api-design-croc',\r\n name: 'API设计鳄',\r\n nameEn: 'API Design Croc',\r\n category: 'domain',\r\n description: 'RESTful API 设计评审:命名/版本/分页/错误处理',\r\n sprite: 'api',\r\n color: '#10b981',\r\n priority: 11,\r\n triggers: {\r\n custom: (ctx) => ctx.hasAPIs,\r\n minEntities: 10,\r\n },\r\n systemPrompt: 'You are an API design expert. Review REST API naming conventions, versioning strategy, pagination, filtering, error response format, rate limiting, and documentation completeness.',\r\n outputType: 'review',\r\n tags: ['domain', 'api', 'rest', 'design'],\r\n },\r\n {\r\n id: 'refactor-croc',\r\n name: '重构建议鳄',\r\n nameEn: 'Refactoring Croc',\r\n category: 'domain',\r\n description: '代码质量评估:技术债/复杂度/重复代码',\r\n sprite: 'refactor',\r\n color: '#ec4899',\r\n priority: 13,\r\n triggers: {\r\n riskCategories: ['maintainability'],\r\n minEntities: 40,\r\n },\r\n systemPrompt: 'You are a refactoring expert. Identify code smells, duplicated logic, high cyclomatic complexity, god classes, feature envy, and suggest targeted refactoring strategies with minimal risk.',\r\n outputType: 'review',\r\n tags: ['domain', 'refactoring', 'quality', 'tech-debt'],\r\n },\r\n {\r\n id: 'microservice-croc',\r\n name: '服务治理鳄',\r\n nameEn: 'Microservice Governance Croc',\r\n category: 'domain',\r\n description: '微服务架构治理:服务边界/熔断/链路追踪',\r\n sprite: 'microservice',\r\n color: '#7c3aed',\r\n priority: 14,\r\n triggers: {\r\n projectTypes: ['microservice', 'monorepo'],\r\n custom: (ctx) => ctx.entityCount > 100,\r\n },\r\n systemPrompt: 'You are a microservice governance expert. Analyze service boundaries, inter-service communication, circuit breakers, distributed tracing, service mesh, and API gateway patterns.',\r\n outputType: 'review',\r\n tags: ['domain', 'microservice', 'governance', 'distributed'],\r\n },\r\n];\r\n\r\n// ─── Role Registry ───────────────────────────────────────────────────────────\r\n\r\nexport class RoleRegistry {\r\n private roles = new Map<string, RoleDefinition>();\r\n\r\n constructor() {\r\n // Register all built-in roles\r\n for (const role of [...CORE_ROLES, ...LANGUAGE_ROLES, ...FRAMEWORK_ROLES, ...DOMAIN_ROLES]) {\r\n this.roles.set(role.id, role);\r\n }\r\n }\r\n\r\n /** Register a new role (community or custom) */\r\n register(role: RoleDefinition): void {\r\n if (this.roles.has(role.id)) {\r\n throw new Error(`Role \"${role.id}\" is already registered`);\r\n }\r\n this.roles.set(role.id, role);\r\n }\r\n\r\n /** Unregister a role */\r\n unregister(id: string): boolean {\r\n return this.roles.delete(id);\r\n }\r\n\r\n /** Get a role by ID */\r\n get(id: string): RoleDefinition | undefined {\r\n return this.roles.get(id);\r\n }\r\n\r\n /** List all registered roles */\r\n list(): RoleDefinition[] {\r\n return Array.from(this.roles.values());\r\n }\r\n\r\n /** List roles by category */\r\n listByCategory(category: RoleCategory): RoleDefinition[] {\r\n return this.list().filter(r => r.category === category);\r\n }\r\n\r\n /** Search roles by tags */\r\n search(query: string): RoleDefinition[] {\r\n const q = query.toLowerCase();\r\n return this.list().filter(r =>\r\n r.name.toLowerCase().includes(q) ||\r\n r.nameEn.toLowerCase().includes(q) ||\r\n r.description.toLowerCase().includes(q) ||\r\n r.tags.some(t => t.includes(q))\r\n );\r\n }\r\n\r\n /** Total number of registered roles */\r\n get size(): number {\r\n return this.roles.size;\r\n }\r\n}\r\n\r\n// ─── Singleton instance ──────────────────────────────────────────────────────\r\n\r\nlet _registry: RoleRegistry | null = null;\r\n\r\nexport function getRoleRegistry(): RoleRegistry {\r\n if (!_registry) {\r\n _registry = new RoleRegistry();\r\n }\r\n return _registry;\r\n}\r\n","/**\r\n * Studio Routes — Universal Project Analysis\r\n *\r\n * New routes for the upgraded OpenCroc Studio that supports\r\n * scanning any project (local or GitHub URL), building knowledge\r\n * graphs, analyzing risks, and generating multi-perspective reports.\r\n */\r\n\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { cloneAndScan } from '../../scanner/github-cloner.js';\r\nimport { buildKnowledgeGraph, getGraphStats, toMermaid } from '../../graph/index.js';\r\nimport { analyzeRisks, analyzeImpact, generateReport } from '../../insight/index.js';\r\nimport type {\r\n ReportPerspective,\r\n ScanResult,\r\n} from '../../graph/types.js';\r\nimport type { CrocOffice } from '../croc-office.js';\r\nimport {\r\n EMPTY_STUDIO_STORE,\r\n type StudioProjectStore,\r\n type StudioSnapshotStore,\r\n} from '../studio-store.js';\r\n\r\nfunction restoreStore(snapshotStore?: StudioSnapshotStore): StudioProjectStore {\r\n return snapshotStore?.load() ?? { ...EMPTY_STUDIO_STORE };\r\n}\r\n\r\nexport function registerStudioRoutes(\r\n app: FastifyInstance,\r\n office: CrocOffice,\r\n snapshotStore?: StudioSnapshotStore,\r\n): void {\r\n const store = restoreStore(snapshotStore);\r\n // Transient — not persisted in snapshots\r\n let lastScanResult: ScanResult | null = null;\r\n\r\n if (store.graph) {\r\n office.log(`♻️ Restored Studio snapshot: ${store.graph.nodes.length} nodes, ${store.risks.length} risks`, 'info');\r\n }\r\n\r\n const persistStore = () => {\r\n snapshotStore?.save(store);\r\n };\r\n\r\n const broadcastGraph = () => {\r\n if (!store.graph) return;\r\n\r\n office.broadcast('graph:update', {\r\n nodes: store.graph.nodes.map(n => ({\r\n id: n.id,\r\n label: n.label,\r\n type: n.type,\r\n module: n.module,\r\n status: n.status,\r\n })),\r\n edges: store.graph.edges.map(e => ({\r\n source: e.source,\r\n target: e.target,\r\n relation: e.relation,\r\n })),\r\n });\r\n };\r\n\r\n // ===== POST /api/studio/scan — Scan a project (local path or GitHub URL) =====\r\n app.post<{\r\n Body: {\r\n target: string; // Local path or GitHub URL or user/repo\r\n branch?: string;\r\n useLlm?: boolean;\r\n };\r\n }>('/api/studio/scan', async (req, reply) => {\r\n const { target, branch, useLlm } = req.body || {};\r\n\r\n if (!target || typeof target !== 'string') {\r\n reply.code(400).send({ error: 'Missing \"target\" field. Provide a local path or GitHub URL.' });\r\n return;\r\n }\r\n\r\n office.log(`🔍 Starting scan: ${target}`, 'info');\r\n office.updateAgent('parser-croc', { status: 'working', currentTask: `Scanning ${target}...`, progress: 0 });\r\n\r\n try {\r\n const scanResult = await cloneAndScan({\r\n target,\r\n branch,\r\n useLlm,\r\n keepClone: true,\r\n onProgress: (phase, percent, detail) => {\r\n office.updateAgent('parser-croc', { currentTask: detail || phase, progress: percent });\r\n office.broadcast('scan:progress', { phase, percent, detail });\r\n },\r\n });\r\n\r\n office.updateAgent('parser-croc', { status: 'done', currentTask: 'Scan complete', progress: 100 });\r\n office.log(`✅ Scan complete: ${scanResult.entities.length} entities, ${scanResult.relationships.length} relationships`);\r\n\r\n // Build knowledge graph\r\n office.updateAgent('analyzer-croc', { status: 'working', currentTask: 'Building knowledge graph...', progress: 0 });\r\n\r\n const projectName = target.includes('/') ? target.split('/').pop()!.replace('.git', '') : target.split(/[\\\\/]/).pop()!;\r\n\r\n const graph = buildKnowledgeGraph(scanResult, {\r\n projectName,\r\n source: target.startsWith('http') || /^[\\w.-]+\\/[\\w.-]+$/.test(target) ? 'github' : 'local',\r\n sourceUrl: target,\r\n rootPath: target,\r\n });\r\n\r\n office.updateAgent('analyzer-croc', { status: 'done', currentTask: 'Graph built', progress: 100 });\r\n office.log(`📊 Knowledge graph: ${graph.nodes.length} nodes, ${graph.edges.length} edges`);\r\n\r\n // Analyze risks\r\n office.updateAgent('planner-croc', { status: 'working', currentTask: 'Analyzing risks...', progress: 0 });\r\n\r\n const risks = await analyzeRisks(graph);\r\n\r\n office.updateAgent('planner-croc', { status: 'done', currentTask: `${risks.length} risks found`, progress: 100 });\r\n\r\n // Store results\r\n store.graph = graph;\r\n store.risks = risks;\r\n store.scanTime = Date.now();\r\n store.source = target;\r\n lastScanResult = scanResult;\r\n persistStore();\r\n\r\n // Broadcast graph update\r\n broadcastGraph();\r\n\r\n return {\r\n ok: true,\r\n project: graph.projectInfo,\r\n stats: getGraphStats(graph),\r\n risks: risks.length,\r\n duration: graph.buildDuration + scanResult.duration,\r\n };\r\n } catch (err) {\r\n office.updateAgent('parser-croc', { status: 'error', currentTask: String(err) });\r\n office.log(`❌ Scan failed: ${err}`, 'error');\r\n reply.code(500).send({ error: `Scan failed: ${(err as Error).message}` });\r\n return;\r\n }\r\n });\r\n\r\n // ===== GET /api/studio/graph — Get current knowledge graph =====\r\n app.get('/api/studio/graph', async (_req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet. POST /api/studio/scan first.' });\r\n return;\r\n }\r\n\r\n return {\r\n nodes: store.graph.nodes,\r\n edges: store.graph.edges,\r\n projectInfo: store.graph.projectInfo,\r\n builtAt: store.graph.builtAt,\r\n stats: getGraphStats(store.graph),\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/graph/mermaid — Get Mermaid diagram =====\r\n app.get<{\r\n Querystring: { types?: string; maxNodes?: string };\r\n }>('/api/studio/graph/mermaid', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const nodeTypes = req.query.types?.split(',');\r\n const maxNodes = req.query.maxNodes ? parseInt(req.query.maxNodes, 10) : 50;\r\n\r\n return {\r\n mermaid: toMermaid(store.graph, { nodeTypes, maxNodes }),\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/risks — Get risk analysis =====\r\n app.get<{\r\n Querystring: { severity?: string; category?: string };\r\n }>('/api/studio/risks', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n let risks = store.risks;\r\n if (req.query.severity) {\r\n risks = risks.filter(r => r.severity === req.query.severity);\r\n }\r\n if (req.query.category) {\r\n risks = risks.filter(r => r.category === req.query.category);\r\n }\r\n\r\n return { total: risks.length, risks };\r\n });\r\n\r\n // ===== GET /api/studio/impact/:nodeId — Analyze impact of a node =====\r\n app.get<{\r\n Params: { nodeId: string };\r\n }>('/api/studio/impact/:nodeId', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n // URL-decode the nodeId (since it contains colons and slashes)\r\n const nodeId = decodeURIComponent(req.params.nodeId);\r\n const impact = analyzeImpact(store.graph, nodeId);\r\n return impact;\r\n });\r\n\r\n // ===== GET /api/studio/report/:perspective — Generate perspective report =====\r\n app.get<{\r\n Params: { perspective: string };\r\n }>('/api/studio/report/:perspective', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const validPerspectives = ['developer', 'architect', 'tester', 'product', 'student', 'executive'];\r\n const perspective = req.params.perspective;\r\n if (!validPerspectives.includes(perspective)) {\r\n reply.code(400).send({ error: `Invalid perspective. Valid: ${validPerspectives.join(', ')}` });\r\n return;\r\n }\r\n\r\n office.updateAgent('reporter-croc', { status: 'working', currentTask: `Generating ${perspective} report...` });\r\n\r\n const report = await generateReport(\r\n store.graph,\r\n perspective as ReportPerspective,\r\n store.risks,\r\n );\r\n\r\n office.updateAgent('reporter-croc', { status: 'done', currentTask: 'Report ready' });\r\n\r\n return report;\r\n });\r\n\r\n // ===== GET /api/studio/nodes — List nodes with filtering =====\r\n app.get<{\r\n Querystring: { type?: string; language?: string; module?: string; search?: string; limit?: string };\r\n }>('/api/studio/nodes', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n let nodes = store.graph.nodes;\r\n if (req.query.type) nodes = nodes.filter(n => n.type === req.query.type);\r\n if (req.query.language) nodes = nodes.filter(n => n.language === req.query.language);\r\n if (req.query.module) nodes = nodes.filter(n => n.module === req.query.module);\r\n if (req.query.search) {\r\n const q = req.query.search.toLowerCase();\r\n nodes = nodes.filter(n => n.label.toLowerCase().includes(q) || n.id.toLowerCase().includes(q));\r\n }\r\n\r\n const limit = req.query.limit ? parseInt(req.query.limit, 10) : 100;\r\n return { total: nodes.length, nodes: nodes.slice(0, limit) };\r\n });\r\n\r\n // ===== GET /api/studio/node/:nodeId — Get node detail with neighbors =====\r\n app.get<{\r\n Params: { nodeId: string };\r\n }>('/api/studio/node/:nodeId', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const nodeId = decodeURIComponent(req.params.nodeId);\r\n const node = store.graph.nodes.find(n => n.id === nodeId);\r\n if (!node) {\r\n reply.code(404).send({ error: 'Node not found.' });\r\n return;\r\n }\r\n\r\n const incoming = store.graph.edges.filter(e => e.target === nodeId);\r\n const outgoing = store.graph.edges.filter(e => e.source === nodeId);\r\n const neighborIds = new Set([...incoming.map(e => e.source), ...outgoing.map(e => e.target)]);\r\n const neighbors = store.graph.nodes.filter(n => neighborIds.has(n.id));\r\n\r\n return { node, incoming, outgoing, neighbors };\r\n });\r\n\r\n // ===== GET /api/studio/summary — Quick one-line summary =====\r\n app.get('/api/studio/summary', async (_req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const { projectInfo } = store.graph;\r\n const stats = getGraphStats(store.graph);\r\n const critical = store.risks.filter(r => r.severity === 'critical').length;\r\n const high = store.risks.filter(r => r.severity === 'high').length;\r\n const healthScore = Math.max(0, 100 - (critical * 20 + high * 10));\r\n\r\n return {\r\n name: projectInfo.name,\r\n oneLiner: `A ${projectInfo.projectType} project using ${projectInfo.frameworks.join(', ') || 'unknown'}, with ${stats.apiCount || 0} APIs and ${stats.modelCount || 0} data models.`,\r\n healthScore,\r\n stats,\r\n topRisks: store.risks.slice(0, 5).map(r => ({ severity: r.severity, title: r.title })),\r\n source: store.source,\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/snapshots — List available snapshots =====\r\n app.get('/api/studio/snapshots', async () => {\r\n const snapshots = snapshotStore?.list() ?? [];\r\n return {\r\n total: snapshots.length,\r\n snapshots,\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/load — Restore a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n }>('/api/studio/snapshots/:id/load', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const restored = snapshotStore.loadById(req.params.id);\r\n if (!restored) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n store.graph = restored.graph;\r\n store.risks = restored.risks;\r\n store.scanTime = restored.scanTime;\r\n store.source = restored.source;\r\n office.log(`♻️ Restored snapshot: ${store.source || 'unknown source'}`, 'info');\r\n broadcastGraph();\r\n\r\n return {\r\n ok: true,\r\n source: store.source,\r\n scanTime: store.scanTime,\r\n graph: store.graph ? {\r\n nodeCount: store.graph.nodes.length,\r\n edgeCount: store.graph.edges.length,\r\n } : null,\r\n risks: store.risks.length,\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/rename — Rename a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n Body: { name?: string };\r\n }>('/api/studio/snapshots/:id/rename', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const name = req.body?.name?.trim();\r\n if (!name) {\r\n reply.code(400).send({ error: 'Snapshot name is required.' });\r\n return;\r\n }\r\n\r\n const renamed = snapshotStore.rename(req.params.id, name);\r\n if (!renamed) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n return {\r\n ok: true,\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/pin — Pin or unpin a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n Body: { pinned?: boolean };\r\n }>('/api/studio/snapshots/:id/pin', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const pinned = Boolean(req.body?.pinned);\r\n const updated = snapshotStore.pin(req.params.id, pinned);\r\n if (!updated) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n return {\r\n ok: true,\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/tags — Replace snapshot tags =====\r\n app.post<{\r\n Params: { id: string };\r\n Body: { tags?: string[] };\r\n }>('/api/studio/snapshots/:id/tags', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const rawTags: string[] = Array.isArray(req.body?.tags) ? req.body.tags : [];\r\n const tags = [...new Set(rawTags\r\n .map((tag: string) => typeof tag === 'string' ? tag.trim() : '')\r\n .filter(Boolean)\r\n )];\r\n\r\n const updated = snapshotStore.updateTags(req.params.id, tags);\r\n if (!updated) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n return {\r\n ok: true,\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/delete — Delete a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n }>('/api/studio/snapshots/:id/delete', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const deleted = snapshotStore.delete(req.params.id);\r\n if (!deleted) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n const current = snapshotStore.load();\r\n store.graph = current?.graph ?? null;\r\n store.risks = current?.risks ?? [];\r\n store.scanTime = current?.scanTime ?? 0;\r\n store.source = current?.source ?? '';\r\n if (store.graph) {\r\n broadcastGraph();\r\n }\r\n\r\n return {\r\n ok: true,\r\n hasCurrent: Boolean(current?.graph),\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/roles — List all registered croc roles =====\r\n app.get('/api/studio/roles', async (req) => {\r\n const { getRoleRegistry } = await import('../../agents/role-registry.js');\r\n const registry = getRoleRegistry();\r\n const category = (req.query as Record<string, string>).category;\r\n const search = (req.query as Record<string, string>).search;\r\n\r\n let roles = registry.list();\r\n if (category) roles = roles.filter(r => r.category === category);\r\n if (search) roles = registry.search(search);\r\n\r\n return {\r\n total: roles.length,\r\n categories: {\r\n core: roles.filter(r => r.category === 'core').length,\r\n language: roles.filter(r => r.category === 'language').length,\r\n framework: roles.filter(r => r.category === 'framework').length,\r\n domain: roles.filter(r => r.category === 'domain').length,\r\n community: roles.filter(r => r.category === 'community').length,\r\n },\r\n roles: roles.map(r => ({\r\n id: r.id,\r\n name: r.name,\r\n nameEn: r.nameEn,\r\n category: r.category,\r\n description: r.description,\r\n color: r.color,\r\n sprite: r.sprite,\r\n priority: r.priority,\r\n tags: r.tags,\r\n outputType: r.outputType,\r\n })),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/summon — Dynamically summon crocs for current project =====\r\n app.post('/api/studio/summon', async (_req, reply) => {\r\n if (!lastScanResult) {\r\n reply.code(400).send({ error: 'No project scanned. Run /api/studio/scan first.' });\r\n return;\r\n }\r\n\r\n const riskCategories = [...new Set(store.risks.map(r => r.category))];\r\n const plan = await office.summonForProject(lastScanResult, riskCategories);\r\n\r\n return {\r\n ok: true,\r\n totalAgents: office.getAgents().length,\r\n coreAgents: 6,\r\n dynamicAgents: office.getAgents().length - 6,\r\n reasoning: plan.reasoning,\r\n agents: office.getAgents().map(a => ({\r\n id: a.id,\r\n name: a.name,\r\n role: a.role,\r\n sprite: a.sprite,\r\n status: a.status,\r\n category: a.category,\r\n color: a.color,\r\n description: a.description,\r\n })),\r\n context: {\r\n languages: plan.context.languages,\r\n frameworks: plan.context.frameworks,\r\n projectType: plan.context.projectType,\r\n entityCount: plan.context.entityCount,\r\n hasAPIs: plan.context.hasAPIs,\r\n hasModels: plan.context.hasModels,\r\n hasFrontend: plan.context.hasFrontend,\r\n hasDocker: plan.context.hasDocker,\r\n hasCI: plan.context.hasCI,\r\n },\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/agents — Current agent roster =====\r\n app.get('/api/studio/agents', async () => {\r\n const info = office.getSummonPlan();\r\n return {\r\n ...info,\r\n agents: info.agents.map(a => ({\r\n id: a.id,\r\n name: a.name,\r\n role: a.role,\r\n sprite: a.sprite,\r\n status: a.status,\r\n currentTask: a.currentTask,\r\n category: a.category,\r\n color: a.color,\r\n description: a.description,\r\n })),\r\n };\r\n });\r\n}\r\n","/**\r\n * OpenCroc Task Router\r\n *\r\n * Analyzes a scanned project and decides which croc roles to summon.\r\n * Returns a prioritized list of roles matching the project's characteristics.\r\n */\r\n\r\nimport type { ScanResult } from '../graph/types.js';\r\nimport type { RoleDefinition, MatchContext, RoleTrigger } from './role-registry.js';\r\nimport { getRoleRegistry } from './role-registry.js';\r\n\r\nexport interface SummonPlan {\r\n /** Roles to summon, sorted by priority (lower = first) */\r\n roles: SummonedRole[];\r\n /** Summary of why each role was picked */\r\n reasoning: string[];\r\n /** Project context used for matching */\r\n context: MatchContext;\r\n}\r\n\r\nexport interface SummonedRole {\r\n role: RoleDefinition;\r\n /** Why this role was summoned */\r\n reason: string;\r\n /** Match confidence 0-1 */\r\n confidence: number;\r\n}\r\n\r\n/**\r\n * Build a MatchContext from a ScanResult.\r\n */\r\nexport function buildMatchContext(scan: ScanResult): MatchContext {\r\n const languages = scan.languages;\r\n const frameworks = scan.frameworks.map(f => f.name);\r\n // Infer project type from frameworks/languages\r\n const frontendFrameworks = ['React', 'Vue', 'Angular', 'Svelte', 'Next.js', 'Nuxt'];\r\n const backendFrameworks = ['Express', 'Fastify', 'NestJS', 'Django', 'Flask', 'Spring Boot', 'Gin', 'Actix'];\r\n const hasFE = frameworks.some(f => frontendFrameworks.includes(f));\r\n const hasBE = frameworks.some(f => backendFrameworks.includes(f));\r\n const projectType = hasFE && hasBE ? 'fullstack' : hasFE ? 'frontend' : hasBE ? 'backend' : 'unknown';\r\n\r\n const entityTypes = new Set(scan.entities.map(e => e.type));\r\n const hasModels = entityTypes.has('model') || entityTypes.has('class');\r\n const hasAPIs = entityTypes.has('api') || entityTypes.has('route');\r\n\r\n const hasFrontend = hasFE ||\r\n (languages['html'] ?? 0) > 10 || (languages['css'] ?? 0) > 5;\r\n\r\n // Detect Docker/CI from file paths\r\n const allPaths = scan.files.map(f => f.path);\r\n const hasDocker = allPaths.some(p =>\r\n p.includes('Dockerfile') || p.includes('docker-compose')\r\n );\r\n const hasCI = allPaths.some(p =>\r\n p.includes('.github/workflows') ||\r\n p.includes('.gitlab-ci') ||\r\n p.includes('Jenkinsfile')\r\n );\r\n\r\n const riskCategories: string[] = [];\r\n\r\n return {\r\n languages,\r\n frameworks,\r\n projectType,\r\n fileCount: scan.files.length,\r\n entityCount: scan.entities.length,\r\n riskCategories,\r\n hasModels,\r\n hasAPIs,\r\n hasFrontend,\r\n hasDocker,\r\n hasCI,\r\n };\r\n}\r\n\r\n/**\r\n * Check if a role's triggers match the given context.\r\n */\r\nfunction matchesTriggers(trigger: RoleTrigger, ctx: MatchContext): { matches: boolean; reason: string; confidence: number } {\r\n const reasons: string[] = [];\r\n let score = 0;\r\n let checks = 0;\r\n\r\n // Language match\r\n if (trigger.languages && trigger.languages.length > 0) {\r\n checks++;\r\n const matched = trigger.languages.filter(l => (ctx.languages[l] ?? 0) > 0);\r\n if (matched.length > 0) {\r\n score++;\r\n reasons.push(`语言匹配: ${matched.join(', ')}`);\r\n }\r\n }\r\n\r\n // Framework match\r\n if (trigger.frameworks && trigger.frameworks.length > 0) {\r\n checks++;\r\n const matched = trigger.frameworks.filter(f =>\r\n ctx.frameworks.some(cf => cf.toLowerCase() === f.toLowerCase())\r\n );\r\n if (matched.length > 0) {\r\n score++;\r\n reasons.push(`框架匹配: ${matched.join(', ')}`);\r\n }\r\n }\r\n\r\n // Project type match\r\n if (trigger.projectTypes && trigger.projectTypes.length > 0) {\r\n checks++;\r\n if (trigger.projectTypes.includes(ctx.projectType)) {\r\n score++;\r\n reasons.push(`项目类型匹配: ${ctx.projectType}`);\r\n }\r\n }\r\n\r\n // Entity threshold\r\n if (trigger.minEntities !== undefined) {\r\n checks++;\r\n if (ctx.entityCount >= trigger.minEntities) {\r\n score++;\r\n reasons.push(`实体数量满足: ${ctx.entityCount} ≥ ${trigger.minEntities}`);\r\n }\r\n }\r\n\r\n // Risk categories\r\n if (trigger.riskCategories && trigger.riskCategories.length > 0) {\r\n checks++;\r\n const matched = trigger.riskCategories.filter(r => ctx.riskCategories.includes(r));\r\n if (matched.length > 0) {\r\n score++;\r\n reasons.push(`风险类别匹配: ${matched.join(', ')}`);\r\n }\r\n }\r\n\r\n // Custom predicate\r\n if (trigger.custom) {\r\n checks++;\r\n try {\r\n if (trigger.custom(ctx)) {\r\n score++;\r\n reasons.push('自定义条件满足');\r\n }\r\n } catch {\r\n // Custom predicate threw — treat as no match\r\n }\r\n }\r\n\r\n // A role matches if ALL specified trigger conditions pass\r\n // (OR logic: at least one condition must match if multiple are specified)\r\n const matches = checks === 0 ? false : score > 0;\r\n const confidence = checks > 0 ? score / checks : 0;\r\n\r\n return {\r\n matches,\r\n reason: reasons.join('; ') || '无匹配',\r\n confidence,\r\n };\r\n}\r\n\r\n/**\r\n * Given a scan result, determine which roles should be summoned.\r\n *\r\n * @param scan - The scan result from the project scanner\r\n * @param maxRoles - Maximum number of non-core roles to summon (default: 8)\r\n * @param riskCategories - Risk categories detected (from insight engine)\r\n * @returns A SummonPlan with prioritized roles\r\n */\r\nexport function planSummon(\r\n scan: ScanResult,\r\n maxRoles: number = 8,\r\n riskCategories: string[] = [],\r\n): SummonPlan {\r\n const registry = getRoleRegistry();\r\n const ctx = buildMatchContext(scan);\r\n ctx.riskCategories = riskCategories;\r\n\r\n const summoned: SummonedRole[] = [];\r\n const reasoning: string[] = [];\r\n\r\n const allRoles = registry.list();\r\n\r\n // Always include core roles\r\n const coreRoles = allRoles.filter(r => r.category === 'core');\r\n for (const role of coreRoles) {\r\n summoned.push({ role, reason: '核心角色(始终召唤)', confidence: 1.0 });\r\n reasoning.push(`✅ ${role.name} — 核心角色`);\r\n }\r\n\r\n // Match non-core roles\r\n const nonCore = allRoles.filter(r => r.category !== 'core');\r\n const candidates: SummonedRole[] = [];\r\n\r\n for (const role of nonCore) {\r\n const result = matchesTriggers(role.triggers, ctx);\r\n if (result.matches) {\r\n candidates.push({\r\n role,\r\n reason: result.reason,\r\n confidence: result.confidence,\r\n });\r\n }\r\n }\r\n\r\n // Sort by priority (lower first), then confidence (higher first)\r\n candidates.sort((a, b) => {\r\n if (a.role.priority !== b.role.priority) return a.role.priority - b.role.priority;\r\n return b.confidence - a.confidence;\r\n });\r\n\r\n // Take top N\r\n const selected = candidates.slice(0, maxRoles);\r\n for (const s of selected) {\r\n summoned.push(s);\r\n reasoning.push(`🐊 ${s.role.name} — ${s.reason} (置信度: ${(s.confidence * 100).toFixed(0)}%)`);\r\n }\r\n\r\n // Log skipped roles\r\n const skipped = candidates.slice(maxRoles);\r\n for (const s of skipped) {\r\n reasoning.push(`⏭️ ${s.role.name} — 匹配但超出限制 (置信度: ${(s.confidence * 100).toFixed(0)}%)`);\r\n }\r\n\r\n return { roles: summoned, reasoning, context: ctx };\r\n}\r\n","import { execSync as nodeExecSync } from 'node:child_process';\r\nimport type { ExecutionMetrics } from '../types.js';\r\nimport type {\r\n ExecutionCoordinator,\r\n ExecutionCoordinatorDeps,\r\n ExecutionRunMode,\r\n ExecutionRunRequest,\r\n ExecutionRunResult,\r\n} from './types.js';\r\n\r\nfunction parseMetrics(output: string): ExecutionMetrics {\r\n const metrics: ExecutionMetrics = { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n const passedMatch = output.match(/(\\d+)\\s+passed/);\r\n const failedMatch = output.match(/(\\d+)\\s+failed/);\r\n const skippedMatch = output.match(/(\\d+)\\s+skipped/);\r\n const timedOutMatch = output.match(/(\\d+)\\s+timed?\\s*out/i);\r\n if (passedMatch) metrics.passed = parseInt(passedMatch[1], 10);\r\n if (failedMatch) metrics.failed = parseInt(failedMatch[1], 10);\r\n if (skippedMatch) metrics.skipped = parseInt(skippedMatch[1], 10);\r\n if (timedOutMatch) metrics.timedOut = parseInt(timedOutMatch[1], 10);\r\n return metrics;\r\n}\r\n\r\nfunction getFailureLines(output: string): string[] {\r\n return output\r\n .split(/\\r?\\n/)\r\n .filter((line) => /fail|error|timeout/i.test(line))\r\n .slice(0, 5);\r\n}\r\n\r\nexport function createExecutionCoordinator(deps: ExecutionCoordinatorDeps = {}): ExecutionCoordinator {\r\n const execSync = deps.execSync ?? nodeExecSync;\r\n const categorizeFailure = deps.categorizeFailure;\r\n\r\n return {\r\n async run(request: ExecutionRunRequest): Promise<ExecutionRunResult> {\r\n const mode: ExecutionRunMode = request.mode ?? 'auto';\r\n const timeoutMs = request.timeoutMs ?? 300_000;\r\n const command = `npx playwright test ${request.testFiles.map((file) => `\"${file}\"`).join(' ')} --reporter=line 2>&1`;\r\n\r\n let output: string;\r\n try {\r\n output = String(execSync(command, {\r\n cwd: request.cwd,\r\n encoding: 'utf-8',\r\n timeout: timeoutMs,\r\n stdio: 'pipe',\r\n env: request.env,\r\n }));\r\n } catch (err: unknown) {\r\n const execErr = err as { stdout?: string; stderr?: string };\r\n output = `${execErr.stdout || ''}\\n${execErr.stderr || ''}`;\r\n }\r\n\r\n output = output.trim();\r\n const metrics = parseMetrics(output);\r\n if (metrics.passed === 0 && metrics.failed === 0 && metrics.skipped === 0 && metrics.timedOut === 0) {\r\n metrics.failed = request.testFiles.length;\r\n }\r\n\r\n const failureHints = getFailureLines(output).map((line) => {\r\n const analyzed = categorizeFailure ? categorizeFailure(line) : { category: 'unknown', confidence: 0.5 };\r\n return {\r\n line,\r\n category: analyzed.category,\r\n confidence: analyzed.confidence,\r\n };\r\n });\r\n\r\n return {\r\n mode,\r\n metrics,\r\n output,\r\n failureHints,\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * Resilient HTTP fetch with exponential backoff retry.\r\n * Framework-level utility — no Playwright dependency required.\r\n */\r\n\r\nexport interface AttemptRecord {\r\n attempt: number;\r\n status: number;\r\n url: string;\r\n method: string;\r\n latencyMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface ResilientFetchOptions {\r\n /** HTTP method */\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\r\n /** Request body (will be JSON-stringified if object) */\r\n body?: string | Record<string, unknown>;\r\n /** Request headers */\r\n headers?: Record<string, string>;\r\n /** Max retry count (default: 3) */\r\n maxRetries?: number;\r\n /** Base delay in ms for exponential backoff (default: 1000) */\r\n baseDelayMs?: number;\r\n /** Per-request timeout in ms (default: 10000) */\r\n timeoutMs?: number;\r\n /** If true, throw on final failure; if false, return error result (default: false) */\r\n throwOnFailure?: boolean;\r\n}\r\n\r\nexport interface ResilientFetchResult {\r\n ok: boolean;\r\n status: number;\r\n data: unknown;\r\n attempts: AttemptRecord[];\r\n}\r\n\r\nconst RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);\r\n\r\nfunction isRetryable(status: number): boolean {\r\n return RETRYABLE_STATUSES.has(status);\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((r) => setTimeout(r, ms));\r\n}\r\n\r\nasync function safeJson(resp: Response): Promise<unknown> {\r\n try {\r\n return await resp.json();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request with automatic retry and exponential backoff.\r\n *\r\n * Retries on: network errors, 408, 429, 5xx.\r\n * Does NOT retry on: 4xx (except 408/429).\r\n */\r\nexport async function resilientFetch(\r\n url: string,\r\n options: ResilientFetchOptions = {},\r\n): Promise<ResilientFetchResult> {\r\n const {\r\n method = 'GET',\r\n body,\r\n headers = {},\r\n maxRetries = 3,\r\n baseDelayMs = 1000,\r\n timeoutMs = 10_000,\r\n throwOnFailure = false,\r\n } = options;\r\n\r\n const attempts: AttemptRecord[] = [];\r\n let lastStatus = 0;\r\n let lastBody: unknown = null;\r\n\r\n const requestHeaders: Record<string, string> = { ...headers };\r\n if (body && typeof body === 'object' && !requestHeaders['Content-Type']) {\r\n requestHeaders['Content-Type'] = 'application/json';\r\n }\r\n\r\n for (let i = 0; i <= maxRetries; i++) {\r\n const start = Date.now();\r\n\r\n try {\r\n const resp = await fetch(url, {\r\n method,\r\n headers: requestHeaders,\r\n body: body ? (typeof body === 'string' ? body : JSON.stringify(body)) : undefined,\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n\r\n const latency = Date.now() - start;\r\n lastStatus = resp.status;\r\n lastBody = await safeJson(resp);\r\n\r\n attempts.push({ attempt: i + 1, status: lastStatus, url, method, latencyMs: latency });\r\n\r\n if (resp.ok) {\r\n return { ok: true, status: lastStatus, data: lastBody, attempts };\r\n }\r\n\r\n if (isRetryable(lastStatus) && i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n\r\n // Non-retryable error\r\n break;\r\n } catch (err) {\r\n const latency = Date.now() - start;\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n attempts.push({ attempt: i + 1, status: 0, url, method, latencyMs: latency, error: errMsg });\r\n\r\n if (i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n const result: ResilientFetchResult = { ok: false, status: lastStatus, data: lastBody, attempts };\r\n\r\n if (throwOnFailure) {\r\n const summary = attempts.map((a) => `[${a.attempt}] ${a.status || 'ERR'} ${a.latencyMs}ms`).join(', ');\r\n throw new Error(`resilientFetch failed: ${method} ${url} (${attempts.length} attempts): ${summary}`);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Wait for a backend to become healthy by polling a health endpoint.\r\n */\r\nexport async function waitForBackend(\r\n baseUrl: string,\r\n options: { timeoutMs?: number; intervalMs?: number; healthPath?: string } = {},\r\n): Promise<void> {\r\n const { timeoutMs = 30_000, intervalMs = 1_000, healthPath = '/health' } = options;\r\n const healthUrl = new URL(healthPath, baseUrl).href;\r\n const start = Date.now();\r\n\r\n while (Date.now() - start < timeoutMs) {\r\n try {\r\n const resp = await fetch(healthUrl, { method: 'GET', signal: AbortSignal.timeout(3_000) });\r\n if (resp.ok) return;\r\n } catch {\r\n // not ready yet\r\n }\r\n await sleep(intervalMs);\r\n }\r\n\r\n throw new Error(`Backend not ready: ${healthUrl} timed out after ${timeoutMs}ms`);\r\n}\r\n","import { resolve } from 'node:path';\r\nimport { spawn as nodeSpawn } from 'node:child_process';\r\nimport { waitForBackend as runtimeWaitForBackend } from '../runtime/resilient-fetch.js';\r\nimport type {\r\n BackendEnsureRequest,\r\n BackendEnsureResult,\r\n BackendManager,\r\n BackendManagerDeps,\r\n BackendServerConfig,\r\n} from './types.js';\r\n\r\nfunction normalizeHealthUrl(server?: BackendServerConfig, baseURL?: string): string {\r\n if (server?.healthUrl) return server.healthUrl;\r\n if (baseURL) return new URL('/health', baseURL).href;\r\n return 'http://localhost:3000/health';\r\n}\r\n\r\nfunction splitHealthUrl(healthUrl: string): { baseUrl: string; healthPath: string } {\r\n const parsed = new URL(healthUrl);\r\n const baseUrl = `${parsed.protocol}//${parsed.host}`;\r\n const healthPath = `${parsed.pathname}${parsed.search}`;\r\n return { baseUrl, healthPath };\r\n}\r\n\r\nasync function waitReady(\r\n waitForBackend: NonNullable<BackendManagerDeps['waitForBackend']>,\r\n healthUrl: string,\r\n timeoutMs: number,\r\n intervalMs: number,\r\n): Promise<void> {\r\n const { baseUrl, healthPath } = splitHealthUrl(healthUrl);\r\n await waitForBackend(baseUrl, {\r\n timeoutMs,\r\n intervalMs,\r\n healthPath,\r\n });\r\n}\r\n\r\nexport function createBackendManager(deps: BackendManagerDeps = {}): BackendManager {\r\n const waitForBackend = deps.waitForBackend ?? runtimeWaitForBackend;\r\n const spawn = deps.spawn ?? nodeSpawn;\r\n\r\n return {\r\n async ensureReady(request: BackendEnsureRequest): Promise<BackendEnsureResult> {\r\n const server = request.server ?? {};\r\n const healthUrl = normalizeHealthUrl(server, request.baseURL);\r\n const quickTimeoutMs = 1_500;\r\n const startTimeoutMs = server.startTimeoutMs ?? 30_000;\r\n const pollIntervalMs = server.pollIntervalMs ?? 800;\r\n const tryReuse = request.mode !== 'managed' || server.reuseExisting !== false;\r\n\r\n if (tryReuse) {\r\n try {\r\n await waitReady(waitForBackend, healthUrl, quickTimeoutMs, 300);\r\n return {\r\n mode: request.mode,\r\n status: 'reused',\r\n healthUrl,\r\n cleanup: async () => {},\r\n };\r\n } catch (err) {\r\n void err;\r\n }\r\n }\r\n\r\n if (request.mode === 'reuse') {\r\n throw new Error(`HEALTH_FAIL: backend is not reachable at ${healthUrl} in reuse mode`);\r\n }\r\n\r\n if (!server.command) {\r\n if (request.mode === 'auto') {\r\n return {\r\n mode: request.mode,\r\n status: 'skipped',\r\n healthUrl,\r\n cleanup: async () => {},\r\n };\r\n }\r\n throw new Error('BOOT_CONFIG_MISSING: runtime.server.command is required for managed mode');\r\n }\r\n\r\n const child = spawn(server.command, server.args ?? [], {\r\n cwd: resolve(request.cwd, server.cwd ?? '.'),\r\n shell: true,\r\n stdio: 'pipe',\r\n env: process.env,\r\n });\r\n\r\n try {\r\n await waitReady(waitForBackend, healthUrl, startTimeoutMs, pollIntervalMs);\r\n } catch {\r\n if (child.exitCode === null) child.kill();\r\n throw new Error(`BOOT_TIMEOUT: backend did not become healthy at ${healthUrl}`);\r\n }\r\n\r\n return {\r\n mode: request.mode,\r\n status: 'started',\r\n healthUrl,\r\n cleanup: async () => {\r\n if (child.exitCode === null) child.kill();\r\n },\r\n };\r\n },\r\n };\r\n}\r\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport type { OpenCrocConfig } from '../types.js';\r\nimport { generatePlaywrightConfig } from '../runtime/playwright-config-generator.js';\r\nimport { generateGlobalSetup } from '../runtime/global-setup-generator.js';\r\nimport { generateGlobalTeardown } from '../runtime/global-teardown-generator.js';\r\nimport { generateAuthSetup } from '../runtime/auth-setup-generator.js';\r\nimport type { RuntimeBootstrap, RuntimeBootstrapRequest, RuntimeBootstrapResult } from './types.js';\r\n\r\nfunction ensureFile(filePath: string, content: string, force: boolean): boolean {\r\n if (existsSync(filePath) && !force) {\r\n return false;\r\n }\r\n mkdirSync(dirname(filePath), { recursive: true });\r\n writeFileSync(filePath, content, 'utf-8');\r\n return true;\r\n}\r\n\r\nexport function createRuntimeBootstrap(config: OpenCrocConfig): RuntimeBootstrap {\r\n return {\r\n async ensure(request: RuntimeBootstrapRequest): Promise<RuntimeBootstrapResult> {\r\n const force = request.force ?? false;\r\n const files = [\r\n {\r\n name: 'playwright.config.ts',\r\n content: generatePlaywrightConfig(config),\r\n },\r\n {\r\n name: 'global-setup.ts',\r\n content: generateGlobalSetup(config),\r\n },\r\n {\r\n name: 'global-teardown.ts',\r\n content: generateGlobalTeardown(config),\r\n },\r\n ];\r\n\r\n if (request.hasAuth) {\r\n files.push({\r\n name: 'auth.setup.ts',\r\n content: generateAuthSetup(config),\r\n });\r\n }\r\n\r\n const writtenFiles: string[] = [];\r\n const skippedFiles: string[] = [];\r\n for (const file of files) {\r\n const filePath = join(request.cwd, file.name);\r\n const written = ensureFile(filePath, file.content, force);\r\n if (written) writtenFiles.push(file.name);\r\n else skippedFiles.push(file.name);\r\n }\r\n\r\n return {\r\n writtenFiles,\r\n skippedFiles,\r\n };\r\n },\r\n };\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\nimport type { AuthProvisionResult, AuthProvisioner, AuthProvisionerDeps } from './types.js';\r\n\r\nfunction selectBaseUrl(configBaseUrl?: string): string {\r\n if (configBaseUrl && /^https?:\\/\\//i.test(configBaseUrl)) return configBaseUrl;\r\n const envBaseUrl = process.env.BASE_URL || '';\r\n if (/^https?:\\/\\//i.test(envBaseUrl)) return envBaseUrl;\r\n return '';\r\n}\r\n\r\nfunction resolveLoginUrl(loginUrl: string, baseUrl?: string): string {\r\n if (/^https?:\\/\\//i.test(loginUrl)) return loginUrl;\r\n if (!baseUrl) {\r\n throw new Error('AUTH_FAIL: playwright.baseURL or BASE_URL is required for relative runtime.auth.loginUrl');\r\n }\r\n try {\r\n return new URL(loginUrl, baseUrl).href;\r\n } catch {\r\n throw new Error('AUTH_FAIL: invalid login URL or base URL');\r\n }\r\n}\r\n\r\nexport function createAuthProvisioner(config: OpenCrocConfig, deps: AuthProvisionerDeps = {}): AuthProvisioner {\r\n const fetchFn = deps.fetchFn ?? fetch;\r\n\r\n return {\r\n async provision(): Promise<AuthProvisionResult> {\r\n const auth = config.runtime?.auth;\r\n const loginUrl = auth?.loginUrl;\r\n const baseURL = selectBaseUrl(config.playwright?.baseURL);\r\n\r\n if (!loginUrl) {\r\n return { status: 'skipped', env: {} };\r\n }\r\n\r\n const username = process.env.AUTH_USERNAME || auth?.username || 'admin';\r\n const password = process.env.AUTH_PASSWORD || auth?.password || '';\r\n if (!password) {\r\n throw new Error('AUTH_FAIL: runtime.auth.password or AUTH_PASSWORD is required');\r\n }\r\n\r\n const resolvedLoginUrl = resolveLoginUrl(loginUrl, baseURL);\r\n const response = await fetchFn(resolvedLoginUrl, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify({ username, password }),\r\n signal: AbortSignal.timeout(8_000),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`AUTH_FAIL: login request failed with status ${response.status}`);\r\n }\r\n\r\n const env: NodeJS.ProcessEnv = {\r\n AUTH_LOGIN_URL: resolvedLoginUrl,\r\n AUTH_USERNAME: username,\r\n AUTH_PASSWORD: password,\r\n };\r\n if (baseURL) env.BASE_URL = baseURL;\r\n\r\n return {\r\n status: 'ready',\r\n env,\r\n };\r\n },\r\n };\r\n}\r\n","import type { ExecutionMetrics } from '../types.js';\r\nimport type { AuthStatus, BackendStatus, ExecutionQualityGateResult } from './types.js';\r\n\r\nexport interface BuildQualityGateInput {\r\n metrics?: ExecutionMetrics | null;\r\n authStatus: AuthStatus;\r\n backendStatus: BackendStatus;\r\n}\r\n\r\nexport function buildExecutionQualityGate(input: BuildQualityGateInput): ExecutionQualityGateResult {\r\n const metrics = input.metrics ?? { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n const total = metrics.passed + metrics.failed + metrics.skipped + metrics.timedOut;\r\n const skipRatio = total > 0 ? metrics.skipped / total : 0;\r\n const effectiveExecutionRate = total > 0 ? metrics.passed / total : 0;\r\n const authFailRatio = input.authStatus === 'failed' ? 1 : 0;\r\n const setupFail =\r\n input.authStatus === 'failed' ||\r\n input.backendStatus === 'failed' ||\r\n (total === 0 && (input.authStatus !== 'skipped' || input.backendStatus !== 'skipped'));\r\n\r\n const reasons: string[] = [];\r\n if (setupFail) reasons.push('setup-failed');\r\n if (skipRatio >= 0.5) reasons.push('high-skip-ratio');\r\n if (metrics.failed > 0) reasons.push('tests-failed');\r\n if (metrics.timedOut > 0) reasons.push('tests-timeout');\r\n\r\n let level: ExecutionQualityGateResult['level'] = 'pass';\r\n if (setupFail || metrics.failed > 0) level = 'fail';\r\n else if (skipRatio >= 0.5 || metrics.timedOut > 0) level = 'warn';\r\n\r\n return {\r\n setupFail,\r\n skipRatio,\r\n authFailRatio,\r\n effectiveExecutionRate,\r\n level,\r\n reasons,\r\n authStatus: input.authStatus,\r\n backendStatus: input.backendStatus,\r\n };\r\n}\r\n","import type { WebSocket } from 'ws';\r\nimport type { OpenCrocConfig, PipelineRunResult, GeneratedTestFile, ExecutionMetrics, ReportOutput } from '../types.js';\r\nimport type { BackendStatus, ExecutionQualityGateResult, ExecutionRunMode, AuthStatus } from '../execution/types.js';\r\nimport type { ScanResult } from '../graph/types.js';\r\nimport type { SummonPlan } from '../agents/task-router.js';\r\n\r\nexport interface CrocAgent {\r\n id: string;\r\n name: string;\r\n role: string; // expanded from fixed union to allow dynamic roles\r\n sprite: string;\r\n status: 'idle' | 'working' | 'thinking' | 'done' | 'error';\r\n currentTask?: string;\r\n tokensUsed: number;\r\n progress?: number; // 0-100\r\n /** Dynamic role metadata */\r\n category?: string;\r\n color?: string;\r\n description?: string;\r\n}\r\n\r\nexport interface KnowledgeGraphNode {\r\n id: string;\r\n label: string;\r\n type: 'model' | 'controller' | 'api' | 'dto' | 'module';\r\n status: 'idle' | 'testing' | 'passed' | 'failed';\r\n fields?: string[];\r\n module?: string;\r\n}\r\n\r\nexport interface KnowledgeGraphEdge {\r\n source: string;\r\n target: string;\r\n relation: string;\r\n}\r\n\r\nexport interface KnowledgeGraph {\r\n nodes: KnowledgeGraphNode[];\r\n edges: KnowledgeGraphEdge[];\r\n}\r\n\r\nexport interface ProjectInfo {\r\n name: string;\r\n backendRoot: string;\r\n adapter: string;\r\n stats: {\r\n modules: number;\r\n models: number;\r\n endpoints: number;\r\n relations: number;\r\n };\r\n graph: KnowledgeGraph;\r\n agents: CrocAgent[];\r\n}\r\n\r\nexport interface TaskResult {\r\n ok: boolean;\r\n task: string;\r\n duration: number;\r\n details?: Record<string, unknown>;\r\n error?: string;\r\n}\r\n\r\nconst DEFAULT_AGENTS: CrocAgent[] = [\r\n { id: 'parser-croc', name: '解析鳄', role: 'parser', sprite: 'parser', status: 'idle', tokensUsed: 0 },\r\n { id: 'analyzer-croc', name: '分析鳄', role: 'analyzer', sprite: 'analyzer', status: 'idle', tokensUsed: 0 },\r\n { id: 'tester-croc', name: '测试鳄', role: 'tester', sprite: 'tester', status: 'idle', tokensUsed: 0 },\r\n { id: 'healer-croc', name: '修复鳄', role: 'healer', sprite: 'healer', status: 'idle', tokensUsed: 0 },\r\n { id: 'planner-croc', name: '规划鳄', role: 'planner', sprite: 'planner', status: 'idle', tokensUsed: 0 },\r\n { id: 'reporter-croc', name: '汇报鳄', role: 'reporter', sprite: 'reporter', status: 'idle', tokensUsed: 0 },\r\n];\r\n\r\nexport class CrocOffice {\r\n private config: OpenCrocConfig;\r\n private cwd: string;\r\n private clients: Set<WebSocket> = new Set();\r\n private agents: CrocAgent[];\r\n private cachedGraph: KnowledgeGraph | null = null;\r\n private running = false;\r\n private lastPipelineResult: PipelineRunResult | null = null;\r\n private lastGeneratedFiles: GeneratedTestFile[] = [];\r\n private lastExecutionMetrics: ExecutionMetrics | null = null;\r\n private lastExecutionQuality: ExecutionQualityGateResult | null = null;\r\n private lastReports: ReportOutput[] = [];\r\n\r\n private static readonly ACTIVE_AGENT_STATUSES = new Set<CrocAgent['status']>([\r\n 'working',\r\n 'thinking',\r\n ]);\r\n\r\n constructor(config: OpenCrocConfig, cwd: string) {\r\n this.config = config;\r\n this.cwd = cwd;\r\n this.agents = DEFAULT_AGENTS.map((a) => ({ ...a }));\r\n }\r\n\r\n addClient(ws: WebSocket): void {\r\n this.clients.add(ws);\r\n }\r\n\r\n removeClient(ws: WebSocket): void {\r\n this.clients.delete(ws);\r\n }\r\n\r\n broadcast(type: string, payload: unknown): void {\r\n const msg = JSON.stringify({ type, payload });\r\n for (const client of this.clients) {\r\n try {\r\n client.send(msg);\r\n } catch {\r\n this.clients.delete(client);\r\n }\r\n }\r\n }\r\n\r\n /** Send a log message to all clients */\r\n log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\r\n this.broadcast('log', { message, level, time: Date.now() });\r\n }\r\n\r\n getAgents(): CrocAgent[] {\r\n return this.agents;\r\n }\r\n\r\n getAgent(id: string): CrocAgent | undefined {\r\n return this.agents.find((a) => a.id === id);\r\n }\r\n\r\n updateAgent(id: string, update: Partial<CrocAgent>): void {\r\n const agent = this.agents.find((a) => a.id === id);\r\n if (agent) {\r\n const wasActive = this.isAgentActive(agent.status);\r\n Object.assign(agent, update);\r\n const isActive = this.isAgentActive(agent.status);\r\n this.broadcast('agent:update', this.agents);\r\n\r\n if (!wasActive && isActive) {\r\n this.broadcast('agent:assigned', {\r\n id: agent.id,\r\n name: agent.name,\r\n role: agent.role,\r\n status: agent.status,\r\n currentTask: agent.currentTask ?? null,\r\n at: Date.now(),\r\n });\r\n } else if (wasActive && !isActive) {\r\n this.broadcast('agent:released', {\r\n id: agent.id,\r\n name: agent.name,\r\n role: agent.role,\r\n status: agent.status,\r\n currentTask: agent.currentTask ?? null,\r\n at: Date.now(),\r\n });\r\n }\r\n }\r\n }\r\n\r\n private isAgentActive(status: CrocAgent['status']): boolean {\r\n return CrocOffice.ACTIVE_AGENT_STATUSES.has(status);\r\n }\r\n\r\n isRunning(): boolean {\r\n return this.running;\r\n }\r\n\r\n getConfig(): OpenCrocConfig {\r\n return this.config;\r\n }\r\n\r\n getCwd(): string {\r\n return this.cwd;\r\n }\r\n\r\n // ============ Real Task Dispatch ============\r\n\r\n /** Run the full scan → graph build pipeline */\r\n async runScan(): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'scan', duration: 0, error: 'Another task is running' };\r\n this.running = true;\r\n const start = Date.now();\r\n\r\n try {\r\n this.invalidateCache();\r\n this.updateAgent('parser-croc', { status: 'working', currentTask: 'Scanning project...', progress: 0 });\r\n this.log('🔍 Parser croc is scanning the project...');\r\n\r\n const graph = await this.buildKnowledgeGraph();\r\n\r\n const duration = Date.now() - start;\r\n this.log(`✅ Scan complete: ${graph.nodes.length} nodes, ${graph.edges.length} edges (${duration}ms)`);\r\n return { ok: true, task: 'scan', duration, details: { nodes: graph.nodes.length, edges: graph.edges.length } };\r\n } catch (err) {\r\n this.updateAgent('parser-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Scan failed: ${err}`, 'error');\r\n return { ok: false, task: 'scan', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n this.running = false;\r\n }\r\n }\r\n\r\n /** Run the real pipeline: scan → er-diagram → api-chain → plan → codegen → report */\r\n async runPipeline(): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'pipeline', duration: 0, error: 'Another task is running' };\r\n this.running = true;\r\n const start = Date.now();\r\n\r\n try {\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { createPipeline } = await import('../pipeline/index.js');\r\n\r\n const backendRoot = resolvePath(this.cwd, this.config.backendRoot);\r\n const pipelineConfig = { ...this.config, backendRoot };\r\n const pipeline = createPipeline(pipelineConfig);\r\n\r\n // Phase 1: Scan + ER Diagram (解析鳄)\r\n this.updateAgent('parser-croc', { status: 'working', currentTask: 'Scanning source code...', progress: 10 });\r\n this.log(`🐊 解析鳄 scanning from: ${backendRoot}`);\r\n this.invalidateCache();\r\n await this.buildKnowledgeGraph();\r\n this.updateNodeStatus('module', 'testing');\r\n\r\n // Run real pipeline: scan + er-diagram\r\n this.updateAgent('parser-croc', { currentTask: 'Parsing models & ER diagrams...', progress: 40 });\r\n const scanResult = await pipeline.run(['scan', 'er-diagram']);\r\n const moduleCount = scanResult.modules.length;\r\n const erCount = scanResult.erDiagrams.size;\r\n this.log(`📊 Found ${moduleCount} modules, ${erCount} ER diagrams`);\r\n this.updateAgent('parser-croc', { status: 'done', currentTask: `${moduleCount} modules parsed`, progress: 100 });\r\n\r\n // Phase 2: API Chain Analysis (分析鳄)\r\n this.updateAgent('analyzer-croc', { status: 'working', currentTask: 'Analyzing API chains...', progress: 0 });\r\n this.log('🐊 分析鳄 is analyzing API dependencies...');\r\n const analyzeResult = await pipeline.run(['api-chain']);\r\n const warnings = analyzeResult.validationErrors.filter(e => e.severity === 'warning');\r\n if (warnings.length > 0) {\r\n this.log(`⚠️ ${warnings.length} API chain warnings`, 'warn');\r\n }\r\n this.updateAgent('analyzer-croc', { status: 'done', currentTask: 'Analysis complete', progress: 100 });\r\n\r\n // Phase 3: Plan test chains (规划鳄)\r\n this.updateAgent('planner-croc', { status: 'thinking', currentTask: 'Planning test chains...', progress: 0 });\r\n this.log('🐊 规划鳄 is planning test chains...');\r\n const planResult = await pipeline.run(['plan']);\r\n let totalChains = 0, totalSteps = 0;\r\n for (const [, plan] of planResult.chainPlans) {\r\n totalChains += plan.chains.length;\r\n totalSteps += plan.totalSteps;\r\n }\r\n this.log(`📋 Planned ${totalChains} test chains with ${totalSteps} steps`);\r\n this.updateAgent('planner-croc', { status: 'done', currentTask: `${totalChains} chains planned`, progress: 100 });\r\n\r\n // Phase 4: Generate test code (测试鳄)\r\n this.updateAgent('tester-croc', { status: 'working', currentTask: 'Generating test code...', progress: 0 });\r\n this.log('🐊 测试鳄 is generating Playwright test code...');\r\n this.updateNodeStatus('controller', 'testing');\r\n\r\n // Full pipeline run for codegen (it needs prior steps' results internally)\r\n const fullResult = await pipeline.run(['scan', 'er-diagram', 'api-chain', 'plan', 'codegen']);\r\n this.lastPipelineResult = fullResult;\r\n this.lastGeneratedFiles = fullResult.generatedFiles;\r\n\r\n // Write generated files to disk\r\n const { writeFileSync, mkdirSync } = await import('node:fs');\r\n const { dirname } = await import('node:path');\r\n let filesWritten = 0;\r\n for (const file of fullResult.generatedFiles) {\r\n const fullPath = resolvePath(this.cwd, file.filePath);\r\n mkdirSync(dirname(fullPath), { recursive: true });\r\n writeFileSync(fullPath, file.content, 'utf-8');\r\n filesWritten++;\r\n }\r\n\r\n this.updateNodeStatus('controller', 'passed');\r\n this.log(`✅ Generated ${filesWritten} test files`);\r\n this.updateAgent('tester-croc', { status: 'done', currentTask: `${filesWritten} files generated`, progress: 100 });\r\n\r\n // Broadcast generated files to frontend\r\n this.broadcast('files:generated', fullResult.generatedFiles.map(f => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n lines: f.content.split('\\n').length,\r\n })));\r\n\r\n // Phase 5: Report (汇报鳄)\r\n this.updateAgent('reporter-croc', { status: 'working', currentTask: 'Compiling report...', progress: 0 });\r\n this.log('🐊 汇报鳄 is compiling results...');\r\n\r\n // Validation\r\n const validateResult = await pipeline.run(['validate']);\r\n const errors = validateResult.validationErrors.filter(e => e.severity === 'error');\r\n if (errors.length > 0) {\r\n this.log(`⚠️ ${errors.length} validation errors`, 'warn');\r\n }\r\n\r\n this.updateNodeStatus('module', 'passed');\r\n this.updateAgent('reporter-croc', { status: 'done', currentTask: 'Report ready', progress: 100 });\r\n\r\n const duration = Date.now() - start;\r\n this.log(`✅ Pipeline complete in ${duration}ms — ${moduleCount} modules, ${totalChains} chains, ${filesWritten} files`);\r\n this.broadcast('pipeline:complete', {\r\n duration, status: 'success',\r\n summary: { modules: moduleCount, chains: totalChains, steps: totalSteps, files: filesWritten },\r\n });\r\n return { ok: true, task: 'pipeline', duration, details: {\r\n modules: moduleCount, chains: totalChains, steps: totalSteps, files: filesWritten,\r\n }};\r\n } catch (err) {\r\n this.updateAgent('tester-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Pipeline failed: ${err}`, 'error');\r\n this.broadcast('pipeline:complete', { status: 'error', error: String(err) });\r\n return { ok: false, task: 'pipeline', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n this.running = false;\r\n }\r\n }\r\n\r\n /** Reset all agents to idle */\r\n resetAgents(): void {\r\n for (const agent of this.agents) {\r\n const wasActive = this.isAgentActive(agent.status);\r\n agent.status = 'idle';\r\n agent.currentTask = undefined;\r\n agent.progress = undefined;\r\n if (wasActive) {\r\n this.broadcast('agent:released', {\r\n id: agent.id,\r\n name: agent.name,\r\n role: agent.role,\r\n status: agent.status,\r\n currentTask: null,\r\n at: Date.now(),\r\n });\r\n }\r\n }\r\n this.broadcast('agent:update', this.agents);\r\n }\r\n\r\n /**\r\n * Dynamically summon crocs based on a project scan result.\r\n * Core 6 are always present; additional expert crocs are added based on project characteristics.\r\n */\r\n async summonForProject(scan: ScanResult, riskCategories: string[] = []): Promise<SummonPlan> {\r\n const { planSummon } = await import('../agents/task-router.js');\r\n const plan = planSummon(scan, 8, riskCategories);\r\n\r\n // Reset to core agents first\r\n const coreIds = new Set(DEFAULT_AGENTS.map(a => a.id));\r\n this.agents = DEFAULT_AGENTS.map((a) => ({ ...a }));\r\n\r\n // Add dynamic roles\r\n for (const summoned of plan.roles) {\r\n if (coreIds.has(summoned.role.id)) continue; // Skip core — already added\r\n\r\n const agent: CrocAgent = {\r\n id: summoned.role.id,\r\n name: summoned.role.name,\r\n role: summoned.role.id.replace(/-croc$/, ''),\r\n sprite: summoned.role.sprite,\r\n status: 'idle',\r\n tokensUsed: 0,\r\n category: summoned.role.category,\r\n color: summoned.role.color,\r\n description: summoned.role.description,\r\n };\r\n this.agents.push(agent);\r\n }\r\n\r\n // Broadcast the full agent list\r\n this.broadcast('agent:update', this.agents);\r\n\r\n // Log the summon plan\r\n for (const line of plan.reasoning) {\r\n this.log(line);\r\n }\r\n this.log(`🐊 共召唤 ${this.agents.length} 个鳄鱼专家 (${plan.roles.length - DEFAULT_AGENTS.length} 个动态角色)`);\r\n\r\n // Animate the summoning — stagger agent assignments\r\n const dynamicAgents = this.agents.filter(a => !coreIds.has(a.id));\r\n for (let i = 0; i < dynamicAgents.length; i++) {\r\n const agent = dynamicAgents[i]!;\r\n setTimeout(() => {\r\n this.updateAgent(agent.id, { status: 'working', currentTask: '分析项目中…' });\r\n setTimeout(() => {\r\n this.updateAgent(agent.id, { status: 'idle', currentTask: undefined });\r\n }, 2000 + Math.random() * 1000);\r\n }, 300 * i);\r\n }\r\n\r\n return plan;\r\n }\r\n\r\n /** Get the current summon plan context */\r\n getSummonPlan(): { agentCount: number; coreCount: number; dynamicCount: number; agents: CrocAgent[] } {\r\n const coreIds = new Set(DEFAULT_AGENTS.map(a => a.id));\r\n const coreCount = this.agents.filter(a => coreIds.has(a.id)).length;\r\n return {\r\n agentCount: this.agents.length,\r\n coreCount,\r\n dynamicCount: this.agents.length - coreCount,\r\n agents: this.agents,\r\n };\r\n }\r\n\r\n /** Get last pipeline result */\r\n getLastPipelineResult(): PipelineRunResult | null {\r\n return this.lastPipelineResult;\r\n }\r\n\r\n /** Get generated test files from last pipeline run */\r\n getGeneratedFiles(): GeneratedTestFile[] {\r\n return this.lastGeneratedFiles;\r\n }\r\n\r\n /** Get last execution metrics */\r\n getLastExecutionMetrics(): ExecutionMetrics | null {\r\n return this.lastExecutionMetrics;\r\n }\r\n\r\n getLastExecutionQuality(): ExecutionQualityGateResult | null {\r\n return this.lastExecutionQuality;\r\n }\r\n\r\n /** Get last generated reports */\r\n getLastReports(): ReportOutput[] {\r\n return this.lastReports;\r\n }\r\n\r\n /** Run generated tests with Playwright */\r\n async runTests(options: { mode?: ExecutionRunMode } = {}): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'execute', duration: 0, error: 'Another task is running' };\r\n if (this.lastGeneratedFiles.length === 0) {\r\n return { ok: false, task: 'execute', duration: 0, error: 'No test files — run Pipeline first' };\r\n }\r\n this.running = true;\r\n const start = Date.now();\r\n let cleanupBackend: (() => Promise<void>) | null = null;\r\n let authStatus: AuthStatus = 'skipped';\r\n let backendStatus!: BackendStatus;\r\n\r\n try {\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { existsSync } = await import('node:fs');\r\n const { createExecutionCoordinator } = await import('../execution/coordinator.js');\r\n const { createBackendManager } = await import('../execution/backend-manager.js');\r\n const { createRuntimeBootstrap } = await import('../execution/runtime-bootstrap.js');\r\n const { createAuthProvisioner } = await import('../execution/auth-provisioner.js');\r\n const { buildExecutionQualityGate } = await import('../execution/quality-gate.js');\r\n const { categorizeFailure } = await import('../self-healing/index.js');\r\n\r\n // Find test files on disk\r\n const testFiles = this.lastGeneratedFiles\r\n .map(f => resolvePath(this.cwd, f.filePath))\r\n .filter(f => existsSync(f));\r\n\r\n if (testFiles.length === 0) {\r\n this.log('⚠️ No test files found on disk', 'warn');\r\n return { ok: false, task: 'execute', duration: Date.now() - start, error: 'No test files found on disk' };\r\n }\r\n\r\n // Tester croc runs the tests\r\n const mode = options.mode ?? 'auto';\r\n this.updateAgent('tester-croc', { status: 'working', currentTask: `Running ${testFiles.length} test files (${mode})...`, progress: 0 });\r\n this.log(`🧪 测试鳄 is running ${testFiles.length} Playwright tests (${mode})...`);\r\n\r\n const runtimeBootstrap = createRuntimeBootstrap(this.config);\r\n const runtimeResult = await runtimeBootstrap.ensure({\r\n cwd: this.cwd,\r\n hasAuth: !!this.config.runtime?.auth?.loginUrl,\r\n });\r\n if (runtimeResult.writtenFiles.length > 0) {\r\n this.log(`🧩 Runtime assets prepared: ${runtimeResult.writtenFiles.join(', ')}`);\r\n }\r\n\r\n const backendManager = createBackendManager();\r\n try {\r\n const backendReady = await backendManager.ensureReady({\r\n mode,\r\n cwd: this.cwd,\r\n server: this.config.runtime?.server,\r\n baseURL: this.config.playwright?.baseURL,\r\n });\r\n backendStatus = backendReady.status;\r\n cleanupBackend = backendReady.cleanup;\r\n if (backendReady.status === 'started') {\r\n this.log(`🚀 Managed backend started (${backendReady.healthUrl})`);\r\n } else if (backendReady.status === 'reused') {\r\n this.log(`🔁 Reusing backend (${backendReady.healthUrl})`);\r\n }\r\n } catch (err) {\r\n backendStatus = 'failed';\r\n this.lastExecutionQuality = buildExecutionQualityGate({\r\n metrics: null,\r\n authStatus,\r\n backendStatus,\r\n });\r\n throw err;\r\n }\r\n\r\n const authProvisioner = createAuthProvisioner(this.config);\r\n let authResult;\r\n try {\r\n authResult = await authProvisioner.provision();\r\n authStatus = authResult.status;\r\n if (authResult.status === 'ready') {\r\n this.log('🔐 Auth environment prepared');\r\n }\r\n } catch (err) {\r\n authStatus = 'failed';\r\n this.lastExecutionQuality = buildExecutionQualityGate({\r\n metrics: null,\r\n authStatus,\r\n backendStatus,\r\n });\r\n throw err;\r\n }\r\n\r\n // Healer croc monitors\r\n this.updateAgent('healer-croc', { status: 'thinking', currentTask: 'Monitoring test run...', progress: 0 });\r\n\r\n const coordinator = createExecutionCoordinator({ categorizeFailure });\r\n const execResult = await coordinator.run({\r\n cwd: this.cwd,\r\n testFiles,\r\n mode,\r\n env: authResult.env,\r\n });\r\n const metrics = execResult.metrics;\r\n\r\n this.lastExecutionMetrics = metrics;\r\n this.lastExecutionQuality = buildExecutionQualityGate({\r\n metrics,\r\n authStatus,\r\n backendStatus,\r\n });\r\n const total = metrics.passed + metrics.failed + metrics.skipped + metrics.timedOut;\r\n\r\n // Update croc states\r\n if (metrics.failed > 0) {\r\n this.updateAgent('tester-croc', { status: 'error', currentTask: `${metrics.failed} tests failed`, progress: 100 });\r\n this.updateAgent('healer-croc', { status: 'working', currentTask: `Analyzing ${metrics.failed} failures...`, progress: 50 });\r\n this.log(`❌ Tests: ${metrics.passed} passed, ${metrics.failed} failed, ${metrics.skipped} skipped`, 'warn');\r\n for (const hint of execResult.failureHints) {\r\n this.log(` 🔍 ${hint.category} (${Math.round(hint.confidence * 100)}%): ${hint.line.substring(0, 100)}`, 'warn');\r\n }\r\n this.updateAgent('healer-croc', { status: 'done', currentTask: 'Failure analysis done', progress: 100 });\r\n } else {\r\n this.updateAgent('tester-croc', { status: 'done', currentTask: `All ${metrics.passed} tests passed!`, progress: 100 });\r\n this.updateAgent('healer-croc', { status: 'done', currentTask: 'No failures', progress: 100 });\r\n this.log(`✅ All ${metrics.passed} tests passed!`);\r\n }\r\n\r\n this.updateNodeStatus('controller', metrics.failed > 0 ? 'failed' : 'passed');\r\n\r\n // Broadcast results\r\n this.broadcast('test:complete', { metrics, total, quality: this.lastExecutionQuality });\r\n\r\n const duration = Date.now() - start;\r\n this.log(`🧪 Test execution complete in ${duration}ms`);\r\n return { ok: metrics.failed === 0, task: 'execute', duration, details: metrics as unknown as Record<string, unknown> };\r\n } catch (err) {\r\n this.updateAgent('tester-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Test execution failed: ${err}`, 'error');\r\n this.broadcast('test:complete', { metrics: null, total: 0, quality: this.lastExecutionQuality });\r\n return { ok: false, task: 'execute', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n if (cleanupBackend) {\r\n try {\r\n await cleanupBackend();\r\n this.log('🧹 Managed backend stopped');\r\n } catch (err) {\r\n this.log(`⚠️ Backend cleanup failed: ${err}`, 'warn');\r\n }\r\n }\r\n this.running = false;\r\n }\r\n }\r\n\r\n /** Generate reports (HTML/JSON/Markdown) */\r\n async generateReport(): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'report', duration: 0, error: 'Another task is running' };\r\n if (!this.lastPipelineResult) {\r\n return { ok: false, task: 'report', duration: 0, error: 'No pipeline result — run Pipeline first' };\r\n }\r\n this.running = true;\r\n const start = Date.now();\r\n\r\n try {\r\n this.updateAgent('reporter-croc', { status: 'working', currentTask: 'Generating reports...', progress: 0 });\r\n this.log('📊 汇报鳄 is generating reports...');\r\n\r\n const { generateReports } = await import('../reporters/index.js');\r\n const formats: ('html' | 'json' | 'markdown')[] = ['html', 'json', 'markdown'];\r\n const reports = generateReports(this.lastPipelineResult, formats, {\r\n metrics: this.lastExecutionMetrics,\r\n quality: this.lastExecutionQuality,\r\n });\r\n this.lastReports = reports;\r\n\r\n // Write reports to disk\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { writeFileSync, mkdirSync } = await import('node:fs');\r\n const outDir = resolvePath(this.cwd, this.config.outDir || './opencroc-output');\r\n mkdirSync(outDir, { recursive: true });\r\n\r\n for (const report of reports) {\r\n const fullPath = resolvePath(outDir, report.filename);\r\n writeFileSync(fullPath, report.content, 'utf-8');\r\n this.log(`📄 Generated ${report.format} report: ${report.filename}`);\r\n }\r\n\r\n this.updateAgent('reporter-croc', { status: 'done', currentTask: `${reports.length} reports generated`, progress: 100 });\r\n\r\n // Broadcast reports to frontend\r\n this.broadcast('reports:generated', reports.map(r => ({\r\n format: r.format,\r\n filename: r.filename,\r\n size: r.content.length,\r\n })));\r\n\r\n const duration = Date.now() - start;\r\n this.log(`✅ Reports generated in ${duration}ms`);\r\n return { ok: true, task: 'report', duration, details: { count: reports.length } };\r\n } catch (err) {\r\n this.updateAgent('reporter-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Report generation failed: ${err}`, 'error');\r\n return { ok: false, task: 'report', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n this.running = false;\r\n }\r\n }\r\n\r\n // ============ Graph Helpers ============\r\n\r\n private updateNodeStatus(type: KnowledgeGraphNode['type'], status: KnowledgeGraphNode['status']): void {\r\n if (!this.cachedGraph) return;\r\n for (const node of this.cachedGraph.nodes) {\r\n if (node.type === type) {\r\n node.status = status;\r\n }\r\n }\r\n this.broadcast('graph:update', this.cachedGraph);\r\n }\r\n\r\n /** Build knowledge graph from project source code */\r\n async buildKnowledgeGraph(): Promise<KnowledgeGraph> {\r\n if (this.cachedGraph) return this.cachedGraph;\r\n\r\n this.updateAgent('parser-croc', { status: 'working', currentTask: 'Scanning project structure...', progress: 20 });\r\n\r\n try {\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { glob } = await import('glob');\r\n\r\n const backendRoot = resolvePath(this.cwd, this.config.backendRoot);\r\n const nodes: KnowledgeGraphNode[] = [];\r\n const edges: KnowledgeGraphEdge[] = [];\r\n const moduleSet = new Set<string>();\r\n\r\n // Helper: infer module from file path\r\n // 1) Subfolder: models/aigc/Foo.ts → \"aigc\"\r\n // 2) Longest known prefix match on filename: workflowTemplate → \"workflow\"\r\n // 3) CamelCase first word: DataModel → \"data\"\r\n\r\n // Known domain prefixes, longest first for greedy matching\r\n const KNOWN_PREFIXES = [\r\n 'notification', 'department', 'application', 'permission', 'computed',\r\n 'delegation', 'dictionary', 'validation', 'simulation', 'statistics',\r\n 'inference', 'panorama', 'designer', 'workflow', 'template', 'relation',\r\n 'recycle', 'monitor', 'timeout', 'column', 'export', 'import', 'batch',\r\n 'field', 'chain', 'tenant', 'model', 'data', 'user', 'role', 'menu',\r\n 'auth', 'dept', 'page', 'app', 'api', 'org', 'log', 'er',\r\n ];\r\n\r\n const DOMAIN_GROUPS: Record<string, string> = {\r\n app: 'app', api: 'api', data: 'data', auth: 'auth',\r\n user: 'user', role: 'user', menu: 'app', dept: 'org',\r\n department: 'org', org: 'org', chain: 'workflow',\r\n workflow: 'workflow', batch: 'batch', column: 'data',\r\n computed: 'data', designer: 'designer', monitor: 'monitor',\r\n notification: 'notification', permission: 'permission',\r\n template: 'template', validation: 'validation',\r\n field: 'data', delegation: 'workflow', import: 'data',\r\n export: 'data', dictionary: 'data', panorama: 'panorama',\r\n inference: 'inference', simulation: 'simulation', er: 'data',\r\n relation: 'data', recycle: 'data', statistics: 'statistics',\r\n operation: 'system', log: 'system', timeout: 'workflow',\r\n tenant: 'system', model: 'data', page: 'app',\r\n application: 'app',\r\n };\r\n\r\n const inferModule = (filePath: string, type: 'model' | 'controller'): string => {\r\n const parts = filePath.replace(/\\\\/g, '/').split('/');\r\n // Subfolder detection\r\n const typeDir = type === 'model' ? 'models' : 'controllers';\r\n const typeDirIdx = parts.indexOf(typeDir);\r\n if (typeDirIdx >= 0 && parts.length - typeDirIdx > 2) {\r\n return parts[typeDirIdx + 1];\r\n }\r\n // Filename-based: strip extension + \"Controller\" suffix\r\n const baseName = parts[parts.length - 1]\r\n .replace(/\\.(ts|js)$/, '')\r\n .replace(/Controller$/i, '');\r\n const lc = baseName.toLowerCase();\r\n // Try longest known prefix match\r\n for (const prefix of KNOWN_PREFIXES) {\r\n if (lc.startsWith(prefix)) {\r\n return DOMAIN_GROUPS[prefix] || prefix;\r\n }\r\n }\r\n // CamelCase first word fallback\r\n const camelMatch = baseName.match(/^([A-Z]?[a-z]+)/);\r\n if (camelMatch) {\r\n const w = camelMatch[1].toLowerCase();\r\n return DOMAIN_GROUPS[w] || w;\r\n }\r\n return 'other';\r\n };\r\n\r\n // Scan for models\r\n this.updateAgent('parser-croc', { progress: 40, currentTask: 'Scanning models...' });\r\n const modelFiles = await glob('**/models/**/*.{ts,js}', {\r\n cwd: backendRoot,\r\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*', '**/index.*', '**/dist/**'],\r\n });\r\n\r\n for (const file of modelFiles) {\r\n const parts = file.replace(/\\\\/g, '/').split('/');\r\n const moduleName = inferModule(file, 'model');\r\n const fileName = parts[parts.length - 1].replace(/\\.(ts|js)$/, '');\r\n const nodeId = `model:${fileName}`;\r\n\r\n moduleSet.add(moduleName);\r\n nodes.push({\r\n id: nodeId,\r\n label: fileName,\r\n type: 'model',\r\n status: 'idle',\r\n module: moduleName,\r\n });\r\n }\r\n\r\n // Scan for controllers\r\n this.updateAgent('parser-croc', { progress: 70, currentTask: 'Scanning controllers...' });\r\n const controllerFiles = await glob('**/controllers/**/*.{ts,js}', {\r\n cwd: backendRoot,\r\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*', '**/index.*', '**/dist/**'],\r\n });\r\n\r\n for (const file of controllerFiles) {\r\n const parts = file.replace(/\\\\/g, '/').split('/');\r\n const moduleName = inferModule(file, 'controller');\r\n const fileName = parts[parts.length - 1].replace(/\\.(ts|js)$/, '').replace(/Controller$/, '');\r\n const nodeId = `controller:${fileName}`;\r\n\r\n moduleSet.add(moduleName);\r\n nodes.push({\r\n id: nodeId,\r\n label: `${fileName} (ctrl)`,\r\n type: 'controller',\r\n status: 'idle',\r\n module: moduleName,\r\n });\r\n\r\n // Link controller to its model with fuzzy match\r\n const lcName = fileName.toLowerCase();\r\n const modelNode = nodes.find((n) => n.type === 'model' && n.label.toLowerCase() === lcName);\r\n if (modelNode) {\r\n edges.push({ source: nodeId, target: modelNode.id, relation: 'uses' });\r\n }\r\n }\r\n\r\n // Add module nodes\r\n this.updateAgent('parser-croc', { progress: 90, currentTask: 'Building graph...' });\r\n for (const mod of moduleSet) {\r\n const moduleNodeId = `module:${mod}`;\r\n nodes.push({\r\n id: moduleNodeId,\r\n label: mod,\r\n type: 'module',\r\n status: 'idle',\r\n });\r\n\r\n // Link models/controllers to their module\r\n for (const n of nodes) {\r\n if (n.module === mod && n.type !== 'module') {\r\n edges.push({ source: moduleNodeId, target: n.id, relation: 'contains' });\r\n }\r\n }\r\n }\r\n\r\n this.cachedGraph = { nodes, edges };\r\n this.updateAgent('parser-croc', { status: 'done', currentTask: `Found ${nodes.length} nodes`, progress: 100 });\r\n this.broadcast('graph:update', this.cachedGraph);\r\n return this.cachedGraph;\r\n\r\n } catch (err) {\r\n this.updateAgent('parser-croc', { status: 'error', currentTask: String(err) });\r\n return { nodes: [], edges: [] };\r\n }\r\n }\r\n\r\n invalidateCache(): void {\r\n this.cachedGraph = null;\r\n }\r\n\r\n async getProjectInfo(): Promise<ProjectInfo> {\r\n const graph = await this.buildKnowledgeGraph();\r\n const stats = {\r\n modules: graph.nodes.filter((n) => n.type === 'module').length,\r\n models: graph.nodes.filter((n) => n.type === 'model').length,\r\n endpoints: graph.nodes.filter((n) => n.type === 'api' || n.type === 'controller').length,\r\n relations: graph.edges.length,\r\n };\r\n\r\n return {\r\n name: this.config.backendRoot.split('/').pop() || 'project',\r\n backendRoot: this.config.backendRoot,\r\n adapter: typeof this.config.adapter === 'string' ? this.config.adapter : 'custom',\r\n stats,\r\n graph,\r\n agents: this.agents,\r\n };\r\n }\r\n}\r\n","import Fastify from 'fastify';\r\nimport fastifyStatic from '@fastify/static';\r\nimport fastifyWebsocket from '@fastify/websocket';\r\nimport { fileURLToPath } from 'node:url';\r\nimport { dirname, join, resolve } from 'node:path';\r\nimport { existsSync } from 'node:fs';\r\nimport { registerProjectRoutes } from './routes/project.js';\r\nimport { registerAgentRoutes } from './routes/agents.js';\r\nimport { registerStudioRoutes } from './routes/studio.js';\r\nimport { CrocOffice } from './croc-office.js';\r\nimport { FileStudioSnapshotStore } from './studio-store.js';\r\nimport type { OpenCrocConfig } from '../types.js';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\n\r\nexport interface ServeOptions {\r\n port: number;\r\n host: string;\r\n open: boolean;\r\n config: OpenCrocConfig;\r\n cwd: string;\r\n}\r\n\r\nexport async function startServer(opts: ServeOptions): Promise<void> {\r\n const app = Fastify({ logger: false });\r\n\r\n // --- WebSocket ---\r\n await app.register(fastifyWebsocket);\r\n\r\n // --- Static frontend assets ---\r\n const webDir = resolve(__dirname, '../web');\r\n if (existsSync(webDir)) {\n await app.register(fastifyStatic, {\n root: webDir,\n prefix: '/',\n decorateReply: false,\n index: false,\n });\n }\n\r\n // --- Croc Office (Agent orchestrator) ---\r\n const office = new CrocOffice(opts.config, opts.cwd);\r\n const snapshotStore = new FileStudioSnapshotStore(resolve(opts.cwd, '.opencroc/studio-snapshot.json'));\r\n\r\n // --- REST API routes ---\r\n registerProjectRoutes(app, office);\r\n registerAgentRoutes(app, office);\r\n registerStudioRoutes(app, office, snapshotStore);\r\n\r\n // --- WebSocket endpoint for real-time updates ---\n app.register(async (fastify) => {\n fastify.get('/ws', { websocket: true }, (socket) => {\n office.addClient(socket);\n socket.on('close', () => office.removeClient(socket));\n });\n });\n\n app.get('/index-studio.html', (_req, reply) => {\n reply.redirect('/studio');\n });\n\n app.get('/index-v2-pixel.html', (_req, reply) => {\n reply.redirect('/pixel');\n });\n\n // --- SPA fallback: serve index.html for non-API, non-asset routes ---\n app.setNotFoundHandler((req, reply) => {\n if (req.url.startsWith('/api/')) {\n reply.code(404).send({ error: 'Not found' });\n return;\r\n }\r\n // Single-entry SPA fallback: route resolution happens in the frontend router.\n const builtIndexPath = join(webDir, 'dist', 'index.html');\n if (existsSync(builtIndexPath)) {\n reply.sendFile('dist/index.html');\n } else {\n reply.code(200).header('content-type', 'text/html').send(getEmbeddedHtml());\n }\n });\r\n\r\n try {\r\n await app.listen({ port: opts.port, host: opts.host });\r\n const url = `http://${opts.host === '0.0.0.0' ? 'localhost' : opts.host}:${opts.port}`;\r\n console.log(`\\n 🐊 OpenCroc Studio is running at ${url}\\n`);\r\n\r\n if (opts.open) {\r\n const { exec } = await import('node:child_process');\r\n const cmd = process.platform === 'win32' ? 'start' :\r\n process.platform === 'darwin' ? 'open' : 'xdg-open';\r\n exec(`${cmd} ${url}`);\r\n }\r\n } catch (err) {\r\n console.error('Failed to start server:', err);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/** Minimal embedded HTML when no web build is present */\r\nfunction getEmbeddedHtml(): string {\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n<title>OpenCroc Studio 🐊</title>\r\n<style>\r\n * { margin:0; padding:0; box-sizing:border-box; }\r\n body { background:#1a1a2e; color:#e0e0e0; font-family:'Courier New',monospace; display:flex; justify-content:center; align-items:center; min-height:100vh; }\r\n .container { text-align:center; }\r\n h1 { font-size:3rem; color:#4ecca3; margin-bottom:1rem; }\r\n .croc { font-size:6rem; animation: bounce 1s infinite alternate; }\r\n @keyframes bounce { from{transform:translateY(0)} to{transform:translateY(-20px)} }\r\n p { margin-top:1rem; color:#888; }\r\n .status { margin-top:2rem; padding:1rem; background:#16213e; border-radius:8px; }\r\n #graph-container { margin-top:2rem; min-height:400px; background:#0f3460; border-radius:8px; position:relative; }\r\n .loading { color:#4ecca3; padding:2rem; }\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"container\">\r\n <div class=\"croc\">🐊</div>\r\n <h1>OpenCroc Studio</h1>\r\n <p>AI-native E2E testing — Pixel Croc Office</p>\r\n <div class=\"status\" id=\"status\">Connecting...</div>\r\n <div id=\"graph-container\"><div class=\"loading\">Loading project graph...</div></div>\r\n</div>\r\n<script>\r\n(async () => {\r\n // Fetch project graph data\r\n try {\r\n const res = await fetch('/api/project');\r\n const data = await res.json();\r\n document.getElementById('status').innerHTML =\r\n '<b>Project:</b> ' + (data.name || 'unknown') +\r\n ' | <b>Modules:</b> ' + (data.stats?.modules || 0) +\r\n ' | <b>Models:</b> ' + (data.stats?.models || 0) +\r\n ' | <b>APIs:</b> ' + (data.stats?.endpoints || 0);\r\n\r\n renderGraph(data.graph);\r\n } catch(e) {\r\n document.getElementById('status').textContent = 'Error loading project: ' + e.message;\r\n }\r\n\r\n // WebSocket for live updates\r\n const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';\r\n const ws = new WebSocket(protocol + '//' + location.host + '/ws');\r\n ws.onmessage = (e) => {\r\n try {\r\n const msg = JSON.parse(e.data);\r\n if (msg.type === 'agent:update') {\r\n updateAgentStatus(msg.payload);\r\n } else if (msg.type === 'graph:update') {\r\n renderGraph(msg.payload);\r\n }\r\n } catch {}\r\n };\r\n ws.onclose = () => {\r\n document.getElementById('status').textContent += ' [disconnected]';\r\n };\r\n})();\r\n\r\nfunction renderGraph(graph) {\r\n if (!graph || (!graph.nodes?.length)) {\r\n document.getElementById('graph-container').innerHTML = '<div class=\"loading\">No modules found. Run opencroc init first.</div>';\r\n return;\r\n }\r\n\r\n const container = document.getElementById('graph-container');\r\n const w = container.clientWidth || 800;\r\n const h = 500;\r\n\r\n // Simple force-directed placement\r\n const nodes = graph.nodes.map((n, i) => ({\r\n ...n,\r\n x: w/2 + Math.cos(i * 2 * Math.PI / graph.nodes.length) * Math.min(w,h) * 0.35,\r\n y: h/2 + Math.sin(i * 2 * Math.PI / graph.nodes.length) * Math.min(w,h) * 0.35,\r\n vx: 0, vy: 0,\r\n }));\r\n\r\n const nodeMap = new Map(nodes.map(n => [n.id, n]));\r\n\r\n // Render SVG\r\n const colors = { model:'#4ecca3', controller:'#e94560', api:'#f39c12', dto:'#3498db', default:'#888' };\r\n\r\n let svg = '<svg width=\"'+w+'\" height=\"'+h+'\" xmlns=\"http://www.w3.org/2000/svg\">';\r\n\r\n // Edges\r\n for (const edge of (graph.edges || [])) {\r\n const s = nodeMap.get(edge.source);\r\n const t = nodeMap.get(edge.target);\r\n if (s && t) {\r\n svg += '<line x1=\"'+s.x+'\" y1=\"'+s.y+'\" x2=\"'+t.x+'\" y2=\"'+t.y+'\" stroke=\"#555\" stroke-width=\"1.5\" opacity=\"0.6\"/>';\r\n }\r\n }\r\n\r\n // Nodes\r\n for (const n of nodes) {\r\n const color = colors[n.type] || colors.default;\r\n const statusColor = n.status === 'passed' ? '#4ecca3' : n.status === 'failed' ? '#e94560' : n.status === 'testing' ? '#f39c12' : '#555';\r\n // Pixel-art style square nodes\r\n svg += '<rect x=\"'+(n.x-16)+'\" y=\"'+(n.y-16)+'\" width=\"32\" height=\"32\" fill=\"'+color+'\" rx=\"4\" stroke=\"'+statusColor+'\" stroke-width=\"2\"/>';\r\n svg += '<text x=\"'+n.x+'\" y=\"'+(n.y+32)+'\" text-anchor=\"middle\" fill=\"#ccc\" font-size=\"10\" font-family=\"Courier New\">'+escapeHtml(n.label || n.id)+'</text>';\r\n }\r\n\r\n svg += '</svg>';\r\n container.innerHTML = svg;\r\n}\r\n\r\nfunction escapeHtml(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }\r\n\r\nfunction updateAgentStatus(agents) {\r\n // Will be enhanced with pixel croc animations in M2\r\n console.log('Agent update:', agents);\r\n}\r\n</script>\r\n</body>\r\n</html>`;\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport type { OpenCrocConfig } from '../../types.js';\r\n\r\nexport interface ServeCommandOptions {\r\n port?: string;\r\n host?: string;\r\n open?: boolean;\r\n}\r\n\r\nexport async function serve(opts: ServeCommandOptions): Promise<void> {\r\n let config: OpenCrocConfig;\r\n let configPath: string;\r\n\r\n try {\r\n const loaded = await loadConfig();\r\n config = loaded.config;\r\n configPath = loaded.filepath;\r\n } catch {\r\n // No config file — use sensible defaults based on cwd\r\n config = { backendRoot: '.' };\r\n configPath = '(auto-detected)';\r\n console.log(chalk.yellow('⚠ No opencroc config found, using current directory as backend root.'));\r\n console.log(chalk.gray(' Tip: run `opencroc init` to create a config file.\\n'));\r\n }\r\n\r\n const port = parseInt(opts.port || '8765', 10);\r\n const host = opts.host || 'localhost';\r\n\r\n console.log(chalk.cyan('🐊 Starting OpenCroc Studio...'));\r\n console.log(chalk.gray(` Config: ${configPath}`));\r\n console.log(chalk.gray(` Backend: ${config.backendRoot}`));\r\n\r\n const { startServer } = await import('../../server/index.js');\r\n await startServer({\r\n port,\r\n host,\r\n open: opts.open ?? true,\r\n config,\r\n cwd: process.cwd(),\r\n });\r\n}\r\n","/**\r\n * CLI Command: scan\r\n *\r\n * Scan any project (local, GitHub URL, user/repo) and build knowledge graph.\r\n *\r\n * Usage:\r\n * opencroc scan ./my-project\r\n * opencroc scan https://github.com/expressjs/express\r\n * opencroc scan facebook/react\r\n * opencroc scan ./backend --risks --report developer --json\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport chalk from 'chalk';\r\nimport { cloneAndScan } from '../../scanner/github-cloner.js';\r\nimport { buildKnowledgeGraph, getGraphStats, toMermaid } from '../../graph/index.js';\r\nimport { analyzeRisks, generateReport } from '../../insight/index.js';\r\nimport type { ReportPerspective, RiskAnnotation } from '../../graph/types.js';\r\n\r\ninterface ScanOptions {\r\n branch?: string;\r\n output: string;\r\n json?: boolean;\r\n mermaid?: boolean;\r\n risks?: boolean;\r\n report?: string;\r\n}\r\n\r\nexport async function scan(target: string, opts: ScanOptions): Promise<void> {\r\n console.log('');\r\n console.log(chalk.green('🐊 OpenCroc Studio — Universal Project Scanner'));\r\n console.log(chalk.gray(` Target: ${target}`));\r\n console.log('');\r\n\r\n const startTime = Date.now();\r\n\r\n // Phase 1: Scan\r\n console.log(chalk.cyan('📡 Phase 1: Scanning project...'));\r\n\r\n const scanResult = await cloneAndScan({\r\n target,\r\n branch: opts.branch,\r\n keepClone: true,\r\n onProgress: (phase, percent, detail) => {\r\n if (percent % 25 === 0 || phase === 'clone') {\r\n console.log(chalk.gray(` [${phase}] ${percent}% ${detail || ''}`));\r\n }\r\n },\r\n });\r\n\r\n console.log(chalk.green(` ✅ Found ${scanResult.entities.length} entities, ${scanResult.relationships.length} relationships`));\r\n console.log(chalk.gray(` Languages: ${Object.entries(scanResult.languages).filter(([k]) => !['json','yaml','markdown'].includes(k)).map(([k, v]) => `${k}(${v})`).join(', ')}`));\r\n console.log(chalk.gray(` Frameworks: ${scanResult.frameworks.map(f => f.name).join(', ') || 'none detected'}`));\r\n console.log('');\r\n\r\n // Phase 2: Build knowledge graph\r\n console.log(chalk.cyan('🧠 Phase 2: Building knowledge graph...'));\r\n\r\n const projectName = target.includes('/') ? target.split('/').pop()!.replace('.git', '') : path.basename(path.resolve(target));\r\n const isRemote = target.startsWith('http') || /^[\\w.-]+\\/[\\w.-]+$/.test(target);\r\n\r\n const graph = buildKnowledgeGraph(scanResult, {\r\n projectName,\r\n source: isRemote ? 'github' : 'local',\r\n sourceUrl: target,\r\n rootPath: target,\r\n });\r\n\r\n const stats = getGraphStats(graph);\r\n console.log(chalk.green(` ✅ ${graph.nodes.length} nodes, ${graph.edges.length} edges`));\r\n printStats(stats);\r\n console.log('');\r\n\r\n // Phase 3: Risk analysis (optional)\r\n let risks: RiskAnnotation[] = [];\r\n if (opts.risks) {\r\n console.log(chalk.cyan('⚠️ Phase 3: Analyzing risks...'));\r\n risks = await analyzeRisks(graph);\r\n printRisks(risks);\r\n console.log('');\r\n }\r\n\r\n // Phase 4: Generate report (optional)\r\n if (opts.report) {\r\n console.log(chalk.cyan(`📋 Phase 4: Generating ${opts.report} report...`));\r\n const report = await generateReport(graph, opts.report as ReportPerspective, risks);\r\n printReport(report);\r\n console.log('');\r\n }\r\n\r\n // Phase 5: Output\r\n fs.mkdirSync(opts.output, { recursive: true });\r\n\r\n // Always save graph JSON\r\n const graphPath = path.join(opts.output, 'knowledge-graph.json');\r\n fs.writeFileSync(graphPath, JSON.stringify({\r\n projectInfo: graph.projectInfo,\r\n stats: getGraphStats(graph),\r\n nodes: graph.nodes.map(n => ({ id: n.id, label: n.label, type: n.type, module: n.module, filePath: n.filePath })),\r\n edges: graph.edges.map(e => ({ source: e.source, target: e.target, relation: e.relation })),\r\n risks: risks.length > 0 ? risks : undefined,\r\n builtAt: graph.builtAt,\r\n }, null, 2));\r\n console.log(chalk.gray(` 📁 Graph saved: ${graphPath}`));\r\n\r\n if (opts.json) {\r\n const jsonPath = path.join(opts.output, 'scan-result.json');\r\n fs.writeFileSync(jsonPath, JSON.stringify({\r\n project: graph.projectInfo,\r\n stats,\r\n risks: risks.length > 0 ? risks : undefined,\r\n }, null, 2));\r\n console.log(chalk.gray(` 📁 JSON saved: ${jsonPath}`));\r\n }\r\n\r\n if (opts.mermaid) {\r\n const mermaidPath = path.join(opts.output, 'graph.mmd');\r\n const mermaidText = toMermaid(graph, { nodeTypes: ['module', 'model', 'api', 'service'], maxNodes: 40 });\r\n fs.writeFileSync(mermaidPath, mermaidText);\r\n console.log(chalk.gray(` 📁 Mermaid saved: ${mermaidPath}`));\r\n }\r\n\r\n const duration = ((Date.now() - startTime) / 1000).toFixed(1);\r\n console.log('');\r\n console.log(chalk.green(`🐊 Done in ${duration}s`));\r\n console.log(chalk.gray(` Run ${chalk.white('opencroc serve')} to explore the knowledge graph in Studio UI`));\r\n console.log('');\r\n}\r\n\r\nfunction printStats(stats: Record<string, number>): void {\r\n const items: string[] = [];\r\n if (stats.moduleCount) items.push(`${stats.moduleCount} modules`);\r\n if (stats.apiCount) items.push(`${stats.apiCount} APIs`);\r\n if (stats.modelCount) items.push(`${stats.modelCount} models`);\r\n if (stats.classCount) items.push(`${stats.classCount} classes`);\r\n if (stats.functionCount) items.push(`${stats.functionCount} functions`);\r\n if (stats.dependencyCount) items.push(`${stats.dependencyCount} dependencies`);\r\n if (items.length > 0) {\r\n console.log(chalk.gray(` ${items.join(' | ')}`));\r\n }\r\n}\r\n\r\nfunction printRisks(risks: RiskAnnotation[]): void {\r\n if (risks.length === 0) {\r\n console.log(chalk.green(' ✅ No significant risks detected.'));\r\n return;\r\n }\r\n\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n const medium = risks.filter(r => r.severity === 'medium').length;\r\n const low = risks.filter(r => r.severity === 'low').length;\r\n\r\n console.log(chalk.yellow(` Found ${risks.length} risks:`));\r\n if (critical) console.log(chalk.red(` 🔴 Critical: ${critical}`));\r\n if (high) console.log(chalk.hex('#e67e22')(` 🟠 High: ${high}`));\r\n if (medium) console.log(chalk.yellow(` 🟡 Medium: ${medium}`));\r\n if (low) console.log(chalk.blue(` 🔵 Low: ${low}`));\r\n\r\n console.log('');\r\n console.log(chalk.white(' Top risks:'));\r\n for (const r of risks.slice(0, 5)) {\r\n const color = r.severity === 'critical' ? chalk.red :\r\n r.severity === 'high' ? chalk.hex('#e67e22') :\r\n r.severity === 'medium' ? chalk.yellow : chalk.blue;\r\n console.log(` ${color(`[${r.severity.toUpperCase()}]`)} ${r.title}`);\r\n }\r\n}\r\n\r\nfunction printReport(report: { title: string; summary: string; sections: Array<{ heading: string; content: string }> }): void {\r\n console.log(chalk.green(` ✅ ${report.title}`));\r\n console.log(chalk.gray(` ${report.summary}`));\r\n for (const section of report.sections) {\r\n console.log(chalk.cyan(`\\n ── ${section.heading} ──`));\r\n // Print first 3 lines of content\r\n const lines = section.content.split('\\n').slice(0, 3);\r\n for (const line of lines) {\r\n console.log(chalk.gray(` ${line}`));\r\n }\r\n if (section.content.split('\\n').length > 3) {\r\n console.log(chalk.gray(' ...'));\r\n }\r\n }\r\n}\r\n","/**\r\n * CLI Command: analyze\r\n *\r\n * Deep analysis of a scanned project — risks, impact, multi-perspective reports.\r\n *\r\n * Usage:\r\n * opencroc analyze ./my-project\r\n * opencroc analyze --perspective architect --risks\r\n * opencroc analyze --impact \"api:GET:/users\"\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport chalk from 'chalk';\r\nimport { scanProject } from '../../scanner/project-scanner.js';\r\nimport { buildKnowledgeGraph } from '../../graph/index.js';\r\nimport { analyzeRisks, analyzeImpact, generateReport } from '../../insight/index.js';\r\nimport type { ReportPerspective } from '../../graph/types.js';\r\n\r\ninterface AnalyzeOptions {\r\n perspective: string;\r\n risks: boolean;\r\n impact?: string;\r\n output: string;\r\n}\r\n\r\nexport async function analyze(target: string, opts: AnalyzeOptions): Promise<void> {\r\n console.log('');\r\n console.log(chalk.green('🐊 OpenCroc Studio — Project Analysis'));\r\n console.log('');\r\n\r\n const absTarget = path.resolve(target);\r\n\r\n // Check for existing graph first\r\n const graphPath = path.join(opts.output, 'knowledge-graph.json');\r\n let graph;\r\n\r\n if (fs.existsSync(graphPath)) {\r\n console.log(chalk.gray(` Loading cached graph from ${graphPath}...`));\r\n // Need to re-scan for full graph (cached is simplified)\r\n }\r\n\r\n // Scan\r\n console.log(chalk.cyan('📡 Scanning project...'));\r\n const scanResult = await scanProject({\r\n rootDir: absTarget,\r\n onProgress: (phase, percent, detail) => {\r\n if (percent === 100) console.log(chalk.gray(` [${phase}] ${detail || 'done'}`));\r\n },\r\n });\r\n\r\n const projectName = path.basename(absTarget);\r\n graph = buildKnowledgeGraph(scanResult, {\r\n projectName,\r\n source: 'local',\r\n rootPath: absTarget,\r\n });\r\n\r\n console.log(chalk.green(` ✅ ${graph.nodes.length} nodes, ${graph.edges.length} edges`));\r\n console.log('');\r\n\r\n // Risk analysis\r\n if (opts.risks) {\r\n console.log(chalk.cyan('⚠️ Risk Analysis'));\r\n const risks = await analyzeRisks(graph);\r\n\r\n if (risks.length === 0) {\r\n console.log(chalk.green(' ✅ No significant risks detected.'));\r\n } else {\r\n for (const r of risks) {\r\n const icon = r.severity === 'critical' ? '🔴' : r.severity === 'high' ? '🟠' : r.severity === 'medium' ? '🟡' : '🔵';\r\n console.log(` ${icon} [${r.severity.toUpperCase()}] ${r.title}`);\r\n console.log(chalk.gray(` ${r.description}`));\r\n if (r.suggestion) {\r\n console.log(chalk.green(` 💡 ${r.suggestion}`));\r\n }\r\n console.log('');\r\n }\r\n }\r\n }\r\n\r\n // Impact analysis\r\n if (opts.impact) {\r\n console.log(chalk.cyan(`🎯 Impact Analysis: ${opts.impact}`));\r\n const impact = analyzeImpact(graph, opts.impact);\r\n console.log(` ${impact.summary}`);\r\n console.log(` Direct impact: ${impact.directImpact.length} entities`);\r\n console.log(` Transitive impact: ${impact.transitiveImpact.length} entities`);\r\n console.log(` Risk level: ${impact.riskLevel}`);\r\n console.log('');\r\n\r\n if (impact.mermaidText) {\r\n const mermaidPath = path.join(opts.output, 'impact.mmd');\r\n fs.mkdirSync(opts.output, { recursive: true });\r\n fs.writeFileSync(mermaidPath, impact.mermaidText);\r\n console.log(chalk.gray(` 📁 Impact diagram saved: ${mermaidPath}`));\r\n }\r\n }\r\n\r\n // Perspective report\r\n const perspective = opts.perspective as ReportPerspective;\r\n console.log(chalk.cyan(`📋 ${perspective.charAt(0).toUpperCase() + perspective.slice(1)} Report`));\r\n console.log('');\r\n\r\n const risks = await analyzeRisks(graph);\r\n const report = await generateReport(graph, perspective, risks);\r\n\r\n console.log(chalk.bold.green(` ${report.title}`));\r\n console.log(chalk.gray(` ${report.summary}`));\r\n console.log('');\r\n\r\n for (const section of report.sections) {\r\n console.log(chalk.cyan(` ━━ ${section.heading} ━━`));\r\n const lines = section.content.split('\\n');\r\n for (const line of lines) {\r\n console.log(` ${line}`);\r\n }\r\n console.log('');\r\n }\r\n\r\n // Save report\r\n fs.mkdirSync(opts.output, { recursive: true });\r\n const reportPath = path.join(opts.output, `report-${perspective}.json`);\r\n fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));\r\n console.log(chalk.gray(` 📁 Report saved: ${reportPath}`));\r\n console.log('');\r\n}\r\n","#!/usr/bin/env node\r\n\r\nimport { Command } from 'commander';\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('opencroc')\r\n .description('AI-native E2E testing framework')\r\n .version('1.0.0');\r\n\r\nprogram\r\n .command('init')\r\n .description('Initialize OpenCroc in the current project')\r\n .option('-y, --yes', 'Skip prompts and use defaults')\r\n .action(async (opts) => {\r\n const { initProject } = await import('./commands/init.js');\r\n await initProject(opts);\r\n });\r\n\r\nprogram\r\n .command('generate')\r\n .description('Generate E2E test cases from source code')\r\n .option('-m, --module <name>', 'Generate for a specific module')\r\n .option('-a, --all', 'Generate for all discovered modules')\r\n .option('--steps <steps>', 'Run specific pipeline steps (comma-separated)')\r\n .option('--dry-run', 'Preview without writing files')\r\n .action(async (opts) => {\r\n const { generate } = await import('./commands/generate.js');\r\n await generate(opts);\r\n });\r\n\r\nprogram\r\n .command('test')\r\n .description('Run generated E2E tests')\r\n .option('-m, --module <name>', 'Run tests for a specific module')\r\n .option('--headed', 'Run in headed browser mode')\r\n .option('--setup-hook <cmd>', 'Run setup hook command before test execution')\r\n .option('--auth-hook <cmd>', 'Run auth hook command before test execution')\r\n .option('--teardown-hook <cmd>', 'Run teardown hook command after test execution')\r\n .action(async (opts) => {\r\n const { runTests } = await import('./commands/test.js');\r\n await runTests(opts);\r\n });\r\n\r\nprogram\r\n .command('validate')\r\n .description('Validate module configurations and generated tests')\r\n .option('-m, --module <name>', 'Validate a specific module')\r\n .action(async (opts) => {\r\n const { validate } = await import('./commands/validate.js');\r\n await validate(opts);\r\n });\r\n\r\nprogram\r\n .command('heal')\r\n .description('Run self-healing loop on failed tests')\r\n .option('-m, --module <name>', 'Heal a specific module')\r\n .option('--max-iterations <n>', 'Maximum healing iterations', '3')\r\n .action(async (opts) => {\r\n const { heal } = await import('./commands/heal.js');\r\n await heal(opts);\r\n });\r\n\r\nprogram\r\n .command('ci')\r\n .description('Generate CI/CD pipeline template')\r\n .option('-p, --platform <name>', 'CI platform (github, gitlab)', 'github')\r\n .option('--self-heal', 'Include self-healing step')\r\n .option('--node <versions>', 'Node.js versions (comma-separated)', '20.x')\r\n .action(async (opts) => {\r\n const { ci } = await import('./commands/ci.js');\r\n await ci(opts);\r\n });\r\n\r\nprogram\r\n .command('report')\r\n .description('Generate pipeline report (HTML/JSON/Markdown)')\r\n .option('-f, --format <formats>', 'Report formats (comma-separated)', 'html')\r\n .option('-o, --output <dir>', 'Output directory')\r\n .action(async (opts) => {\r\n const { report } = await import('./commands/report.js');\r\n await report(opts);\r\n });\r\n\r\nprogram\r\n .command('dashboard')\r\n .description('Generate visual dashboard (opencroc-dashboard.html)')\r\n .option('-i, --input <file>', 'Build from existing opencroc-report.json file')\r\n .option('-o, --output <dir>', 'Output directory', './opencroc-output')\r\n .action(async (opts) => {\r\n const { dashboard } = await import('./commands/dashboard.js');\r\n await dashboard(opts);\r\n });\r\n\r\nprogram\r\n .command('init-runtime')\r\n .description('Generate Playwright runtime infrastructure (config, setup, teardown, auth)')\r\n .option('-o, --output <dir>', 'Output directory for generated files', '.')\r\n .option('--force', 'Overwrite existing files')\r\n .action(async (opts) => {\r\n const { initRuntime } = await import('./commands/init-runtime.js');\r\n await initRuntime(opts);\r\n });\r\n\r\nprogram\r\n .command('run')\r\n .description('Full orchestration: generate → execute → analyze → heal → report')\r\n .option('-m, --module <name>', 'Run for a specific module')\r\n .option('--phases <phases>', 'Phases to run (comma-separated: generate,execute,analyze,heal,report)')\r\n .option('--self-heal', 'Enable self-healing on test failures')\r\n .option('--headed', 'Run Playwright in headed mode')\r\n .option('--report <formats>', 'Report formats (comma-separated)', 'html,json')\r\n .option('--token-budget <n>', 'LLM token budget (0 = unlimited)')\r\n .option('--abort-on-error', 'Abort pipeline on first phase error')\r\n .action(async (opts) => {\r\n const { run } = await import('./commands/run.js');\r\n await run(opts);\r\n });\r\n\r\nprogram\r\n .command('serve')\r\n .description('Start OpenCroc Studio — pixel croc office + knowledge graph UI')\r\n .option('-p, --port <port>', 'Server port', '8765')\r\n .option('-H, --host <host>', 'Server host', 'localhost')\r\n .option('--no-open', 'Do not auto-open browser')\r\n .action(async (opts) => {\r\n const { serve } = await import('./commands/serve.js');\r\n await serve(opts);\r\n });\r\n\r\n// ===== Studio Commands — Universal Project Analysis =====\r\n\r\nprogram\r\n .command('scan')\r\n .description('Scan any project and build knowledge graph (local path, GitHub URL, or user/repo)')\r\n .argument('<target>', 'Local path, GitHub URL (https://github.com/user/repo), or shorthand (user/repo)')\r\n .option('-b, --branch <branch>', 'Git branch to clone')\r\n .option('-o, --output <dir>', 'Output directory for results', './opencroc-output')\r\n .option('--json', 'Output as JSON')\r\n .option('--mermaid', 'Output Mermaid diagram')\r\n .option('--risks', 'Include risk analysis')\r\n .option('--report <perspective>', 'Generate perspective report (developer/architect/tester/product/student/executive)')\r\n .action(async (target, opts) => {\r\n const { scan } = await import('./commands/scan.js');\r\n await scan(target, opts);\r\n });\r\n\r\nprogram\r\n .command('analyze')\r\n .description('Analyze a scanned project for risks and generate reports')\r\n .argument('[target]', 'Project path (default: current directory)', '.')\r\n .option('--perspective <role>', 'Report perspective (developer/architect/tester/product/student/executive)', 'developer')\r\n .option('--risks', 'Show risk analysis', true)\r\n .option('--impact <nodeId>', 'Analyze impact of a specific node')\r\n .option('-o, --output <dir>', 'Output directory', './opencroc-output')\r\n .action(async (target, opts) => {\r\n const { analyze } = await import('./commands/analyze.js');\r\n await analyze(target, opts);\r\n });\r\n\r\nprogram.parse();\r\n"],"mappings":"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","names":["path","fs","path","Project","SyntaxKind","fullPath","fs","path","Project","SyntaxKind","producer","path","Project","report","fs","path","backendRoot","chalk","writeFileSync","mkdirSync","existsSync","VALID_STEPS","chalk","readdirSync","existsSync","join","resolve","chalk","stdout","DEFAULTS","existsSync","readFileSync","writeFileSync","mkdirSync","dirname","fs","chalk","ci_exports","fs","path","chalk","init_ci","fs","path","chalk","escapeHtml","fs","path","chalk","init_dashboard","chalk","existsSync","mkdirSync","writeFileSync","join","resolve","writeFileSync","mkdirSync","existsSync","readdirSync","dirname","join","execFileSync","discoverTestFiles","writeFileSync","mkdirSync","existsSync","join","chalk","report","generateGitHubActionsTemplate","generateGitLabCITemplate","fs","path","fs","path","fs","path","detectCycles","path","prompt","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","report","getRoleRegistry","scan","execSync","categorizeFailure","resolve","waitForBackend","existsSync","mkdirSync","writeFileSync","dirname","join","createPipeline","writeFileSync","mkdirSync","dirname","scan","planSummon","existsSync","createExecutionCoordinator","createBackendManager","createRuntimeBootstrap","createAuthProvisioner","buildExecutionQualityGate","categorizeFailure","generateReports","report","inferModule","fileURLToPath","dirname","join","resolve","existsSync","__dirname","__filename","chalk","startServer","fs","path","chalk","report","fs","path","chalk","risks","report","initProject","generate","runTests","validate","heal","ci","report","dashboard","initRuntime","run","serve","scan","analyze"]}
|
|
1
|
+
{"version":3,"sources":["../../node_modules/tsup/assets/esm_shims.js","../../src/cli/commands/init.ts","../../src/cli/load-config.ts","../../src/parsers/model-parser.ts","../../src/parsers/controller-parser.ts","../../src/parsers/association-parser.ts","../../src/analyzers/api-chain-analyzer.ts","../../src/generators/er-diagram-generator.ts","../../src/generators/test-code-generator.ts","../../src/validators/schema-validator.ts","../../src/validators/semantic-validator.ts","../../src/validators/dryrun-validator.ts","../../src/validators/config-validator.ts","../../src/pipeline/index.ts","../../src/cli/commands/generate.ts","../../src/cli/commands/test.ts","../../src/cli/commands/validate.ts","../../src/llm/openai.ts","../../src/llm/ollama.ts","../../src/llm/index.ts","../../src/self-healing/dialog-loop-runner.ts","../../src/self-healing/controlled-fixer.ts","../../src/self-healing/auto-fix-generator.ts","../../src/self-healing/index.ts","../../src/cli/commands/heal.ts","../../src/ci/index.ts","../../src/cli/commands/ci.ts","../../src/reporters/checklist-reporter.ts","../../src/reporters/workorder-reporter.ts","../../src/reporters/token-reporter.ts","../../src/reporters/index.ts","../../src/cli/commands/report.ts","../../src/dashboard/index.ts","../../src/cli/commands/dashboard.ts","../../src/runtime/playwright-config-generator.ts","../../src/runtime/global-setup-generator.ts","../../src/runtime/global-teardown-generator.ts","../../src/runtime/auth-setup-generator.ts","../../src/cli/commands/init-runtime.ts","../../src/orchestrator/index.ts","../../src/orchestrator/reporter.ts","../../src/cli/commands/run.ts","../../src/server/routes/project.ts","../../src/server/routes/agents.ts","../../src/scanner/language-detector.ts","../../src/scanner/project-scanner.ts","../../src/scanner/github-cloner.ts","../../src/graph/index.ts","../../src/insight/index.ts","../../src/server/studio-store.ts","../../src/agents/role-registry.ts","../../src/server/routes/studio.ts","../../src/agents/task-router.ts","../../src/execution/coordinator.ts","../../src/runtime/resilient-fetch.ts","../../src/execution/backend-manager.ts","../../src/execution/runtime-bootstrap.ts","../../src/execution/auth-provisioner.ts","../../src/execution/quality-gate.ts","../../src/server/croc-office.ts","../../src/server/index.ts","../../src/cli/commands/serve.ts","../../src/cli/commands/scan.ts","../../src/cli/commands/analyze.ts","../../src/cli/index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","import chalk from 'chalk';\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { createInterface } from 'node:readline/promises';\r\nimport { stdin, stdout } from 'node:process';\r\n\r\nconst ADAPTERS = ['sequelize', 'typeorm', 'prisma'] as const;\r\nconst LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'none'] as const;\r\n\r\nexport interface InitAnswers {\r\n backendRoot: string;\r\n adapter: string;\r\n llmProvider: string;\r\n outDir: string;\r\n}\r\n\r\nconst DEFAULTS: InitAnswers = {\r\n backendRoot: './backend',\r\n adapter: 'sequelize',\r\n llmProvider: 'openai',\r\n outDir: './opencroc-output',\r\n};\r\n\r\nexport function buildConfigContent(answers: InitAnswers): string {\r\n const llmBlock =\r\n answers.llmProvider === 'none'\r\n ? ''\r\n : `\r\n llm: {\r\n provider: '${answers.llmProvider}',${answers.llmProvider === 'ollama' ? '' : \"\\n // apiKey: process.env.OPENCROC_LLM_API_KEY,\"}\r\n model: '${answers.llmProvider === 'zhipu' ? 'glm-4' : answers.llmProvider === 'ollama' ? 'llama3' : 'gpt-4o-mini'}',\r\n },`;\r\n\r\n return `import { defineConfig } from 'opencroc';\r\n\r\nexport default defineConfig({\r\n backendRoot: '${answers.backendRoot}',\r\n adapter: '${answers.adapter}',${llmBlock}\r\n outDir: '${answers.outDir}',\r\n selfHealing: {\r\n enabled: true,\r\n maxIterations: 3,\r\n },\r\n});\r\n`;\r\n}\r\n\r\nasync function prompt(\r\n rl: ReturnType<typeof createInterface>,\r\n question: string,\r\n defaultValue: string,\r\n): Promise<string> {\r\n const answer = await rl.question(` ${question} ${chalk.gray(`(${defaultValue})`)}: `);\r\n return answer.trim() || defaultValue;\r\n}\r\n\r\nasync function promptChoice(\r\n rl: ReturnType<typeof createInterface>,\r\n question: string,\r\n choices: readonly string[],\r\n defaultValue: string,\r\n): Promise<string> {\r\n const list = choices\r\n .map((c) => (c === defaultValue ? chalk.underline(c) : c))\r\n .join(' / ');\r\n const answer = await rl.question(` ${question} [${list}]: `);\r\n const trimmed = answer.trim().toLowerCase();\r\n if (!trimmed) return defaultValue;\r\n return choices.find((c) => c.toLowerCase() === trimmed) || defaultValue;\r\n}\r\n\r\nasync function collectAnswers(): Promise<InitAnswers> {\r\n const rl = createInterface({ input: stdin, output: stdout });\r\n try {\r\n const backendRoot = await prompt(rl, 'Backend source root', DEFAULTS.backendRoot);\r\n const adapter = await promptChoice(rl, 'ORM adapter', ADAPTERS, DEFAULTS.adapter);\r\n const llmProvider = await promptChoice(rl, 'LLM provider', LLM_PROVIDERS, DEFAULTS.llmProvider);\r\n const outDir = await prompt(rl, 'Test output directory', DEFAULTS.outDir);\r\n return { backendRoot, adapter, llmProvider, outDir };\r\n } finally {\r\n rl.close();\r\n }\r\n}\r\n\r\nfunction writeProject(cwd: string, answers: InitAnswers): void {\r\n const configPath = join(cwd, 'opencroc.config.ts');\r\n writeFileSync(configPath, buildConfigContent(answers), 'utf-8');\r\n console.log(chalk.green(' ✓ Created opencroc.config.ts'));\r\n\r\n const outputDir = join(cwd, answers.outDir);\r\n if (!existsSync(outputDir)) {\r\n mkdirSync(outputDir, { recursive: true });\r\n console.log(chalk.green(` ✓ Created ${answers.outDir}/`));\r\n }\r\n}\r\n\r\nfunction printNextSteps(answers: InitAnswers): void {\r\n const needsKey = answers.llmProvider !== 'none' && answers.llmProvider !== 'ollama';\r\n console.log('');\r\n console.log(chalk.cyan(' Next steps:'));\r\n let step = 1;\r\n console.log(` ${step++}. Review opencroc.config.ts`);\r\n if (needsKey) {\r\n console.log(` ${step++}. Set OPENCROC_LLM_API_KEY environment variable`);\r\n }\r\n console.log(` ${step++}. npx opencroc generate --all`);\r\n console.log(` ${step}. npx opencroc test`);\r\n}\r\n\r\nexport async function initProject(opts?: { yes?: boolean }): Promise<void> {\r\n const cwd = process.cwd();\r\n const configPath = join(cwd, 'opencroc.config.ts');\r\n\r\n if (existsSync(configPath)) {\r\n console.log(chalk.yellow('\\n ⚠ opencroc.config.ts already exists. Skipping.\\n'));\r\n return;\r\n }\r\n\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Project Setup\\n'));\r\n\r\n const answers = opts?.yes ? { ...DEFAULTS } : await collectAnswers();\r\n\r\n console.log('');\r\n writeProject(cwd, answers);\r\n printNextSteps(answers);\r\n console.log('');\r\n}\r\n","import { cosmiconfig } from 'cosmiconfig';\r\nimport type { OpenCrocConfig } from '../types.js';\r\n\r\nconst MODULE_NAME = 'opencroc';\r\n\r\nconst SEARCH_PLACES = [\r\n 'opencroc.config.ts',\r\n 'opencroc.config.js',\r\n 'opencroc.config.json',\r\n '.opencrocrc.json',\r\n 'package.json',\r\n];\r\n\r\nexport interface LoadConfigResult {\r\n config: OpenCrocConfig;\r\n filepath: string;\r\n}\r\n\r\nexport async function loadConfig(cwd?: string): Promise<LoadConfigResult> {\r\n const explorer = cosmiconfig(MODULE_NAME, {\r\n searchPlaces: SEARCH_PLACES,\r\n ...(cwd ? { stopDir: cwd } : {}),\r\n });\r\n\r\n const result = cwd ? await explorer.search(cwd) : await explorer.search();\r\n\r\n if (!result || result.isEmpty) {\r\n throw new Error(\r\n 'No opencroc config found. Run `opencroc init` to create one.',\r\n );\r\n }\r\n\r\n const config: OpenCrocConfig =\r\n result.config?.default ?? result.config;\r\n\r\n if (!config.backendRoot) {\r\n throw new Error(\r\n `Invalid config in ${result.filepath}: \"backendRoot\" is required.`,\r\n );\r\n }\r\n\r\n return { config, filepath: result.filepath };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type Node,\r\n} from 'ts-morph';\r\nimport type { TableSchema, FieldSchema, IndexSchema } from '../types.js';\r\n\r\nexport interface ModelParser {\r\n parseFile(filePath: string): Promise<TableSchema | null>;\r\n parseDirectory(dirPath: string): Promise<TableSchema[]>;\r\n}\r\n\r\n/**\r\n * Parse a single Sequelize Model file and extract TableSchema.\r\n */\r\nexport function parseModelFile(filePath: string): TableSchema | null {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return null;\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const initCall = findInitCall(sourceFile);\r\n if (!initCall) return null;\r\n\r\n const args = initCall.getArguments();\r\n if (args.length < 2) return null;\r\n\r\n const fields = parseFieldDefinitions(args[0]);\r\n const { tableName, indexes } = parseOptions(args[1]);\r\n\r\n if (!tableName) return null;\r\n\r\n return { tableName, fields, indexes };\r\n}\r\n\r\n/**\r\n * Batch parse all Model files in a directory.\r\n */\r\nexport function parseModuleModels(modelDir: string): TableSchema[] {\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n const schemas: TableSchema[] = [];\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) schemas.push(schema);\r\n } catch {\r\n // skip unparseable files\r\n }\r\n }\r\n return schemas;\r\n}\r\n\r\nfunction findInitCall(sourceFile: Node): CallExpression | null {\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n if (propAccess.getName() === 'init') return call;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\r\n const fields: FieldSchema[] = [];\r\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\r\n\r\n const objLiteral = fieldsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const initializer = propAssign.getInitializer();\r\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n fields.push(parseFieldObject(propAssign.getName(), initializer as ObjectLiteralExpression));\r\n }\r\n return fields;\r\n}\r\n\r\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\r\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\r\n\r\n for (const prop of fieldObj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n switch (key) {\r\n case 'type': field.type = extractDataType(init); break;\r\n case 'allowNull': field.allowNull = init.getText().trim() === 'true'; break;\r\n case 'primaryKey': field.primaryKey = init.getText().trim() === 'true'; break;\r\n case 'defaultValue': field.defaultValue = extractDefaultValue(init); break;\r\n }\r\n }\r\n return field;\r\n}\r\n\r\nfunction extractDataType(node: Node): string {\r\n const text = node.getText().trim();\r\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\r\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\r\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\r\n if (propMatch) return propMatch[1];\r\n return text;\r\n}\r\n\r\nfunction extractDefaultValue(node: Node): unknown {\r\n const text = node.getText().trim();\r\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\r\n if (text === 'true') return true;\r\n if (text === 'false') return false;\r\n if (text === 'null') return null;\r\n return text;\r\n}\r\n\r\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\r\n let tableName: string | null = null;\r\n let indexes: IndexSchema[] = [];\r\n\r\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\r\n\r\n const objLiteral = optionsNode as ObjectLiteralExpression;\r\n for (const prop of objLiteral.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const propAssign = prop as PropertyAssignment;\r\n const key = propAssign.getName();\r\n const init = propAssign.getInitializer();\r\n if (!init) continue;\r\n\r\n if (key === 'tableName') tableName = extractStringValue(init);\r\n if (key === 'indexes') indexes = parseIndexes(init);\r\n }\r\n return { tableName, indexes };\r\n}\r\n\r\nfunction extractStringValue(node: Node): string | null {\r\n const text = node.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction parseIndexes(node: Node): IndexSchema[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n const indexes: IndexSchema[] = [];\r\n for (const el of arr.getElements()) {\r\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\r\n const idx = parseIndexObject(el as ObjectLiteralExpression);\r\n if (idx) indexes.push(idx);\r\n }\r\n return indexes;\r\n}\r\n\r\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\r\n let name = '';\r\n let fields: string[] = [];\r\n let unique = false;\r\n\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n switch (pa.getName()) {\r\n case 'name': name = extractStringValue(init) || ''; break;\r\n case 'fields': fields = extractStringArray(init); break;\r\n case 'unique': unique = init.getText().trim() === 'true'; break;\r\n }\r\n }\r\n if (!name || fields.length === 0) return null;\r\n return { name, fields, unique };\r\n}\r\n\r\nfunction extractStringArray(node: Node): string[] {\r\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\r\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\r\n return arr.getElements()\r\n .map((el) => el.getText().trim())\r\n .filter((t) => (t.startsWith(\"'\") || t.startsWith('\"')))\r\n .map((t) => t.slice(1, -1));\r\n}\r\n\r\nexport function createModelParser(): ModelParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseModelFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseModuleModels(dirPath);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type CallExpression,\r\n type SourceFile,\r\n Node,\r\n type PropertyAccessExpression,\r\n type Decorator,\r\n type MethodDeclaration,\r\n type ObjectLiteralExpression,\r\n} from 'ts-morph';\r\nimport type { ApiEndpoint } from '../types.js';\r\n\r\nexport interface ControllerParser {\r\n parseFile(filePath: string): Promise<ApiEndpoint[]>;\r\n parseDirectory(dirPath: string): Promise<ApiEndpoint[]>;\r\n}\r\n\r\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\nconst METHOD_MAP: Record<string, string> = {\r\n get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH',\r\n};\r\n\r\nconst NEST_HTTP_DECORATORS = new Set(['get', 'post', 'put', 'delete', 'patch']);\r\n\r\n/**\r\n * Parse a single Controller file and extract API endpoints.\r\n */\r\nexport function parseControllerFile(filePath: string): ApiEndpoint[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n try {\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n endpoints.push(...extractRouterCalls(sourceFile));\r\n endpoints.push(...extractBaseCrudRoutes(sourceFile));\r\n endpoints.push(...extractNestControllerRoutes(sourceFile));\r\n\r\n return deduplicateEndpoints(endpoints);\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Parse all Controller files in a directory.\r\n */\r\nexport function parseControllerDirectory(dirPath: string): ApiEndpoint[] {\r\n const absoluteDir = path.resolve(dirPath);\r\n if (!fs.existsSync(absoluteDir)) return [];\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts',\r\n );\r\n\r\n const endpoints: ApiEndpoint[] = [];\r\n for (const file of files) {\r\n endpoints.push(...parseControllerFile(path.join(absoluteDir, file)));\r\n }\r\n return deduplicateEndpoints(endpoints);\r\n}\r\n\r\nfunction extractRouterCalls(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr as PropertyAccessExpression;\r\n const methodName = propAccess.getName().toLowerCase();\r\n if (!HTTP_METHODS.has(methodName)) continue;\r\n\r\n const objectText = propAccess.getExpression().getText().trim();\r\n if (!isRouterLike(objectText)) continue;\r\n\r\n const args = call.getArguments();\r\n if (args.length === 0) continue;\r\n\r\n const routePath = resolveRoutePath(args[0], sourceFile);\r\n if (!routePath) continue;\r\n\r\n endpoints.push({\r\n method: METHOD_MAP[methodName],\r\n path: routePath,\r\n pathParams: extractPathParams(routePath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractDescription(call),\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction isRouterLike(text: string): boolean {\r\n return text === 'router' || text === 'this.router';\r\n}\r\n\r\nfunction extractBaseCrudRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n let isBaseCrud = false;\r\n for (const cls of sourceFile.getClasses()) {\r\n const heritage = cls.getExtends();\r\n if (heritage?.getText().includes('BaseCrudController')) {\r\n isBaseCrud = true;\r\n break;\r\n }\r\n }\r\n if (!isBaseCrud) return endpoints;\r\n\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n let resourcePath: string | null = null;\r\n\r\n for (const call of calls) {\r\n const exprText = call.getExpression().getText();\r\n if (\r\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\r\n !exprText.includes('Custom')\r\n ) {\r\n const args = call.getArguments();\r\n if (args.length >= 2) resourcePath = extractStringLiteral(args[1]);\r\n }\r\n }\r\n if (!resourcePath) return endpoints;\r\n\r\n const basePath = `/v1/:tenantId/${resourcePath}`;\r\n const crudRoutes: Array<{ method: string; path: string; desc: string }> = [\r\n { method: 'GET', path: basePath, desc: `List ${resourcePath}` },\r\n { method: 'GET', path: `${basePath}/:id`, desc: `Get ${resourcePath} by ID` },\r\n { method: 'POST', path: basePath, desc: `Create ${resourcePath}` },\r\n { method: 'PUT', path: `${basePath}/:id`, desc: `Update ${resourcePath}` },\r\n { method: 'DELETE', path: `${basePath}/:id`, desc: `Delete ${resourcePath}` },\r\n { method: 'POST', path: `${basePath}/batch-delete`, desc: `Batch delete ${resourcePath}` },\r\n ];\r\n\r\n for (const route of crudRoutes) {\r\n endpoints.push({\r\n method: route.method,\r\n path: route.path,\r\n pathParams: extractPathParams(route.path),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: route.desc,\r\n });\r\n }\r\n return endpoints;\r\n}\r\n\r\nfunction extractNestControllerRoutes(sourceFile: SourceFile): ApiEndpoint[] {\r\n const endpoints: ApiEndpoint[] = [];\r\n\r\n for (const cls of sourceFile.getClasses()) {\r\n const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === 'controller');\r\n if (!controllerDecorator) continue;\r\n\r\n const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? '');\r\n\r\n for (const methodDecl of cls.getMethods()) {\r\n const requestMapping = extractRequestMapping(methodDecl, sourceFile);\r\n if (requestMapping) {\r\n const fullPath = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));\r\n endpoints.push({\r\n method: requestMapping.method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n continue;\r\n }\r\n\r\n const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));\r\n if (!httpDecorator) continue;\r\n\r\n const methodName = httpDecorator.getName().toLowerCase();\r\n const method = METHOD_MAP[methodName];\r\n if (!method) continue;\r\n\r\n const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? '');\r\n const fullPath = joinRoutePath(controllerBasePath, methodPath);\r\n\r\n endpoints.push({\r\n method,\r\n path: fullPath,\r\n pathParams: extractPathParams(fullPath),\r\n queryParams: [],\r\n bodyFields: [],\r\n responseFields: [],\r\n relatedTables: [],\r\n description: extractMethodDescription(methodDecl),\r\n });\r\n }\r\n }\r\n\r\n return endpoints;\r\n}\r\n\r\n/**\r\n * Infer related database table names from Service file imports.\r\n */\r\nexport function inferRelatedTables(servicePaths: string[]): string[] {\r\n const tables = new Set<string>();\r\n for (const sp of servicePaths) {\r\n const absolutePath = path.resolve(sp);\r\n if (!fs.existsSync(absolutePath)) continue;\r\n try {\r\n const content = fs.readFileSync(absolutePath, 'utf-8');\r\n const importRegex = /import\\s*\\{([^}]+)\\}\\s*from\\s*['\"][^'\"]*models[^'\"]*['\"]/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const names = match[1].split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n const cleanName = name.replace(/\\s+as\\s+\\w+/, '').trim();\r\n if (cleanName) tables.add(pascalToSnake(cleanName));\r\n }\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return Array.from(tables);\r\n}\r\n\r\nfunction resolveRoutePath(node: Node, sourceFile: SourceFile): string | null {\r\n const kind = node.getKind();\r\n if (kind === SyntaxKind.StringLiteral) return node.getText().slice(1, -1);\r\n if (kind === SyntaxKind.TemplateExpression || kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\r\n return resolveTemplateLiteral(node, sourceFile);\r\n }\r\n if (kind === SyntaxKind.Identifier) {\r\n return resolveVariableValue(sourceFile, node.getText().trim());\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractDecoratorPath(decorator: Decorator, sourceFile: SourceFile): string | null {\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return '';\r\n\r\n const firstArg = args[0];\r\n if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n return extractPathFromObjectLiteral(firstArg as ObjectLiteralExpression, sourceFile);\r\n }\r\n\r\n return resolveRoutePath(firstArg, sourceFile);\r\n}\r\n\r\nfunction extractPathFromObjectLiteral(node: ObjectLiteralExpression, sourceFile: SourceFile): string | null {\r\n const pathProp = node.getProperty('path');\r\n if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;\r\n const initializer = pathProp.getInitializer();\r\n if (!initializer) return null;\r\n return resolveRoutePath(initializer, sourceFile);\r\n}\r\n\r\nfunction extractRequestMapping(\r\n methodDecl: MethodDeclaration,\r\n sourceFile: SourceFile,\r\n): { method: string; path: string } | null {\r\n const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === 'requestmapping');\r\n if (!decorator) return null;\r\n\r\n const args = decorator.getArguments();\r\n if (args.length === 0) return null;\r\n const firstArg = args[0];\r\n if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return null;\r\n\r\n const obj = firstArg as ObjectLiteralExpression;\r\n const methodProp = obj.getProperty('method');\r\n let method = 'GET';\r\n if (methodProp && Node.isPropertyAssignment(methodProp)) {\r\n const init = methodProp.getInitializer();\r\n const methodText = init?.getText() || '';\r\n const normalized = methodText\r\n .replace(/['\"`]/g, '')\r\n .split('.')\r\n .pop()\r\n ?.toUpperCase();\r\n if (normalized && ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) {\r\n method = normalized;\r\n }\r\n }\r\n\r\n const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? '';\r\n return { method, path: pathValue };\r\n}\r\n\r\nfunction normalizeRoutePath(routePath: string): string {\r\n const cleaned = routePath.trim();\r\n if (!cleaned || cleaned === '/') return '';\r\n return `/${cleaned.replace(/^\\/+|\\/+$/g, '')}`;\r\n}\r\n\r\nfunction joinRoutePath(basePath: string, childPath: string): string {\r\n const joined = `${basePath}${childPath}`.replace(/\\/+/g, '/');\r\n return joined || '/';\r\n}\r\n\r\nfunction extractMethodDescription(methodDecl: MethodDeclaration): string {\r\n const docs = methodDecl.getJsDocs();\r\n if (docs.length > 0) {\r\n const desc = docs[0].getDescription().trim();\r\n if (desc) return desc;\r\n }\r\n return '';\r\n}\r\n\r\nfunction resolveTemplateLiteral(node: Node, sourceFile: SourceFile): string {\r\n let result = node.getText().slice(1, -1);\r\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\r\n const resolved = resolveVariableValue(sourceFile, expr.trim());\r\n return resolved || `{${expr.trim()}}`;\r\n });\r\n return result;\r\n}\r\n\r\nfunction resolveVariableValue(sourceFile: SourceFile, varName: string): string | null {\r\n for (const decl of sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\r\n if (decl.getName() === varName) {\r\n const init = decl.getInitializer();\r\n if (!init) continue;\r\n const t = init.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n if (t.startsWith('`') && t.endsWith('`'))\r\n return resolveTemplateLiteral(init, sourceFile);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction extractDescription(call: CallExpression): string {\r\n let current: Node = call;\r\n while (\r\n current.getParent() &&\r\n current.getParent()!.getKind() !== SyntaxKind.SourceFile &&\r\n current.getParent()!.getKind() !== SyntaxKind.Block\r\n ) {\r\n current = current.getParent()!;\r\n }\r\n const fullText = current.getFullText();\r\n const leadingText = fullText.substring(0, fullText.indexOf(current.getText()));\r\n const jsdocMatch = leadingText.match(/\\/\\*\\*[\\s\\S]*?\\*\\s+(.+?)(?:\\n|\\*\\/)/);\r\n if (jsdocMatch) return jsdocMatch[1].replace(/^\\*\\s*/, '').trim();\r\n const lineMatch = leadingText.match(/\\/\\/\\s*(.+)/);\r\n if (lineMatch) return lineMatch[1].trim();\r\n return '';\r\n}\r\n\r\nfunction extractStringLiteral(node: Node): string | null {\r\n const t = node.getText().trim();\r\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\r\n return t.slice(1, -1);\r\n return null;\r\n}\r\n\r\nfunction pascalToSnake(name: string): string {\r\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction deduplicateEndpoints(endpoints: ApiEndpoint[]): ApiEndpoint[] {\r\n const seen = new Map<string, ApiEndpoint>();\r\n for (const ep of endpoints) {\r\n const key = `${ep.method}:${ep.path}`;\r\n if (!seen.has(key)) {\r\n seen.set(key, ep);\r\n } else {\r\n const existing = seen.get(key)!;\r\n const merged = new Set([...existing.relatedTables, ...ep.relatedTables]);\r\n existing.relatedTables = Array.from(merged);\r\n if (!existing.description && ep.description) existing.description = ep.description;\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createControllerParser(): ControllerParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseControllerFile(filePath);\r\n },\r\n async parseDirectory(dirPath: string) {\r\n return parseControllerDirectory(dirPath);\r\n },\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport {\r\n Project,\r\n SyntaxKind,\r\n type ObjectLiteralExpression,\r\n type PropertyAssignment,\r\n type SourceFile,\r\n} from 'ts-morph';\r\nimport type { ForeignKeyRelation } from '../types.js';\r\nimport { parseModelFile } from './model-parser.js';\r\n\r\nexport interface AssociationParser {\r\n parseFile(filePath: string): Promise<ForeignKeyRelation[]>;\r\n}\r\n\r\ninterface RawAssociation {\r\n sourceClass: string;\r\n targetClass: string;\r\n foreignKey: string;\r\n type: 'hasMany' | 'belongsTo' | 'hasOne';\r\n importPath?: string;\r\n}\r\n\r\n/**\r\n * Parse an associations.ts file to extract all foreign key relations.\r\n */\r\nexport function parseAssociationFile(\r\n filePath: string,\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const absolutePath = path.resolve(filePath);\r\n if (!fs.existsSync(absolutePath)) return [];\r\n\r\n const project = new Project({ compilerOptions: { strict: false } });\r\n const sourceFile = project.addSourceFileAtPath(absolutePath);\r\n\r\n const importPathMap = collectImportPaths(sourceFile);\r\n const rawAssociations = extractAssociationCalls(sourceFile, importPathMap);\r\n if (rawAssociations.length === 0) return [];\r\n\r\n return deduplicateRelations(rawAssociations, classToTableMap, moduleTablePrefix);\r\n}\r\n\r\n/**\r\n * Build className → tableName map from Model files in a directory.\r\n */\r\nexport function buildClassToTableMap(modelDir: string): Map<string, string> {\r\n const map = new Map<string, string>();\r\n const absoluteDir = path.resolve(modelDir);\r\n if (!fs.existsSync(absoluteDir)) return map;\r\n\r\n const files = fs.readdirSync(absoluteDir).filter((f) =>\r\n f.endsWith('.ts') &&\r\n !f.endsWith('.test.ts') &&\r\n !f.endsWith('.spec.ts') &&\r\n f !== 'index.ts' &&\r\n f !== 'associations.ts',\r\n );\r\n\r\n for (const file of files) {\r\n try {\r\n const schema = parseModelFile(path.join(absoluteDir, file));\r\n if (schema) {\r\n const className = file.replace('.ts', '');\r\n map.set(className, schema.tableName);\r\n }\r\n } catch {\r\n // skip\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction collectImportPaths(sourceFile: SourceFile): Map<string, string> {\r\n const map = new Map<string, string>();\r\n for (const decl of sourceFile.getImportDeclarations()) {\r\n const moduleSpecifier = decl.getModuleSpecifierValue();\r\n for (const named of decl.getNamedImports()) {\r\n map.set(named.getName(), moduleSpecifier);\r\n }\r\n }\r\n return map;\r\n}\r\n\r\nfunction extractAssociationCalls(\r\n sourceFile: SourceFile,\r\n importPathMap: Map<string, string>,\r\n): RawAssociation[] {\r\n const associations: RawAssociation[] = [];\r\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\r\n\r\n for (const call of calls) {\r\n const expr = call.getExpression();\r\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\r\n\r\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\r\n const methodName = propAccess.getName();\r\n if (methodName !== 'hasMany' && methodName !== 'belongsTo' && methodName !== 'hasOne') continue;\r\n\r\n const sourceClass = propAccess.getExpression().getText().trim();\r\n const args = call.getArguments();\r\n if (args.length < 1) continue;\r\n\r\n const targetClass = args[0].getText().trim();\r\n let foreignKey = '';\r\n\r\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\r\n foreignKey = extractStringProperty(args[1] as ObjectLiteralExpression, 'foreignKey');\r\n }\r\n\r\n associations.push({\r\n sourceClass,\r\n targetClass,\r\n foreignKey,\r\n type: methodName as RawAssociation['type'],\r\n importPath: importPathMap.get(targetClass),\r\n });\r\n }\r\n return associations;\r\n}\r\n\r\nfunction extractStringProperty(obj: ObjectLiteralExpression, propertyName: string): string {\r\n for (const prop of obj.getProperties()) {\r\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\r\n const pa = prop as PropertyAssignment;\r\n if (pa.getName() !== propertyName) continue;\r\n const init = pa.getInitializer();\r\n if (!init) continue;\r\n const text = init.getText().trim();\r\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\r\n return text.slice(1, -1);\r\n return text;\r\n }\r\n return '';\r\n}\r\n\r\nexport function classNameToTableName(className: string): string {\r\n return className.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\r\n}\r\n\r\nfunction resolveTableName(className: string, classToTableMap?: Map<string, string>): string {\r\n if (classToTableMap?.has(className)) return classToTableMap.get(className)!;\r\n return classNameToTableName(className);\r\n}\r\n\r\nfunction isCrossModuleRef(\r\n targetTableName: string,\r\n importPath: string | undefined,\r\n moduleTablePrefix?: string,\r\n): boolean {\r\n if (moduleTablePrefix) return !targetTableName.startsWith(moduleTablePrefix);\r\n if (importPath) {\r\n const upLevels = (importPath.match(/\\.\\.\\//g) || []).length;\r\n return upLevels >= 2;\r\n }\r\n return false;\r\n}\r\n\r\nfunction deduplicateRelations(\r\n rawAssociations: RawAssociation[],\r\n classToTableMap?: Map<string, string>,\r\n moduleTablePrefix?: string,\r\n): ForeignKeyRelation[] {\r\n const seen = new Map<string, ForeignKeyRelation>();\r\n\r\n for (const raw of rawAssociations) {\r\n const sourceTable = resolveTableName(raw.sourceClass, classToTableMap);\r\n const targetTable = resolveTableName(raw.targetClass, classToTableMap);\r\n const crossModule = isCrossModuleRef(targetTable, raw.importPath, moduleTablePrefix);\r\n\r\n let parentTable: string;\r\n let childTable: string;\r\n let cardinality: ForeignKeyRelation['cardinality'];\r\n\r\n switch (raw.type) {\r\n case 'hasMany':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:N'; break;\r\n case 'belongsTo':\r\n parentTable = targetTable; childTable = sourceTable; cardinality = 'N:1'; break;\r\n case 'hasOne':\r\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:1'; break;\r\n }\r\n\r\n const dedupeKey = `${parentTable}|${childTable}|${raw.foreignKey}`;\r\n if (seen.has(dedupeKey)) {\r\n const existing = seen.get(dedupeKey)!;\r\n if (existing.cardinality === 'N:1' && (cardinality === '1:N' || cardinality === '1:1')) {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule || existing.isCrossModule,\r\n });\r\n }\r\n } else {\r\n seen.set(dedupeKey, {\r\n sourceTable: parentTable, sourceField: 'id',\r\n targetTable: childTable, targetField: raw.foreignKey,\r\n cardinality, isCrossModule: crossModule,\r\n });\r\n }\r\n }\r\n return Array.from(seen.values());\r\n}\r\n\r\nexport function createAssociationParser(): AssociationParser {\r\n return {\r\n async parseFile(filePath: string) {\r\n return parseAssociationFile(filePath);\r\n },\r\n };\r\n}\r\n","import type {\r\n ApiEndpoint,\r\n ApiDependency,\r\n ApiChainAnalysisResult,\r\n DirectedAcyclicGraph,\r\n} from '../types.js';\r\n\r\nconst EXCLUDED_PARAMS = new Set(['tenantId']);\r\n\r\nconst enum Color { WHITE = 0, GRAY = 1, BLACK = 2 }\r\n\r\nfunction toNodeKey(endpoint: ApiEndpoint): string {\r\n return `${endpoint.method} ${endpoint.path}`;\r\n}\r\n\r\nfunction paramToResourceHint(param: string): string {\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n return stripped.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\r\n}\r\n\r\nfunction postProducesResource(postEndpoint: ApiEndpoint, resourceHint: string): boolean {\r\n const segments = postEndpoint.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n if (segments.length === 0) return false;\r\n\r\n const lastSegment = segments[segments.length - 1].toLowerCase();\r\n if (lastSegment.includes(resourceHint)) return true;\r\n\r\n const parts = lastSegment.split('-');\r\n if (parts.some((p) => p === resourceHint || p.startsWith(resourceHint))) return true;\r\n\r\n if (resourceHint.length <= 4) {\r\n const abbreviation = parts.map((p) => p[0]).join('');\r\n if (abbreviation.startsWith(resourceHint)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Infer API dependencies via path parameter matching.\r\n * POST endpoints produce IDs; GET/PUT/DELETE endpoints consume them.\r\n */\r\nexport function inferDependencies(endpoints: ApiEndpoint[]): ApiDependency[] {\r\n const dependencies: ApiDependency[] = [];\r\n const postEndpoints = endpoints.filter((ep) => ep.method === 'POST');\r\n\r\n for (const consumer of endpoints) {\r\n const consumedParams = consumer.pathParams.filter((p) => !EXCLUDED_PARAMS.has(p));\r\n if (consumedParams.length === 0) continue;\r\n\r\n for (const param of consumedParams) {\r\n if (param === 'id') {\r\n const basePath = consumer.path.replace(/\\/:id(\\/.*)?$/, '');\r\n const producer = postEndpoints.find((ep) => ep.path === basePath);\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n continue;\r\n }\r\n\r\n const resourceHint = paramToResourceHint(param);\r\n if (!resourceHint) continue;\r\n\r\n const producer = postEndpoints.find((ep) => postProducesResource(ep, resourceHint));\r\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\r\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\r\n }\r\n }\r\n }\r\n return deduplicateDependencies(dependencies);\r\n}\r\n\r\nfunction deduplicateDependencies(deps: ApiDependency[]): ApiDependency[] {\r\n const map = new Map<string, ApiDependency>();\r\n for (const dep of deps) {\r\n const key = `${toNodeKey(dep.from)}→${toNodeKey(dep.to)}`;\r\n if (map.has(key)) {\r\n Object.assign(map.get(key)!.paramMapping, dep.paramMapping);\r\n } else {\r\n map.set(key, { ...dep, paramMapping: { ...dep.paramMapping } });\r\n }\r\n }\r\n return Array.from(map.values());\r\n}\r\n\r\n/**\r\n * Build a directed graph from endpoints and their dependencies.\r\n */\r\nexport function buildGraph(\r\n endpoints: ApiEndpoint[],\r\n dependencies: ApiDependency[],\r\n): DirectedAcyclicGraph {\r\n const nodeSet = new Set<string>();\r\n for (const ep of endpoints) nodeSet.add(toNodeKey(ep));\r\n\r\n const edges: Array<{ from: string; to: string; label?: string }> = [];\r\n for (const dep of dependencies) {\r\n edges.push({\r\n from: toNodeKey(dep.from),\r\n to: toNodeKey(dep.to),\r\n label: Object.keys(dep.paramMapping).join(', ') || undefined,\r\n });\r\n }\r\n return { nodes: Array.from(nodeSet), edges };\r\n}\r\n\r\n/**\r\n * Detect cycles in a directed graph using DFS coloring.\r\n */\r\nexport function detectCycles(dag: DirectedAcyclicGraph): string[] {\r\n const adjacency = new Map<string, string[]>();\r\n for (const node of dag.nodes) adjacency.set(node, []);\r\n for (const edge of dag.edges) adjacency.get(edge.from)?.push(edge.to);\r\n\r\n const color = new Map<string, Color>();\r\n for (const node of dag.nodes) color.set(node, Color.WHITE);\r\n\r\n const warnings: string[] = [];\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n color.set(node, Color.GRAY);\r\n path.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nc = color.get(neighbor);\r\n if (nc === Color.GRAY) {\r\n const cycleStart = path.indexOf(neighbor);\r\n warnings.push(`Cycle detected: ${path.slice(cycleStart).concat(neighbor).join(' → ')}`);\r\n } else if (nc === Color.WHITE) {\r\n dfs(neighbor);\r\n }\r\n }\r\n path.pop();\r\n color.set(node, Color.BLACK);\r\n }\r\n\r\n for (const node of dag.nodes) {\r\n if (color.get(node) === Color.WHITE) dfs(node);\r\n }\r\n return warnings;\r\n}\r\n\r\n/**\r\n * Topological sort using Kahn's algorithm.\r\n */\r\nexport function topologicalSort(dag: DirectedAcyclicGraph): string[] {\r\n const inDegree = new Map<string, number>();\r\n const adjacency = new Map<string, string[]>();\r\n\r\n for (const node of dag.nodes) { inDegree.set(node, 0); adjacency.set(node, []); }\r\n for (const edge of dag.edges) {\r\n adjacency.get(edge.from)?.push(edge.to);\r\n inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);\r\n }\r\n\r\n const queue: string[] = [];\r\n for (const [node, degree] of inDegree) {\r\n if (degree === 0) queue.push(node);\r\n }\r\n\r\n const sorted: string[] = [];\r\n while (queue.length > 0) {\r\n const node = queue.shift()!;\r\n sorted.push(node);\r\n for (const neighbor of adjacency.get(node) || []) {\r\n const nd = (inDegree.get(neighbor) || 1) - 1;\r\n inDegree.set(neighbor, nd);\r\n if (nd === 0) queue.push(neighbor);\r\n }\r\n }\r\n return sorted;\r\n}\r\n\r\nexport interface ApiChainAnalyzer {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult;\r\n}\r\n\r\n/**\r\n * Analyze API endpoints: infer dependencies, build DAG, detect cycles, topological sort.\r\n */\r\nexport function createApiChainAnalyzer(): ApiChainAnalyzer {\r\n return {\r\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult {\r\n const dependencies = inferDependencies(endpoints);\r\n const dag = buildGraph(endpoints, dependencies);\r\n const cycleWarnings = detectCycles(dag);\r\n\r\n return {\r\n moduleName: '',\r\n endpoints,\r\n dependencies,\r\n dag,\r\n hasCycles: cycleWarnings.length > 0,\r\n cycleWarnings,\r\n };\r\n },\r\n };\r\n}\r\n","import type { ERDiagramResult, TableSchema, ForeignKeyRelation } from '../types.js';\r\n\r\nexport interface ERDiagramGenerator {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult;\r\n}\r\n\r\n/**\r\n * Map field type string to a short Mermaid ER type label.\r\n */\r\nfunction toMermaidType(fieldType: string): string {\r\n const upper = fieldType.toUpperCase();\r\n if (upper.startsWith('STRING')) return 'string';\r\n if (upper === 'BIGINT' || upper === 'INTEGER') return 'bigint';\r\n if (upper === 'BOOLEAN') return 'boolean';\r\n if (upper.startsWith('DATE') || upper === 'NOW') return 'datetime';\r\n if (upper === 'JSON' || upper === 'JSONB') return 'json';\r\n if (upper === 'TEXT') return 'text';\r\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return 'float';\r\n if (upper === 'UUID') return 'uuid';\r\n if (upper.startsWith('ENUM')) return 'enum';\r\n return 'string';\r\n}\r\n\r\n/**\r\n * Mermaid requires entity names without special characters.\r\n */\r\nfunction sanitizeEntityName(name: string): string {\r\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n\r\n/**\r\n * Generate Mermaid ER diagram syntax from parsed schemas and relations.\r\n */\r\nfunction generateMermaidER(tables: TableSchema[], relations: ForeignKeyRelation[]): string {\r\n const lines: string[] = ['erDiagram'];\r\n\r\n // Entity blocks\r\n for (const table of tables) {\r\n const entityName = sanitizeEntityName(table.tableName);\r\n lines.push(` ${entityName} {`);\r\n for (const field of table.fields) {\r\n const mType = toMermaidType(field.type);\r\n const pk = field.primaryKey ? 'PK' : '';\r\n const comment = field.comment ? ` \"${field.comment}\"` : '';\r\n lines.push(` ${mType} ${field.name}${pk ? ' ' + pk : ''}${comment}`);\r\n }\r\n lines.push(' }');\r\n }\r\n\r\n // Relationships\r\n const tableNames = new Set(tables.map((t) => t.tableName));\r\n for (const rel of relations) {\r\n if (!tableNames.has(rel.sourceTable) || !tableNames.has(rel.targetTable)) continue;\r\n\r\n const src = sanitizeEntityName(rel.sourceTable);\r\n const tgt = sanitizeEntityName(rel.targetTable);\r\n const linkStyle = rel.isCrossModule ? '..' : '--';\r\n\r\n let cardinality: string;\r\n switch (rel.cardinality) {\r\n case '1:N': cardinality = `||${linkStyle}o{`; break;\r\n case 'N:1': cardinality = `}o${linkStyle}||`; break;\r\n case '1:1': cardinality = `||${linkStyle}||`; break;\r\n default: cardinality = `||${linkStyle}o{`;\r\n }\r\n\r\n lines.push(` ${src} ${cardinality} ${tgt} : \"${rel.targetField}\"`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createERDiagramGenerator(): ERDiagramGenerator {\r\n return {\r\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult {\r\n const mermaidText = generateMermaidER(tables, relations);\r\n return { tables, relations, mermaidText };\r\n },\r\n };\r\n}\r\n","import type { GeneratedTestFile, TestChain, TestStep } from '../types.js';\r\n\r\nexport interface TestCodeGenerator {\r\n generate(chains: TestChain[]): GeneratedTestFile[];\r\n}\r\n\r\n/**\r\n * Resolve a path parameter from the available createdIds.\r\n */\r\nfunction resolvePathParam(param: string, ids: string[]): string {\r\n // Try direct match (e.g., 'kbId' → look for 'kbId' in ids)\r\n if (ids.includes(param)) return `createdIds['${param}']`;\r\n // Try with 'Id' suffix stripped\r\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\r\n if (ids.includes(stripped)) return `createdIds['${stripped}']`;\r\n // Generic id\r\n if (param === 'id') return `createdIds['id']`;\r\n return `createdIds['${param}'] || '1'`;\r\n}\r\n\r\n/**\r\n * Generate URL building code for a test step.\r\n */\r\nfunction buildUrlCode(step: TestStep): string {\r\n const pathParams = step.endpoint.pathParams;\r\n if (pathParams.length === 0) return `const url = '${step.endpoint.path}';`;\r\n\r\n let urlTemplate = step.endpoint.path;\r\n const replacements: string[] = [];\r\n for (const param of pathParams) {\r\n urlTemplate = urlTemplate.replace(`:${param}`, `\\${${resolvePathParam(param, pathParams)}}`);\r\n replacements.push(param);\r\n }\r\n return `const url = \\`${urlTemplate}\\`;`;\r\n}\r\n\r\n/**\r\n * Generate assertion code for a test step.\r\n */\r\nfunction generateAssertions(step: TestStep): string[] {\r\n const lines: string[] = [];\r\n if (step.assertions.length > 0) {\r\n for (const assertion of step.assertions) {\r\n lines.push(` expect(${assertion}).toBeTruthy();`);\r\n }\r\n } else {\r\n // Default assertions\r\n if (step.endpoint.method === 'POST') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n lines.push(' const body = await response.json();');\r\n lines.push(\" if (body.data?.id) createdIds['id'] = body.data.id;\");\r\n } else if (step.endpoint.method === 'GET') {\r\n lines.push(' expect(response.ok()).toBeTruthy();');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n } else {\r\n lines.push(' expect(response.status()).toBeLessThan(400);');\r\n }\r\n }\r\n return lines;\r\n}\r\n\r\n/**\r\n * Generate a single Playwright test file from a test chain.\r\n */\r\nfunction generateTestFile(chain: TestChain): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test, expect } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push(`test.describe('${chain.name}', () => {`);\r\n lines.push(\" const createdIds: Record<string, string> = {};\");\r\n lines.push('');\r\n\r\n for (const step of chain.steps) {\r\n lines.push(` test('Step ${step.order}: ${step.description}', async ({ request }) => {`);\r\n lines.push(` // ${step.action}: ${step.endpoint.method} ${step.endpoint.path}`);\r\n lines.push(` ${buildUrlCode(step)}`);\r\n lines.push('');\r\n\r\n if (step.endpoint.method === 'GET') {\r\n lines.push(' const response = await request.get(url);');\r\n } else if (step.endpoint.method === 'POST') {\r\n lines.push(' const response = await request.post(url, { data: {} });');\r\n } else if (step.endpoint.method === 'PUT') {\r\n lines.push(' const response = await request.put(url, { data: {} });');\r\n } else if (step.endpoint.method === 'DELETE') {\r\n lines.push(' const response = await request.delete(url);');\r\n } else if (step.endpoint.method === 'PATCH') {\r\n lines.push(' const response = await request.patch(url, { data: {} });');\r\n }\r\n\r\n lines.push('');\r\n lines.push(...generateAssertions(step));\r\n lines.push(' });');\r\n lines.push('');\r\n }\r\n\r\n lines.push('});');\r\n return lines.join('\\n');\r\n}\r\n\r\nexport function createTestCodeGenerator(): TestCodeGenerator {\r\n return {\r\n generate(chains: TestChain[]): GeneratedTestFile[] {\r\n return chains.map((chain) => ({\r\n filePath: `${chain.module}/${chain.name.replace(/\\s+/g, '-').toLowerCase()}.spec.ts`,\r\n content: generateTestFile(chain),\r\n module: chain.module,\r\n chain: chain.name,\r\n }));\r\n },\r\n };\r\n}\r\n","/**\r\n * Schema Validator — Layer 1 of three-layer module config validation.\r\n * Checks structural integrity, field types, format conventions.\r\n */\r\n\r\nimport type {\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] as const;\r\n\r\nexport function validateSchema(config: unknown): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n if (config === null || config === undefined || typeof config !== 'object') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: '', message: 'Config must be a non-null object' });\r\n return { passed: false, layer: 'schema', errors, warnings };\r\n }\r\n\r\n const cfg = config as Record<string, unknown>;\r\n\r\n // Required top-level fields\r\n const required: Array<{ name: string; type: string }> = [\r\n { name: 'moduleName', type: 'string' },\r\n { name: 'version', type: 'string' },\r\n { name: 'generatedAt', type: 'string' },\r\n { name: 'bodyTemplates', type: 'object' },\r\n { name: 'paramRewrites', type: 'object' },\r\n { name: 'idAliases', type: 'array' },\r\n { name: 'seed', type: 'array' },\r\n ];\r\n\r\n for (const f of required) {\r\n if (cfg[f.name] === undefined || cfg[f.name] === null) {\r\n errors.push({\r\n layer: 'schema', type: 'missing-field', path: f.name,\r\n message: `Required field '${f.name}' is missing`,\r\n suggestion: `Add '${f.name}' field of type ${f.type}`,\r\n });\r\n }\r\n }\r\n\r\n // Field type checks\r\n validateFieldTypes(cfg, errors);\r\n\r\n // bodyTemplates structure\r\n if (cfg.bodyTemplates && typeof cfg.bodyTemplates === 'object' && !Array.isArray(cfg.bodyTemplates)) {\r\n validateBodyTemplates(cfg.bodyTemplates as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // paramRewrites structure\r\n if (cfg.paramRewrites && typeof cfg.paramRewrites === 'object' && !Array.isArray(cfg.paramRewrites)) {\r\n validateParamRewrites(cfg.paramRewrites as Record<string, unknown>, errors, warnings);\r\n }\r\n\r\n // idAliases structure\r\n if (Array.isArray(cfg.idAliases)) {\r\n validateIdAliases(cfg.idAliases, errors);\r\n }\r\n\r\n // seed array\r\n if (Array.isArray(cfg.seed)) {\r\n validateSeedArray(cfg.seed, errors, warnings);\r\n }\r\n\r\n // version format\r\n if (typeof cfg.version === 'string' && !/^\\d+\\.\\d+(\\.\\d+)?$/.test(cfg.version)) {\r\n warnings.push({ layer: 'schema', path: 'version', message: `Version '${cfg.version}' does not follow semver format` });\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'schema', errors, warnings };\r\n}\r\n\r\nfunction validateFieldTypes(cfg: Record<string, unknown>, errors: ModuleConfigValidationError[]): void {\r\n if (cfg.moduleName !== undefined && typeof cfg.moduleName !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'moduleName', message: `'moduleName' must be a string` });\r\n } else if (typeof cfg.moduleName === 'string' && cfg.moduleName.trim() === '') {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: 'moduleName', message: \"'moduleName' must not be empty\" });\r\n }\r\n\r\n if (cfg.bodyTemplates !== undefined && (typeof cfg.bodyTemplates !== 'object' || Array.isArray(cfg.bodyTemplates))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'bodyTemplates', message: \"'bodyTemplates' must be a plain object\" });\r\n }\r\n if (cfg.paramRewrites !== undefined && (typeof cfg.paramRewrites !== 'object' || Array.isArray(cfg.paramRewrites))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'paramRewrites', message: \"'paramRewrites' must be a plain object\" });\r\n }\r\n if (cfg.idAliases !== undefined && !Array.isArray(cfg.idAliases)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'idAliases', message: \"'idAliases' must be an array\" });\r\n }\r\n if (cfg.seed !== undefined && !Array.isArray(cfg.seed)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: 'seed', message: \"'seed' must be an array\" });\r\n }\r\n}\r\n\r\nfunction validateBodyTemplates(\r\n templates: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(templates)) {\r\n const p = `bodyTemplates.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Body template '${key}' must be a plain object` });\r\n continue;\r\n }\r\n if (!/^(GET|POST|PUT|PATCH|DELETE)\\s+\\//.test(key)) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template key '${key}' should follow format 'METHOD /path'` });\r\n }\r\n if (Object.keys(value).length === 0) {\r\n warnings.push({ layer: 'schema', path: p, message: `Body template '${key}' is empty` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewrites(\r\n rewrites: Record<string, unknown>,\r\n errors: ModuleConfigValidationError[],\r\n _warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, value] of Object.entries(rewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Param rewrite '${key}' must be a plain object` });\r\n continue;\r\n }\r\n for (const [paramName, paramValue] of Object.entries(value as Record<string, unknown>)) {\r\n if (typeof paramValue !== 'string') {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.${paramName}`, message: `Param rewrite value for '${paramName}' must be a string` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliases(aliases: unknown[], errors: ModuleConfigValidationError[]): void {\r\n for (let i = 0; i < aliases.length; i++) {\r\n const alias = aliases[i] as Record<string, unknown> | null;\r\n const p = `idAliases[${i}]`;\r\n if (typeof alias !== 'object' || alias === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `idAlias at index ${i} must be an object` });\r\n continue;\r\n }\r\n if (typeof alias.pathPattern !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.pathPattern`, message: `idAlias at index ${i} must have a string 'pathPattern'` });\r\n }\r\n if (typeof alias.alias !== 'string') {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.alias`, message: `idAlias at index ${i} must have a string 'alias'` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedArray(\r\n seed: unknown[],\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (seed.length === 0) {\r\n warnings.push({ layer: 'schema', path: 'seed', message: 'Seed array is empty, no setup steps will be executed' });\r\n return;\r\n }\r\n\r\n const capturedVars = new Set<string>();\r\n const stepNumbers = new Set<number>();\r\n\r\n for (let i = 0; i < seed.length; i++) {\r\n const step = seed[i] as Record<string, unknown> | null;\r\n const p = `seed[${i}]`;\r\n if (typeof step !== 'object' || step === null) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: p, message: `Seed step at index ${i} must be an object` });\r\n continue;\r\n }\r\n\r\n // step number\r\n if (step.step === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.step`, message: `Seed step at index ${i} is missing 'step' number` });\r\n } else if (typeof step.step !== 'number' || !Number.isInteger(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.step`, message: `'step' must be an integer` });\r\n } else {\r\n if (stepNumbers.has(step.step)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.step`, message: `Duplicate step number ${step.step}` });\r\n }\r\n stepNumbers.add(step.step);\r\n }\r\n\r\n // method\r\n if (step.method === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.method`, message: `Seed step at index ${i} is missing 'method'` });\r\n } else if (typeof step.method !== 'string' || !(VALID_HTTP_METHODS as readonly string[]).includes(step.method)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.method`, message: `'method' must be one of ${VALID_HTTP_METHODS.join(', ')}` });\r\n }\r\n\r\n // path\r\n if (step.path === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.path`, message: `Seed step at index ${i} is missing 'path'` });\r\n } else if (typeof step.path !== 'string' || !(step.path as string).startsWith('/')) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.path`, message: `'path' must start with '/'` });\r\n }\r\n\r\n // required\r\n if (step.required === undefined) {\r\n errors.push({ layer: 'schema', type: 'missing-field', path: `${p}.required`, message: `Seed step at index ${i} is missing 'required'` });\r\n }\r\n\r\n // body\r\n if (step.body !== undefined && (typeof step.body !== 'object' || step.body === null || Array.isArray(step.body))) {\r\n errors.push({ layer: 'schema', type: 'invalid-type', path: `${p}.body`, message: `'body' must be a plain object` });\r\n } else if (step.body === undefined && typeof step.method === 'string' && ['POST', 'PUT', 'PATCH'].includes(step.method)) {\r\n warnings.push({ layer: 'schema', path: `${p}.body`, message: `${step.method} step at index ${i} has no body template` });\r\n }\r\n\r\n // captureAs uniqueness\r\n if (typeof step.captureAs === 'string') {\r\n if (capturedVars.has(step.captureAs)) {\r\n errors.push({ layer: 'schema', type: 'invalid-format', path: `${p}.captureAs`, message: `Duplicate captureAs variable '${step.captureAs}'` });\r\n }\r\n capturedVars.add(step.captureAs);\r\n }\r\n\r\n // dependsOn reference check\r\n if (Array.isArray(step.dependsOn)) {\r\n for (const dep of step.dependsOn) {\r\n if (typeof dep === 'string' && !capturedVars.has(dep)) {\r\n errors.push({\r\n layer: 'schema', type: 'dependency-missing', path: `${p}.dependsOn`,\r\n message: `Seed step ${step.step ?? i} depends on '${dep}' not captured by any preceding step`,\r\n suggestion: `Ensure a preceding step has captureAs: '${dep}'`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * Semantic Validator — Layer 2 of three-layer module config validation.\r\n * Checks that config matches actual source code (routes, DTO fields, dependencies).\r\n */\r\n\r\nimport type {\r\n ModuleTestConfig,\r\n SeedStep,\r\n ApiEndpoint,\r\n DTOInfo,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateSemantic(\r\n config: ModuleTestConfig,\r\n context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n validateBodyTemplatesSemantic(config, context, errors, warnings);\r\n validateParamRewritesSemantic(config, context, errors, warnings);\r\n validateIdAliasesSemantic(config, context, warnings);\r\n validateSeedRoutesSemantic(config, context, errors);\r\n validateSeedDependenciesSemantic(config, errors, warnings);\r\n\r\n return { passed: errors.length === 0, layer: 'semantic', errors, warnings };\r\n}\r\n\r\n// ============================================================\r\n// Helpers\r\n// ============================================================\r\n\r\nfunction normalizePath(p: string): string {\r\n return p.replace(/\\/+$/, '').replace(/\\/+/g, '/');\r\n}\r\n\r\nfunction extractPathParams(routePath: string): string[] {\r\n const params: string[] = [];\r\n const regex = /:(\\w+)/g;\r\n let match;\r\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\r\n return params;\r\n}\r\n\r\nfunction findMatchingEndpoint(\r\n method: string, configPath: string, endpoints: ApiEndpoint[],\r\n): ApiEndpoint | undefined {\r\n const normalized = normalizePath(configPath);\r\n return endpoints.find((ep) => {\r\n if (ep.method !== method.toUpperCase()) return false;\r\n const epNorm = normalizePath(ep.path);\r\n if (epNorm === normalized) return true;\r\n const cSegs = normalized.split('/');\r\n const eSegs = epNorm.split('/');\r\n if (cSegs.length !== eSegs.length) return false;\r\n return cSegs.every((seg, idx) => seg === eSegs[idx] || seg.startsWith(':') || eSegs[idx].startsWith(':'));\r\n });\r\n}\r\n\r\nfunction findMatchingDTO(method: string, dtos: DTOInfo[]): DTOInfo | undefined {\r\n if (dtos.length === 0) return undefined;\r\n if (['POST'].includes(method)) return dtos.find((d) => /Create|Input|Request/.test(d.name));\r\n if (['PUT', 'PATCH'].includes(method)) return dtos.find((d) => /Update/.test(d.name)) || dtos.find((d) => /Create|Input/.test(d.name));\r\n if (['GET'].includes(method)) return dtos.find((d) => /Query|List|Params/.test(d.name));\r\n return undefined;\r\n}\r\n\r\n// ============================================================\r\n// Validators\r\n// ============================================================\r\n\r\nfunction validateBodyTemplatesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const p = `bodyTemplates.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: p,\r\n message: `Route '${method} ${routePath}' in bodyTemplates does not match any parsed API endpoint`,\r\n suggestion: `Check that the controller defines ${method} ${routePath}`,\r\n });\r\n continue;\r\n }\r\n\r\n const bodyFields = Object.keys(body);\r\n if (bodyFields.length === 0) continue;\r\n\r\n const dto = findMatchingDTO(method, ctx.dtos);\r\n if (!dto) {\r\n warnings.push({ layer: 'semantic', path: p, message: `No matching DTO found for '${method} ${routePath}', cannot verify field completeness` });\r\n continue;\r\n }\r\n\r\n const dtoFieldNames = new Set(dto.fields.map((f) => f.name));\r\n for (const fieldName of bodyFields) {\r\n if (!dtoFieldNames.has(fieldName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${fieldName}`, message: `Field '${fieldName}' in body template not found in DTO '${dto.name}'` });\r\n }\r\n }\r\n\r\n const bodyFieldSet = new Set(bodyFields);\r\n for (const field of dto.fields) {\r\n if (field.required && !field.isSystemField && !bodyFieldSet.has(field.name)) {\r\n warnings.push({ layer: 'semantic', path: p, message: `Required DTO field '${field.name}' (from ${dto.name}) not present in body template` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateParamRewritesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (const [key, mapping] of Object.entries(config.paramRewrites)) {\r\n const p = `paramRewrites.${key}`;\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n\r\n const method = key.substring(0, spaceIdx).toUpperCase();\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n const endpoint = findMatchingEndpoint(method, routePath, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({ layer: 'semantic', type: 'param-mapping-invalid', path: p, message: `Route '${method} ${routePath}' in paramRewrites does not match any parsed API endpoint` });\r\n continue;\r\n }\r\n\r\n const actualParams = new Set(extractPathParams(endpoint.path));\r\n for (const paramName of Object.keys(mapping)) {\r\n if (!actualParams.has(paramName)) {\r\n warnings.push({ layer: 'semantic', path: `${p}.${paramName}`, message: `Param '${paramName}' in paramRewrites not found in route path params [${[...actualParams].join(', ')}]` });\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction validateIdAliasesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n for (let i = 0; i < config.idAliases.length; i++) {\r\n const alias = config.idAliases[i];\r\n const matched = ctx.endpoints.some((ep) => {\r\n try { return new RegExp(alias.pathPattern).test(ep.path); } catch { return ep.path.includes(alias.pathPattern); }\r\n });\r\n if (!matched) {\r\n warnings.push({ layer: 'semantic', path: `idAliases[${i}].pathPattern`, message: `idAlias pathPattern '${alias.pathPattern}' does not match any known API route` });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedRoutesSemantic(\r\n config: ModuleTestConfig,\r\n ctx: ModuleConfigValidationContext,\r\n errors: ModuleConfigValidationError[],\r\n): void {\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n const endpoint = findMatchingEndpoint(step.method, step.path, ctx.endpoints);\r\n if (!endpoint) {\r\n errors.push({\r\n layer: 'semantic', type: 'interface-not-found', path: `seed[${i}].path`,\r\n message: `Seed step ${step.step}: route '${step.method} ${step.path}' does not match any parsed API endpoint`,\r\n suggestion: `Verify that '${step.method} ${step.path}' exists in the module controllers`,\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction validateSeedDependenciesSemantic(\r\n config: ModuleTestConfig,\r\n errors: ModuleConfigValidationError[],\r\n warnings: ModuleConfigValidationWarning[],\r\n): void {\r\n if (config.seed.length === 0) return;\r\n\r\n const capturedSet = new Set<string>();\r\n const variablePattern = /\\{\\{(\\w+)\\}\\}|\\$\\{(\\w+)\\}/g;\r\n\r\n for (let i = 0; i < config.seed.length; i++) {\r\n const step = config.seed[i];\r\n\r\n // Check body variable references\r\n if (step.body) {\r\n const bodyStr = JSON.stringify(step.body);\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(bodyStr)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].body`, message: `Body references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n // Check path variable references\r\n if (step.path) {\r\n variablePattern.lastIndex = 0;\r\n let match;\r\n while ((match = variablePattern.exec(step.path)) !== null) {\r\n const varName = match[1] || match[2];\r\n if (!capturedSet.has(varName)) {\r\n warnings.push({ layer: 'semantic', path: `seed[${i}].path`, message: `Path references variable '${varName}' which may not be captured by a preceding seed step` });\r\n }\r\n }\r\n }\r\n\r\n if (step.captureAs) capturedSet.add(step.captureAs);\r\n }\r\n\r\n // Cycle detection via DFS\r\n detectDependencyCycle(config.seed, errors);\r\n}\r\n\r\nfunction detectDependencyCycle(seed: SeedStep[], errors: ModuleConfigValidationError[]): void {\r\n const graph = new Map<string, string[]>();\r\n for (const step of seed) {\r\n if (step.captureAs) {\r\n graph.set(step.captureAs, step.dependsOn || []);\r\n }\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n\r\n function dfs(node: string): boolean {\r\n if (inStack.has(node)) return true;\r\n if (visited.has(node)) return false;\r\n visited.add(node);\r\n inStack.add(node);\r\n for (const neighbor of graph.get(node) || []) {\r\n if (dfs(neighbor)) {\r\n errors.push({ layer: 'semantic', type: 'dependency-cycle', path: 'seed', message: `Circular dependency detected involving '${node}' → '${neighbor}'` });\r\n return true;\r\n }\r\n }\r\n inStack.delete(node);\r\n return false;\r\n }\r\n\r\n for (const node of graph.keys()) {\r\n if (!visited.has(node)) dfs(node);\r\n }\r\n}\r\n","/**\r\n * Dry-run Validator — Layer 3 of three-layer module config validation.\r\n * Generates temporary TypeScript code from config and runs ts-morph compile check.\r\n */\r\n\r\nimport { Project, DiagnosticCategory } from 'ts-morph';\r\nimport type {\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n LayerValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\n\r\nexport function validateDryrun(\r\n config: ModuleTestConfig,\r\n _context: ModuleConfigValidationContext,\r\n): LayerValidationResult {\r\n const errors: ModuleConfigValidationError[] = [];\r\n const warnings: ModuleConfigValidationWarning[] = [];\r\n\r\n const project = new Project({\r\n compilerOptions: {\r\n strict: false,\r\n noEmit: true,\r\n target: 2, // ES2015\r\n module: 1, // CommonJS\r\n esModuleInterop: true,\r\n skipLibCheck: true,\r\n },\r\n useInMemoryFileSystem: true,\r\n });\r\n\r\n // Add helper type declarations\r\n project.createSourceFile(\r\n '__helpers.d.ts',\r\n `\r\ndeclare function apiRequest(\r\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH',\r\n path: string,\r\n body?: Record<string, any>,\r\n params?: Record<string, string>\r\n): Promise<{ status: number; data: any }>;\r\ndeclare function captureId(response: { data: any }, field?: string): string;\r\ndeclare const tenantId: string;\r\ndeclare const captured: Record<string, string>;\r\n`,\r\n );\r\n\r\n // Generate and check bodyTemplates test code\r\n const bodyCode = generateBodyTemplateTestCode(config);\r\n if (bodyCode) {\r\n const bodyFile = project.createSourceFile('__dryrun_body_test.ts', bodyCode);\r\n for (const diag of bodyFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `bodyTemplates (line ${line})` : 'bodyTemplates';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the body template that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n // Generate and check seed test code\r\n const seedCode = generateSeedTestCode(config);\r\n if (seedCode) {\r\n const seedFile = project.createSourceFile('__dryrun_seed_test.ts', seedCode);\r\n for (const diag of seedFile.getPreEmitDiagnostics()) {\r\n const msg = diag.getMessageText();\r\n const msgStr = typeof msg === 'string' ? msg : msg.getMessageText();\r\n const line = diag.getLineNumber();\r\n const location = line ? `seed (line ${line})` : 'seed';\r\n\r\n if (diag.getCategory() === DiagnosticCategory.Error) {\r\n errors.push({\r\n layer: 'dryrun', type: 'compile-error', path: location,\r\n message: `TypeScript compile error: ${msgStr}`,\r\n suggestion: 'Fix the seed step that causes this type error',\r\n });\r\n } else if (diag.getCategory() === DiagnosticCategory.Warning) {\r\n warnings.push({ layer: 'dryrun', path: location, message: `TypeScript warning: ${msgStr}` });\r\n }\r\n }\r\n }\r\n\r\n return { passed: errors.length === 0, layer: 'dryrun', errors, warnings };\r\n}\r\n\r\nfunction generateBodyTemplateTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.bodyTemplates || Object.keys(config.bodyTemplates).length === 0) return null;\r\n\r\n const lines = ['async function testBodyTemplates() {'];\r\n let idx = 0;\r\n for (const [key, body] of Object.entries(config.bodyTemplates)) {\r\n const spaceIdx = key.indexOf(' ');\r\n if (spaceIdx === -1) continue;\r\n const method = key.substring(0, spaceIdx);\r\n const routePath = key.substring(spaceIdx + 1);\r\n\r\n lines.push(` const body_${idx} = ${JSON.stringify(body, null, 2)};`);\r\n lines.push(` const result_${idx} = await apiRequest('${method}', '${routePath}', body_${idx});`);\r\n lines.push(` if (result_${idx}.status !== 200 && result_${idx}.status !== 201) {`);\r\n lines.push(` throw new Error('Unexpected status: ' + result_${idx}.status);`);\r\n lines.push(' }');\r\n idx++;\r\n }\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction generateSeedTestCode(config: ModuleTestConfig): string | null {\r\n if (!config.seed || config.seed.length === 0) return null;\r\n\r\n const lines = [\r\n 'async function testSeedSteps() {',\r\n ' const captured: Record<string, string> = {};',\r\n '',\r\n ];\r\n\r\n for (const step of config.seed) {\r\n if (step.body) {\r\n lines.push(` const body_step${step.step} = ${JSON.stringify(step.body, null, 2)};`);\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}', body_step${step.step});`);\r\n } else {\r\n lines.push(` const result_step${step.step} = await apiRequest('${step.method}', '${step.path}');`);\r\n }\r\n\r\n if (step.captureAs) {\r\n lines.push(` captured['${step.captureAs}'] = captureId(result_step${step.step});`);\r\n }\r\n\r\n if (step.required) {\r\n lines.push(` if (result_step${step.step}.status >= 400) {`);\r\n lines.push(` throw new Error('${step.failureMessage || `Required step ${step.step} failed`}');`);\r\n lines.push(' }');\r\n }\r\n lines.push('');\r\n }\r\n\r\n lines.push('}');\r\n return lines.join('\\n');\r\n}\r\n","import type {\r\n ValidationError,\r\n ModuleTestConfig,\r\n ModuleConfigValidationContext,\r\n ModuleConfigValidationResult,\r\n ModuleConfigValidationError,\r\n ModuleConfigValidationWarning,\r\n} from '../types.js';\r\nimport { validateSchema } from './schema-validator.js';\r\nimport { validateSemantic } from './semantic-validator.js';\r\nimport { validateDryrun } from './dryrun-validator.js';\r\n\r\nconst REQUIRED_FIELDS = ['backendRoot'];\r\n\r\nconst VALID_ADAPTERS = ['sequelize', 'typeorm', 'prisma', 'drizzle'];\r\nconst VALID_STEPS = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\nconst VALID_LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'custom'];\r\nconst VALID_REPORT_FORMATS = ['html', 'json', 'markdown'];\r\nconst VALID_HEAL_MODES = ['config-only', 'config-and-source'];\r\n\r\n/**\r\n * Validate an OpenCroc configuration object.\r\n * Returns an array of ValidationErrors (empty = valid).\r\n */\r\nexport function validateConfig(config: Record<string, unknown>): ValidationError[] {\r\n const errors: ValidationError[] = [];\r\n\r\n // Required fields\r\n for (const field of REQUIRED_FIELDS) {\r\n if (!config[field]) {\r\n errors.push({\r\n module: 'config',\r\n field,\r\n message: `Missing required field: ${field}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // backendRoot must be a string\r\n if (config.backendRoot && typeof config.backendRoot !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: 'backendRoot',\r\n message: 'backendRoot must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n // adapter validation\r\n if (config.adapter && typeof config.adapter === 'string') {\r\n if (!VALID_ADAPTERS.includes(config.adapter)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'adapter',\r\n message: `Invalid adapter: ${config.adapter}. Must be one of: ${VALID_ADAPTERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // steps validation\r\n if (config.steps && Array.isArray(config.steps)) {\r\n for (const step of config.steps) {\r\n if (!VALID_STEPS.includes(step as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'steps',\r\n message: `Invalid pipeline step: ${step}. Must be one of: ${VALID_STEPS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n // LLM config validation\r\n if (config.llm && typeof config.llm === 'object') {\r\n const llm = config.llm as Record<string, unknown>;\r\n if (llm.provider && !VALID_LLM_PROVIDERS.includes(llm.provider as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.provider',\r\n message: `Invalid LLM provider: ${llm.provider}. Must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (llm.provider && llm.provider !== 'ollama' && !llm.apiKey) {\r\n errors.push({\r\n module: 'config',\r\n field: 'llm.apiKey',\r\n message: 'LLM apiKey is required for cloud providers',\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n\r\n // Report config validation\r\n if (config.report && typeof config.report === 'object') {\r\n const report = config.report as Record<string, unknown>;\r\n if (report.format && Array.isArray(report.format)) {\r\n for (const fmt of report.format) {\r\n if (!VALID_REPORT_FORMATS.includes(fmt as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'report.format',\r\n message: `Invalid report format: ${fmt}. Must be one of: ${VALID_REPORT_FORMATS.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Self-healing config validation\r\n if (config.selfHealing && typeof config.selfHealing === 'object') {\r\n const sh = config.selfHealing as Record<string, unknown>;\r\n if (sh.mode && !VALID_HEAL_MODES.includes(sh.mode as string)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.mode',\r\n message: `Invalid self-healing mode: ${sh.mode}. Must be one of: ${VALID_HEAL_MODES.join(', ')}`,\r\n severity: 'error',\r\n });\r\n }\r\n if (sh.maxIterations && (typeof sh.maxIterations !== 'number' || sh.maxIterations < 1)) {\r\n errors.push({\r\n module: 'config',\r\n field: 'selfHealing.maxIterations',\r\n message: 'maxIterations must be a positive number',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n\r\n // Execution hooks validation\r\n if (config.execution && typeof config.execution === 'object') {\r\n const execution = config.execution as Record<string, unknown>;\r\n const hookFields = ['setupHook', 'authHook', 'teardownHook'];\r\n\r\n for (const hookField of hookFields) {\r\n const hook = execution[hookField];\r\n if (hook === undefined) continue;\r\n\r\n if (typeof hook === 'string') continue;\r\n\r\n if (typeof hook !== 'object' || hook === null) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}`,\r\n message: `${hookField} must be a string command or an object { command, args?, cwd? }`,\r\n severity: 'error',\r\n });\r\n continue;\r\n }\r\n\r\n const hookObj = hook as Record<string, unknown>;\r\n if (typeof hookObj.command !== 'string' || hookObj.command.trim() === '') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.command`,\r\n message: 'command is required and must be a non-empty string',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.args !== undefined && (!Array.isArray(hookObj.args) || hookObj.args.some((a) => typeof a !== 'string'))) {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.args`,\r\n message: 'args must be an array of strings',\r\n severity: 'error',\r\n });\r\n }\r\n\r\n if (hookObj.cwd !== undefined && typeof hookObj.cwd !== 'string') {\r\n errors.push({\r\n module: 'config',\r\n field: `execution.${hookField}.cwd`,\r\n message: 'cwd must be a string path',\r\n severity: 'error',\r\n });\r\n }\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n// ============================================================\r\n// Three-Layer Module Config Validator\r\n// ============================================================\r\n\r\nexport interface ValidateModuleConfigOptions {\r\n stopOnFailure?: boolean;\r\n skipLayers?: Array<'schema' | 'semantic' | 'dryrun'>;\r\n}\r\n\r\nexport function validateModuleConfig(\r\n config: unknown,\r\n context?: ModuleConfigValidationContext,\r\n options?: ValidateModuleConfigOptions,\r\n): ModuleConfigValidationResult {\r\n const stopOnFailure = options?.stopOnFailure ?? true;\r\n const skipLayers = new Set(options?.skipLayers ?? []);\r\n\r\n const allErrors: ModuleConfigValidationError[] = [];\r\n const allWarnings: ModuleConfigValidationWarning[] = [];\r\n const result: ModuleConfigValidationResult = {\r\n passed: false,\r\n errors: allErrors,\r\n warnings: allWarnings,\r\n };\r\n\r\n if (!skipLayers.has('schema')) {\r\n const schemaResult = validateSchema(config);\r\n result.schemaResult = schemaResult;\r\n allErrors.push(...schemaResult.errors);\r\n allWarnings.push(...schemaResult.warnings);\r\n\r\n if (!schemaResult.passed) {\r\n result.failedAtLayer = 'schema';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'schema';\r\n }\r\n }\r\n\r\n const validConfig = config as ModuleTestConfig;\r\n\r\n if (!skipLayers.has('semantic')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'semantic', path: '', message: 'ValidationContext not provided, skipping semantic validation' });\r\n } else {\r\n const semanticResult = validateSemantic(validConfig, context);\r\n result.semanticResult = semanticResult;\r\n allErrors.push(...semanticResult.errors);\r\n allWarnings.push(...semanticResult.warnings);\r\n\r\n if (!semanticResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'semantic';\r\n if (stopOnFailure) return result;\r\n } else {\r\n result.lastPassedLayer = 'semantic';\r\n }\r\n }\r\n }\r\n\r\n if (!skipLayers.has('dryrun')) {\r\n if (!context) {\r\n allWarnings.push({ layer: 'dryrun', path: '', message: 'ValidationContext not provided, skipping dry-run validation' });\r\n } else {\r\n const dryrunResult = validateDryrun(validConfig, context);\r\n result.dryrunResult = dryrunResult;\r\n allErrors.push(...dryrunResult.errors);\r\n allWarnings.push(...dryrunResult.warnings);\r\n\r\n if (!dryrunResult.passed) {\r\n result.failedAtLayer = result.failedAtLayer || 'dryrun';\r\n } else {\r\n result.lastPassedLayer = 'dryrun';\r\n }\r\n }\r\n }\r\n\r\n result.passed = allErrors.length === 0;\r\n return result;\r\n}\r\n\r\nexport function formatValidationResult(result: ModuleConfigValidationResult): string {\r\n const lines: string[] = [];\r\n lines.push(result.passed ? '\\u2705 Validation PASSED' : '\\u274c Validation FAILED');\r\n if (result.failedAtLayer) lines.push(` Failed at layer: ${result.failedAtLayer}`);\r\n if (result.lastPassedLayer) lines.push(` Last passed layer: ${result.lastPassedLayer}`);\r\n\r\n if (result.errors.length > 0) {\r\n lines.push('', `Errors (${result.errors.length}):`);\r\n for (const err of result.errors) {\r\n lines.push(` [${err.layer}] ${err.path}: ${err.message}`);\r\n if (err.suggestion) lines.push(` \\ud83d\\udca1 ${err.suggestion}`);\r\n }\r\n }\r\n\r\n if (result.warnings.length > 0) {\r\n lines.push('', `Warnings (${result.warnings.length}):`);\r\n for (const warn of result.warnings) {\r\n lines.push(` [${warn.layer}] ${warn.path}: ${warn.message}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n PipelineStep,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n} from '../types.js';\r\nimport { parseModuleModels } from '../parsers/model-parser.js';\r\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\r\nimport { parseAssociationFile } from '../parsers/association-parser.js';\r\nimport { createApiChainAnalyzer, topologicalSort } from '../analyzers/api-chain-analyzer.js';\r\nimport { createERDiagramGenerator } from '../generators/er-diagram-generator.js';\r\nimport { createTestCodeGenerator } from '../generators/test-code-generator.js';\r\nimport { validateConfig } from '../validators/config-validator.js';\r\n\r\nexport interface Pipeline {\r\n run(steps?: PipelineStep[]): Promise<PipelineRunResult>;\r\n}\r\n\r\nconst ALL_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\n\r\nexport function createPipeline(config: OpenCrocConfig): Pipeline {\r\n return {\r\n async run(steps) {\r\n const startTime = Date.now();\r\n const activeSteps = steps || config.steps || ALL_STEPS;\r\n\r\n const result: PipelineRunResult = {\r\n modules: [],\r\n erDiagrams: new Map(),\r\n chainPlans: new Map(),\r\n generatedFiles: [],\r\n validationErrors: [],\r\n duration: 0,\r\n };\r\n\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n // Smart discovery: find models/ and controllers/ in common locations\r\n const findDir = (name: string): string | null => {\r\n const candidates = [\r\n path.join(backendRoot, name), // ./models\r\n path.join(backendRoot, 'src', name), // ./src/models\r\n path.join(backendRoot, 'backend', 'src', name), // ./backend/src/models\r\n path.join(backendRoot, 'backend', name), // ./backend/models\r\n path.join(backendRoot, 'server', 'src', name), // ./server/src/models\r\n path.join(backendRoot, 'app', name), // ./app/models\r\n ];\r\n for (const c of candidates) {\r\n if (fs.existsSync(c)) return c;\r\n }\r\n return null;\r\n };\r\n\r\n const modelsRoot = findDir('models');\r\n const controllersRoot = findDir('controllers');\r\n\r\n // Step 1: Scan — discover modules\r\n if (activeSteps.includes('scan')) {\r\n if (modelsRoot) {\r\n // Discover modules from subdirectories\r\n const dirs = fs.readdirSync(modelsRoot, { withFileTypes: true })\r\n .filter((d) => d.isDirectory())\r\n .map((d) => d.name);\r\n\r\n const moduleFilter = config.modules;\r\n for (const dir of dirs) {\r\n if (moduleFilter && !moduleFilter.includes(dir)) continue;\r\n result.modules.push(dir);\r\n }\r\n\r\n // If no subdirectories, treat root as single \"default\" module\r\n if (result.modules.length === 0) {\r\n result.modules.push('default');\r\n } else {\r\n // Also include root-level model files as \"default\" module\r\n const rootFiles = fs.readdirSync(modelsRoot)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts');\r\n if (rootFiles.length > 0) {\r\n result.modules.unshift('default');\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Helper: resolve model dir for a module\r\n const resolveModelDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (modelsRoot || path.join(backendRoot, 'models'))\r\n : path.join(modelsRoot || path.join(backendRoot, 'models'), mod);\r\n\r\n // Helper: resolve controller dir for a module\r\n const resolveControllerDir = (_backendRoot: string, mod: string): string =>\r\n mod === 'default'\r\n ? (controllersRoot || path.join(backendRoot, 'controllers'))\r\n : path.join(controllersRoot || path.join(backendRoot, 'controllers'), mod);\r\n\r\n // Step 2: ER Diagram — parse models and generate relationship graphs\r\n if (activeSteps.includes('er-diagram')) {\r\n const erGen = createERDiagramGenerator();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const modelDir = resolveModelDir(backendRoot, mod);\r\n\r\n // For flat layouts, scan all model files for embedded associations\r\n const tables = fs.existsSync(modelDir) ? parseModuleModels(modelDir) : [];\r\n const relations: import('../types.js').ForeignKeyRelation[] = [];\r\n\r\n // Check for dedicated associations.ts first\r\n const assocFile = path.join(modelDir, 'associations.ts');\r\n if (fs.existsSync(assocFile)) {\r\n relations.push(...parseAssociationFile(assocFile));\r\n }\r\n\r\n // Also scan model files for embedded associations (belongsTo/hasMany at end of file)\r\n if (fs.existsSync(modelDir)) {\r\n const modelFiles = fs.readdirSync(modelDir)\r\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts');\r\n for (const file of modelFiles) {\r\n try {\r\n const embedded = parseAssociationFile(path.join(modelDir, file));\r\n relations.push(...embedded);\r\n } catch {\r\n // skip files that fail to parse\r\n }\r\n }\r\n }\r\n\r\n const erResult: ERDiagramResult = erGen.generate(tables, relations);\r\n result.erDiagrams.set(mod, erResult);\r\n }\r\n }\r\n\r\n // Step 3: API Chain — analyze controller routes and build dependency DAG\r\n if (activeSteps.includes('api-chain')) {\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n const backendRoot = path.resolve(config.backendRoot);\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n analysis.moduleName = mod;\r\n\r\n if (analysis.hasCycles) {\r\n for (const warning of analysis.cycleWarnings) {\r\n result.validationErrors.push({\r\n module: mod,\r\n field: 'api-chain',\r\n message: warning,\r\n severity: 'warning',\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Step 4: Plan — generate test chains from dependency analysis\r\n if (activeSteps.includes('plan')) {\r\n const backendRoot = path.resolve(config.backendRoot);\r\n const chainAnalyzer = createApiChainAnalyzer();\r\n\r\n for (const mod of result.modules) {\r\n const controllerDir = resolveControllerDir(backendRoot, mod);\r\n const endpoints = fs.existsSync(controllerDir)\r\n ? parseControllerDirectory(controllerDir)\r\n : [];\r\n\r\n const analysis = chainAnalyzer.analyze(endpoints);\r\n const topoOrder = topologicalSort(analysis.dag);\r\n\r\n // Group by resource to create chains\r\n const chains = generateChainPlan(mod, endpoints, topoOrder);\r\n result.chainPlans.set(mod, chains);\r\n }\r\n }\r\n\r\n // Step 5: Codegen — emit Playwright test files from chain plans\r\n if (activeSteps.includes('codegen')) {\r\n const testGen = createTestCodeGenerator();\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n for (const [_mod, plan] of result.chainPlans) {\r\n const files = testGen.generate(plan.chains);\r\n for (const file of files) {\r\n file.filePath = path.join(outDir, file.filePath);\r\n }\r\n result.generatedFiles.push(...files);\r\n }\r\n }\r\n\r\n // Step 6: Validate — run validation on generated configs\r\n if (activeSteps.includes('validate')) {\r\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\r\n result.validationErrors.push(...configErrors);\r\n }\r\n\r\n result.duration = Date.now() - startTime;\r\n return result;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Generate a basic chain plan from endpoints and topological order.\r\n */\r\nfunction generateChainPlan(\r\n moduleName: string,\r\n endpoints: import('../types.js').ApiEndpoint[],\r\n _topoOrder: string[],\r\n): ChainPlanResult {\r\n // Group endpoints by resource (first non-param path segment)\r\n const groups = new Map<string, import('../types.js').ApiEndpoint[]>();\r\n\r\n for (const ep of endpoints) {\r\n const segments = ep.path.split('/').filter((s) => s && !s.startsWith(':'));\r\n const resource = segments[segments.length - 1] || 'default';\r\n if (!groups.has(resource)) groups.set(resource, []);\r\n groups.get(resource)!.push(ep);\r\n }\r\n\r\n const chains: import('../types.js').TestChain[] = [];\r\n let totalSteps = 0;\r\n\r\n for (const [resource, eps] of groups) {\r\n const steps: import('../types.js').TestStep[] = eps.map((ep, i) => ({\r\n order: i + 1,\r\n action: ep.method,\r\n endpoint: ep,\r\n description: ep.description || `${ep.method} ${ep.path}`,\r\n assertions: [],\r\n }));\r\n\r\n chains.push({ name: `${resource} CRUD chain`, module: moduleName, steps });\r\n totalSteps += steps.length;\r\n }\r\n\r\n return { chains, totalSteps };\r\n}\r\n","import chalk from 'chalk';\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport type { PipelineStep, PipelineRunResult } from '../../types.js';\r\n\r\nconst VALID_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\r\n\r\nexport interface GenerateOptions {\r\n module?: string;\r\n all?: boolean;\r\n steps?: string;\r\n dryRun?: boolean;\r\n}\r\n\r\nfunction parseSteps(raw?: string): PipelineStep[] | undefined {\r\n if (!raw) return undefined;\r\n const names = raw.split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n if (!VALID_STEPS.includes(name as PipelineStep)) {\r\n throw new Error(`Unknown pipeline step \"${name}\". Valid steps: ${VALID_STEPS.join(', ')}`);\r\n }\r\n }\r\n return names as PipelineStep[];\r\n}\r\n\r\nfunction writeGeneratedFiles(result: PipelineRunResult): number {\r\n let written = 0;\r\n for (const file of result.generatedFiles) {\r\n const dir = dirname(file.filePath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n writeFileSync(file.filePath, file.content, 'utf-8');\r\n written++;\r\n console.log(chalk.green(` ✓ ${file.filePath}`));\r\n }\r\n return written;\r\n}\r\n\r\nfunction printSummary(result: PipelineRunResult, dryRun: boolean): void {\r\n console.log('');\r\n console.log(chalk.cyan.bold(' Summary'));\r\n console.log(` Modules discovered : ${result.modules.length}`);\r\n console.log(` ER diagrams : ${result.erDiagrams.size}`);\r\n console.log(` Chain plans : ${result.chainPlans.size}`);\r\n console.log(` Generated files : ${result.generatedFiles.length}${dryRun ? ' (dry-run, not written)' : ''}`);\r\n\r\n if (result.validationErrors.length > 0) {\r\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\r\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\r\n if (errors.length > 0) console.log(chalk.red(` Errors : ${errors.length}`));\r\n if (warnings.length > 0) console.log(chalk.yellow(` Warnings : ${warnings.length}`));\r\n\r\n for (const err of result.validationErrors) {\r\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\r\n console.log(` ${icon} [${err.module}] ${err.message}`);\r\n }\r\n }\r\n\r\n console.log(chalk.gray(` Duration : ${result.duration}ms`));\r\n console.log('');\r\n}\r\n\r\nexport async function generate(opts: GenerateOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Generate E2E Tests\\n'));\r\n\r\n // Load config\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n // Apply --module filter\r\n if (opts.module) {\r\n config.modules = [opts.module];\r\n }\r\n\r\n // Parse --steps\r\n const steps = parseSteps(opts.steps);\r\n\r\n // Create and run pipeline\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run(steps);\r\n\r\n // Write files (unless dry-run)\r\n if (!opts.dryRun && result.generatedFiles.length > 0) {\r\n console.log('');\r\n console.log(chalk.cyan(' Generated files:'));\r\n writeGeneratedFiles(result);\r\n } else if (opts.dryRun && result.generatedFiles.length > 0) {\r\n console.log('');\r\n console.log(chalk.yellow(' Dry-run — files that would be generated:'));\r\n for (const file of result.generatedFiles) {\r\n console.log(chalk.gray(` ${file.filePath}`));\r\n }\r\n }\r\n\r\n printSummary(result, !!opts.dryRun);\r\n}\r\n","import chalk from 'chalk';\r\nimport { readdirSync, existsSync } from 'node:fs';\r\nimport { join, resolve } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport { loadConfig } from '../load-config.js';\r\nimport type { ExecutionConfig, HookConfig } from '../../types.js';\r\n\r\nexport interface TestOptions {\r\n module?: string;\r\n headed?: boolean;\r\n setupHook?: string;\r\n authHook?: string;\r\n teardownHook?: string;\r\n}\r\n\r\nfunction normalizeHook(hook: HookConfig | undefined): HookConfig | undefined {\r\n if (!hook) return undefined;\r\n if (typeof hook === 'string') return hook.trim() ? hook : undefined;\r\n return hook.command.trim() ? hook : undefined;\r\n}\r\n\r\nfunction runShellCommand(command: string): void {\r\n if (process.platform === 'win32') {\r\n execFileSync('cmd.exe', ['/d', '/s', '/c', command], {\r\n stdio: 'inherit',\r\n cwd: process.cwd(),\r\n });\r\n return;\r\n }\r\n\r\n execFileSync('sh', ['-lc', command], {\r\n stdio: 'inherit',\r\n cwd: process.cwd(),\r\n });\r\n}\r\n\r\nfunction runHook(name: string, hook: HookConfig | undefined): void {\r\n const normalized = normalizeHook(hook);\r\n if (!normalized) return;\r\n\r\n console.log(chalk.cyan(` Running ${name} hook...`));\r\n\r\n if (typeof normalized === 'string') {\r\n runShellCommand(normalized);\r\n console.log(chalk.green(` ✓ ${name} hook passed`));\r\n return;\r\n }\r\n\r\n execFileSync(normalized.command, normalized.args ?? [], {\r\n stdio: 'inherit',\r\n cwd: normalized.cwd ? resolve(normalized.cwd) : process.cwd(),\r\n });\r\n console.log(chalk.green(` ✓ ${name} hook passed`));\r\n}\r\n\r\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\r\n const absDir = resolve(outDir);\r\n if (!existsSync(absDir)) return [];\r\n\r\n const files: string[] = [];\r\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\r\n for (const entry of entries) {\r\n if (!entry.isFile()) continue;\r\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\r\n const fullPath = join(entry.parentPath || (entry as unknown as { path: string }).path || absDir, entry.name);\r\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\r\n files.push(fullPath);\r\n }\r\n return files;\r\n}\r\n\r\nexport async function runTests(opts: TestOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Run E2E Tests\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const execution: ExecutionConfig = {\r\n ...(config.execution || {}),\r\n ...(opts.setupHook ? { setupHook: opts.setupHook } : {}),\r\n ...(opts.authHook ? { authHook: opts.authHook } : {}),\r\n ...(opts.teardownHook ? { teardownHook: opts.teardownHook } : {}),\r\n };\r\n\r\n try {\r\n runHook('setup', execution.setupHook);\r\n runHook('auth', execution.authHook);\r\n } catch {\r\n console.log(chalk.red(' ✗ setup/auth hook failed. Abort test run.\\n'));\r\n process.exitCode = 1;\r\n try {\r\n runHook('teardown', execution.teardownHook);\r\n } catch {\r\n console.log(chalk.red(' ✗ teardown hook also failed.\\n'));\r\n }\r\n return;\r\n }\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const testFiles = discoverTestFiles(outDir, opts.module);\r\n\r\n if (testFiles.length === 0) {\r\n console.log(chalk.yellow(' No test files found. Run `opencroc generate` first.\\n'));\r\n return;\r\n }\r\n\r\n console.log(` Found ${testFiles.length} test file(s)`);\r\n for (const f of testFiles) {\r\n console.log(chalk.gray(` ${f}`));\r\n }\r\n console.log('');\r\n\r\n // Build Playwright args\r\n const args = ['test', ...testFiles];\r\n if (!opts.headed) {\r\n args.push('--reporter=list');\r\n } else {\r\n args.push('--headed');\r\n }\r\n\r\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\r\n\r\n try {\r\n console.log(chalk.cyan(' Running Playwright...\\n'));\r\n execFileSync(npxCmd, ['playwright', ...args], {\r\n stdio: 'inherit',\r\n cwd: process.cwd(),\r\n });\r\n console.log(chalk.green('\\n ✓ All tests passed.\\n'));\r\n } catch {\r\n console.log(chalk.red('\\n ✗ Some tests failed.\\n'));\r\n process.exitCode = 1;\r\n } finally {\r\n try {\r\n runHook('teardown', execution.teardownHook);\r\n } catch {\r\n console.log(chalk.red(' ✗ teardown hook failed.\\n'));\r\n process.exitCode = 1;\r\n }\r\n }\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { validateConfig } from '../../validators/config-validator.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport type { ValidationError } from '../../types.js';\r\n\r\nexport interface ValidateOptions {\r\n module?: string;\r\n}\r\n\r\nfunction printErrors(errors: ValidationError[]): void {\r\n for (const err of errors) {\r\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\r\n const scope = err.module === 'config' ? '' : ` [${err.module}]`;\r\n console.log(` ${icon}${scope} ${err.field}: ${err.message}`);\r\n }\r\n}\r\n\r\nexport async function validate(opts: ValidateOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Validate\\n'));\r\n\r\n // Load and validate config\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\r\n\r\n // Apply module filter\r\n if (opts.module) {\r\n config.modules = [opts.module];\r\n }\r\n\r\n // Run pipeline in scan + validate mode to discover module-level issues\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run(['scan', 'validate']);\r\n\r\n const allErrors = [...configErrors, ...result.validationErrors];\r\n const errors = allErrors.filter((e) => e.severity === 'error');\r\n const warnings = allErrors.filter((e) => e.severity === 'warning');\r\n\r\n if (allErrors.length === 0) {\r\n console.log(chalk.green(' ✓ Configuration is valid.'));\r\n console.log(chalk.gray(` Modules: ${result.modules.join(', ') || '(none)'}\\n`));\r\n return;\r\n }\r\n\r\n if (errors.length > 0) {\r\n console.log(chalk.red(` ${errors.length} error(s):`));\r\n printErrors(errors);\r\n }\r\n if (warnings.length > 0) {\r\n console.log(chalk.yellow(` ${warnings.length} warning(s):`));\r\n printErrors(warnings);\r\n }\r\n\r\n console.log('');\r\n\r\n if (errors.length > 0) {\r\n process.exitCode = 1;\r\n }\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\nexport interface ChatMessage {\r\n role: 'system' | 'user' | 'assistant';\r\n content: string;\r\n}\r\n\r\ninterface OpenAIResponse {\r\n choices: Array<{ message: { content: string } }>;\r\n usage?: { total_tokens: number };\r\n}\r\n\r\nconst DEFAULT_MODELS: Record<string, string> = {\r\n openai: 'gpt-4o-mini',\r\n zhipu: 'glm-4',\r\n};\r\n\r\nconst DEFAULT_BASE_URLS: Record<string, string> = {\r\n openai: 'https://api.openai.com/v1',\r\n zhipu: 'https://open.bigmodel.cn/api/paas/v4',\r\n};\r\n\r\n/**\r\n * Create an OpenAI-compatible LLM provider.\r\n * Works with OpenAI, Zhipu (GLM), and any OpenAI-compatible API.\r\n */\r\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\r\n const provider = config.provider === 'zhipu' ? 'zhipu' : 'openai';\r\n const baseUrl = config.baseUrl || DEFAULT_BASE_URLS[provider];\r\n const model = config.model || DEFAULT_MODELS[provider];\r\n const maxTokens = config.maxTokens || 2048;\r\n const temperature = config.temperature ?? 0.3;\r\n\r\n if (!config.apiKey) {\r\n throw new Error(\r\n `API key is required for ${provider}. Set it in config or via OPENCROC_LLM_API_KEY env variable.`,\r\n );\r\n }\r\n\r\n return {\r\n name: provider,\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/chat/completions`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${config.apiKey}`,\r\n },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n max_tokens: maxTokens,\r\n temperature,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`LLM API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OpenAIResponse;\r\n const content = data.choices?.[0]?.message?.content;\r\n if (!content) {\r\n throw new Error('LLM returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Rough estimate: ~4 chars per token for English, ~2 for CJK\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\n\r\ninterface OllamaResponse {\r\n message: { content: string };\r\n}\r\n\r\n/**\r\n * Create an Ollama LLM provider for local model inference.\r\n */\r\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\r\n const baseUrl = config.baseUrl || 'http://localhost:11434';\r\n const model = config.model || 'llama3';\r\n\r\n return {\r\n name: 'ollama',\r\n\r\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\r\n const url = `${baseUrl}/api/chat`;\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model,\r\n messages,\r\n stream: false,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'unknown error');\r\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\r\n }\r\n\r\n const data = (await response.json()) as OllamaResponse;\r\n const content = data.message?.content;\r\n if (!content) {\r\n throw new Error('Ollama returned empty response');\r\n }\r\n return content;\r\n },\r\n\r\n estimateTokens(text: string): number {\r\n // Same rough estimate as OpenAI provider\r\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\r\n const otherChars = text.length - cjkChars;\r\n return Math.ceil(otherChars / 4 + cjkChars / 2);\r\n },\r\n };\r\n}\r\n","import type { LlmProvider, LlmConfig } from '../types.js';\r\nimport { createOpenAIProvider } from './openai.js';\r\nimport { createOllamaProvider } from './ollama.js';\r\n\r\nexport { createOpenAIProvider } from './openai.js';\r\nexport { createOllamaProvider } from './ollama.js';\r\n\r\n/**\r\n * Create an LLM provider from config.\r\n * Resolves apiKey from config or OPENCROC_LLM_API_KEY env variable.\r\n */\r\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\r\n const resolved: LlmConfig = {\r\n ...config,\r\n apiKey: config.apiKey || process.env.OPENCROC_LLM_API_KEY,\r\n };\r\n\r\n switch (config.provider) {\r\n case 'openai':\r\n case 'zhipu':\r\n return createOpenAIProvider(resolved);\r\n case 'ollama':\r\n return createOllamaProvider(resolved);\r\n default:\r\n throw new Error(\r\n `Unknown LLM provider: \"${config.provider}\". Available: openai, zhipu, ollama`,\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Token usage tracker — accumulates tokens across multiple LLM calls.\r\n */\r\nexport interface TokenTracker {\r\n track(text: string): void;\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string): void;\r\n total: number;\r\n reset(): void;\r\n}\r\n\r\nexport function createTokenTracker(provider: LlmProvider): TokenTracker {\r\n let total = 0;\r\n\r\n return {\r\n track(text: string) {\r\n total += provider.estimateTokens(text);\r\n },\r\n\r\n trackChat(messages: Array<{ role: string; content: string }>, response: string) {\r\n for (const msg of messages) {\r\n total += provider.estimateTokens(msg.content);\r\n }\r\n total += provider.estimateTokens(response);\r\n },\r\n\r\n get total() {\r\n return total;\r\n },\r\n\r\n reset() {\r\n total = 0;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * System prompts for different LLM use cases in OpenCroc.\r\n */\r\nexport const SYSTEM_PROMPTS = {\r\n failureAnalysis: `You are an expert test failure analyst for an E2E testing framework.\r\nGiven a test failure error message and its context, analyze the root cause and suggest a fix.\r\nRespond in JSON format: { \"rootCause\": string, \"category\": string, \"suggestedFix\": string, \"confidence\": number }\r\nCategories: backend-5xx, timeout, endpoint-not-found, data-constraint, network, frontend-render, test-script, unknown.`,\r\n\r\n chainPlanning: `You are an API test chain planner.\r\nGiven a list of API endpoints and their dependencies, generate an optimal test execution order.\r\nConsider data dependencies, authentication requirements, and cleanup steps.\r\nRespond in JSON format: { \"chains\": [{ \"name\": string, \"steps\": [{ \"endpoint\": string, \"method\": string, \"description\": string }] }] }`,\r\n} as const;\r\n","/**\r\n * Dialog Loop Runner — multi-iteration self-healing loop.\r\n *\r\n * Runs tests, parses results, applies controlled fixes, and reruns\r\n * until all tests pass or the maximum iteration count is reached.\r\n * Tracks error history to avoid infinite loops on recurring failures.\r\n */\r\n\r\nimport type {\r\n DialogLoopConfig,\r\n TestFailureInfo,\r\n IterationResult,\r\n DialogLoopSummary,\r\n ControlledFixOutcome,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface TestRunner {\r\n run(): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface ResultParser {\r\n parse(stdout: string): TestFailureInfo[];\r\n countTotal(stdout: string): number;\r\n}\r\n\r\nexport interface FixApplier {\r\n apply(failure: TestFailureInfo): Promise<ControlledFixOutcome>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULTS: Required<DialogLoopConfig> = {\r\n maxIterations: 3,\r\n pollIntervalMs: 10_000,\r\n sameErrorThreshold: 2,\r\n autoRerunOnFix: true,\r\n};\r\n\r\n// ===== JSON result parser (reads Playwright JSON output) =====\r\n\r\nexport function createJsonResultParser(): ResultParser {\r\n return {\r\n parse(stdout: string): TestFailureInfo[] {\r\n const failures: TestFailureInfo[] = [];\r\n // Match pass/fail summary from Playwright output\r\n const lines = stdout.split('\\n');\r\n for (const line of lines) {\r\n // Playwright format: \" ✘ [chromium] › test.spec.ts:10:5 › suite › title\"\r\n // or stderr lines with \"Error:\" prefix\r\n const failMatch = line.match(/[✘✗×]\\s+.*?›\\s+(.+)/);\r\n if (failMatch) {\r\n failures.push({\r\n title: failMatch[1].trim(),\r\n error: failMatch[1].trim(),\r\n });\r\n }\r\n }\r\n return failures;\r\n },\r\n countTotal(stdout: string): number {\r\n // Match \"X passed\" or \"X failed\" from Playwright summary\r\n let total = 0;\r\n const passMatch = stdout.match(/(\\d+)\\s+passed/);\r\n const failMatch = stdout.match(/(\\d+)\\s+failed/);\r\n if (passMatch) total += parseInt(passMatch[1], 10);\r\n if (failMatch) total += parseInt(failMatch[1], 10);\r\n return total || 1; // at least 1 to avoid division by zero\r\n },\r\n };\r\n}\r\n\r\n// ===== Dialog Loop =====\r\n\r\nexport interface DialogLoopOptions {\r\n runner: TestRunner;\r\n parser: ResultParser;\r\n fixer: FixApplier;\r\n config?: DialogLoopConfig;\r\n onIteration?: (result: IterationResult) => void;\r\n}\r\n\r\nexport async function runDialogLoop(options: DialogLoopOptions): Promise<DialogLoopSummary> {\r\n const cfg = { ...DEFAULTS, ...options.config };\r\n const { runner, parser, fixer } = options;\r\n\r\n const history: IterationResult[] = [];\r\n const errorTracker = new Map<string, number>();\r\n\r\n for (let iteration = 1; iteration <= cfg.maxIterations + 1; iteration++) {\r\n const iterStart = Date.now();\r\n\r\n // Step 1: Run tests\r\n const { stdout } = await runner.run();\r\n\r\n // Step 2: Parse results\r\n const failures = parser.parse(stdout);\r\n const totalTests = parser.countTotal(stdout);\r\n const passed = totalTests - failures.length;\r\n\r\n const iterResult: IterationResult = {\r\n iteration,\r\n totalTests,\r\n passed,\r\n failed: failures.length,\r\n failedTests: failures.map(f => f.title),\r\n fixesApplied: [],\r\n durationMs: 0,\r\n };\r\n\r\n // Step 3: All passed → success\r\n if (failures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 4: Max iterations exceeded\r\n if (iteration > cfg.maxIterations) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 5: Filter out repeated errors beyond threshold\r\n const newFailures = failures.filter(f => {\r\n const key = `${f.title}::${f.error}`;\r\n const count = (errorTracker.get(key) ?? 0) + 1;\r\n errorTracker.set(key, count);\r\n return count <= cfg.sameErrorThreshold;\r\n });\r\n\r\n if (newFailures.length === 0) {\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n break;\r\n }\r\n\r\n // Step 6: Apply controlled fixes\r\n for (const failure of newFailures) {\r\n const outcome = await fixer.apply(failure);\r\n if (outcome.success) {\r\n iterResult.fixesApplied.push(failure.title);\r\n }\r\n }\r\n\r\n iterResult.durationMs = Date.now() - iterStart;\r\n history.push(iterResult);\r\n options.onIteration?.(iterResult);\r\n\r\n // Step 7: If any fixes applied and autoRerun, continue loop\r\n if (iterResult.fixesApplied.length === 0 || !cfg.autoRerunOnFix) {\r\n break;\r\n }\r\n }\r\n\r\n const final = history[history.length - 1];\r\n const totalFixesApplied = history.reduce((sum, h) => sum + h.fixesApplied.length, 0);\r\n\r\n return {\r\n iterations: history,\r\n finalPassed: final?.passed ?? 0,\r\n finalFailed: final?.failed ?? 0,\r\n totalFixesApplied,\r\n success: (final?.failed ?? 1) === 0,\r\n };\r\n}\r\n","/**\r\n * Controlled Fixer — two-phase fix engine with safety guarantees.\r\n *\r\n * Phase A (config-only): backup → validate → fix → dry-run → write → verify → cleanup.\r\n * Phase B (config-and-source): generates a draft PR with the AI-suggested code patch.\r\n *\r\n * All mutations are reversible — failures trigger automatic rollback.\r\n */\r\n\r\nimport { existsSync, copyFileSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type {\r\n FixScope,\r\n ControlledFixOptions,\r\n ControlledFixOutcome,\r\n AIAttributionResult,\r\n} from '../types.js';\r\n\r\n// ===== Abstractions for testability =====\r\n\r\nexport interface ConfigValidator {\r\n validate(configContent: string): { passed: boolean; errors: string[] };\r\n}\r\n\r\nexport interface ConfigFixer {\r\n fix(configContent: string, errors: string[]): { success: boolean; fixedContent: string; fixedItems: string[]; remainingErrors: string[] };\r\n}\r\n\r\nexport interface PRGenerator {\r\n generate(attribution: AIAttributionResult): Promise<string>;\r\n}\r\n\r\n// ===== FS abstraction (injectable for tests) =====\r\n\r\nexport interface FsOps {\r\n exists(path: string): boolean;\r\n read(path: string): string;\r\n write(path: string, content: string): void;\r\n copy(src: string, dest: string): void;\r\n remove(path: string): void;\r\n mkdirp(dir: string): void;\r\n}\r\n\r\nconst defaultFs: FsOps = {\r\n exists: existsSync,\r\n read: (p) => readFileSync(p, 'utf-8'),\r\n write: (p, c) => { mkdirSync(dirname(p), { recursive: true }); writeFileSync(p, c, 'utf-8'); },\r\n copy: copyFileSync,\r\n remove: unlinkSync,\r\n mkdirp: (d) => mkdirSync(d, { recursive: true }),\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport interface ControlledFixerOptions {\r\n configPath: string;\r\n validator: ConfigValidator;\r\n fixer: ConfigFixer;\r\n prGenerator?: PRGenerator;\r\n attribution?: AIAttributionResult;\r\n fs?: FsOps;\r\n options?: ControlledFixOptions;\r\n}\r\n\r\nexport async function applyControlledFix(opts: ControlledFixerOptions): Promise<ControlledFixOutcome> {\r\n const fs = opts.fs ?? defaultFs;\r\n const scope: FixScope = opts.options?.scope ?? 'config-only';\r\n const dryRun = opts.options?.dryRun ?? true;\r\n const verify = opts.options?.verify ?? true;\r\n const configPath = opts.configPath;\r\n const backupPath = configPath + '.backup';\r\n\r\n // --- Phase A: Config-only fix ---\r\n\r\n // Load config\r\n if (!fs.exists(configPath)) {\r\n return { success: false, scope, fixedItems: [], rolledBack: false, error: `Config file not found: ${configPath}` };\r\n }\r\n\r\n const originalContent = fs.read(configPath);\r\n\r\n // Backup before mutation\r\n fs.write(backupPath, originalContent);\r\n\r\n // Validate current config\r\n const validation = opts.validator.validate(originalContent);\r\n\r\n if (validation.passed) {\r\n // No errors to fix\r\n cleanup(fs, backupPath);\r\n return { success: true, scope, fixedItems: [], rolledBack: false };\r\n }\r\n\r\n // Attempt fix\r\n let fixResult: ReturnType<ConfigFixer['fix']>;\r\n try {\r\n fixResult = opts.fixer.fix(originalContent, validation.errors);\r\n } catch (err) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: [], rolledBack: true, error: `Fix threw: ${err instanceof Error ? err.message : String(err)}` };\r\n }\r\n\r\n if (!fixResult.success) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Remaining errors: ${fixResult.remainingErrors.join('; ')}` };\r\n }\r\n\r\n // Dry-run: validate fixed content before writing\r\n if (dryRun) {\r\n const dryValidation = opts.validator.validate(fixResult.fixedContent);\r\n if (!dryValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Dry-run validation failed: ${dryValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Write fixed content\r\n fs.write(configPath, fixResult.fixedContent);\r\n\r\n // Verify after write\r\n if (verify) {\r\n const reloaded = fs.read(configPath);\r\n const postValidation = opts.validator.validate(reloaded);\r\n if (!postValidation.passed) {\r\n rollback(fs, backupPath, configPath);\r\n return { success: false, scope, fixedItems: fixResult.fixedItems, rolledBack: true, error: `Post-write verification failed: ${postValidation.errors.join('; ')}` };\r\n }\r\n }\r\n\r\n // Phase A success — clean up backup\r\n cleanup(fs, backupPath);\r\n\r\n // --- Phase B: Config-and-source (optional) ---\r\n let prUrl: string | undefined;\r\n if (scope === 'config-and-source' && opts.attribution && opts.prGenerator) {\r\n try {\r\n prUrl = await opts.prGenerator.generate(opts.attribution);\r\n } catch {\r\n // PR generation failure is non-fatal; config fix already succeeded\r\n }\r\n }\r\n\r\n return { success: true, scope, fixedItems: fixResult.fixedItems, rolledBack: false, prUrl };\r\n}\r\n\r\nfunction rollback(fs: FsOps, backupPath: string, configPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n const backup = fs.read(backupPath);\r\n fs.write(configPath, backup);\r\n fs.remove(backupPath);\r\n }\r\n}\r\n\r\nfunction cleanup(fs: FsOps, backupPath: string): void {\r\n if (fs.exists(backupPath)) {\r\n fs.remove(backupPath);\r\n }\r\n}\r\n","/**\r\n * Auto-Fix PR Generator — creates draft PRs from AI attribution results.\r\n *\r\n * Flow: create branch → write patch → git apply → commit → push → gh pr create --draft.\r\n * All PRs are draft-only as a safety invariant.\r\n */\r\n\r\nimport type { AIAttributionResult, AutoFixPROptions, AutoFixPRResult } from '../types.js';\r\n\r\n// ===== Executor abstraction (injectable for tests) =====\r\n\r\nexport interface GitExecutor {\r\n exec(command: string, args: string[]): Promise<{ stdout: string; exitCode: number }>;\r\n}\r\n\r\nexport interface PatchWriter {\r\n write(path: string, content: string): Promise<void>;\r\n mkdir(dir: string): Promise<void>;\r\n}\r\n\r\n// ===== Defaults =====\r\n\r\nconst DEFAULT_OPTIONS: Required<AutoFixPROptions> = {\r\n branchPrefix: 'autofix/',\r\n baseBranch: 'main',\r\n draftOnly: true,\r\n};\r\n\r\n// ===== Core =====\r\n\r\nexport async function generateFixPR(\r\n attribution: AIAttributionResult,\r\n git: GitExecutor,\r\n patchWriter: PatchWriter,\r\n options?: AutoFixPROptions,\r\n): Promise<AutoFixPRResult> {\r\n const opts = { ...DEFAULT_OPTIONS, ...options };\r\n const ts = new Date().toISOString().replace(/[:.]/g, '-');\r\n const branch = `${opts.branchPrefix}${ts}`;\r\n const patchFile = `report/patch-${ts}.patch`;\r\n\r\n // Create branch\r\n await git.exec('git', ['checkout', '-b', branch]);\r\n\r\n // Write patch\r\n await patchWriter.mkdir('report');\r\n await patchWriter.write(patchFile, attribution.fixSuggestion.codePatch);\r\n\r\n // Apply patch (non-fatal if fails)\r\n try {\r\n await git.exec('git', ['apply', patchFile]);\r\n } catch {\r\n // Patch may not apply cleanly — continue anyway\r\n }\r\n\r\n // Stage, commit, push\r\n await git.exec('git', ['add', '.']);\r\n await git.exec('git', ['commit', '-m', `fix: AI auto-patch for \"${attribution.testName}\"`]);\r\n await git.exec('git', ['push', 'origin', branch]);\r\n\r\n // Create draft PR (always draft for safety)\r\n const prArgs = [\r\n 'pr', 'create', '--draft',\r\n '--title', `[AI Fix] ${attribution.testName}`,\r\n '--body', buildPRBody(attribution),\r\n ];\r\n const { stdout: prUrl } = await git.exec('gh', prArgs);\r\n\r\n // Return to base branch\r\n await git.exec('git', ['checkout', opts.baseBranch]);\r\n\r\n return { prUrl: prUrl.trim(), branch, patchFile };\r\n}\r\n\r\nfunction buildPRBody(a: AIAttributionResult): string {\r\n return [\r\n '## AI Auto-Fix PR',\r\n '',\r\n `**Test:** ${a.testName}`,\r\n `**Category:** ${a.category} | **Severity:** ${a.severity} | **Confidence:** ${(a.confidence * 100).toFixed(0)}%`,\r\n '',\r\n '### Root Cause',\r\n a.rootCause,\r\n '',\r\n '### Fix',\r\n a.fixSuggestion.description,\r\n '',\r\n '---',\r\n '> This PR was auto-generated by AI and **must be reviewed before merging**.',\r\n ].join('\\n');\r\n}\r\n","import type { SelfHealingConfig, SelfHealingResult, FixOutcome, LlmProvider } from '../types.js';\r\nimport { SYSTEM_PROMPTS } from '../llm/index.js';\r\n\r\nexport type { SelfHealingResult, FixOutcome };\r\n\r\n// Advanced Self-Healing (v1.1)\r\nexport { runDialogLoop, createJsonResultParser } from './dialog-loop-runner.js';\r\nexport type { TestRunner, ResultParser, FixApplier, DialogLoopOptions } from './dialog-loop-runner.js';\r\nexport { applyControlledFix } from './controlled-fixer.js';\r\nexport type { ConfigValidator, ConfigFixer, PRGenerator, FsOps, ControlledFixerOptions } from './controlled-fixer.js';\r\nexport { generateFixPR } from './auto-fix-generator.js';\r\nexport type { GitExecutor, PatchWriter } from './auto-fix-generator.js';\r\n\r\nexport interface SelfHealingLoop {\r\n run(testResultsDir: string): Promise<SelfHealingResult>;\r\n}\r\n\r\nexport interface SelfHealingOptions {\r\n config: SelfHealingConfig;\r\n llm?: LlmProvider;\r\n}\r\n\r\n/**\r\n * Categorize a test failure by heuristic rules.\r\n */\r\nexport function categorizeFailure(errorMessage: string): {\r\n category: string;\r\n confidence: number;\r\n} {\r\n const msg = errorMessage.toLowerCase();\r\n\r\n if (/5\\d{2}|internal server error/.test(msg))\r\n return { category: 'backend-5xx', confidence: 0.9 };\r\n if (/timeout|timed?\\s*out/.test(msg))\r\n return { category: 'timeout', confidence: 0.8 };\r\n if (/404|not found/.test(msg))\r\n return { category: 'endpoint-not-found', confidence: 0.85 };\r\n if (/4[0-2]\\d|validation|constraint/.test(msg))\r\n return { category: 'data-constraint', confidence: 0.75 };\r\n if (/econnrefused|enotfound|network/.test(msg))\r\n return { category: 'network', confidence: 0.9 };\r\n if (/selector|locator|element/.test(msg))\r\n return { category: 'frontend-render', confidence: 0.7 };\r\n if (/storage\\s*state|auth|login/.test(msg))\r\n return { category: 'test-script', confidence: 0.8 };\r\n\r\n return { category: 'unknown', confidence: 0.5 };\r\n}\r\n\r\n/**\r\n * LLM-enhanced failure analysis with heuristic fallback.\r\n */\r\nexport async function analyzeFailureWithLLM(\r\n errorMessage: string,\r\n llm?: LlmProvider,\r\n): Promise<{ rootCause: string; category: string; suggestedFix: string; confidence: number }> {\r\n // Always get heuristic result as fallback\r\n const heuristic = categorizeFailure(errorMessage);\r\n\r\n if (!llm) {\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n\r\n try {\r\n const response = await llm.chat([\r\n { role: 'system', content: SYSTEM_PROMPTS.failureAnalysis },\r\n { role: 'user', content: `Analyze this test failure:\\n\\n${errorMessage}` },\r\n ]);\r\n\r\n const parsed = JSON.parse(response) as {\r\n rootCause?: string;\r\n category?: string;\r\n suggestedFix?: string;\r\n confidence?: number;\r\n };\r\n\r\n return {\r\n rootCause: parsed.rootCause || errorMessage,\r\n category: parsed.category || heuristic.category,\r\n suggestedFix: parsed.suggestedFix || '',\r\n confidence: parsed.confidence || heuristic.confidence,\r\n };\r\n } catch {\r\n // LLM failed — fall back to heuristic\r\n return {\r\n rootCause: errorMessage,\r\n category: heuristic.category,\r\n suggestedFix: '',\r\n confidence: heuristic.confidence,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Attempt a config-only fix: validate and write corrected config JSON.\r\n */\r\nasync function attemptConfigFix(\r\n _testResultsDir: string,\r\n _mode: SelfHealingConfig['mode'],\r\n _llm?: LlmProvider,\r\n): Promise<FixOutcome> {\r\n // TODO: Load module config → run autoFix validation → write corrected JSON\r\n // For now, return a no-op outcome\r\n return {\r\n success: false,\r\n scope: 'config-only',\r\n fixedItems: [],\r\n rolledBack: false,\r\n };\r\n}\r\n\r\n/**\r\n * Create a self-healing loop. Accepts an optional LLM provider for AI-enhanced analysis.\r\n */\r\nexport function createSelfHealingLoop(config: SelfHealingConfig, llm?: LlmProvider): SelfHealingLoop {\r\n return {\r\n async run(testResultsDir: string): Promise<SelfHealingResult> {\r\n const maxIterations = config.maxIterations || 3;\r\n const mode = config.mode || 'config-only';\r\n const fixed: string[] = [];\r\n const remaining: string[] = [];\r\n let iterations = 0;\r\n let totalTokensUsed = 0;\r\n\r\n for (let i = 0; i < maxIterations; i++) {\r\n iterations = i + 1;\r\n\r\n const outcome = await attemptConfigFix(testResultsDir, mode, llm);\r\n if (outcome.success) {\r\n fixed.push(...outcome.fixedItems);\r\n } else {\r\n remaining.push(`iteration-${i + 1}: no fix applied`);\r\n }\r\n\r\n // Track token usage if LLM is available\r\n if (llm) {\r\n totalTokensUsed += llm.estimateTokens(`iteration-${i + 1}`);\r\n }\r\n\r\n // If all fixed, stop early\r\n if (outcome.success && outcome.fixedItems.length > 0) break;\r\n }\r\n\r\n return {\r\n iterations,\r\n fixed,\r\n remaining,\r\n totalTokensUsed,\r\n };\r\n },\r\n };\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createSelfHealingLoop } from '../../self-healing/index.js';\r\nimport type { SelfHealingConfig } from '../../types.js';\r\n\r\nexport interface HealOptions {\r\n module?: string;\r\n maxIterations?: string;\r\n}\r\n\r\nexport async function heal(opts: HealOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Self-Healing\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const maxIterations = opts.maxIterations ? parseInt(opts.maxIterations, 10) : 3;\r\n\r\n const healingConfig: SelfHealingConfig = {\r\n enabled: true,\r\n maxIterations,\r\n mode: config.selfHealing?.mode || 'config-only',\r\n };\r\n\r\n console.log(chalk.gray(` Mode: ${healingConfig.mode}`));\r\n console.log(chalk.gray(` Max iterations: ${maxIterations}`));\r\n\r\n if (opts.module) {\r\n console.log(chalk.gray(` Module: ${opts.module}`));\r\n }\r\n console.log('');\r\n\r\n const loop = createSelfHealingLoop(healingConfig);\r\n const result = await loop.run(outDir);\r\n\r\n // Report results\r\n console.log(chalk.cyan(' Results:'));\r\n console.log(` Iterations : ${result.iterations}`);\r\n console.log(` Fixed : ${result.fixed.length > 0 ? chalk.green(result.fixed.join(', ')) : chalk.gray('(none)')}`);\r\n console.log(` Remaining : ${result.remaining.length > 0 ? chalk.yellow(result.remaining.join(', ')) : chalk.gray('(none)')}`);\r\n if (result.totalTokensUsed > 0) {\r\n console.log(` Tokens used : ${result.totalTokensUsed}`);\r\n }\r\n\r\n console.log('');\r\n\r\n if (result.remaining.length > 0) {\r\n console.log(chalk.yellow(' Some issues could not be auto-fixed. Manual review needed.\\n'));\r\n } else if (result.fixed.length > 0) {\r\n console.log(chalk.green(' ✓ All issues resolved.\\n'));\r\n } else {\r\n console.log(chalk.gray(' No issues detected.\\n'));\r\n }\r\n}\r\n","/**\r\n * CI template generators for popular CI/CD platforms.\r\n *\r\n * Usage:\r\n * npx opencroc ci --platform=github\r\n * npx opencroc ci --platform=gitlab\r\n */\r\n\r\nexport interface CiTemplateOptions {\r\n /** Node.js version(s). Default: ['20.x'] */\r\n nodeVersions?: string[];\r\n /** Install command. Default: 'npm ci' */\r\n installCommand?: string;\r\n /** Whether to run self-healing. Default: false */\r\n selfHeal?: boolean;\r\n /** Custom opencroc generate args */\r\n generateArgs?: string;\r\n /** Custom opencroc test args */\r\n testArgs?: string;\r\n}\r\n\r\nexport function generateGitHubActionsTemplate(opts: CiTemplateOptions = {}): string {\r\n const nodeVersions = opts.nodeVersions ?? ['20.x'];\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const healStep = opts.selfHeal\r\n ? `\r\n - name: Self-heal failures\r\n if: failure()\r\n run: npx opencroc heal --max-iterations 3`\r\n : '';\r\n\r\n const matrix =\r\n nodeVersions.length > 1\r\n ? `\r\n strategy:\r\n matrix:\r\n node-version: [${nodeVersions.join(', ')}]`\r\n : '';\r\n\r\n const nodeSetup =\r\n nodeVersions.length > 1\r\n ? '${{ matrix.node-version }}'\r\n : nodeVersions[0];\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nname: OpenCroc E2E\r\n\r\non:\r\n push:\r\n branches: [main]\r\n pull_request:\r\n branches: [main]\r\n\r\njobs:\r\n e2e:\r\n runs-on: ubuntu-latest${matrix}\r\n steps:\r\n - uses: actions/checkout@v4\r\n\r\n - uses: actions/setup-node@v4\r\n with:\r\n node-version: '${nodeSetup}'\r\n\r\n - name: Install dependencies\r\n run: ${install}\r\n\r\n - name: Install Playwright browsers\r\n run: npx playwright install --with-deps chromium\r\n\r\n - name: Generate E2E tests\r\n run: npx opencroc generate ${genArgs}\r\n\r\n - name: Run E2E tests\r\n run: npx opencroc test ${testArgs}\r\n${healStep}\r\n - name: Upload test report\r\n if: always()\r\n uses: actions/upload-artifact@v4\r\n with:\r\n name: opencroc-report\r\n path: opencroc-output/\r\n retention-days: 14\r\n`;\r\n}\r\n\r\nexport function generateGitLabCITemplate(opts: CiTemplateOptions = {}): string {\r\n const install = opts.installCommand ?? 'npm ci';\r\n const genArgs = opts.generateArgs ?? '--all';\r\n const testArgs = opts.testArgs ?? '';\r\n const nodeVersion = opts.nodeVersions?.[0] ?? '20';\r\n\r\n return `# Generated by OpenCroc — AI-native E2E testing\r\n# https://github.com/opencroc/opencroc\r\n\r\nimage: node:${nodeVersion}\r\n\r\nstages:\r\n - generate\r\n - test\r\n\r\nvariables:\r\n PLAYWRIGHT_BROWSERS_PATH: \\${CI_PROJECT_DIR}/.cache/ms-playwright\r\n\r\ncache:\r\n key: \\${CI_COMMIT_REF_SLUG}\r\n paths:\r\n - node_modules/\r\n - .cache/ms-playwright/\r\n\r\ngenerate:\r\n stage: generate\r\n script:\r\n - ${install}\r\n - npx opencroc generate ${genArgs}\r\n artifacts:\r\n paths:\r\n - opencroc-output/\r\n expire_in: 1 day\r\n\r\ne2e:\r\n stage: test\r\n needs: [generate]\r\n before_script:\r\n - ${install}\r\n - npx playwright install --with-deps chromium\r\n script:\r\n - npx opencroc test ${testArgs}\r\n artifacts:\r\n when: always\r\n paths:\r\n - opencroc-output/\r\n expire_in: 14 days\r\n`;\r\n}\r\n\r\nconst TEMPLATES: Record<string, (opts: CiTemplateOptions) => string> = {\r\n github: generateGitHubActionsTemplate,\r\n gitlab: generateGitLabCITemplate,\r\n};\r\n\r\n/**\r\n * Get available CI platform names.\r\n */\r\nexport function listCiPlatforms(): string[] {\r\n return Object.keys(TEMPLATES);\r\n}\r\n\r\n/**\r\n * Generate a CI template for the given platform.\r\n */\r\nexport function generateCiTemplate(\r\n platform: string,\r\n opts: CiTemplateOptions = {},\r\n): string {\r\n const generator = TEMPLATES[platform];\r\n if (!generator) {\r\n throw new Error(\r\n `Unknown CI platform: \"${platform}\". Available: ${Object.keys(TEMPLATES).join(', ')}`,\r\n );\r\n }\r\n return generator(opts);\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport chalk from 'chalk';\r\nimport { generateCiTemplate, listCiPlatforms } from '../../ci/index.js';\r\nimport type { CiTemplateOptions } from '../../ci/index.js';\r\n\r\nexport interface CiCommandOptions {\r\n platform?: string;\r\n selfHeal?: boolean;\r\n node?: string;\r\n}\r\n\r\nexport async function ci(opts: CiCommandOptions): Promise<void> {\r\n const platform = opts.platform ?? 'github';\r\n const available = listCiPlatforms();\r\n\r\n if (!available.includes(platform)) {\r\n console.error(chalk.red(`Unknown platform: \"${platform}\". Available: ${available.join(', ')}`));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const templateOpts: CiTemplateOptions = {\r\n selfHeal: opts.selfHeal ?? false,\r\n };\r\n if (opts.node) {\r\n templateOpts.nodeVersions = opts.node.split(',').map((s) => s.trim());\r\n }\r\n\r\n const content = generateCiTemplate(platform, templateOpts);\r\n\r\n let outputPath: string;\r\n if (platform === 'github') {\r\n outputPath = path.join('.github', 'workflows', 'opencroc.yml');\r\n } else if (platform === 'gitlab') {\r\n outputPath = '.gitlab-ci.yml';\r\n } else {\r\n outputPath = `opencroc-ci-${platform}.yml`;\r\n }\r\n\r\n const dir = path.dirname(outputPath);\r\n if (dir !== '.' && !fs.existsSync(dir)) {\r\n fs.mkdirSync(dir, { recursive: true });\r\n }\r\n\r\n fs.writeFileSync(outputPath, content, 'utf-8');\r\n console.log(chalk.green(`✔ CI template written to ${outputPath}`));\r\n console.log(chalk.dim(` Platform: ${platform}`));\r\n}\r\n","/**\r\n * Checklist Reporter — generates backend fix checklists from test results.\r\n *\r\n * Groups failures by API domain, lists affected tests and endpoints,\r\n * and produces both structured data and Markdown output.\r\n */\r\n\r\nimport type {\r\n TestResultRecord,\r\n FailureCategory,\r\n FailureSummary,\r\n BackendDomainItem,\r\n LogCompletionSummary,\r\n} from '../types.js';\r\n\r\n// ===== Failure classification =====\r\n\r\nexport function classifyFailure(error?: string): FailureCategory {\r\n if (!error) return 'other';\r\n if (error.includes('[BACKEND_5XX]')) return 'backend-5xx';\r\n if (error.includes('[MIXED_5XX]')) return 'mixed-5xx';\r\n if (error.includes('[SLOW_API_FATAL]')) return 'slow-api';\r\n if (error.includes('[LOG_COMPLETION_FAIL]')) return 'log-fail';\r\n if (error.includes('[LOG_COMPLETION_TIMEOUT]')) return 'log-timeout';\r\n if (/waitForSelector|toHaveURL|Timeout/i.test(error)) return 'frontend-load';\r\n return 'other';\r\n}\r\n\r\n// ===== Failure summary =====\r\n\r\nexport function buildFailureSummary(records: TestResultRecord[]): FailureSummary {\r\n const failed = records.filter(r => r.status === 'failed');\r\n const cats = failed.map(r => classifyFailure(r.error));\r\n return {\r\n totalFailed: failed.length,\r\n backend5xx: cats.filter(c => c === 'backend-5xx').length,\r\n mixed5xx: cats.filter(c => c === 'mixed-5xx').length,\r\n slowApi: cats.filter(c => c === 'slow-api').length,\r\n logFail: cats.filter(c => c === 'log-fail').length,\r\n logTimeout: cats.filter(c => c === 'log-timeout').length,\r\n frontendLoad: cats.filter(c => c === 'frontend-load').length,\r\n other: cats.filter(c => c === 'other').length,\r\n };\r\n}\r\n\r\n// ===== Log completion aggregation =====\r\n\r\nexport function aggregateLogCompletion(records: TestResultRecord[]): LogCompletionSummary {\r\n let totalCandidates = 0;\r\n let succeeded = 0;\r\n let failed = 0;\r\n let timedOut = 0;\r\n const timedOutFreq = new Map<string, { method: string; path: string; count: number }>();\r\n\r\n for (const r of records) {\r\n const lc = r.logCompletion;\r\n if (!lc || lc.candidateCount === 0) continue;\r\n\r\n totalCandidates += lc.candidateCount;\r\n succeeded += lc.succeeded.length;\r\n failed += lc.failed.length;\r\n timedOut += lc.timedOut.length;\r\n\r\n for (const item of lc.timedOut) {\r\n const key = `${item.method}:${item.path}`;\r\n const existing = timedOutFreq.get(key);\r\n if (existing) existing.count += 1;\r\n else timedOutFreq.set(key, { method: item.method, path: item.path, count: 1 });\r\n }\r\n }\r\n\r\n const timedOutTop5 = Array.from(timedOutFreq.values())\r\n .sort((a, b) => b.count - a.count)\r\n .slice(0, 5)\r\n .map(t => ({ method: t.method, path: t.path, occurrences: t.count }));\r\n\r\n const matchRate = totalCandidates > 0 ? (succeeded + failed) / totalCandidates * 100 : 0;\r\n const effectiveRate = totalCandidates > 0 ? succeeded / totalCandidates * 100 : 0;\r\n\r\n return { totalCandidates, succeeded, failed, timedOut, matchRate, effectiveRate, timedOutTop5 };\r\n}\r\n\r\n// ===== URL extraction helpers =====\r\n\r\nfunction extractUrls(error?: string): string[] {\r\n if (!error) return [];\r\n const matched = error.match(/https?:\\/\\/[^\\s\\n]+/g);\r\n return matched ? Array.from(new Set(matched)) : [];\r\n}\r\n\r\nexport function parseApiDomain(urlStr: string): string | null {\r\n try {\r\n const u = new URL(urlStr);\r\n const segments = u.pathname.split('/').filter(Boolean);\r\n const v1Index = segments.findIndex(s => s === 'v1');\r\n if (v1Index === -1 || v1Index + 1 >= segments.length) return segments[0] || null;\r\n const afterV1 = segments.slice(v1Index + 1);\r\n if (afterV1.length === 0) return null;\r\n const first = afterV1[0];\r\n if (/^\\d+$/.test(first) && afterV1.length > 1) return afterV1[1];\r\n return first;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ===== Backend checklist =====\r\n\r\nexport function buildBackendChecklist(records: TestResultRecord[]): BackendDomainItem[] {\r\n const domainMap = new Map<string, { tests: Set<string>; endpoints: Set<string> }>();\r\n const failed = records.filter(r => r.status === 'failed');\r\n\r\n for (const item of failed) {\r\n const cat = classifyFailure(item.error);\r\n if (cat !== 'backend-5xx' && cat !== 'mixed-5xx') continue;\r\n const urls = extractUrls(item.error);\r\n for (const url of urls) {\r\n const domain = parseApiDomain(url);\r\n if (!domain) continue;\r\n const current = domainMap.get(domain) ?? { tests: new Set<string>(), endpoints: new Set<string>() };\r\n current.tests.add(item.title);\r\n current.endpoints.add(url);\r\n domainMap.set(domain, current);\r\n }\r\n }\r\n\r\n return Array.from(domainMap.entries())\r\n .map(([domain, v]) => ({\r\n domain,\r\n tests: Array.from(v.tests).sort(),\r\n endpoints: Array.from(v.endpoints).sort(),\r\n }))\r\n .sort((a, b) => b.tests.length - a.tests.length || a.domain.localeCompare(b.domain));\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderChecklistMarkdown(\r\n items: BackendDomainItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Fix Checklist',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}% (candidates=${logSummary.totalCandidates}, succeeded=${logSummary.succeeded}, failed=${logSummary.failed}, timedOut=${logSummary.timedOut})`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (logSummary && logSummary.timedOutTop5.length > 0) {\r\n lines.push('### Timed-out APIs Top 5', '', '| # | Method | Path | Occurrences |', '|---|--------|------|-------------|');\r\n logSummary.timedOutTop5.forEach((t, i) => {\r\n lines.push(`| ${i + 1} | ${t.method} | ${t.path} | ${t.occurrences} |`);\r\n });\r\n lines.push('');\r\n }\r\n\r\n if (items.length === 0) {\r\n lines.push('No backend 5xx failures this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const item of items) {\r\n lines.push(\r\n `## ${item.domain}`,\r\n '',\r\n `- Failed tests: ${item.tests.length}`,\r\n '- Affected tests:',\r\n );\r\n for (const t of item.tests) lines.push(` - ${t}`);\r\n lines.push('- Failed endpoints:');\r\n for (const e of item.endpoints) lines.push(` - ${e}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Workorder Reporter — auto-generates prioritized backend work orders.\r\n *\r\n * Priority rules:\r\n * - P0: ≥3 affected tests OR log completion rate < 90%\r\n * - P1: 2 affected tests\r\n * - P2: 1 affected test\r\n *\r\n * Each workorder includes objective, affected scope, and acceptance criteria.\r\n */\r\n\r\nimport type {\r\n BackendDomainItem,\r\n FailureSummary,\r\n LogCompletionSummary,\r\n WorkorderItem,\r\n} from '../types.js';\r\n\r\n// ===== Priority assignment =====\r\n\r\nfunction assignPriority(item: BackendDomainItem, isLogRate: boolean): 'P0' | 'P1' | 'P2' {\r\n if (isLogRate) return 'P0';\r\n if (item.tests.length >= 3) return 'P0';\r\n if (item.tests.length === 2) return 'P1';\r\n return 'P2';\r\n}\r\n\r\n// ===== Workorder builder =====\r\n\r\nexport interface BuildWorkordersOptions {\r\n checklist: BackendDomainItem[];\r\n summary: FailureSummary;\r\n logSummary?: LogCompletionSummary;\r\n logRateThreshold?: number;\r\n}\r\n\r\nexport function buildWorkorders(opts: BuildWorkordersOptions): WorkorderItem[] {\r\n const { checklist, logSummary, logRateThreshold = 90 } = opts;\r\n const result: WorkorderItem[] = [];\r\n let idx = 1;\r\n\r\n // Auto P0 workorder if log completion rate is below threshold\r\n if (logSummary && logSummary.totalCandidates > 0 && logSummary.matchRate < logRateThreshold) {\r\n const logItem: BackendDomainItem = {\r\n domain: 'Log Completion Standards',\r\n tests: logSummary.timedOutTop5.map(t => `${t.method} ${t.path} (×${t.occurrences})`),\r\n endpoints: logSummary.timedOutTop5.map(t => t.path),\r\n };\r\n result.push({\r\n index: idx++,\r\n domain: logItem.domain,\r\n priority: 'P0',\r\n tests: logItem.tests,\r\n endpoints: logItem.endpoints,\r\n objective: 'Add missing end-phase structured logs for timed-out APIs',\r\n acceptanceCriteria: [\r\n `Log completion match rate ≥ ${logRateThreshold}%`,\r\n 'TimedOut API count drops to 0 or only SSE/long-polling endpoints remain',\r\n ],\r\n });\r\n }\r\n\r\n // Standard workorders from checklist\r\n for (const item of checklist) {\r\n const priority = assignPriority(item, false);\r\n result.push({\r\n index: idx++,\r\n domain: item.domain,\r\n priority,\r\n tests: item.tests,\r\n endpoints: item.endpoints,\r\n objective: 'Fix 500 errors and return a valid business response',\r\n acceptanceCriteria: [\r\n 'HTTP status returns 2xx for affected endpoints',\r\n 'No [BACKEND_5XX] errors in corresponding page traversal',\r\n 'All covered tests pass',\r\n ],\r\n });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderWorkordersMarkdown(\r\n workorders: WorkorderItem[],\r\n summary: FailureSummary,\r\n logSummary?: LogCompletionSummary,\r\n): string {\r\n const lines: string[] = [\r\n '# Backend Work Orders',\r\n '',\r\n ];\r\n\r\n if (logSummary) {\r\n lines.push(\r\n `- Log match rate: ${logSummary.matchRate.toFixed(2)}%`,\r\n `- Effective success rate: ${logSummary.effectiveRate.toFixed(2)}%`,\r\n );\r\n }\r\n lines.push(\r\n `- Total failed: ${summary.totalFailed}`,\r\n `- Backend 5xx: ${summary.backend5xx}`,\r\n `- Mixed 5xx: ${summary.mixed5xx}`,\r\n `- Slow API: ${summary.slowApi}`,\r\n `- Log fail: ${summary.logFail}`,\r\n `- Log timeout: ${summary.logTimeout}`,\r\n `- Frontend load: ${summary.frontendLoad}`,\r\n `- Other: ${summary.other}`,\r\n '',\r\n );\r\n\r\n if (workorders.length === 0) {\r\n lines.push('No backend work orders this run.');\r\n return lines.join('\\n') + '\\n';\r\n }\r\n\r\n for (const wo of workorders) {\r\n lines.push(\r\n `## Workorder ${wo.index} - ${wo.domain}`,\r\n '',\r\n `- Priority: ${wo.priority}`,\r\n `- Affected tests: ${wo.tests.length}`,\r\n '- Scope:',\r\n );\r\n for (const t of wo.tests) lines.push(` - ${t}`);\r\n if (wo.endpoints.length > 0) {\r\n lines.push('- Endpoints:');\r\n for (const e of wo.endpoints) lines.push(` - ${e}`);\r\n }\r\n lines.push(`- Objective: ${wo.objective}`);\r\n lines.push('- Acceptance criteria:');\r\n for (const c of wo.acceptanceCriteria) lines.push(` - ${c}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","/**\r\n * Token Usage Reporter — tracks and reports LLM token consumption.\r\n *\r\n * Aggregates usage entries by category and model, computes costs,\r\n * tracks budget utilization, and renders both structured data and Markdown.\r\n */\r\n\r\nimport type { TokenUsageEntry, TokenUsageSummary } from '../types.js';\r\n\r\n// ===== Token Tracker =====\r\n\r\nexport class TokenTracker {\r\n private entries: TokenUsageEntry[] = [];\r\n private budget: number | null = null;\r\n\r\n setBudget(maxTokens: number): void {\r\n this.budget = maxTokens;\r\n }\r\n\r\n record(entry: TokenUsageEntry): void {\r\n this.entries.push(entry);\r\n }\r\n\r\n reset(): void {\r\n this.entries = [];\r\n }\r\n\r\n getSummary(): TokenUsageSummary {\r\n const totalRequests = this.entries.length;\r\n let totalPromptTokens = 0;\r\n let totalCompletionTokens = 0;\r\n let totalEstimatedCost = 0;\r\n let totalLatency = 0;\r\n\r\n const byCategory: TokenUsageSummary['byCategory'] = {};\r\n const byModel: TokenUsageSummary['byModel'] = {};\r\n\r\n for (const e of this.entries) {\r\n totalPromptTokens += e.promptTokens;\r\n totalCompletionTokens += e.completionTokens;\r\n totalEstimatedCost += e.estimatedCost;\r\n totalLatency += e.latencyMs;\r\n\r\n // By category\r\n if (!byCategory[e.category]) {\r\n byCategory[e.category] = { requests: 0, promptTokens: 0, completionTokens: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const cat = byCategory[e.category];\r\n cat.requests++;\r\n cat.promptTokens += e.promptTokens;\r\n cat.completionTokens += e.completionTokens;\r\n cat.totalTokens += e.promptTokens + e.completionTokens;\r\n cat.estimatedCost += e.estimatedCost;\r\n\r\n // By model\r\n if (!byModel[e.model]) {\r\n byModel[e.model] = { requests: 0, totalTokens: 0, estimatedCost: 0 };\r\n }\r\n const mod = byModel[e.model];\r\n mod.requests++;\r\n mod.totalTokens += e.promptTokens + e.completionTokens;\r\n mod.estimatedCost += e.estimatedCost;\r\n }\r\n\r\n const totalTokens = totalPromptTokens + totalCompletionTokens;\r\n const budgetUsedPercent = this.budget && this.budget > 0\r\n ? Math.round(totalTokens / this.budget * 10000) / 100\r\n : null;\r\n\r\n return {\r\n totalRequests,\r\n totalTokens,\r\n totalPromptTokens,\r\n totalCompletionTokens,\r\n totalEstimatedCost,\r\n avgLatencyMs: totalRequests > 0 ? Math.round(totalLatency / totalRequests) : 0,\r\n byCategory,\r\n byModel,\r\n budgetUsedPercent,\r\n budgetExceeded: budgetUsedPercent !== null && budgetUsedPercent > 100,\r\n };\r\n }\r\n}\r\n\r\n// ===== Markdown renderer =====\r\n\r\nexport function renderTokenReportMarkdown(summary: TokenUsageSummary): string {\r\n const lines: string[] = [\r\n '# AI Token Usage Report',\r\n '',\r\n `- Total requests: ${summary.totalRequests}`,\r\n `- Total tokens: ${summary.totalTokens.toLocaleString()}`,\r\n `- Prompt tokens: ${summary.totalPromptTokens.toLocaleString()}`,\r\n `- Completion tokens: ${summary.totalCompletionTokens.toLocaleString()}`,\r\n `- Estimated cost: ¥${summary.totalEstimatedCost.toFixed(4)}`,\r\n `- Average latency: ${summary.avgLatencyMs}ms`,\r\n ];\r\n\r\n if (summary.budgetUsedPercent !== null) {\r\n lines.push(`- Budget used: ${summary.budgetUsedPercent}%${summary.budgetExceeded ? ' **EXCEEDED**' : ''}`);\r\n }\r\n lines.push('');\r\n\r\n // By category\r\n const cats = Object.entries(summary.byCategory).sort((a, b) => b[1].totalTokens - a[1].totalTokens);\r\n if (cats.length > 0) {\r\n lines.push(\r\n '## By Category',\r\n '',\r\n '| Category | Requests | Prompt | Completion | Total | Cost |',\r\n '|----------|----------|--------|------------|-------|------|',\r\n );\r\n for (const [cat, d] of cats) {\r\n lines.push(`| ${cat} | ${d.requests} | ${d.promptTokens.toLocaleString()} | ${d.completionTokens.toLocaleString()} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // By model\r\n const models = Object.entries(summary.byModel);\r\n if (models.length > 0) {\r\n lines.push(\r\n '## By Model',\r\n '',\r\n '| Model | Requests | Total Tokens | Cost |',\r\n '|-------|----------|-------------|------|',\r\n );\r\n for (const [model, d] of models) {\r\n lines.push(`| ${model} | ${d.requests} | ${d.totalTokens.toLocaleString()} | ¥${d.estimatedCost.toFixed(4)} |`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n') + '\\n';\r\n}\r\n","import type {\r\n PipelineRunResult,\r\n ERDiagramResult,\r\n ChainPlanResult,\r\n GeneratedTestFile,\r\n ValidationError,\r\n ExecutionMetrics,\r\n} from '../types.js';\r\nimport type { ExecutionQualityGateResult } from '../execution/types.js';\r\n\r\n// ===== Reporter Types =====\r\n\r\nexport interface ReportOutput {\r\n format: 'html' | 'json' | 'markdown';\r\n content: string;\r\n filename: string;\r\n}\r\n\r\nexport interface ReportExecutionContext {\r\n metrics?: ExecutionMetrics | null;\r\n quality?: ExecutionQualityGateResult | null;\r\n}\r\n\r\n// ===== JSON Reporter =====\r\n\r\nexport function generateJsonReport(\r\n result: PipelineRunResult,\r\n context?: ReportExecutionContext,\r\n): ReportOutput {\r\n const serializable = {\r\n modules: result.modules,\r\n erDiagrams: Object.fromEntries(\r\n Array.from(result.erDiagrams.entries()).map(([k, v]) => [\r\n k,\r\n { tables: v.tables.length, relations: v.relations.length, mermaidText: v.mermaidText },\r\n ]),\r\n ),\r\n chainPlans: Object.fromEntries(\r\n Array.from(result.chainPlans.entries()).map(([k, v]) => [\r\n k,\r\n { chains: v.chains.length, totalSteps: v.totalSteps },\r\n ]),\r\n ),\r\n generatedFiles: result.generatedFiles.map((f) => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n })),\r\n execution: context\r\n ? {\r\n metrics: context.metrics ?? null,\r\n quality: context.quality ?? null,\r\n }\r\n : undefined,\r\n validationErrors: result.validationErrors,\r\n duration: result.duration,\r\n };\r\n\r\n return {\r\n format: 'json',\r\n content: JSON.stringify(serializable, null, 2),\r\n filename: 'opencroc-report.json',\r\n };\r\n}\r\n\r\n// ===== Markdown Reporter =====\r\n\r\nexport function generateMarkdownReport(\r\n result: PipelineRunResult,\r\n context?: ReportExecutionContext,\r\n): ReportOutput {\r\n const lines: string[] = [\r\n '# OpenCroc Report',\r\n '',\r\n `**Duration**: ${result.duration}ms`,\r\n `**Modules**: ${result.modules.length} (${result.modules.join(', ')})`,\r\n '',\r\n '## ER Diagrams',\r\n '',\r\n ];\r\n\r\n for (const [mod, er] of result.erDiagrams) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Tables: ${er.tables.length}`);\r\n lines.push(`- Relations: ${er.relations.length}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push('## Chain Plans', '');\r\n for (const [mod, plan] of result.chainPlans) {\r\n lines.push(`### ${mod}`);\r\n lines.push(`- Chains: ${plan.chains.length}`);\r\n lines.push(`- Total Steps: ${plan.totalSteps}`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(`## Generated Files (${result.generatedFiles.length})`, '');\r\n for (const f of result.generatedFiles) {\r\n lines.push(`- \\`${f.filePath}\\` (${f.module} / ${f.chain})`);\r\n }\r\n\r\n if (result.validationErrors.length > 0) {\r\n lines.push('', '## Validation Issues', '');\r\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\r\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\r\n if (errors.length > 0) {\r\n lines.push(`### Errors (${errors.length})`, '');\r\n for (const e of errors) {\r\n lines.push(`- **[${e.module}]** ${e.field}: ${e.message}`);\r\n }\r\n }\r\n if (warnings.length > 0) {\r\n lines.push(`### Warnings (${warnings.length})`, '');\r\n for (const w of warnings) {\r\n lines.push(`- **[${w.module}]** ${w.field}: ${w.message}`);\r\n }\r\n }\r\n }\r\n\r\n if (context?.metrics || context?.quality) {\r\n lines.push('', '## Execution Quality', '');\r\n if (context.metrics) {\r\n lines.push(\r\n `- Passed: ${context.metrics.passed}`,\r\n `- Failed: ${context.metrics.failed}`,\r\n `- Skipped: ${context.metrics.skipped}`,\r\n `- TimedOut: ${context.metrics.timedOut}`,\r\n );\r\n }\r\n if (context.quality) {\r\n lines.push(\r\n `- Gate Level: ${context.quality.level}`,\r\n `- Setup Fail: ${context.quality.setupFail}`,\r\n `- Skip Ratio: ${(context.quality.skipRatio * 100).toFixed(2)}%`,\r\n `- Auth Fail Ratio: ${(context.quality.authFailRatio * 100).toFixed(2)}%`,\r\n `- Effective Execution Rate: ${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%`,\r\n `- Auth Status: ${context.quality.authStatus}`,\r\n `- Backend Status: ${context.quality.backendStatus}`,\r\n );\r\n if (context.quality.reasons.length > 0) {\r\n lines.push(`- Reasons: ${context.quality.reasons.join(', ')}`);\r\n }\r\n }\r\n }\r\n\r\n lines.push('', '---', '*Generated by [OpenCroc](https://github.com/opencroc/opencroc)*');\r\n\r\n return {\r\n format: 'markdown',\r\n content: lines.join('\\n'),\r\n filename: 'opencroc-report.md',\r\n };\r\n}\r\n\r\n// ===== HTML Reporter =====\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n\r\nfunction erSummaryRows(erDiagrams: Map<string, ERDiagramResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, er] of erDiagrams) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${er.tables.length}</td><td>${er.relations.length}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction chainSummaryRows(chainPlans: Map<string, ChainPlanResult>): string {\r\n const rows: string[] = [];\r\n for (const [mod, plan] of chainPlans) {\r\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${plan.chains.length}</td><td>${plan.totalSteps}</td></tr>`);\r\n }\r\n return rows.join('\\n');\r\n}\r\n\r\nfunction fileListRows(files: GeneratedTestFile[]): string {\r\n return files\r\n .map((f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`)\r\n .join('\\n');\r\n}\r\n\r\nfunction validationRows(errors: ValidationError[]): string {\r\n return errors\r\n .map(\r\n (e) =>\r\n `<tr class=\"${e.severity}\"><td><span class=\"badge ${e.severity}\">${e.severity}</span></td><td>${escapeHtml(e.module)}</td><td>${escapeHtml(e.field)}</td><td>${escapeHtml(e.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n}\r\n\r\nexport function generateHtmlReport(\r\n result: PipelineRunResult,\r\n context?: ReportExecutionContext,\r\n): ReportOutput {\r\n const totalTables = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.tables.length, 0);\r\n const totalRelations = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.relations.length, 0);\r\n const totalChains = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.chains.length, 0);\r\n const totalSteps = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.totalSteps, 0);\r\n const errorCount = result.validationErrors.filter((e) => e.severity === 'error').length;\r\n const warnCount = result.validationErrors.filter((e) => e.severity === 'warning').length;\r\n\r\n const html = `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\" />\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n<title>OpenCroc Report</title>\r\n<style>\r\n :root { --bg: #0d1117; --fg: #c9d1d9; --card: #161b22; --border: #30363d; --accent: #58a6ff; --green: #3fb950; --yellow: #d29922; --red: #f85149; }\r\n * { box-sizing: border-box; margin: 0; padding: 0; }\r\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--fg); padding: 2rem; }\r\n h1 { color: var(--accent); margin-bottom: 0.25rem; }\r\n .subtitle { color: #8b949e; margin-bottom: 2rem; }\r\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\r\n .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }\r\n .card .label { font-size: 0.85rem; color: #8b949e; }\r\n .card .value { font-size: 2rem; font-weight: 700; color: var(--accent); }\r\n .card .value.green { color: var(--green); }\r\n .card .value.yellow { color: var(--yellow); }\r\n .card .value.red { color: var(--red); }\r\n section { margin-bottom: 2rem; }\r\n h2 { color: var(--fg); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }\r\n table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 8px; overflow: hidden; }\r\n th, td { text-align: left; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }\r\n th { background: #21262d; color: #8b949e; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; }\r\n tr:last-child td { border-bottom: none; }\r\n code { background: #21262d; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; }\r\n .badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }\r\n .badge.error { background: rgba(248,81,73,0.15); color: var(--red); }\r\n .badge.warning { background: rgba(210,153,34,0.15); color: var(--yellow); }\r\n footer { margin-top: 3rem; text-align: center; color: #484f58; font-size: 0.85rem; }\r\n footer a { color: var(--accent); text-decoration: none; }\r\n</style>\r\n</head>\r\n<body>\r\n<h1>OpenCroc Report</h1>\r\n<p class=\"subtitle\">Generated in ${result.duration}ms · ${result.modules.length} module(s)</p>\r\n\r\n<div class=\"grid\">\r\n <div class=\"card\"><div class=\"label\">Modules</div><div class=\"value\">${result.modules.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Tables</div><div class=\"value\">${totalTables}</div></div>\r\n <div class=\"card\"><div class=\"label\">Relations</div><div class=\"value\">${totalRelations}</div></div>\r\n <div class=\"card\"><div class=\"label\">Chains</div><div class=\"value\">${totalChains}</div></div>\r\n <div class=\"card\"><div class=\"label\">Steps</div><div class=\"value\">${totalSteps}</div></div>\r\n <div class=\"card\"><div class=\"label\">Files</div><div class=\"value green\">${result.generatedFiles.length}</div></div>\r\n <div class=\"card\"><div class=\"label\">Errors</div><div class=\"value${errorCount > 0 ? ' red' : ''}\">${errorCount}</div></div>\r\n <div class=\"card\"><div class=\"label\">Warnings</div><div class=\"value${warnCount > 0 ? ' yellow' : ''}\">${warnCount}</div></div>\r\n</div>\r\n\r\n<section>\r\n<h2>ER Diagrams</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Tables</th><th>Relations</th></tr></thead>\r\n<tbody>${erSummaryRows(result.erDiagrams)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Chain Plans</h2>\r\n<table>\r\n<thead><tr><th>Module</th><th>Chains</th><th>Steps</th></tr></thead>\r\n<tbody>${chainSummaryRows(result.chainPlans)}</tbody>\r\n</table>\r\n</section>\r\n\r\n<section>\r\n<h2>Generated Files (${result.generatedFiles.length})</h2>\r\n<table>\r\n<thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n<tbody>${fileListRows(result.generatedFiles)}</tbody>\r\n</table>\r\n</section>\r\n\r\n${\r\n context?.quality || context?.metrics\r\n ? `<section>\r\n<h2>Execution Quality</h2>\r\n<table>\r\n<thead><tr><th>Item</th><th>Value</th></tr></thead>\r\n<tbody>\r\n${context.metrics ? `<tr><td>Passed</td><td>${context.metrics.passed}</td></tr><tr><td>Failed</td><td>${context.metrics.failed}</td></tr><tr><td>Skipped</td><td>${context.metrics.skipped}</td></tr><tr><td>TimedOut</td><td>${context.metrics.timedOut}</td></tr>` : ''}\r\n${context.quality ? `<tr><td>Gate Level</td><td>${escapeHtml(context.quality.level)}</td></tr><tr><td>Setup Fail</td><td>${String(context.quality.setupFail)}</td></tr><tr><td>Skip Ratio</td><td>${(context.quality.skipRatio * 100).toFixed(2)}%</td></tr><tr><td>Auth Fail Ratio</td><td>${(context.quality.authFailRatio * 100).toFixed(2)}%</td></tr><tr><td>Effective Execution Rate</td><td>${(context.quality.effectiveExecutionRate * 100).toFixed(2)}%</td></tr><tr><td>Auth Status</td><td>${escapeHtml(context.quality.authStatus)}</td></tr><tr><td>Backend Status</td><td>${escapeHtml(context.quality.backendStatus)}</td></tr><tr><td>Reasons</td><td>${escapeHtml(context.quality.reasons.join(', ') || '-')}</td></tr>` : ''}\r\n</tbody>\r\n</table>\r\n</section>`\r\n : ''\r\n}\r\n\r\n${\r\n result.validationErrors.length > 0\r\n ? `<section>\r\n<h2>Validation Issues (${result.validationErrors.length})</h2>\r\n<table>\r\n<thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n<tbody>${validationRows(result.validationErrors)}</tbody>\r\n</table>\r\n</section>`\r\n : ''\r\n}\r\n\r\n<footer>\r\n Generated by <a href=\"https://github.com/opencroc/opencroc\">OpenCroc</a>\r\n</footer>\r\n</body>\r\n</html>`;\r\n\r\n return {\r\n format: 'html',\r\n content: html,\r\n filename: 'opencroc-report.html',\r\n };\r\n}\r\n\r\n// ===== Report Orchestrator =====\r\n\r\nconst REPORTERS: Record<string, (result: PipelineRunResult, context?: ReportExecutionContext) => ReportOutput> = {\r\n html: generateHtmlReport,\r\n json: generateJsonReport,\r\n markdown: generateMarkdownReport,\r\n};\r\n\r\n/**\r\n * Generate reports in the specified formats.\r\n */\r\nexport function generateReports(\r\n result: PipelineRunResult,\r\n formats: ('html' | 'json' | 'markdown')[] = ['html'],\r\n context?: ReportExecutionContext,\r\n): ReportOutput[] {\r\n return formats.map((fmt) => {\r\n const gen = REPORTERS[fmt];\r\n if (!gen) throw new Error(`Unknown report format: \"${fmt}\". Available: ${Object.keys(REPORTERS).join(', ')}`);\r\n return gen(result, context);\r\n });\r\n}\r\n\r\n// ===== Advanced Reporters (v1.2) =====\r\nexport {\r\n classifyFailure,\r\n buildFailureSummary,\r\n aggregateLogCompletion,\r\n parseApiDomain,\r\n buildBackendChecklist,\r\n renderChecklistMarkdown,\r\n} from './checklist-reporter.js';\r\n\r\nexport {\r\n buildWorkorders,\r\n renderWorkordersMarkdown,\r\n} from './workorder-reporter.js';\r\nexport type { BuildWorkordersOptions } from './workorder-reporter.js';\r\n\r\nexport {\r\n TokenTracker,\r\n renderTokenReportMarkdown,\r\n} from './token-reporter.js';\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport { generateReports } from '../../reporters/index.js';\r\n\r\nexport interface ReportCommandOptions {\r\n format?: string;\r\n output?: string;\r\n}\r\n\r\nexport async function report(opts: ReportCommandOptions): Promise<void> {\r\n let loaded;\r\n try {\r\n loaded = await loadConfig();\r\n } catch {\r\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const { config } = loaded;\r\n\r\n console.log(chalk.cyan('Running pipeline to generate report...'));\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run();\r\n\r\n const formats = (opts.format ?? 'html').split(',').map((s) => s.trim()) as ('html' | 'json' | 'markdown')[];\r\n const reports = generateReports(result, formats);\r\n\r\n const outDir = opts.output ?? config.outDir ?? './opencroc-output';\r\n if (!fs.existsSync(outDir)) {\r\n fs.mkdirSync(outDir, { recursive: true });\r\n }\r\n\r\n for (const r of reports) {\r\n const filePath = path.join(outDir, r.filename);\r\n fs.writeFileSync(filePath, r.content, 'utf-8');\r\n console.log(chalk.green(`✔ ${r.format} report → ${filePath}`));\r\n }\r\n\r\n console.log(chalk.dim(` ${result.modules.length} modules, ${result.generatedFiles.length} files, ${result.duration}ms`));\r\n}\r\n","import type { PipelineRunResult } from '../types.js';\r\n\r\nexport interface DashboardData {\r\n generatedAt: string;\r\n durationMs: number;\r\n modules: string[];\r\n totals: {\r\n modules: number;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n files: number;\r\n errors: number;\r\n warnings: number;\r\n };\r\n moduleCards: Array<{\r\n module: string;\r\n tables: number;\r\n relations: number;\r\n chains: number;\r\n steps: number;\r\n }>;\r\n files: Array<{ filePath: string; module: string; chain: string }>;\r\n issues: Array<{ severity: string; module: string; field: string; message: string }>;\r\n}\r\n\r\nexport interface DashboardOutput {\r\n filename: string;\r\n content: string;\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction number(v: unknown): number {\r\n return typeof v === 'number' && Number.isFinite(v) ? v : 0;\r\n}\r\n\r\nexport function buildDashboardDataFromPipeline(result: PipelineRunResult): DashboardData {\r\n const moduleCards = result.modules.map((mod) => {\r\n const er = result.erDiagrams.get(mod);\r\n const plan = result.chainPlans.get(mod);\r\n return {\r\n module: mod,\r\n tables: er?.tables.length ?? 0,\r\n relations: er?.relations.length ?? 0,\r\n chains: plan?.chains.length ?? 0,\r\n steps: plan?.totalSteps ?? 0,\r\n };\r\n });\r\n\r\n const totals = {\r\n modules: result.modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: result.generatedFiles.length,\r\n errors: result.validationErrors.filter((e) => e.severity === 'error').length,\r\n warnings: result.validationErrors.filter((e) => e.severity === 'warning').length,\r\n };\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: result.duration,\r\n modules: [...result.modules],\r\n totals,\r\n moduleCards,\r\n files: result.generatedFiles.map((f) => ({ filePath: f.filePath, module: f.module, chain: f.chain })),\r\n issues: result.validationErrors.map((e) => ({\r\n severity: e.severity,\r\n module: e.module,\r\n field: e.field,\r\n message: e.message,\r\n })),\r\n };\r\n}\r\n\r\nexport function buildDashboardDataFromReportJson(input: unknown): DashboardData {\r\n const src = (input ?? {}) as Record<string, unknown>;\r\n const modules = Array.isArray(src.modules) ? src.modules.map((m) => String(m)) : [];\r\n const er = (src.erDiagrams ?? {}) as Record<string, { tables?: unknown; relations?: unknown }>;\r\n const plans = (src.chainPlans ?? {}) as Record<string, { chains?: unknown; totalSteps?: unknown }>;\r\n const files = Array.isArray(src.generatedFiles)\r\n ? src.generatedFiles.map((f) => {\r\n const row = f as Record<string, unknown>;\r\n return {\r\n filePath: String(row.filePath ?? ''),\r\n module: String(row.module ?? ''),\r\n chain: String(row.chain ?? ''),\r\n };\r\n })\r\n : [];\r\n\r\n const rawIssues = Array.isArray(src.validationErrors) ? src.validationErrors : [];\r\n const issues = rawIssues.map((item) => {\r\n const row = item as Record<string, unknown>;\r\n return {\r\n severity: String(row.severity ?? 'warning'),\r\n module: String(row.module ?? 'unknown'),\r\n field: String(row.field ?? 'unknown'),\r\n message: String(row.message ?? ''),\r\n };\r\n });\r\n\r\n const moduleCards = modules.map((mod) => ({\r\n module: mod,\r\n tables: number(er[mod]?.tables),\r\n relations: number(er[mod]?.relations),\r\n chains: number(plans[mod]?.chains),\r\n steps: number(plans[mod]?.totalSteps),\r\n }));\r\n\r\n return {\r\n generatedAt: new Date().toISOString(),\r\n durationMs: number(src.duration),\r\n modules,\r\n totals: {\r\n modules: modules.length,\r\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\r\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\r\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\r\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\r\n files: files.length,\r\n errors: issues.filter((i) => i.severity === 'error').length,\r\n warnings: issues.filter((i) => i.severity === 'warning').length,\r\n },\r\n moduleCards,\r\n files,\r\n issues,\r\n };\r\n}\r\n\r\nexport function generateVisualDashboardHtml(data: DashboardData): string {\r\n const moduleCardHtml = data.moduleCards\r\n .map(\r\n (m) => `<article class=\"module-card reveal\">\r\n <h3>${escapeHtml(m.module)}</h3>\r\n <div class=\"meta\">${m.tables} tables · ${m.relations} relations</div>\r\n <div class=\"bars\">\r\n <div class=\"bar\"><span>Chains</span><strong>${m.chains}</strong></div>\r\n <div class=\"bar\"><span>Steps</span><strong>${m.steps}</strong></div>\r\n </div>\r\n</article>`,\r\n )\r\n .join('\\n');\r\n\r\n const fileRows = data.files\r\n .slice(0, 20)\r\n .map(\r\n (f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n const issueRows = data.issues\r\n .map(\r\n (i) => `<tr class=\"${escapeHtml(i.severity)}\"><td>${escapeHtml(i.severity)}</td><td>${escapeHtml(i.module)}</td><td>${escapeHtml(i.field)}</td><td>${escapeHtml(i.message)}</td></tr>`,\r\n )\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n <meta charset=\"utf-8\" />\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\r\n <title>OpenCroc Visual Dashboard</title>\r\n <style>\r\n @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');\r\n :root {\r\n --bg: #f4efe6;\r\n --ink: #18222c;\r\n --card: #fff8ef;\r\n --line: #d8c7b4;\r\n --accent: #0b7a75;\r\n --accent-2: #f26a2e;\r\n --ok: #2f7d32;\r\n --warn: #b7791f;\r\n --err: #c0392b;\r\n }\r\n * { box-sizing: border-box; }\r\n body {\r\n margin: 0;\r\n font-family: 'Space Grotesk', 'Segoe UI', sans-serif;\r\n color: var(--ink);\r\n background:\r\n radial-gradient(circle at 15% 10%, #f9e2c5 0%, transparent 32%),\r\n radial-gradient(circle at 85% 0%, #d3efe4 0%, transparent 28%),\r\n var(--bg);\r\n min-height: 100vh;\r\n }\r\n .wrap { max-width: 1160px; margin: 0 auto; padding: 24px 18px 40px; }\r\n .hero {\r\n border: 2px solid var(--line);\r\n border-radius: 18px;\r\n background: linear-gradient(130deg, #fff8ef 0%, #f8f2ea 45%, #f3ece3 100%);\r\n padding: 22px;\r\n box-shadow: 0 12px 24px rgba(24, 34, 44, 0.08);\r\n position: relative;\r\n overflow: hidden;\r\n }\r\n .hero::after {\r\n content: '';\r\n position: absolute;\r\n right: -42px;\r\n top: -38px;\r\n width: 160px;\r\n height: 160px;\r\n border-radius: 50%;\r\n background: conic-gradient(from 50deg, #f26a2e 0deg, #f7a35a 90deg, #0b7a75 220deg, #f26a2e 360deg);\r\n opacity: 0.14;\r\n }\r\n h1 { margin: 0; font-size: clamp(1.6rem, 3vw, 2.5rem); letter-spacing: -0.03em; }\r\n .subtitle { margin-top: 8px; font-size: 0.95rem; opacity: 0.82; }\r\n .kpi-grid {\r\n margin-top: 16px;\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\r\n gap: 10px;\r\n }\r\n .kpi {\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n padding: 10px 12px;\r\n background: #fffdf9;\r\n }\r\n .kpi .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }\r\n .kpi .value { font-size: 1.45rem; font-weight: 700; margin-top: 4px; }\r\n .kpi.error .value { color: var(--err); }\r\n .kpi.warning .value { color: var(--warn); }\r\n .kpi.files .value { color: var(--accent); }\r\n\r\n .section-title {\r\n margin: 24px 0 10px;\r\n font-size: 1rem;\r\n text-transform: uppercase;\r\n letter-spacing: 0.08em;\r\n color: #344250;\r\n }\r\n\r\n .module-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\r\n gap: 12px;\r\n }\r\n .module-card {\r\n border: 1px solid var(--line);\r\n border-radius: 14px;\r\n padding: 14px;\r\n background: var(--card);\r\n box-shadow: 0 8px 16px rgba(24, 34, 44, 0.06);\r\n }\r\n .module-card h3 { margin: 0 0 6px; font-size: 1.05rem; }\r\n .module-card .meta { font-size: 0.85rem; opacity: 0.78; }\r\n .bars { margin-top: 10px; display: grid; gap: 8px; }\r\n .bar { display: flex; justify-content: space-between; border-top: 1px dashed var(--line); padding-top: 7px; }\r\n\r\n table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n border: 1px solid var(--line);\r\n border-radius: 12px;\r\n overflow: hidden;\r\n background: #fffdf9;\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n font-size: 0.82rem;\r\n }\r\n thead { background: #efe5d8; }\r\n th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eadfce; }\r\n tbody tr:last-child td { border-bottom: none; }\r\n tr.error td:first-child { color: var(--err); font-weight: 700; }\r\n tr.warning td:first-child { color: var(--warn); font-weight: 700; }\r\n\r\n code {\r\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\r\n background: #f5ece0;\r\n border: 1px solid #eadfce;\r\n border-radius: 6px;\r\n padding: 1px 5px;\r\n }\r\n\r\n .reveal { opacity: 0; transform: translateY(12px); animation: rise .55s ease forwards; }\r\n .module-card.reveal:nth-child(2) { animation-delay: .06s; }\r\n .module-card.reveal:nth-child(3) { animation-delay: .12s; }\r\n .module-card.reveal:nth-child(4) { animation-delay: .18s; }\r\n .module-card.reveal:nth-child(5) { animation-delay: .24s; }\r\n @keyframes rise {\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n\r\n @media (max-width: 700px) {\r\n .wrap { padding: 14px 12px 28px; }\r\n .hero { padding: 16px; }\r\n table { font-size: 0.76rem; }\r\n th, td { padding: 7px 8px; }\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <main class=\"wrap\">\r\n <section class=\"hero reveal\">\r\n <h1>OpenCroc Visual Dashboard</h1>\r\n <p class=\"subtitle\">Pipeline finished in ${data.durationMs}ms · Generated ${escapeHtml(data.generatedAt)}</p>\r\n <div class=\"kpi-grid\">\r\n <div class=\"kpi\"><div class=\"label\">Modules</div><div class=\"value\">${data.totals.modules}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Tables</div><div class=\"value\">${data.totals.tables}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Relations</div><div class=\"value\">${data.totals.relations}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Chains</div><div class=\"value\">${data.totals.chains}</div></div>\r\n <div class=\"kpi\"><div class=\"label\">Steps</div><div class=\"value\">${data.totals.steps}</div></div>\r\n <div class=\"kpi files\"><div class=\"label\">Files</div><div class=\"value\">${data.totals.files}</div></div>\r\n <div class=\"kpi error\"><div class=\"label\">Errors</div><div class=\"value\">${data.totals.errors}</div></div>\r\n <div class=\"kpi warning\"><div class=\"label\">Warnings</div><div class=\"value\">${data.totals.warnings}</div></div>\r\n </div>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Module Health</h2>\r\n <section class=\"module-grid\">\r\n ${moduleCardHtml || '<article class=\"module-card\">No module data</article>'}\r\n </section>\r\n\r\n <h2 class=\"section-title\">Generated Files (Top 20)</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\r\n <tbody>${fileRows || '<tr><td colspan=\"3\">No files generated</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n\r\n <h2 class=\"section-title\">Validation Issues</h2>\r\n <section>\r\n <table>\r\n <thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\r\n <tbody>${issueRows || '<tr><td colspan=\"4\">No validation issues</td></tr>'}</tbody>\r\n </table>\r\n </section>\r\n </main>\r\n</body>\r\n</html>`;\r\n}\r\n\r\nexport function generateVisualDashboard(result: PipelineRunResult): DashboardOutput {\r\n const data = buildDashboardDataFromPipeline(result);\r\n return {\r\n filename: 'opencroc-dashboard.html',\r\n content: generateVisualDashboardHtml(data),\r\n };\r\n}\r\n","import * as fs from 'fs';\r\nimport * as path from 'path';\r\nimport chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createPipeline } from '../../pipeline/index.js';\r\nimport {\r\n buildDashboardDataFromReportJson,\r\n buildDashboardDataFromPipeline,\r\n generateVisualDashboardHtml,\r\n} from '../../dashboard/index.js';\r\n\r\nexport interface DashboardCommandOptions {\r\n output?: string;\r\n input?: string;\r\n}\r\n\r\nexport async function dashboard(opts: DashboardCommandOptions): Promise<void> {\r\n let dashboardHtml: string;\r\n\r\n if (opts.input) {\r\n const inputPath = path.resolve(opts.input);\r\n if (!fs.existsSync(inputPath)) {\r\n console.error(chalk.red(`Input report not found: ${inputPath}`));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const raw = fs.readFileSync(inputPath, 'utf-8');\r\n let parsed: unknown;\r\n try {\r\n parsed = JSON.parse(raw);\r\n } catch {\r\n console.error(chalk.red('Invalid JSON input. Please provide opencroc-report.json output.'));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const data = buildDashboardDataFromReportJson(parsed);\r\n dashboardHtml = generateVisualDashboardHtml(data);\r\n console.log(chalk.cyan(`Building visual dashboard from ${inputPath}...`));\r\n } else {\r\n let loaded;\r\n try {\r\n loaded = await loadConfig();\r\n } catch {\r\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\r\n process.exitCode = 1;\r\n return;\r\n }\r\n\r\n const { config } = loaded;\r\n console.log(chalk.cyan('Running pipeline to build visual dashboard...'));\r\n const pipeline = createPipeline(config);\r\n const result = await pipeline.run();\r\n\r\n const data = buildDashboardDataFromPipeline(result);\r\n dashboardHtml = generateVisualDashboardHtml(data);\r\n }\r\n\r\n const outDir = opts.output ? path.resolve(opts.output) : path.resolve('./opencroc-output');\r\n if (!fs.existsSync(outDir)) {\r\n fs.mkdirSync(outDir, { recursive: true });\r\n }\r\n\r\n const outPath = path.join(outDir, 'opencroc-dashboard.html');\r\n fs.writeFileSync(outPath, dashboardHtml, 'utf-8');\r\n console.log(chalk.green(`✔ visual dashboard → ${outPath}`));\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate playwright.config.ts content based on OpenCroc config.\r\n */\r\nexport function generatePlaywrightConfig(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const outDir = config.outDir || './opencroc-output';\r\n\r\n const baseURL = pw.baseURL ? `'${pw.baseURL}'` : \"process.env.BASE_URL || 'http://localhost:3000'\";\r\n const timeout = pw.timeout ?? 30_000;\r\n const workers = pw.workers ?? (null as number | null); // null → use expression\r\n const retries = pw.retries ?? (null as number | null);\r\n const actionTimeout = pw.actionTimeout ?? 10_000;\r\n const navigationTimeout = pw.navigationTimeout ?? timeout;\r\n const storageState = rt.auth?.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const hasAuth = !!(rt.auth?.loginUrl);\r\n\r\n const lines: string[] = [];\r\n lines.push(`import { defineConfig, devices } from '@playwright/test';`);\r\n lines.push('');\r\n lines.push('export default defineConfig({');\r\n lines.push(` testDir: '${outDir}',`);\r\n lines.push(` testMatch: ['**/*.spec.ts', '**/*.test.ts'],`);\r\n lines.push(` fullyParallel: false,`);\r\n lines.push(` forbidOnly: !!process.env.CI,`);\r\n lines.push(` retries: ${retries !== null ? retries : 'process.env.CI ? 1 : 0'},`);\r\n lines.push(` workers: ${workers !== null ? workers : 'process.env.CI ? 4 : 2'},`);\r\n lines.push(` timeout: ${timeout},`);\r\n lines.push(` globalSetup: './global-setup.ts',`);\r\n lines.push(` globalTeardown: './global-teardown.ts',`);\r\n lines.push(` reporter: [['list'], ['html', { open: 'never' }]],`);\r\n lines.push(` use: {`);\r\n lines.push(` baseURL: ${baseURL},`);\r\n lines.push(` trace: 'retain-on-failure',`);\r\n lines.push(` screenshot: 'only-on-failure',`);\r\n lines.push(` video: 'retain-on-failure',`);\r\n lines.push(` actionTimeout: ${actionTimeout},`);\r\n lines.push(` navigationTimeout: ${navigationTimeout},`);\r\n lines.push(` },`);\r\n\r\n // Projects\r\n lines.push(` projects: [`);\r\n\r\n if (hasAuth) {\r\n lines.push(` {`);\r\n lines.push(` name: 'setup',`);\r\n lines.push(` testMatch: '**/auth.setup.ts',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` dependencies: ['setup'],`);\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n lines.push(` },`);\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium-no-auth',`);\r\n lines.push(` testMatch: '**/login-flow.test.ts',`);\r\n lines.push(` testIgnore: ['**/*.setup.ts'],`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` {`);\r\n lines.push(` name: 'chromium',`);\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n lines.push(` },`);\r\n }\r\n\r\n // Extra projects from config\r\n if (rt.extraProjects) {\r\n for (const proj of rt.extraProjects) {\r\n lines.push(` {`);\r\n lines.push(` name: '${proj.name}',`);\r\n lines.push(` testMatch: '${proj.testMatch}',`);\r\n if (proj.dependencies?.length) {\r\n lines.push(` dependencies: [${proj.dependencies.map((d) => `'${d}'`).join(', ')}],`);\r\n }\r\n if (proj.useAuth !== false && hasAuth) {\r\n lines.push(` use: {`);\r\n lines.push(` ...devices['Desktop Chrome'],`);\r\n lines.push(` storageState: '${storageState}',`);\r\n lines.push(` },`);\r\n } else {\r\n lines.push(` use: { ...devices['Desktop Chrome'] },`);\r\n }\r\n lines.push(` },`);\r\n }\r\n }\r\n\r\n lines.push(` ],`);\r\n lines.push('});');\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-setup.ts content for Playwright.\r\n * Handles backend readiness probe, seed endpoint call, and log cleanup.\r\n */\r\nexport function generateGlobalSetup(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasSeedEndpoint = !!rt.db?.seedEndpoint;\r\n const hasLogEndpoint = !!rt.logEndpoint;\r\n const hasSeedFile = !!rt.db?.seedFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global setup — generated by OpenCroc.`);\r\n lines.push(` * Runs once before all test projects.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n // fetchWithRetry helper\r\n lines.push(`async function fetchWithRetry(`);\r\n lines.push(` url: string,`);\r\n lines.push(` options: RequestInit,`);\r\n lines.push(` retries = 3,`);\r\n lines.push(`): Promise<Response | null> {`);\r\n lines.push(` for (let i = 0; i < retries; i++) {`);\r\n lines.push(` try {`);\r\n lines.push(` const resp = await fetch(url, { ...options, signal: AbortSignal.timeout(10_000) });`);\r\n lines.push(` if (resp.ok) return resp;`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} → \\${resp.status} (\\${i + 1}/\\${retries})\\`);`);\r\n lines.push(` } catch (err: unknown) {`);\r\n lines.push(` const msg = err instanceof Error ? err.message : String(err);`);\r\n lines.push(` console.warn(\\`[global-setup] \\${options.method} \\${url} error (\\${i + 1}/\\${retries}): \\${msg}\\`);`);\r\n lines.push(` }`);\r\n lines.push(` if (i < retries - 1) await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, i)));`);\r\n lines.push(` }`);\r\n lines.push(` return null;`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // waitForBackend helper\r\n lines.push(`async function waitForBackend(origin: string, timeoutMs = 30_000): Promise<void> {`);\r\n lines.push(` const start = Date.now();`);\r\n lines.push(` while (Date.now() - start < timeoutMs) {`);\r\n lines.push(` try {`);\r\n lines.push(` const res = await fetch(\\`\\${origin}/health\\`, { signal: AbortSignal.timeout(3_000) });`);\r\n lines.push(` if (res.ok) return;`);\r\n lines.push(` } catch {`);\r\n lines.push(` // not ready yet`);\r\n lines.push(` }`);\r\n lines.push(` await new Promise((r) => setTimeout(r, 1_000));`);\r\n lines.push(` }`);\r\n lines.push(` throw new Error(\\`Backend not ready after \\${timeoutMs}ms\\`);`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n // Main function\r\n lines.push(`export default async function globalSetup(): Promise<void> {`);\r\n lines.push(` console.log('[global-setup] Starting...');`);\r\n lines.push('');\r\n lines.push(` // Backend readiness probe`);\r\n lines.push(` try {`);\r\n lines.push(` await waitForBackend(BASE_URL, 30_000);`);\r\n lines.push(` console.log('[global-setup] Backend is ready.');`);\r\n lines.push(` } catch (e: unknown) {`);\r\n lines.push(` console.warn(\\`[global-setup] \\${e instanceof Error ? e.message : String(e)}\\`);`);\r\n lines.push(` }`);\r\n lines.push('');\r\n\r\n if (hasSeedEndpoint) {\r\n lines.push(` // Seed data via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(`);\r\n lines.push(` \\`\\${BASE_URL}${rt.db!.seedEndpoint}\\`,`);\r\n lines.push(` { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' },`);\r\n lines.push(` );`);\r\n lines.push(` console.log('[global-setup] Seed endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Seed endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasLogEndpoint) {\r\n lines.push(` // Clear test logs`);\r\n lines.push(` try {`);\r\n lines.push(` await fetchWithRetry(\\`\\${BASE_URL}${rt.logEndpoint}\\`, { method: 'DELETE' });`);\r\n lines.push(` console.log('[global-setup] Test logs cleared.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-setup] Failed to clear test logs.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasSeedFile) {\r\n lines.push(` // SQL seed file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.seedFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-setup] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate global-teardown.ts content for Playwright.\r\n * Handles cleanup endpoint call and optional SQL cleanup.\r\n */\r\nexport function generateGlobalTeardown(config: OpenCrocConfig): string {\r\n const pw = config.playwright ?? {};\r\n const rt = config.runtime ?? {};\r\n const baseURL = pw.baseURL || '';\r\n\r\n const hasCleanupEndpoint = !!rt.db?.cleanupEndpoint;\r\n const hasCleanupFile = !!rt.db?.cleanupFile;\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`/**`);\r\n lines.push(` * Global teardown — generated by OpenCroc.`);\r\n lines.push(` * Runs once after all test projects complete.`);\r\n lines.push(` */`);\r\n lines.push('');\r\n lines.push(`const BASE_URL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push('');\r\n\r\n lines.push(`export default async function globalTeardown(): Promise<void> {`);\r\n lines.push(` console.log('[global-teardown] Starting...');`);\r\n lines.push('');\r\n\r\n if (hasCleanupEndpoint) {\r\n lines.push(` // Cleanup via backend endpoint`);\r\n lines.push(` try {`);\r\n lines.push(` await fetch(\\`\\${BASE_URL}${rt.db!.cleanupEndpoint}\\`, { method: 'POST' });`);\r\n lines.push(` console.log('[global-teardown] Cleanup endpoint called.');`);\r\n lines.push(` } catch {`);\r\n lines.push(` console.warn('[global-teardown] Cleanup endpoint failed.');`);\r\n lines.push(` }`);\r\n lines.push('');\r\n }\r\n\r\n if (hasCleanupFile) {\r\n lines.push(` // SQL cleanup file execution (placeholder — wire to your DB helper)`);\r\n lines.push(` // import { executeSeedSQL } from './utils/db-helper';`);\r\n lines.push(` // await executeSeedSQL('${rt.db!.cleanupFile}');`);\r\n lines.push('');\r\n }\r\n\r\n lines.push(` console.log('[global-teardown] Done.');`);\r\n lines.push(`}`);\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\n\r\n/**\r\n * Generate auth.setup.ts content for Playwright.\r\n * Creates an authentication setup project that stores state for reuse.\r\n */\r\nexport function generateAuthSetup(config: OpenCrocConfig): string {\r\n const rt = config.runtime ?? {};\r\n const pw = config.playwright ?? {};\r\n const auth = rt.auth ?? {};\r\n const baseURL = pw.baseURL || '';\r\n const storageStatePath = auth.storageStatePath || 'playwright/.auth/user.json';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`import { test as setup, expect } from '@playwright/test';`);\r\n lines.push(`import * as fs from 'fs/promises';`);\r\n lines.push(`import * as path from 'path';`);\r\n lines.push('');\r\n\r\n lines.push(`const authFile = '${storageStatePath}';`);\r\n lines.push('');\r\n\r\n if (auth.loginUrl) {\r\n // API-based authentication\r\n lines.push(`setup('authenticate', async ({ request }) => {`);\r\n lines.push(` const loginUrl = process.env.AUTH_LOGIN_URL || '${auth.loginUrl}';`);\r\n lines.push(` const username = process.env.AUTH_USERNAME || '${auth.username || 'admin'}';`);\r\n lines.push(` const password = process.env.AUTH_PASSWORD || '${auth.password || ''}';`);\r\n lines.push('');\r\n lines.push(` // API login`);\r\n lines.push(` const response = await request.post(loginUrl, {`);\r\n lines.push(` data: { username, password },`);\r\n lines.push(` });`);\r\n lines.push(` expect(response.ok()).toBeTruthy();`);\r\n lines.push('');\r\n lines.push(` const body = await response.json();`);\r\n lines.push(` const token = body.data?.token || body.token || '';`);\r\n lines.push(` console.log('[auth.setup] Login successful, token obtained:', !!token);`);\r\n lines.push('');\r\n lines.push(` // Save storage state with auth cookie/localStorage`);\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push('');\r\n lines.push(` // Build storage state JSON`);\r\n lines.push(` const baseURL = process.env.BASE_URL || '${baseURL || 'http://localhost:3000'}';`);\r\n lines.push(` const origin = new URL(baseURL).origin;`);\r\n lines.push(` const storageState = {`);\r\n lines.push(` cookies: [],`);\r\n lines.push(` origins: [`);\r\n lines.push(` {`);\r\n lines.push(` origin,`);\r\n lines.push(` localStorage: [`);\r\n lines.push(` { name: 'token', value: token },`);\r\n lines.push(` ],`);\r\n lines.push(` },`);\r\n lines.push(` ],`);\r\n lines.push(` };`);\r\n lines.push('');\r\n lines.push(` await fs.writeFile(authFile, JSON.stringify(storageState, null, 2));`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push(`});`);\r\n } else {\r\n // Browser-based authentication (placeholder)\r\n lines.push(`setup('authenticate', async ({ browser }) => {`);\r\n lines.push(` const context = await browser.newContext();`);\r\n lines.push(` const page = await context.newPage();`);\r\n lines.push('');\r\n lines.push(` // TODO: Implement your login flow here`);\r\n lines.push(` // await page.goto('/login');`);\r\n lines.push(` // await page.fill('[name=username]', 'admin');`);\r\n lines.push(` // await page.fill('[name=password]', 'password');`);\r\n lines.push(` // await page.click('button[type=submit]');`);\r\n lines.push(` // await page.waitForURL('/dashboard');`);\r\n lines.push('');\r\n lines.push(` await fs.mkdir(path.dirname(authFile), { recursive: true });`);\r\n lines.push(` await context.storageState({ path: authFile });`);\r\n lines.push(` console.log(\\`[auth.setup] Storage state saved → \\${authFile}\\`);`);\r\n lines.push('');\r\n lines.push(` await context.close();`);\r\n lines.push(`});`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n","import chalk from 'chalk';\r\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { join, resolve } from 'node:path';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { generatePlaywrightConfig } from '../../runtime/playwright-config-generator.js';\r\nimport { generateGlobalSetup } from '../../runtime/global-setup-generator.js';\r\nimport { generateGlobalTeardown } from '../../runtime/global-teardown-generator.js';\r\nimport { generateAuthSetup } from '../../runtime/auth-setup-generator.js';\r\n\r\nexport interface InitRuntimeOptions {\r\n output?: string;\r\n force?: boolean;\r\n}\r\n\r\nfunction writeIfNotExists(filePath: string, content: string, force: boolean): boolean {\r\n if (existsSync(filePath) && !force) {\r\n console.log(chalk.yellow(` ⊘ ${filePath} already exists (use --force to overwrite)`));\r\n return false;\r\n }\r\n const dir = resolve(filePath, '..');\r\n mkdirSync(dir, { recursive: true });\r\n writeFileSync(filePath, content, 'utf-8');\r\n console.log(chalk.green(` ✓ ${filePath}`));\r\n return true;\r\n}\r\n\r\nexport async function initRuntime(opts: InitRuntimeOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Initialize Playwright Runtime\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const outDir = resolve(opts.output || '.');\r\n const force = opts.force ?? false;\r\n const hasAuth = !!config.runtime?.auth?.loginUrl;\r\n\r\n let written = 0;\r\n\r\n console.log(chalk.cyan('\\n Generating runtime files...\\n'));\r\n\r\n if (writeIfNotExists(join(outDir, 'playwright.config.ts'), generatePlaywrightConfig(config), force)) written++;\r\n if (writeIfNotExists(join(outDir, 'global-setup.ts'), generateGlobalSetup(config), force)) written++;\r\n if (writeIfNotExists(join(outDir, 'global-teardown.ts'), generateGlobalTeardown(config), force)) written++;\r\n\r\n if (hasAuth) {\r\n if (writeIfNotExists(join(outDir, 'auth.setup.ts'), generateAuthSetup(config), force)) written++;\r\n }\r\n\r\n console.log('');\r\n if (written > 0) {\r\n console.log(chalk.green(` ✓ Generated ${written} runtime file(s) in ${outDir}\\n`));\r\n } else {\r\n console.log(chalk.yellow(` No files written. Use --force to overwrite existing files.\\n`));\r\n }\r\n}\r\n","/**\r\n * Full orchestration engine: generate → execute → analyze → heal → report.\r\n *\r\n * Runs a multi-phase pipeline with per-phase tracking, failure detection,\r\n * token budget management, and structured result reporting.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, readdirSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport type {\r\n OpenCrocConfig,\r\n PipelineRunResult,\r\n SelfHealingConfig,\r\n SelfHealingResult,\r\n} from '../types.js';\r\nimport { createPipeline } from '../pipeline/index.js';\r\nimport { createSelfHealingLoop } from '../self-healing/index.js';\r\nimport { generateReports } from '../reporters/index.js';\r\nimport type { ReportOutput } from '../reporters/index.js';\r\n\r\n// ===== Types =====\r\n\r\nexport type PhaseStatus = 'success' | 'warn' | 'error' | 'skipped';\r\n\r\nexport interface PhaseResult<T = unknown> {\r\n phase: string;\r\n status: PhaseStatus;\r\n output?: T;\r\n error?: string;\r\n durationMs: number;\r\n}\r\n\r\nexport interface OrchestrationOptions {\r\n /** Which phases to run (default: all) */\r\n phases?: OrchestrationPhase[];\r\n /** Enable self-healing phase (default: false) */\r\n selfHeal?: boolean;\r\n /** Max self-healing iterations */\r\n maxHealIterations?: number;\r\n /** Report formats to generate */\r\n reportFormats?: ('html' | 'json' | 'markdown')[];\r\n /** Run Playwright in headed mode */\r\n headed?: boolean;\r\n /** Module filter */\r\n module?: string;\r\n /** LLM token budget (0 = unlimited) */\r\n tokenBudget?: number;\r\n /** Abort on phase error (default: false — continue where possible) */\r\n abortOnError?: boolean;\r\n}\r\n\r\nexport type OrchestrationPhase = 'generate' | 'execute' | 'analyze' | 'heal' | 'report';\r\n\r\nexport interface ExecutionMetrics {\r\n passed: number;\r\n failed: number;\r\n skipped: number;\r\n timedOut: number;\r\n}\r\n\r\nexport interface OrchestrationSummary {\r\n overallStatus: 'success' | 'partial-fail' | 'fatal-fail';\r\n phases: PhaseResult[];\r\n totalDurationMs: number;\r\n modules: string[];\r\n executionMetrics?: ExecutionMetrics;\r\n reports?: ReportOutput[];\r\n healingResult?: SelfHealingResult;\r\n recommendation?: string;\r\n}\r\n\r\nconst ALL_PHASES: OrchestrationPhase[] = ['generate', 'execute', 'analyze', 'heal', 'report'];\r\n\r\n// ===== Helpers =====\r\n\r\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\r\n const absDir = join(process.cwd(), outDir);\r\n if (!existsSync(absDir)) return [];\r\n\r\n const files: string[] = [];\r\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\r\n for (const entry of entries) {\r\n if (!entry.isFile()) continue;\r\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\r\n const fullPath = join(\r\n entry.parentPath || (entry as unknown as { path: string }).path || absDir,\r\n entry.name,\r\n );\r\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\r\n files.push(fullPath);\r\n }\r\n return files;\r\n}\r\n\r\nfunction parsePlaywrightOutput(stderr: string): ExecutionMetrics {\r\n const metrics: ExecutionMetrics = { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n\r\n // Playwright summary line: \"X passed\", \"Y failed\", \"Z skipped\"\r\n const passedMatch = stderr.match(/(\\d+)\\s+passed/);\r\n const failedMatch = stderr.match(/(\\d+)\\s+failed/);\r\n const skippedMatch = stderr.match(/(\\d+)\\s+skipped/);\r\n const timedOutMatch = stderr.match(/(\\d+)\\s+timed?\\s*out/i);\r\n\r\n if (passedMatch) metrics.passed = parseInt(passedMatch[1], 10);\r\n if (failedMatch) metrics.failed = parseInt(failedMatch[1], 10);\r\n if (skippedMatch) metrics.skipped = parseInt(skippedMatch[1], 10);\r\n if (timedOutMatch) metrics.timedOut = parseInt(timedOutMatch[1], 10);\r\n\r\n return metrics;\r\n}\r\n\r\n// ===== Orchestrator =====\r\n\r\nexport function createOrchestrator(config: OpenCrocConfig, options: OrchestrationOptions = {}) {\r\n const {\r\n phases = ALL_PHASES,\r\n selfHeal = false,\r\n maxHealIterations = 3,\r\n reportFormats = ['html', 'json'],\r\n headed = false,\r\n module: moduleFilter,\r\n tokenBudget = 0,\r\n abortOnError = false,\r\n } = options;\r\n\r\n const outDir = config.outDir || './opencroc-output';\r\n const phaseResults: PhaseResult[] = [];\r\n let pipelineResult: PipelineRunResult | undefined;\r\n let executionMetrics: ExecutionMetrics | undefined;\r\n let healingResult: SelfHealingResult | undefined;\r\n let reports: ReportOutput[] | undefined;\r\n let tokensUsed = 0;\r\n\r\n function isBudgetExceeded(): boolean {\r\n return tokenBudget > 0 && tokensUsed >= tokenBudget;\r\n }\r\n\r\n function shouldRun(phase: OrchestrationPhase): boolean {\r\n if (phase === 'heal' && !selfHeal) return false;\r\n return phases.includes(phase);\r\n }\r\n\r\n async function runPhase<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n ): Promise<PhaseResult<T>> {\r\n const start = Date.now();\r\n try {\r\n const output = await fn();\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'success',\r\n output,\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n } catch (err) {\r\n const result: PhaseResult<T> = {\r\n phase: name,\r\n status: 'error',\r\n error: err instanceof Error ? err.message : String(err),\r\n durationMs: Date.now() - start,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n }\r\n\r\n function skipPhase(name: string, reason: string): PhaseResult {\r\n const result: PhaseResult = {\r\n phase: name,\r\n status: 'skipped',\r\n error: reason,\r\n durationMs: 0,\r\n };\r\n phaseResults.push(result);\r\n return result;\r\n }\r\n\r\n return {\r\n async run(): Promise<OrchestrationSummary> {\r\n const orchestrationStart = Date.now();\r\n\r\n // ── Phase 1: Generate ──\r\n if (shouldRun('generate')) {\r\n const genResult = await runPhase('generate', async () => {\r\n if (moduleFilter) config.modules = [moduleFilter];\r\n const pipeline = createPipeline(config);\r\n pipelineResult = await pipeline.run();\r\n\r\n // Write generated files\r\n for (const file of pipelineResult.generatedFiles) {\r\n const dir = dirname(file.filePath);\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n writeFileSync(file.filePath, file.content, 'utf-8');\r\n }\r\n\r\n return pipelineResult;\r\n });\r\n\r\n if (genResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n\r\n // ── Phase 2: Execute ──\r\n if (shouldRun('execute')) {\r\n const testFiles = discoverTestFiles(outDir, moduleFilter);\r\n\r\n if (testFiles.length === 0) {\r\n skipPhase('execute', 'No test files found');\r\n } else {\r\n const execResult = await runPhase('execute', async () => {\r\n const args = ['test', ...testFiles];\r\n if (!headed) args.push('--reporter=list');\r\n else args.push('--headed');\r\n\r\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\r\n\r\n try {\r\n execFileSync(npxCmd, ['playwright', ...args], {\r\n cwd: process.cwd(),\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n timeout: 300_000,\r\n });\r\n return { passed: testFiles.length, failed: 0, skipped: 0, timedOut: 0 } as ExecutionMetrics;\r\n } catch (err) {\r\n const stderr = (err as { stderr?: Buffer })?.stderr?.toString() ?? '';\r\n const metrics = parsePlaywrightOutput(stderr);\r\n if (metrics.passed === 0 && metrics.failed === 0) {\r\n metrics.failed = testFiles.length;\r\n }\r\n executionMetrics = metrics;\r\n if (metrics.failed > 0) {\r\n throw new Error(`${metrics.failed} test(s) failed, ${metrics.passed} passed`, { cause: err });\r\n }\r\n return metrics;\r\n }\r\n });\r\n\r\n if (!executionMetrics && execResult.output) {\r\n executionMetrics = execResult.output as ExecutionMetrics;\r\n }\r\n\r\n if (execResult.status === 'error' && abortOnError) {\r\n return buildSummary(orchestrationStart);\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 3: Analyze ──\r\n if (shouldRun('analyze')) {\r\n if (!pipelineResult || !executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('analyze', 'No failures to analyze');\r\n } else {\r\n await runPhase('analyze', async () => {\r\n // Re-run pipeline validation for failure context\r\n const pipeline = createPipeline(config);\r\n const validationResult = await pipeline.run(['validate']);\r\n return {\r\n validationErrors: validationResult.validationErrors,\r\n failedTestCount: executionMetrics!.failed,\r\n };\r\n });\r\n }\r\n }\r\n\r\n // ── Phase 4: Heal ──\r\n if (shouldRun('heal')) {\r\n if (isBudgetExceeded()) {\r\n skipPhase('heal', 'Token budget exceeded');\r\n } else if (!executionMetrics || executionMetrics.failed === 0) {\r\n skipPhase('heal', 'No failures to heal');\r\n } else {\r\n const healResult = await runPhase('heal', async () => {\r\n const healConfig: SelfHealingConfig = {\r\n enabled: true,\r\n maxIterations: maxHealIterations,\r\n mode: config.selfHealing?.mode || 'config-only',\r\n };\r\n\r\n const loop = createSelfHealingLoop(healConfig);\r\n const result = await loop.run(outDir);\r\n tokensUsed += result.totalTokensUsed;\r\n healingResult = result;\r\n return result;\r\n });\r\n\r\n if (healResult.status === 'success' && healingResult && healingResult.remaining.length > 0) {\r\n healResult.status = 'warn';\r\n phaseResults[phaseResults.length - 1] = healResult;\r\n }\r\n }\r\n }\r\n\r\n // ── Phase 5: Report ──\r\n if (shouldRun('report')) {\r\n if (!pipelineResult) {\r\n skipPhase('report', 'No pipeline results to report');\r\n } else {\r\n await runPhase('report', async () => {\r\n reports = generateReports(pipelineResult!, reportFormats);\r\n\r\n if (!existsSync(outDir)) mkdirSync(outDir, { recursive: true });\r\n for (const r of reports) {\r\n writeFileSync(join(outDir, r.filename), r.content, 'utf-8');\r\n }\r\n\r\n return reports;\r\n });\r\n }\r\n }\r\n\r\n return buildSummary(orchestrationStart);\r\n },\r\n };\r\n\r\n function buildSummary(startTime: number): OrchestrationSummary {\r\n const errorCount = phaseResults.filter((p) => p.status === 'error').length;\r\n const allSuccess = phaseResults.every((p) => p.status === 'success' || p.status === 'skipped');\r\n\r\n let overallStatus: OrchestrationSummary['overallStatus'];\r\n if (allSuccess) overallStatus = 'success';\r\n else if (errorCount > 1) overallStatus = 'fatal-fail';\r\n else overallStatus = 'partial-fail';\r\n\r\n let recommendation: string | undefined;\r\n if (executionMetrics && executionMetrics.failed > 0 && !selfHeal) {\r\n recommendation = 'Test failures detected. Consider running with --self-heal to attempt automated fixes.';\r\n } else if (healingResult && healingResult.remaining.length > 0) {\r\n recommendation = `${healingResult.remaining.length} issue(s) could not be auto-fixed. Manual review needed.`;\r\n }\r\n\r\n return {\r\n overallStatus,\r\n phases: phaseResults,\r\n totalDurationMs: Date.now() - startTime,\r\n modules: pipelineResult?.modules ?? [],\r\n executionMetrics,\r\n reports,\r\n healingResult,\r\n recommendation,\r\n };\r\n }\r\n}\r\n","/**\r\n * Orchestration summary reporter.\r\n * Writes phase-by-phase JSON and a human-readable console summary.\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { OrchestrationSummary, PhaseResult } from './index.js';\r\n\r\nexport interface OrchestrationReportOptions {\r\n outputDir: string;\r\n module?: string;\r\n}\r\n\r\n/**\r\n * Write the orchestration summary to a JSON file.\r\n * Returns the written file path.\r\n */\r\nexport function writeOrchestrationSummary(\r\n summary: OrchestrationSummary,\r\n options: OrchestrationReportOptions,\r\n): string {\r\n const { outputDir, module: mod } = options;\r\n if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-');\r\n const moduleName = mod ?? 'all';\r\n const filename = `orchestration-${moduleName}-${timestamp}.json`;\r\n const filePath = join(outputDir, filename);\r\n\r\n const serializable = {\r\n ...summary,\r\n phases: summary.phases.map((p) => ({\r\n phase: p.phase,\r\n status: p.status,\r\n error: p.error,\r\n durationMs: p.durationMs,\r\n })),\r\n // Strip report content to avoid massive JSON\r\n reports: summary.reports?.map((r) => ({\r\n format: r.format,\r\n filename: r.filename,\r\n })),\r\n };\r\n\r\n writeFileSync(filePath, JSON.stringify(serializable, null, 2), 'utf-8');\r\n return filePath;\r\n}\r\n\r\n/**\r\n * Format a phase result as a single console line.\r\n */\r\nfunction formatPhase(p: PhaseResult): string {\r\n const icons: Record<string, string> = {\r\n success: '✓',\r\n warn: '⚠',\r\n error: '✗',\r\n skipped: '○',\r\n };\r\n const icon = icons[p.status] ?? '?';\r\n const dur = p.durationMs > 0 ? ` (${p.durationMs}ms)` : '';\r\n const err = p.error ? ` — ${p.error}` : '';\r\n return ` ${icon} ${p.phase}${dur}${err}`;\r\n}\r\n\r\n/**\r\n * Print a human-readable console summary.\r\n */\r\nexport function printOrchestrationSummary(summary: OrchestrationSummary): string[] {\r\n const lines: string[] = [];\r\n\r\n lines.push('');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push(' Orchestration Summary');\r\n lines.push(' ═══════════════════════════════════════');\r\n lines.push('');\r\n\r\n for (const p of summary.phases) {\r\n lines.push(formatPhase(p));\r\n }\r\n\r\n lines.push('');\r\n lines.push(` Overall : ${summary.overallStatus}`);\r\n lines.push(` Modules : ${summary.modules.join(', ') || '(none)'}`);\r\n lines.push(` Duration : ${summary.totalDurationMs}ms`);\r\n\r\n if (summary.executionMetrics) {\r\n const m = summary.executionMetrics;\r\n lines.push(` Tests : ${m.passed} passed, ${m.failed} failed, ${m.skipped} skipped`);\r\n }\r\n\r\n if (summary.healingResult) {\r\n const h = summary.healingResult;\r\n lines.push(` Healing : ${h.fixed.length} fixed, ${h.remaining.length} remaining (${h.iterations} iterations)`);\r\n }\r\n\r\n if (summary.reports) {\r\n lines.push(` Reports : ${summary.reports.map((r) => r.format).join(', ')}`);\r\n }\r\n\r\n if (summary.recommendation) {\r\n lines.push('');\r\n lines.push(` → ${summary.recommendation}`);\r\n }\r\n\r\n lines.push('');\r\n\r\n return lines;\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport { createOrchestrator } from '../../orchestrator/index.js';\r\nimport { writeOrchestrationSummary, printOrchestrationSummary } from '../../orchestrator/reporter.js';\r\nimport type { OrchestrationPhase } from '../../orchestrator/index.js';\r\n\r\nexport interface RunOptions {\r\n module?: string;\r\n phases?: string;\r\n selfHeal?: boolean;\r\n headed?: boolean;\r\n report?: string;\r\n tokenBudget?: string;\r\n abortOnError?: boolean;\r\n}\r\n\r\nconst VALID_PHASES: OrchestrationPhase[] = ['generate', 'execute', 'analyze', 'heal', 'report'];\r\n\r\nfunction parsePhases(raw?: string): OrchestrationPhase[] | undefined {\r\n if (!raw) return undefined;\r\n const names = raw.split(',').map((s) => s.trim());\r\n for (const name of names) {\r\n if (!VALID_PHASES.includes(name as OrchestrationPhase)) {\r\n console.log(chalk.red(` Unknown phase \"${name}\". Valid: ${VALID_PHASES.join(', ')}`));\r\n process.exitCode = 1;\r\n return undefined;\r\n }\r\n }\r\n return names as OrchestrationPhase[];\r\n}\r\n\r\nexport async function run(opts: RunOptions): Promise<void> {\r\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Full Orchestration\\n'));\r\n\r\n const { config, filepath } = await loadConfig();\r\n console.log(chalk.gray(` Config: ${filepath}`));\r\n\r\n const phases = parsePhases(opts.phases);\r\n if (phases === undefined && opts.phases) return;\r\n\r\n const reportFormats = (opts.report ?? 'html,json').split(',').map((s) => s.trim()) as ('html' | 'json' | 'markdown')[];\r\n\r\n const orchestrator = createOrchestrator(config, {\r\n phases,\r\n selfHeal: opts.selfHeal ?? false,\r\n headed: opts.headed ?? false,\r\n module: opts.module,\r\n reportFormats,\r\n tokenBudget: opts.tokenBudget ? parseInt(opts.tokenBudget, 10) : 0,\r\n abortOnError: opts.abortOnError ?? false,\r\n });\r\n\r\n console.log(chalk.gray(` Phases: ${(phases ?? VALID_PHASES).join(' → ')}`));\r\n if (opts.selfHeal) console.log(chalk.gray(' Self-heal: enabled'));\r\n console.log('');\r\n\r\n const summary = await orchestrator.run();\r\n\r\n // Print console summary\r\n const lines = printOrchestrationSummary(summary);\r\n for (const line of lines) {\r\n const color =\r\n summary.overallStatus === 'success' ? chalk.green :\r\n summary.overallStatus === 'partial-fail' ? chalk.yellow :\r\n chalk.red;\r\n console.log(color(line));\r\n }\r\n\r\n // Write JSON summary\r\n const outDir = config.outDir || './opencroc-output';\r\n const summaryPath = writeOrchestrationSummary(summary, { outputDir: outDir, module: opts.module });\r\n console.log(chalk.gray(` Summary: ${summaryPath}\\n`));\r\n\r\n if (summary.overallStatus !== 'success') {\r\n process.exitCode = 1;\r\n }\r\n}\r\n","import type { FastifyInstance } from 'fastify';\r\nimport type { CrocOffice } from '../croc-office.js';\r\n\r\nexport function registerProjectRoutes(app: FastifyInstance, office: CrocOffice): void {\r\n // GET /api/project — full project info + knowledge graph\r\n app.get('/api/project', async () => {\r\n return office.getProjectInfo();\r\n });\r\n\r\n // GET /api/project/graph — knowledge graph only\r\n app.get('/api/project/graph', async () => {\r\n return office.buildKnowledgeGraph();\r\n });\r\n\r\n // POST /api/project/refresh — invalidate cache and re-scan\r\n app.post('/api/project/refresh', async () => {\r\n office.invalidateCache();\r\n const graph = await office.buildKnowledgeGraph();\r\n office.broadcast('graph:update', graph);\r\n return { ok: true, nodes: graph.nodes.length, edges: graph.edges.length };\r\n });\r\n}\r\n","import type { FastifyInstance } from 'fastify';\r\nimport type { CrocOffice } from '../croc-office.js';\r\nimport type { ExecutionRunMode } from '../../execution/types.js';\r\n\r\nexport function registerAgentRoutes(app: FastifyInstance, office: CrocOffice): void {\r\n // GET /api/agents — list all croc agents\r\n app.get('/api/agents', async () => {\r\n return office.getAgents();\r\n });\r\n\r\n // GET /api/agents/:id — get specific agent\r\n app.get<{ Params: { id: string } }>('/api/agents/:id', async (req, reply) => {\r\n const agent = office.getAgent(req.params.id);\r\n if (!agent) {\r\n reply.code(404).send({ error: 'Agent not found' });\r\n return;\r\n }\r\n return agent;\r\n });\r\n\r\n // POST /api/scan — trigger project scan (parser croc)\r\n app.post('/api/scan', async (_req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n // Run async — don't await, respond immediately\r\n office.runScan().catch(() => { /* errors handled in runScan */ });\r\n return { ok: true, message: 'Scan started' };\r\n });\r\n\r\n // POST /api/pipeline — trigger full pipeline (all crocs)\r\n app.post('/api/pipeline', async (_req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n office.runPipeline().catch(() => { /* errors handled in runPipeline */ });\r\n return { ok: true, message: 'Pipeline started' };\r\n });\r\n\r\n // POST /api/reset — reset all agents to idle\r\n app.post('/api/reset', async () => {\r\n office.resetAgents();\r\n return { ok: true };\r\n });\r\n\r\n // GET /api/status — overall status\r\n app.get('/api/status', async () => {\r\n return {\r\n running: office.isRunning(),\r\n agents: office.getAgents(),\r\n };\r\n });\r\n\r\n // GET /api/files — generated test files from last pipeline run\r\n app.get('/api/files', async () => {\r\n const files = office.getGeneratedFiles();\r\n return files.map(f => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n lines: f.content.split('\\n').length,\r\n size: f.content.length,\r\n }));\r\n });\r\n\r\n // GET /api/files/:index — get content of a specific generated file\r\n app.get<{ Params: { index: string } }>('/api/files/:index', async (req, reply) => {\r\n const files = office.getGeneratedFiles();\r\n const idx = parseInt(req.params.index, 10);\r\n if (isNaN(idx) || idx < 0 || idx >= files.length) {\r\n reply.code(404).send({ error: 'File not found' });\r\n return;\r\n }\r\n return files[idx];\r\n });\r\n\r\n // GET /api/pipeline/result — last pipeline result summary\r\n app.get('/api/pipeline/result', async () => {\r\n const result = office.getLastPipelineResult();\r\n if (!result) return { ok: false, message: 'No pipeline has been run yet' };\r\n return {\r\n ok: true,\r\n modules: result.modules,\r\n erDiagramCount: result.erDiagrams.size,\r\n chainCount: [...result.chainPlans.values()].reduce((s, p) => s + p.chains.length, 0),\r\n totalSteps: [...result.chainPlans.values()].reduce((s, p) => s + p.totalSteps, 0),\r\n filesGenerated: result.generatedFiles.length,\r\n validationErrors: result.validationErrors.length,\r\n duration: result.duration,\r\n };\r\n });\r\n\r\n // POST /api/run-tests — execute generated tests with Playwright\r\n app.post<{ Body: { mode?: ExecutionRunMode } }>('/api/run-tests', async (req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n const mode = req.body?.mode;\r\n if (mode && !['auto', 'reuse', 'managed'].includes(mode)) {\r\n reply.code(400).send({ error: 'Invalid mode. Valid values: auto, reuse, managed' });\r\n return;\r\n }\r\n office.runTests({ mode }).catch(() => { /* errors handled internally */ });\r\n return { ok: true, message: 'Test execution started' };\r\n });\r\n\r\n // GET /api/test-results — last test execution metrics\r\n app.get('/api/test-results', async () => {\r\n const metrics = office.getLastExecutionMetrics();\r\n const quality = office.getLastExecutionQuality();\r\n if (!metrics && !quality) return { ok: false, message: 'No tests have been run yet' };\r\n if (!metrics) {\r\n return { ok: true, metrics: null, total: 0, quality };\r\n }\r\n const total = metrics.passed + metrics.failed + metrics.skipped + metrics.timedOut;\r\n return { ok: true, metrics, total, quality };\r\n });\r\n\r\n // POST /api/reports/generate — generate reports from last pipeline result\r\n app.post('/api/reports/generate', async (_req, reply) => {\r\n if (office.isRunning()) {\r\n reply.code(409).send({ error: 'A task is already running' });\r\n return;\r\n }\r\n office.generateReport().catch(() => { /* errors handled internally */ });\r\n return { ok: true, message: 'Report generation started' };\r\n });\r\n\r\n // GET /api/reports — list last generated reports\r\n app.get('/api/reports', async () => {\r\n const reports = office.getLastReports();\r\n if (reports.length === 0) return { ok: false, message: 'No reports generated yet' };\r\n return {\r\n ok: true,\r\n reports: reports.map(r => ({\r\n format: r.format,\r\n filename: r.filename,\r\n size: r.content.length,\r\n })),\r\n };\r\n });\r\n\r\n // GET /api/reports/:format — get report content by format (html|json|markdown)\r\n app.get<{ Params: { format: string } }>('/api/reports/:format', async (req, reply) => {\r\n const reports = office.getLastReports();\r\n const report = reports.find(r => r.format === req.params.format);\r\n if (!report) {\r\n reply.code(404).send({ error: `No ${req.params.format} report found` });\r\n return;\r\n }\r\n const contentType = req.params.format === 'html' ? 'text/html'\r\n : req.params.format === 'json' ? 'application/json'\r\n : 'text/markdown';\r\n reply.type(contentType).send(report.content);\r\n });\r\n\r\n // GET /api/ci/template — generate CI config template\r\n app.get<{ Querystring: { provider?: string } }>('/api/ci/template', async (req) => {\r\n const provider = req.query.provider || 'github';\r\n const { generateGitHubActionsTemplate, generateGitLabCITemplate } = await import('../../ci/index.js');\r\n if (provider === 'gitlab') {\r\n return { ok: true, provider: 'gitlab', template: generateGitLabCITemplate() };\r\n }\r\n return { ok: true, provider: 'github', template: generateGitHubActionsTemplate() };\r\n });\r\n}\r\n","/**\r\n * Language Detector\r\n *\r\n * Detects programming languages, frameworks, and project type\r\n * from a project directory without reading source code ASTs.\r\n * Uses file extensions, config files, and package manifests.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type { ProjectType, FrameworkDetection } from '../graph/types.js';\r\n\r\n// ===== Language Detection by File Extension =====\r\n\r\nconst EXTENSION_MAP: Record<string, string> = {\r\n '.ts': 'typescript', '.tsx': 'typescript', '.mts': 'typescript', '.cts': 'typescript',\r\n '.js': 'javascript', '.jsx': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript',\r\n '.py': 'python', '.pyw': 'python', '.pyi': 'python',\r\n '.go': 'go',\r\n '.java': 'java', '.kt': 'kotlin', '.kts': 'kotlin',\r\n '.rs': 'rust',\r\n '.rb': 'ruby',\r\n '.php': 'php',\r\n '.cs': 'csharp',\r\n '.cpp': 'cpp', '.cc': 'cpp', '.cxx': 'cpp', '.c': 'c', '.h': 'c',\r\n '.swift': 'swift',\r\n '.dart': 'dart',\r\n '.vue': 'vue',\r\n '.svelte': 'svelte',\r\n '.astro': 'astro',\r\n '.sql': 'sql',\r\n '.graphql': 'graphql', '.gql': 'graphql',\r\n '.proto': 'protobuf',\r\n '.yaml': 'yaml', '.yml': 'yaml',\r\n '.json': 'json',\r\n '.toml': 'toml',\r\n '.md': 'markdown',\r\n '.html': 'html', '.htm': 'html',\r\n '.css': 'css', '.scss': 'scss', '.less': 'less', '.sass': 'sass',\r\n '.sh': 'shell', '.bash': 'shell', '.zsh': 'shell',\r\n '.ps1': 'powershell',\r\n '.dockerfile': 'docker',\r\n '.tf': 'terraform',\r\n '.lua': 'lua',\r\n '.r': 'r', '.R': 'r',\r\n '.scala': 'scala',\r\n '.ex': 'elixir', '.exs': 'elixir',\r\n '.erl': 'erlang',\r\n '.zig': 'zig',\r\n};\r\n\r\n/** Directories to skip during scanning */\r\nconst SKIP_DIRS = new Set([\r\n 'node_modules', '.git', '.svn', '.hg', 'dist', 'build', 'out', 'target',\r\n '__pycache__', '.cache', '.next', '.nuxt', '.output', 'vendor', 'venv',\r\n '.venv', 'env', '.env', 'coverage', '.idea', '.vscode', '.vs',\r\n '.turbo', '.nx', 'bower_components', 'jspm_packages',\r\n]);\r\n\r\n/** Max depth to scan */\r\nconst MAX_DEPTH = 8;\r\n\r\n/** Max files to scan for detection (avoid huge repos) */\r\nconst MAX_FILES = 10000;\r\n\r\nexport interface LanguageDetectionResult {\r\n /** Language → file count */\r\n languages: Record<string, number>;\r\n /** Language → total line count */\r\n linesByLanguage: Record<string, number>;\r\n /** Total files found */\r\n totalFiles: number;\r\n /** Total lines of code */\r\n totalLines: number;\r\n /** Primary language */\r\n primaryLanguage: string;\r\n /** Detected frameworks */\r\n frameworks: FrameworkDetection[];\r\n /** Detected project type */\r\n projectType: ProjectType;\r\n /** Package manager */\r\n packageManager?: string;\r\n /** All discovered source files */\r\n files: Array<{ path: string; language: string; lines: number; size: number }>;\r\n}\r\n\r\n/**\r\n * Detect languages, frameworks, and project type from a directory.\r\n */\r\nexport function detectProject(rootDir: string): LanguageDetectionResult {\r\n const absRoot = path.resolve(rootDir);\r\n const languages: Record<string, number> = {};\r\n const linesByLanguage: Record<string, number> = {};\r\n const files: Array<{ path: string; language: string; lines: number; size: number }> = [];\r\n let totalFiles = 0;\r\n let totalLines = 0;\r\n\r\n // Recursive file scan\r\n function walk(dir: string, depth: number): void {\r\n if (depth > MAX_DEPTH || totalFiles > MAX_FILES) return;\r\n let entries: fs.Dirent[];\r\n try {\r\n entries = fs.readdirSync(dir, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n for (const entry of entries) {\r\n if (totalFiles > MAX_FILES) break;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) {\r\n walk(fullPath, depth + 1);\r\n }\r\n continue;\r\n }\r\n\r\n if (!entry.isFile()) continue;\r\n\r\n const ext = path.extname(entry.name).toLowerCase();\r\n // Special file name detection\r\n const lang = detectLanguageByFile(entry.name, ext);\r\n if (!lang) continue;\r\n\r\n let lineCount = 0;\r\n let fileSize = 0;\r\n try {\r\n const stat = fs.statSync(fullPath);\r\n fileSize = stat.size;\r\n // Only count lines for reasonable files (< 1MB)\r\n if (fileSize < 1_048_576) {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n lineCount = content.split('\\n').length;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n\r\n languages[lang] = (languages[lang] || 0) + 1;\r\n linesByLanguage[lang] = (linesByLanguage[lang] || 0) + lineCount;\r\n totalFiles++;\r\n totalLines += lineCount;\r\n\r\n const relPath = path.relative(absRoot, fullPath).replace(/\\\\/g, '/');\r\n files.push({ path: relPath, language: lang, lines: lineCount, size: fileSize });\r\n }\r\n }\r\n\r\n walk(absRoot, 0);\r\n\r\n // Determine primary language (by file count, ignoring config-only languages)\r\n const codeLangs = Object.entries(languages)\r\n .filter(([k]) => !['json', 'yaml', 'toml', 'markdown', 'html', 'css', 'scss', 'less', 'sass'].includes(k))\r\n .sort((a, b) => b[1] - a[1]);\r\n const primaryLanguage = codeLangs[0]?.[0] || 'unknown';\r\n\r\n // Detect frameworks\r\n const frameworks = detectFrameworks(absRoot, languages, files);\r\n\r\n // Detect project type\r\n const projectType = detectProjectType(absRoot, languages, frameworks);\r\n\r\n // Detect package manager\r\n const packageManager = detectPackageManager(absRoot);\r\n\r\n return {\r\n languages,\r\n linesByLanguage,\r\n totalFiles,\r\n totalLines,\r\n primaryLanguage,\r\n frameworks,\r\n projectType,\r\n packageManager,\r\n files,\r\n };\r\n}\r\n\r\nfunction detectLanguageByFile(fileName: string, ext: string): string | null {\r\n // Special file names\r\n if (fileName === 'Dockerfile' || fileName.startsWith('Dockerfile.')) return 'docker';\r\n if (fileName === 'Makefile') return 'makefile';\r\n if (fileName === 'CMakeLists.txt') return 'cmake';\r\n if (fileName === 'Vagrantfile') return 'ruby';\r\n if (fileName === 'Gemfile') return 'ruby';\r\n if (fileName === 'Rakefile') return 'ruby';\r\n if (fileName === 'Cargo.toml') return 'rust';\r\n if (fileName === 'go.mod' || fileName === 'go.sum') return 'go';\r\n\r\n return EXTENSION_MAP[ext] || null;\r\n}\r\n\r\n// ===== Framework Detection =====\r\n\r\ninterface FrameworkRule {\r\n name: string;\r\n detect: (root: string, langs: Record<string, number>, files: Array<{ path: string }>) => FrameworkDetection | null;\r\n}\r\n\r\nconst FRAMEWORK_RULES: FrameworkRule[] = [\r\n // --- Node.js / JavaScript ---\r\n {\r\n name: 'express',\r\n detect: (root) => detectFromPackageJson(root, 'express', 'Express'),\r\n },\r\n {\r\n name: 'nestjs',\r\n detect: (root) => detectFromPackageJson(root, '@nestjs/core', 'NestJS'),\r\n },\r\n {\r\n name: 'fastify',\r\n detect: (root) => detectFromPackageJson(root, 'fastify', 'Fastify'),\r\n },\r\n {\r\n name: 'koa',\r\n detect: (root) => detectFromPackageJson(root, 'koa', 'Koa'),\r\n },\r\n {\r\n name: 'hapi',\r\n detect: (root) => detectFromPackageJson(root, '@hapi/hapi', 'Hapi'),\r\n },\r\n {\r\n name: 'nextjs',\r\n detect: (root) => detectFromPackageJson(root, 'next', 'Next.js'),\r\n },\r\n {\r\n name: 'nuxtjs',\r\n detect: (root) => detectFromPackageJson(root, 'nuxt', 'Nuxt.js'),\r\n },\r\n {\r\n name: 'react',\r\n detect: (root) => detectFromPackageJson(root, 'react', 'React'),\r\n },\r\n {\r\n name: 'vue',\r\n detect: (root) => detectFromPackageJson(root, 'vue', 'Vue'),\r\n },\r\n {\r\n name: 'angular',\r\n detect: (root) => detectFromPackageJson(root, '@angular/core', 'Angular'),\r\n },\r\n {\r\n name: 'svelte',\r\n detect: (root) => detectFromPackageJson(root, 'svelte', 'Svelte'),\r\n },\r\n {\r\n name: 'electron',\r\n detect: (root) => detectFromPackageJson(root, 'electron', 'Electron'),\r\n },\r\n {\r\n name: 'sequelize',\r\n detect: (root) => detectFromPackageJson(root, 'sequelize', 'Sequelize'),\r\n },\r\n {\r\n name: 'typeorm',\r\n detect: (root) => detectFromPackageJson(root, 'typeorm', 'TypeORM'),\r\n },\r\n {\r\n name: 'prisma',\r\n detect: (root) => detectFromPackageJson(root, 'prisma', 'Prisma') || detectFromPackageJson(root, '@prisma/client', 'Prisma'),\r\n },\r\n {\r\n name: 'mongoose',\r\n detect: (root) => detectFromPackageJson(root, 'mongoose', 'Mongoose'),\r\n },\r\n {\r\n name: 'playwright',\r\n detect: (root) => detectFromPackageJson(root, '@playwright/test', 'Playwright'),\r\n },\r\n // --- Python ---\r\n {\r\n name: 'django',\r\n detect: (root) => detectFromRequirements(root, 'django', 'Django') || detectFromFile(root, 'manage.py', 'Django'),\r\n },\r\n {\r\n name: 'flask',\r\n detect: (root) => detectFromRequirements(root, 'flask', 'Flask'),\r\n },\r\n {\r\n name: 'fastapi',\r\n detect: (root) => detectFromRequirements(root, 'fastapi', 'FastAPI'),\r\n },\r\n {\r\n name: 'pytorch',\r\n detect: (root) => detectFromRequirements(root, 'torch', 'PyTorch'),\r\n },\r\n {\r\n name: 'tensorflow',\r\n detect: (root) => detectFromRequirements(root, 'tensorflow', 'TensorFlow'),\r\n },\r\n // --- Go ---\r\n {\r\n name: 'gin',\r\n detect: (root) => detectFromGoMod(root, 'github.com/gin-gonic/gin', 'Gin'),\r\n },\r\n {\r\n name: 'echo',\r\n detect: (root) => detectFromGoMod(root, 'github.com/labstack/echo', 'Echo'),\r\n },\r\n {\r\n name: 'fiber',\r\n detect: (root) => detectFromGoMod(root, 'github.com/gofiber/fiber', 'Fiber'),\r\n },\r\n // --- Java ---\r\n {\r\n name: 'spring-boot',\r\n detect: (root) => detectFromFile(root, 'pom.xml', 'Spring Boot', 'spring-boot') || detectFromFile(root, 'build.gradle', 'Spring Boot', 'spring-boot'),\r\n },\r\n // --- Rust ---\r\n {\r\n name: 'actix-web',\r\n detect: (root) => detectFromCargoToml(root, 'actix-web', 'Actix Web'),\r\n },\r\n {\r\n name: 'axum',\r\n detect: (root) => detectFromCargoToml(root, 'axum', 'Axum'),\r\n },\r\n // --- Ruby ---\r\n {\r\n name: 'rails',\r\n detect: (root) => detectFromFile(root, 'Gemfile', 'Ruby on Rails', 'rails'),\r\n },\r\n // --- PHP ---\r\n {\r\n name: 'laravel',\r\n detect: (root) => detectFromFile(root, 'artisan', 'Laravel'),\r\n },\r\n];\r\n\r\nfunction detectFromPackageJson(root: string, dep: string, name: string): FrameworkDetection | null {\r\n // Search in root and common subdirs\r\n const candidates = [\r\n path.join(root, 'package.json'),\r\n path.join(root, 'backend', 'package.json'),\r\n path.join(root, 'server', 'package.json'),\r\n path.join(root, 'api', 'package.json'),\r\n path.join(root, 'frontend', 'package.json'),\r\n path.join(root, 'web', 'package.json'),\r\n path.join(root, 'client', 'package.json'),\r\n ];\r\n\r\n for (const pkgPath of candidates) {\r\n try {\r\n if (!fs.existsSync(pkgPath)) continue;\r\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\r\n const allDeps = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies };\r\n if (dep in allDeps) {\r\n return {\r\n name,\r\n version: allDeps[dep]?.replace(/[\\^~>=<]*/g, ''),\r\n confidence: 0.95,\r\n evidence: `Found \"${dep}\" in ${path.relative(root, pkgPath)}`,\r\n };\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromRequirements(root: string, dep: string, name: string): FrameworkDetection | null {\r\n const candidates = [\r\n path.join(root, 'requirements.txt'),\r\n path.join(root, 'Pipfile'),\r\n path.join(root, 'pyproject.toml'),\r\n path.join(root, 'setup.py'),\r\n path.join(root, 'setup.cfg'),\r\n ];\r\n\r\n for (const filePath of candidates) {\r\n try {\r\n if (!fs.existsSync(filePath)) continue;\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n const pattern = new RegExp(`^${dep}([>=<~!\\\\s]|$)`, 'im');\r\n if (pattern.test(content)) {\r\n return {\r\n name,\r\n confidence: 0.9,\r\n evidence: `Found \"${dep}\" in ${path.basename(filePath)}`,\r\n };\r\n }\r\n } catch {\r\n continue;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromGoMod(root: string, module: string, name: string): FrameworkDetection | null {\r\n const goModPath = path.join(root, 'go.mod');\r\n try {\r\n if (!fs.existsSync(goModPath)) return null;\r\n const content = fs.readFileSync(goModPath, 'utf-8');\r\n if (content.includes(module)) {\r\n return {\r\n name,\r\n confidence: 0.95,\r\n evidence: `Found \"${module}\" in go.mod`,\r\n };\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromCargoToml(root: string, crate: string, name: string): FrameworkDetection | null {\r\n const cargoPath = path.join(root, 'Cargo.toml');\r\n try {\r\n if (!fs.existsSync(cargoPath)) return null;\r\n const content = fs.readFileSync(cargoPath, 'utf-8');\r\n if (content.includes(crate)) {\r\n return {\r\n name,\r\n confidence: 0.9,\r\n evidence: `Found \"${crate}\" in Cargo.toml`,\r\n };\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n}\r\n\r\nfunction detectFromFile(root: string, fileName: string, name: string, searchTerm?: string): FrameworkDetection | null {\r\n const filePath = path.join(root, fileName);\r\n try {\r\n if (!fs.existsSync(filePath)) return null;\r\n if (searchTerm) {\r\n const content = fs.readFileSync(filePath, 'utf-8');\r\n if (!content.toLowerCase().includes(searchTerm.toLowerCase())) return null;\r\n }\r\n return {\r\n name,\r\n confidence: 0.8,\r\n evidence: `Found ${fileName}${searchTerm ? ` containing \"${searchTerm}\"` : ''}`,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction detectFrameworks(root: string, langs: Record<string, number>, files: Array<{ path: string }>): FrameworkDetection[] {\r\n const detected: FrameworkDetection[] = [];\r\n for (const rule of FRAMEWORK_RULES) {\r\n const result = rule.detect(root, langs, files);\r\n if (result) detected.push(result);\r\n }\r\n return detected;\r\n}\r\n\r\n// ===== Project Type Detection =====\r\n\r\nfunction detectProjectType(root: string, langs: Record<string, number>, frameworks: FrameworkDetection[]): ProjectType {\r\n const frameworkNames = new Set(frameworks.map(f => f.name.toLowerCase()));\r\n\r\n // Monorepo detection\r\n const hasLerna = fs.existsSync(path.join(root, 'lerna.json'));\r\n const hasPnpmWorkspace = fs.existsSync(path.join(root, 'pnpm-workspace.yaml'));\r\n const hasNxJson = fs.existsSync(path.join(root, 'nx.json'));\r\n const hasTurboJson = fs.existsSync(path.join(root, 'turbo.json'));\r\n let hasWorkspaces = false;\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));\r\n hasWorkspaces = Array.isArray(pkg.workspaces) || typeof pkg.workspaces === 'object';\r\n } catch {\r\n // ignore\r\n }\r\n if (hasLerna || hasPnpmWorkspace || hasNxJson || hasTurboJson || hasWorkspaces) {\r\n return 'monorepo';\r\n }\r\n\r\n // Library detection\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));\r\n if (pkg.main || pkg.exports || pkg.module) {\r\n const hasNoServer = !frameworkNames.has('express') && !frameworkNames.has('fastify') &&\r\n !frameworkNames.has('koa') && !frameworkNames.has('nestjs');\r\n const hasNoFrontend = !frameworkNames.has('react') && !frameworkNames.has('vue') &&\r\n !frameworkNames.has('angular') && !frameworkNames.has('svelte');\r\n if (hasNoServer && hasNoFrontend && pkg.keywords) return 'library';\r\n }\r\n if (pkg.bin) return 'cli-tool';\r\n } catch {\r\n // ignore\r\n }\r\n\r\n // SSR frameworks\r\n if (frameworkNames.has('next.js') || frameworkNames.has('nuxt.js')) return 'frontend-ssr';\r\n\r\n // Mobile\r\n if (frameworkNames.has('electron')) return 'fullstack';\r\n if (langs['dart']) return 'mobile';\r\n if (langs['swift'] && !langs['typescript'] && !langs['python']) return 'mobile';\r\n\r\n // Fullstack detection (has both frontend and backend frameworks)\r\n const hasBackend = frameworkNames.has('express') || frameworkNames.has('fastify') ||\r\n frameworkNames.has('nestjs') || frameworkNames.has('koa') ||\r\n frameworkNames.has('django') || frameworkNames.has('flask') ||\r\n frameworkNames.has('fastapi') || frameworkNames.has('gin') ||\r\n frameworkNames.has('spring boot') || frameworkNames.has('rails') ||\r\n frameworkNames.has('laravel');\r\n const hasFrontend = frameworkNames.has('react') || frameworkNames.has('vue') ||\r\n frameworkNames.has('angular') || frameworkNames.has('svelte');\r\n\r\n if (hasBackend && hasFrontend) return 'fullstack';\r\n if (hasBackend) return 'backend-api';\r\n if (hasFrontend) return 'frontend-spa';\r\n\r\n // Rust/Go API\r\n if (frameworkNames.has('actix web') || frameworkNames.has('axum') ||\r\n frameworkNames.has('gin') || frameworkNames.has('echo') || frameworkNames.has('fiber')) {\r\n return 'backend-api';\r\n }\r\n\r\n return 'unknown';\r\n}\r\n\r\n// ===== Package Manager Detection =====\r\n\r\nfunction detectPackageManager(root: string): string | undefined {\r\n if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';\r\n if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';\r\n if (fs.existsSync(path.join(root, 'bun.lockb'))) return 'bun';\r\n if (fs.existsSync(path.join(root, 'package-lock.json'))) return 'npm';\r\n if (fs.existsSync(path.join(root, 'Pipfile.lock'))) return 'pipenv';\r\n if (fs.existsSync(path.join(root, 'poetry.lock'))) return 'poetry';\r\n if (fs.existsSync(path.join(root, 'go.sum'))) return 'go-modules';\r\n if (fs.existsSync(path.join(root, 'Cargo.lock'))) return 'cargo';\r\n if (fs.existsSync(path.join(root, 'Gemfile.lock'))) return 'bundler';\r\n if (fs.existsSync(path.join(root, 'composer.lock'))) return 'composer';\r\n return undefined;\r\n}\r\n","/**\r\n * Universal Project Scanner\r\n *\r\n * Scans any project directory and extracts entities (modules, classes,\r\n * functions, APIs, models) and relationships. Works with any language\r\n * by combining:\r\n * 1. Static analysis (ts-morph for TS/JS)\r\n * 2. Pattern matching (regex for Python/Go/Java/etc.)\r\n * 3. Config file parsing (package.json, OpenAPI, etc.)\r\n * 4. LLM fallback (for unknown patterns)\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport type {\r\n ScanResult,\r\n ExtractedEntity,\r\n ExtractedRelationship,\r\n GraphNodeType,\r\n GraphEdgeRelation,\r\n DiscoveredFile,\r\n} from '../graph/types.js';\r\nimport { detectProject, type LanguageDetectionResult } from './language-detector.js';\r\n\r\nexport interface ScanOptions {\r\n /** Project root directory */\r\n rootDir: string;\r\n /** Max files to deeply analyze (default: 500) */\r\n maxDeepScan?: number;\r\n /** Enable LLM fallback for unknown patterns */\r\n useLlm?: boolean;\r\n /** Progress callback */\r\n onProgress?: (phase: string, percent: number, detail?: string) => void;\r\n}\r\n\r\n/**\r\n * Scan a project and extract all entities and relationships.\r\n */\r\nexport async function scanProject(options: ScanOptions): Promise<ScanResult> {\r\n const { rootDir, maxDeepScan = 500, onProgress } = options;\r\n const startTime = Date.now();\r\n\r\n onProgress?.('detecting', 0, 'Detecting languages and frameworks...');\r\n\r\n // Phase 1: Language detection\r\n const detection = detectProject(rootDir);\r\n\r\n onProgress?.('detecting', 100, `Found ${detection.totalFiles} files, primary: ${detection.primaryLanguage}`);\r\n\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Phase 2: Extract entities by language\r\n const sourceFiles = detection.files.filter(f => {\r\n const lang = f.language;\r\n return !['json', 'yaml', 'toml', 'markdown', 'html', 'css', 'scss', 'less', 'sass', 'docker', 'shell', 'powershell'].includes(lang);\r\n });\r\n\r\n const filesToAnalyze = sourceFiles.slice(0, maxDeepScan);\r\n\r\n for (let i = 0; i < filesToAnalyze.length; i++) {\r\n const file = filesToAnalyze[i]!;\r\n const percent = Math.round((i / filesToAnalyze.length) * 100);\r\n if (i % 20 === 0) {\r\n onProgress?.('scanning', percent, `Scanning ${file.path}...`);\r\n }\r\n\r\n const fullPath = path.join(rootDir, file.path);\r\n try {\r\n const extracted = extractEntitiesFromFile(fullPath, file.path, file.language);\r\n entities.push(...extracted.entities);\r\n relationships.push(...extracted.relationships);\r\n } catch {\r\n // Skip files that fail to parse\r\n }\r\n }\r\n\r\n onProgress?.('scanning', 100, `Extracted ${entities.length} entities`);\r\n\r\n // Phase 3: Extract from config files\r\n onProgress?.('configs', 0, 'Parsing config files...');\r\n const configEntities = extractFromConfigs(rootDir, detection);\r\n entities.push(...configEntities.entities);\r\n relationships.push(...configEntities.relationships);\r\n onProgress?.('configs', 100, 'Config parsing complete');\r\n\r\n // Phase 4: Infer cross-file relationships\r\n onProgress?.('relations', 0, 'Building relationships...');\r\n const inferredRelations = inferRelationships(entities, rootDir);\r\n relationships.push(...inferredRelations);\r\n onProgress?.('relations', 100, `${relationships.length} total relationships`);\r\n\r\n // Convert detection files to DiscoveredFile format\r\n const discoveredFiles: DiscoveredFile[] = detection.files.map(f => ({\r\n path: f.path,\r\n language: f.language,\r\n category: categorizeFile(f.path, f.language),\r\n lines: f.lines,\r\n size: f.size,\r\n }));\r\n\r\n return {\r\n languages: detection.languages,\r\n frameworks: detection.frameworks,\r\n files: discoveredFiles,\r\n entities,\r\n relationships,\r\n duration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n// ===== File Entity Extraction =====\r\n\r\ninterface ExtractionResult {\r\n entities: ExtractedEntity[];\r\n relationships: ExtractedRelationship[];\r\n}\r\n\r\nfunction extractEntitiesFromFile(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n switch (language) {\r\n case 'typescript':\r\n case 'javascript':\r\n return extractFromTsJs(fullPath, relPath, language);\r\n case 'python':\r\n return extractFromPython(fullPath, relPath);\r\n case 'go':\r\n return extractFromGo(fullPath, relPath);\r\n case 'java':\r\n case 'kotlin':\r\n return extractFromJavaKotlin(fullPath, relPath, language);\r\n case 'rust':\r\n return extractFromRust(fullPath, relPath);\r\n case 'ruby':\r\n return extractFromRuby(fullPath, relPath);\r\n case 'php':\r\n return extractFromPHP(fullPath, relPath);\r\n case 'vue':\r\n case 'svelte':\r\n return extractFromTsJs(fullPath, relPath, 'typescript'); // Extract script section\r\n default:\r\n return { entities: [], relationships: [] };\r\n }\r\n}\r\n\r\n// ===== TypeScript / JavaScript Extraction =====\r\n\r\nfunction extractFromTsJs(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({\r\n id: fileId,\r\n name: path.basename(relPath),\r\n type: 'file',\r\n filePath: relPath,\r\n language,\r\n metadata: {},\r\n });\r\n\r\n // Extract classes\r\n const classRegex = /(?:export\\s+)?(?:abstract\\s+)?class\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?(?:\\s+implements\\s+([\\w,\\s]+))?\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const extendsClass = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n\r\n entities.push({\r\n id: classId,\r\n name: className,\r\n type: detectClassType(className, content),\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { extends: extendsClass },\r\n });\r\n\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n\r\n if (extendsClass) {\r\n relationships.push({\r\n sourceId: classId,\r\n targetId: `class:*:${extendsClass}`,\r\n relation: 'extends',\r\n });\r\n }\r\n }\r\n\r\n // Extract functions (top-level and exported)\r\n const funcRegex = /(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId,\r\n name: funcName,\r\n type: 'function',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract arrow function exports\r\n const arrowFuncRegex = /export\\s+(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?\\(/g;\r\n while ((match = arrowFuncRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId,\r\n name: funcName,\r\n type: 'function',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { arrow: true },\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract Express/Fastify routes\r\n const routeRegex = /(?:router|app)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/gi;\r\n while ((match = routeRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId,\r\n name: `${method} ${routePath}`,\r\n type: 'api',\r\n filePath: relPath,\r\n line: getLineNumber(content, match.index),\r\n language,\r\n metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Extract imports\r\n const importRegex = /(?:import\\s+.*from\\s+['\"`]([^'\"`]+)['\"`]|require\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*\\))/g;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const importPath = match[1] || match[2]!;\r\n if (importPath.startsWith('.')) {\r\n // Relative import → file dependency\r\n const resolved = resolveRelativeImport(relPath, importPath);\r\n relationships.push({\r\n sourceId: fileId,\r\n targetId: `file:${resolved}`,\r\n relation: 'imports',\r\n });\r\n } else {\r\n // External dependency\r\n const depName = importPath.startsWith('@') ? importPath.split('/').slice(0, 2).join('/') : importPath.split('/')[0]!;\r\n const depId = `dep:${depName}`;\r\n entities.push({\r\n id: depId,\r\n name: depName,\r\n type: 'dependency',\r\n filePath: '',\r\n language: 'external',\r\n metadata: { external: true },\r\n });\r\n relationships.push({ sourceId: fileId, targetId: depId, relation: 'depends-on' });\r\n }\r\n }\r\n\r\n // Extract Sequelize/TypeORM model definitions\r\n if (content.includes('.init(') || content.includes('Model.init') || content.includes('@Entity') || content.includes('defineModel')) {\r\n const tableMatch = content.match(/tableName:\\s*['\"`](\\w+)['\"`]/);\r\n if (tableMatch) {\r\n const tableName = tableMatch[1]!;\r\n const modelId = `model:${tableName}`;\r\n entities.push({\r\n id: modelId,\r\n name: tableName,\r\n type: 'model',\r\n filePath: relPath,\r\n language,\r\n metadata: { orm: 'sequelize' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Python Extraction =====\r\n\r\nfunction extractFromPython(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'python', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /^class\\s+(\\w+)(?:\\(([^)]*)\\))?\\s*:/gm;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const bases = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n entities.push({\r\n id: classId, name: className,\r\n type: detectPythonClassType(className, bases || '', content),\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { bases },\r\n });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /^(?:async\\s+)?def\\s+(\\w+)\\s*\\(/gm;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName.startsWith('_') && funcName !== '__init__') continue;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId, name: funcName, type: 'function',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // FastAPI/Flask routes\r\n const routeRegex = /@(?:app|router)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"]([^'\"]+)['\"]/gi;\r\n while ((match = routeRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId, name: `${method} ${routePath}`, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Django URL patterns\r\n const djangoUrlRegex = /path\\s*\\(\\s*['\"]([^'\"]+)['\"],\\s*(\\w+)/g;\r\n while ((match = djangoUrlRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'route',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'python', metadata: { handler: match[2] },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Django models\r\n const djangoModelRegex = /class\\s+(\\w+)\\((?:models\\.)?Model\\)/g;\r\n while ((match = djangoModelRegex.exec(content)) !== null) {\r\n const modelName = match[1]!;\r\n const modelId = `model:${modelName}`;\r\n entities.push({\r\n id: modelId, name: modelName, type: 'model',\r\n filePath: relPath, language: 'python', metadata: { orm: 'django' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // SQLAlchemy models\r\n const sqlalchemyRegex = /class\\s+(\\w+)\\(.*(?:Base|DeclarativeBase|db\\.Model)\\)/g;\r\n while ((match = sqlalchemyRegex.exec(content)) !== null) {\r\n const modelName = match[1]!;\r\n const modelId = `model:${modelName}`;\r\n entities.push({\r\n id: modelId, name: modelName, type: 'model',\r\n filePath: relPath, language: 'python', metadata: { orm: 'sqlalchemy' },\r\n });\r\n relationships.push({ sourceId: modelId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Imports\r\n const importRegex = /^(?:from\\s+([\\w.]+)\\s+import|import\\s+([\\w.]+))/gm;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const mod = match[1] || match[2]!;\r\n if (mod.startsWith('.')) {\r\n relationships.push({ sourceId: fileId, targetId: `file:${mod}`, relation: 'imports' });\r\n } else {\r\n const depName = mod.split('.')[0]!;\r\n entities.push({ id: `dep:${depName}`, name: depName, type: 'dependency', filePath: '', language: 'external', metadata: { external: true } });\r\n relationships.push({ sourceId: fileId, targetId: `dep:${depName}`, relation: 'depends-on' });\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Go Extraction =====\r\n\r\nfunction extractFromGo(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'go', metadata: {} });\r\n\r\n // Structs\r\n const structRegex = /type\\s+(\\w+)\\s+struct\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = structRegex.exec(content)) !== null) {\r\n const structName = match[1]!;\r\n const structId = `class:${relPath}:${structName}`;\r\n entities.push({\r\n id: structId, name: structName,\r\n type: structName.endsWith('Model') || structName.endsWith('Entity') ? 'model' : 'class',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: {},\r\n });\r\n relationships.push({ sourceId: structId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /func\\s+(?:\\(\\w+\\s+\\*?\\w+\\)\\s+)?(\\w+)\\s*\\(/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName[0] !== funcName[0]!.toUpperCase()) continue; // Skip unexported\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({\r\n id: funcId, name: funcName, type: 'function',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: {},\r\n });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Gin/Echo routes\r\n const ginRouteRegex = /\\.(GET|POST|PUT|PATCH|DELETE)\\s*\\(\\s*\"([^\"]+)\"/gi;\r\n while ((match = ginRouteRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({\r\n id: apiId, name: `${method} ${routePath}`, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language: 'go', metadata: { method, path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Java/Kotlin Extraction =====\r\n\r\nfunction extractFromJavaKotlin(fullPath: string, relPath: string, language: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language, metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /(?:public\\s+)?(?:abstract\\s+)?(?:class|interface|enum)\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const classId = `class:${relPath}:${className}`;\r\n entities.push({\r\n id: classId, name: className,\r\n type: content.includes('@Entity') || content.includes('@Table') ? 'model' : 'class',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language, metadata: {},\r\n });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Spring Boot endpoints\r\n const springRegex = /@(?:Get|Post|Put|Patch|Delete|Request)Mapping\\s*\\(\\s*(?:value\\s*=\\s*)?[\"']([^\"']+)[\"']/g;\r\n while ((match = springRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'api',\r\n filePath: relPath, line: getLineNumber(content, match.index),\r\n language, metadata: { path: routePath },\r\n });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Rust Extraction =====\r\n\r\nfunction extractFromRust(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'rust', metadata: {} });\r\n\r\n // Structs\r\n const structRegex = /pub\\s+struct\\s+(\\w+)/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = structRegex.exec(content)) !== null) {\r\n const structName = match[1]!;\r\n const structId = `class:${relPath}:${structName}`;\r\n entities.push({ id: structId, name: structName, type: 'class', filePath: relPath, line: getLineNumber(content, match.index), language: 'rust', metadata: {} });\r\n relationships.push({ sourceId: structId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Functions\r\n const funcRegex = /pub\\s+(?:async\\s+)?fn\\s+(\\w+)/g;\r\n while ((match = funcRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({ id: funcId, name: funcName, type: 'function', filePath: relPath, line: getLineNumber(content, match.index), language: 'rust', metadata: {} });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Ruby Extraction =====\r\n\r\nfunction extractFromRuby(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'ruby', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /class\\s+(\\w+)(?:\\s*<\\s*(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const base = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n const type: GraphNodeType = base === 'ApplicationRecord' || base === 'ActiveRecord::Base' ? 'model' : 'class';\r\n entities.push({ id: classId, name: className, type, filePath: relPath, line: getLineNumber(content, match.index), language: 'ruby', metadata: { extends: base } });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Methods\r\n const defRegex = /def\\s+(?:self\\.)?(\\w+)/g;\r\n while ((match = defRegex.exec(content)) !== null) {\r\n const funcName = match[1]!;\r\n if (funcName.startsWith('_')) continue;\r\n const funcId = `func:${relPath}:${funcName}`;\r\n entities.push({ id: funcId, name: funcName, type: 'function', filePath: relPath, line: getLineNumber(content, match.index), language: 'ruby', metadata: {} });\r\n relationships.push({ sourceId: funcId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== PHP Extraction =====\r\n\r\nfunction extractFromPHP(fullPath: string, relPath: string): ExtractionResult {\r\n const content = fs.readFileSync(fullPath, 'utf-8');\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n const fileId = `file:${relPath}`;\r\n entities.push({ id: fileId, name: path.basename(relPath), type: 'file', filePath: relPath, language: 'php', metadata: {} });\r\n\r\n // Classes\r\n const classRegex = /(?:abstract\\s+)?class\\s+(\\w+)(?:\\s+extends\\s+(\\w+))?/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = classRegex.exec(content)) !== null) {\r\n const className = match[1]!;\r\n const base = match[2];\r\n const classId = `class:${relPath}:${className}`;\r\n const type: GraphNodeType = base === 'Model' || base === 'Eloquent' ? 'model' : 'class';\r\n entities.push({ id: classId, name: className, type, filePath: relPath, line: getLineNumber(content, match.index), language: 'php', metadata: {} });\r\n relationships.push({ sourceId: classId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n // Laravel routes\r\n const laravelRouteRegex = /Route::(get|post|put|patch|delete)\\s*\\(\\s*['\"]([^'\"]+)['\"]/gi;\r\n while ((match = laravelRouteRegex.exec(content)) !== null) {\r\n const method = match[1]!.toUpperCase();\r\n const routePath = match[2]!;\r\n const apiId = `api:${method}:${routePath}`;\r\n entities.push({ id: apiId, name: `${method} ${routePath}`, type: 'api', filePath: relPath, line: getLineNumber(content, match.index), language: 'php', metadata: { method, path: routePath } });\r\n relationships.push({ sourceId: apiId, targetId: fileId, relation: 'belongs-to' });\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Config File Extraction =====\r\n\r\nfunction extractFromConfigs(rootDir: string, _detection: LanguageDetectionResult): ExtractionResult {\r\n const entities: ExtractedEntity[] = [];\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Extract dependencies from package.json\r\n const pkgPath = path.join(rootDir, 'package.json');\r\n if (fs.existsSync(pkgPath)) {\r\n try {\r\n const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));\r\n const allDeps = { ...pkg.dependencies };\r\n for (const [name, version] of Object.entries(allDeps)) {\r\n const depId = `dep:${name}`;\r\n entities.push({\r\n id: depId, name, type: 'dependency',\r\n filePath: 'package.json', language: 'external',\r\n metadata: { version, source: 'npm', external: true },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n\r\n // Extract from OpenAPI/Swagger spec\r\n const openAPIFiles = ['openapi.json', 'openapi.yaml', 'openapi.yml', 'swagger.json', 'swagger.yaml'];\r\n for (const apiFile of openAPIFiles) {\r\n const apiPath = path.join(rootDir, apiFile);\r\n if (fs.existsSync(apiPath)) {\r\n try {\r\n const content = fs.readFileSync(apiPath, 'utf-8');\r\n // Simple path extraction from OpenAPI\r\n const pathRegex = /\"(\\/[^\"]+)\":\\s*\\{/g;\r\n let match: RegExpExecArray | null;\r\n while ((match = pathRegex.exec(content)) !== null) {\r\n const routePath = match[1]!;\r\n const apiId = `api:ANY:${routePath}`;\r\n entities.push({\r\n id: apiId, name: routePath, type: 'api',\r\n filePath: apiFile, language: 'openapi',\r\n metadata: { source: 'openapi' },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n }\r\n\r\n // Extract Docker services\r\n const composeFiles = ['docker-compose.yml', 'docker-compose.yaml', 'compose.yml', 'compose.yaml'];\r\n for (const composeFile of composeFiles) {\r\n const composePath = path.join(rootDir, composeFile);\r\n if (fs.existsSync(composePath)) {\r\n try {\r\n const content = fs.readFileSync(composePath, 'utf-8');\r\n // Simple service extraction\r\n const serviceRegex = /^\\s{2}(\\w[\\w-]*):\\s*$/gm;\r\n let match: RegExpExecArray | null;\r\n while ((match = serviceRegex.exec(content)) !== null) {\r\n const serviceName = match[1]!;\r\n if (serviceName === 'services' || serviceName === 'volumes' || serviceName === 'networks') continue;\r\n entities.push({\r\n id: `service:${serviceName}`, name: serviceName,\r\n type: detectServiceType(serviceName),\r\n filePath: composeFile, language: 'docker',\r\n metadata: { source: 'docker-compose' },\r\n });\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n }\r\n\r\n return { entities, relationships };\r\n}\r\n\r\n// ===== Relationship Inference =====\r\n\r\nfunction inferRelationships(entities: ExtractedEntity[], _rootDir: string): ExtractedRelationship[] {\r\n const relationships: ExtractedRelationship[] = [];\r\n\r\n // Group entities by type\r\n const models = entities.filter(e => e.type === 'model');\r\n const apis = entities.filter(e => e.type === 'api');\r\n // const classes = entities.filter(e => e.type === 'class' || e.type === 'service');\r\n\r\n // Infer API → Model relationships by path patterns\r\n for (const api of apis) {\r\n const apiPath = (api.metadata.path as string) || api.name;\r\n for (const model of models) {\r\n const modelName = model.name.toLowerCase().replace(/_/g, '');\r\n const pathLower = apiPath.toLowerCase().replace(/[/-]/g, '');\r\n if (pathLower.includes(modelName) || modelName.includes(pathLower.split('/').pop() || '')) {\r\n const method = (api.metadata.method as string) || 'ANY';\r\n const relation: GraphEdgeRelation = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(method) ? 'writes' : 'reads';\r\n relationships.push({ sourceId: api.id, targetId: model.id, relation });\r\n }\r\n }\r\n }\r\n\r\n // Infer module groupings from directory structure\r\n const fileEntities = entities.filter(e => e.type === 'file');\r\n for (const file of fileEntities) {\r\n const dir = path.dirname(file.filePath).split('/')[0];\r\n if (dir && dir !== '.') {\r\n const moduleId = `module:${dir}`;\r\n // Only add module entity if not already exists\r\n if (!entities.some(e => e.id === moduleId)) {\r\n entities.push({\r\n id: moduleId, name: dir, type: 'module',\r\n filePath: dir, language: 'directory',\r\n metadata: {},\r\n });\r\n }\r\n relationships.push({ sourceId: file.id, targetId: moduleId, relation: 'belongs-to' });\r\n }\r\n }\r\n\r\n return relationships;\r\n}\r\n\r\n// ===== Helpers =====\r\n\r\nfunction getLineNumber(content: string, index: number): number {\r\n return content.slice(0, index).split('\\n').length;\r\n}\r\n\r\nfunction resolveRelativeImport(currentFile: string, importPath: string): string {\r\n const dir = path.dirname(currentFile);\r\n let resolved = path.posix.join(dir, importPath);\r\n // Normalize: add .ts extension if missing\r\n if (!path.extname(resolved)) {\r\n resolved += '.ts';\r\n }\r\n return resolved;\r\n}\r\n\r\nfunction categorizeFile(filePath: string, language: string): 'source' | 'config' | 'test' | 'docs' | 'build' | 'asset' | 'other' {\r\n const lower = filePath.toLowerCase();\r\n if (lower.includes('.test.') || lower.includes('.spec.') || lower.includes('__tests__') || lower.includes('/test/') || lower.includes('/tests/')) return 'test';\r\n if (['json', 'yaml', 'toml'].includes(language) || lower.includes('config') || lower.includes('.env')) return 'config';\r\n if (language === 'markdown' || lower.includes('/docs/') || lower.includes('/doc/')) return 'docs';\r\n if (language === 'docker' || lower.includes('makefile') || lower.includes('webpack') || lower.includes('rollup') || lower.includes('vite')) return 'build';\r\n if (['html', 'css', 'scss', 'less'].includes(language)) return 'asset';\r\n return 'source';\r\n}\r\n\r\nfunction detectClassType(name: string, content: string): GraphNodeType {\r\n if (content.includes('.init(') || content.includes('@Entity') || content.includes('tableName')) return 'model';\r\n if (name.includes('Controller') || name.includes('Handler')) return 'service';\r\n if (name.includes('Service') || name.includes('Provider')) return 'service';\r\n if (name.includes('Middleware')) return 'middleware';\r\n if (name.includes('Component') || name.includes('Widget')) return 'component';\r\n return 'class';\r\n}\r\n\r\nfunction detectPythonClassType(name: string, bases: string, _content: string): GraphNodeType {\r\n if (bases.includes('Model') || bases.includes('Base') || bases.includes('db.Model')) return 'model';\r\n if (name.includes('View') || name.includes('ViewSet') || bases.includes('APIView')) return 'service';\r\n if (name.includes('Serializer')) return 'class';\r\n return 'class';\r\n}\r\n\r\nfunction detectServiceType(name: string): GraphNodeType {\r\n const lower = name.toLowerCase();\r\n if (lower.includes('redis') || lower.includes('memcache')) return 'cache';\r\n if (lower.includes('rabbit') || lower.includes('kafka') || lower.includes('nats')) return 'queue';\r\n if (lower.includes('postgres') || lower.includes('mysql') || lower.includes('mongo') || lower.includes('db')) return 'database';\r\n return 'external-api';\r\n}\r\n","/**\r\n * GitHub Cloner\r\n *\r\n * Clone a GitHub/GitLab/any git repository and scan it.\r\n * Supports: HTTPS URLs, shorthand (user/repo), and local paths.\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as os from 'node:os';\r\nimport * as path from 'node:path';\r\nimport { execSync } from 'node:child_process';\r\nimport { scanProject, type ScanOptions } from './project-scanner.js';\r\nimport type { ScanResult } from '../graph/types.js';\r\n\r\nexport interface CloneOptions extends Omit<ScanOptions, 'rootDir'> {\r\n /** GitHub URL, shorthand (user/repo), or local path */\r\n target: string;\r\n /** Where to clone into (default: os temp dir) */\r\n cloneDir?: string;\r\n /** Branch/tag to clone (default: default branch) */\r\n branch?: string;\r\n /** Shallow clone depth (default: 1) */\r\n depth?: number;\r\n /** Keep cloned repo after scan (default: false for remote, true for local) */\r\n keepClone?: boolean;\r\n}\r\n\r\ninterface ResolvedTarget {\r\n type: 'local' | 'git';\r\n path: string;\r\n url?: string;\r\n repoName: string;\r\n}\r\n\r\n/**\r\n * Clone (if needed) and scan a project.\r\n */\r\nexport async function cloneAndScan(options: CloneOptions): Promise<ScanResult & { clonedPath?: string }> {\r\n const { target, cloneDir, branch, depth = 1, keepClone, onProgress, ...scanOpts } = options;\r\n\r\n const resolved = resolveTarget(target);\r\n\r\n let projectDir: string;\r\n\r\n if (resolved.type === 'local') {\r\n // Local path — scan directly\r\n projectDir = resolved.path;\r\n onProgress?.('clone', 100, `Using local directory: ${projectDir}`);\r\n } else {\r\n // Git URL — clone first\r\n const tempBase = cloneDir || path.join(os.tmpdir(), 'opencroc-scan');\r\n fs.mkdirSync(tempBase, { recursive: true });\r\n projectDir = path.join(tempBase, resolved.repoName);\r\n\r\n // Clean previous clone\r\n if (fs.existsSync(projectDir)) {\r\n fs.rmSync(projectDir, { recursive: true, force: true });\r\n }\r\n\r\n onProgress?.('clone', 10, `Cloning ${resolved.url}...`);\r\n\r\n const branchArg = branch ? `--branch ${branch}` : '';\r\n const depthArg = depth > 0 ? `--depth ${depth}` : '';\r\n const cmd = `git clone ${branchArg} ${depthArg} --single-branch ${resolved.url} \"${projectDir}\"`;\r\n\r\n try {\r\n execSync(cmd, {\r\n stdio: 'pipe',\r\n timeout: 120_000, // 2 minutes max\r\n });\r\n } catch (err) {\r\n throw new Error(`Failed to clone repository: ${(err as Error).message}`);\r\n }\r\n\r\n onProgress?.('clone', 100, `Cloned to ${projectDir}`);\r\n }\r\n\r\n // Scan the project\r\n const scanResult = await scanProject({\r\n rootDir: projectDir,\r\n ...scanOpts,\r\n onProgress,\r\n });\r\n\r\n // Cleanup if remote and not keeping\r\n if (resolved.type === 'git' && !keepClone) {\r\n try {\r\n fs.rmSync(projectDir, { recursive: true, force: true });\r\n } catch {\r\n // Best effort cleanup\r\n }\r\n }\r\n\r\n return {\r\n ...scanResult,\r\n clonedPath: resolved.type === 'git' ? projectDir : undefined,\r\n };\r\n}\r\n\r\n/**\r\n * Resolve a target string into a local path or git URL.\r\n */\r\nfunction resolveTarget(target: string): ResolvedTarget {\r\n // Local path — resolve first so relative paths work correctly\r\n const resolved = path.resolve(target);\r\n if (fs.existsSync(resolved)) {\r\n return {\r\n type: 'local',\r\n path: resolved,\r\n repoName: path.basename(resolved),\r\n };\r\n }\r\n\r\n // Full git URL (https://github.com/user/repo, git@github.com:user/repo.git)\r\n if (target.startsWith('https://') || target.startsWith('http://') || target.startsWith('git@')) {\r\n let url = target;\r\n // Ensure .git suffix\r\n if (!url.endsWith('.git')) url += '.git';\r\n const repoName = path.basename(url, '.git');\r\n return { type: 'git', path: '', url, repoName };\r\n }\r\n\r\n // Shorthand: user/repo → https://github.com/user/repo.git\r\n if (/^[\\w.-]+\\/[\\w.-]+$/.test(target)) {\r\n const url = `https://github.com/${target}.git`;\r\n const repoName = target.split('/')[1]!;\r\n return { type: 'git', path: '', url, repoName };\r\n }\r\n\r\n throw new Error(\r\n `Cannot resolve target \"${target}\". Expected: local path, GitHub URL, or shorthand (user/repo).`\r\n );\r\n}\r\n","/**\r\n * Knowledge Graph Builder\r\n *\r\n * Transforms raw ScanResult entities and relationships into a\r\n * fully connected KnowledgeGraph with deduplication, wildcard\r\n * resolution, module grouping, and statistics.\r\n */\r\n\r\nimport type {\r\n KnowledgeGraph,\r\n GraphNode,\r\n GraphEdge,\r\n ProjectMetadata,\r\n ProjectStats,\r\n ScanResult,\r\n ExtractedEntity,\r\n} from './types.js';\r\n\r\nexport interface GraphBuildOptions {\r\n /** Project name (from package.json or dir name) */\r\n projectName: string;\r\n /** Source type */\r\n source: 'local' | 'github' | 'gitlab' | 'url';\r\n sourceUrl?: string;\r\n /** Project root path */\r\n rootPath: string;\r\n}\r\n\r\n/**\r\n * Build a KnowledgeGraph from scan results.\r\n */\r\nexport function buildKnowledgeGraph(scanResult: ScanResult, options: GraphBuildOptions): KnowledgeGraph {\r\n const startTime = Date.now();\r\n\r\n // Deduplicate entities by ID\r\n const entityMap = new Map<string, ExtractedEntity>();\r\n for (const entity of scanResult.entities) {\r\n if (!entityMap.has(entity.id)) {\r\n entityMap.set(entity.id, entity);\r\n }\r\n }\r\n\r\n // Convert entities to graph nodes\r\n const nodes: GraphNode[] = [];\r\n for (const entity of entityMap.values()) {\r\n nodes.push({\r\n id: entity.id,\r\n label: entity.name,\r\n type: entity.type,\r\n filePath: entity.filePath || undefined,\r\n line: entity.line,\r\n module: inferModule(entity),\r\n language: entity.language,\r\n metadata: entity.metadata,\r\n status: 'idle',\r\n });\r\n }\r\n\r\n // Resolve wildcard references and build edges\r\n const edges: GraphEdge[] = [];\r\n const edgeSet = new Set<string>();\r\n\r\n for (const rel of scanResult.relationships) {\r\n let targetId = rel.targetId;\r\n\r\n // Resolve wildcard references (e.g., class:*:ClassName)\r\n if (targetId.includes(':*:')) {\r\n const suffix = targetId.split(':*:')[1]!;\r\n const resolved = findMatchingEntity(entityMap, targetId.split(':')[0]!, suffix);\r\n if (resolved) {\r\n targetId = resolved;\r\n } else {\r\n continue; // Can't resolve — skip\r\n }\r\n }\r\n\r\n // Skip self-references\r\n if (rel.sourceId === targetId) continue;\r\n\r\n // Skip if either node doesn't exist\r\n if (!entityMap.has(rel.sourceId) && !entityMap.has(targetId)) continue;\r\n\r\n // Deduplicate edges\r\n const edgeKey = `${rel.sourceId}->${targetId}:${rel.relation}`;\r\n if (edgeSet.has(edgeKey)) continue;\r\n edgeSet.add(edgeKey);\r\n\r\n edges.push({\r\n id: `edge-${edges.length}`,\r\n source: rel.sourceId,\r\n target: targetId,\r\n relation: rel.relation,\r\n metadata: rel.metadata,\r\n });\r\n }\r\n\r\n // Build project metadata\r\n const projectInfo = buildProjectMetadata(scanResult, options, nodes);\r\n\r\n return {\r\n nodes,\r\n edges,\r\n projectInfo,\r\n builtAt: new Date().toISOString(),\r\n buildDuration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n/**\r\n * Query the knowledge graph for nodes matching criteria.\r\n */\r\nexport function queryNodes(graph: KnowledgeGraph, filter: Partial<Pick<GraphNode, 'type' | 'language' | 'module'>>): GraphNode[] {\r\n return graph.nodes.filter(n => {\r\n if (filter.type && n.type !== filter.type) return false;\r\n if (filter.language && n.language !== filter.language) return false;\r\n if (filter.module && n.module !== filter.module) return false;\r\n return true;\r\n });\r\n}\r\n\r\n/**\r\n * Get all neighbors of a node (incoming + outgoing).\r\n */\r\nexport function getNeighbors(graph: KnowledgeGraph, nodeId: string): { incoming: GraphEdge[]; outgoing: GraphEdge[] } {\r\n return {\r\n incoming: graph.edges.filter(e => e.target === nodeId),\r\n outgoing: graph.edges.filter(e => e.source === nodeId),\r\n };\r\n}\r\n\r\n/**\r\n * BFS traversal from a node, returning all reachable nodes within maxDepth.\r\n */\r\nexport function bfsTraversal(graph: KnowledgeGraph, startNodeId: string, maxDepth = 3): string[] {\r\n const visited = new Set<string>();\r\n const queue: Array<{ id: string; depth: number }> = [{ id: startNodeId, depth: 0 }];\r\n visited.add(startNodeId);\r\n\r\n // Build adjacency list\r\n const adjacency = new Map<string, string[]>();\r\n for (const edge of graph.edges) {\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n // Bidirectional for impact analysis\r\n if (!adjacency.has(edge.target)) adjacency.set(edge.target, []);\r\n adjacency.get(edge.target)!.push(edge.source);\r\n }\r\n\r\n while (queue.length > 0) {\r\n const current = queue.shift()!;\r\n if (current.depth >= maxDepth) continue;\r\n\r\n const neighbors = adjacency.get(current.id) || [];\r\n for (const neighbor of neighbors) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n queue.push({ id: neighbor, depth: current.depth + 1 });\r\n }\r\n }\r\n }\r\n\r\n visited.delete(startNodeId);\r\n return [...visited];\r\n}\r\n\r\n/**\r\n * Find all paths between two nodes (up to maxPaths).\r\n */\r\nexport function findPaths(\r\n graph: KnowledgeGraph,\r\n fromId: string,\r\n toId: string,\r\n maxPaths = 5,\r\n maxDepth = 6,\r\n): string[][] {\r\n const paths: string[][] = [];\r\n\r\n // Build directed adjacency\r\n const adjacency = new Map<string, string[]>();\r\n for (const edge of graph.edges) {\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n }\r\n\r\n function dfs(current: string, target: string, path: string[], visited: Set<string>): void {\r\n if (paths.length >= maxPaths) return;\r\n if (path.length > maxDepth) return;\r\n\r\n if (current === target) {\r\n paths.push([...path]);\r\n return;\r\n }\r\n\r\n const neighbors = adjacency.get(current) || [];\r\n for (const neighbor of neighbors) {\r\n if (!visited.has(neighbor)) {\r\n visited.add(neighbor);\r\n path.push(neighbor);\r\n dfs(neighbor, target, path, visited);\r\n path.pop();\r\n visited.delete(neighbor);\r\n }\r\n }\r\n }\r\n\r\n const visited = new Set([fromId]);\r\n dfs(fromId, toId, [fromId], visited);\r\n return paths;\r\n}\r\n\r\n/**\r\n * Generate a Mermaid diagram from the knowledge graph.\r\n */\r\nexport function toMermaid(graph: KnowledgeGraph, options?: { maxNodes?: number; nodeTypes?: string[] }): string {\r\n const maxNodes = options?.maxNodes || 50;\r\n const nodeTypes = options?.nodeTypes;\r\n\r\n let filteredNodes = graph.nodes;\r\n if (nodeTypes) {\r\n filteredNodes = filteredNodes.filter(n => nodeTypes.includes(n.type));\r\n }\r\n filteredNodes = filteredNodes.slice(0, maxNodes);\r\n\r\n const nodeIds = new Set(filteredNodes.map(n => n.id));\r\n const filteredEdges = graph.edges.filter(e => nodeIds.has(e.source) && nodeIds.has(e.target));\r\n\r\n const lines: string[] = ['graph TD'];\r\n\r\n // Style definitions\r\n lines.push(' classDef model fill:#4ecca3,color:#000,stroke:#2d9970');\r\n lines.push(' classDef api fill:#e94560,color:#fff,stroke:#c23049');\r\n lines.push(' classDef service fill:#3498db,color:#fff,stroke:#2378b8');\r\n lines.push(' classDef module fill:#f39c12,color:#000,stroke:#c27d0e');\r\n lines.push(' classDef component fill:#9b59b6,color:#fff,stroke:#7d3c98');\r\n lines.push(' classDef file fill:#555,color:#fff,stroke:#333');\r\n\r\n // Nodes\r\n for (const node of filteredNodes) {\r\n const safeId = sanitizeMermaidId(node.id);\r\n const safeLabel = node.label.replace(/\"/g, \"'\");\r\n lines.push(` ${safeId}[\"${safeLabel}\"]:::${node.type}`);\r\n }\r\n\r\n // Edges\r\n for (const edge of filteredEdges) {\r\n const safeSource = sanitizeMermaidId(edge.source);\r\n const safeTarget = sanitizeMermaidId(edge.target);\r\n const label = edge.relation;\r\n lines.push(` ${safeSource} -->|${label}| ${safeTarget}`);\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Get graph statistics summary.\r\n */\r\nexport function getGraphStats(graph: KnowledgeGraph): Record<string, number> {\r\n const stats: Record<string, number> = {\r\n totalNodes: graph.nodes.length,\r\n totalEdges: graph.edges.length,\r\n };\r\n\r\n // Count by node type\r\n for (const node of graph.nodes) {\r\n const key = `${node.type}Count`;\r\n stats[key] = (stats[key] || 0) + 1;\r\n }\r\n\r\n // Count by edge relation\r\n for (const edge of graph.edges) {\r\n const key = `${edge.relation}Count`;\r\n stats[key] = (stats[key] || 0) + 1;\r\n }\r\n\r\n return stats;\r\n}\r\n\r\n// ===== Helpers =====\r\n\r\nfunction inferModule(entity: ExtractedEntity): string | undefined {\r\n if (!entity.filePath) return undefined;\r\n const parts = entity.filePath.split('/');\r\n if (parts.length > 1) {\r\n // Use first meaningful directory as module\r\n const dir = parts[0]!;\r\n if (dir === 'src' && parts.length > 2) return parts[1];\r\n return dir;\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction findMatchingEntity(entityMap: Map<string, ExtractedEntity>, typePrefix: string, nameSuffix: string): string | null {\r\n for (const [id, entity] of entityMap) {\r\n if (id.startsWith(`${typePrefix}:`) && entity.name === nameSuffix) {\r\n return id;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction buildProjectMetadata(scanResult: ScanResult, options: GraphBuildOptions, nodes: GraphNode[]): ProjectMetadata {\r\n const stats: ProjectStats = {\r\n totalFiles: scanResult.files.length,\r\n totalLines: scanResult.files.reduce((sum, f) => sum + f.lines, 0),\r\n modules: nodes.filter(n => n.type === 'module').length,\r\n classes: nodes.filter(n => n.type === 'class').length,\r\n functions: nodes.filter(n => n.type === 'function').length,\r\n apiEndpoints: nodes.filter(n => n.type === 'api').length,\r\n dataModels: nodes.filter(n => n.type === 'model').length,\r\n dependencies: nodes.filter(n => n.type === 'dependency').length,\r\n linesByLanguage: scanResult.languages,\r\n };\r\n\r\n return {\r\n name: options.projectName,\r\n source: options.source,\r\n sourceUrl: options.sourceUrl,\r\n rootPath: options.rootPath,\r\n languages: scanResult.languages,\r\n frameworks: scanResult.frameworks.map(f => f.name),\r\n packageManager: undefined,\r\n projectType: 'unknown',\r\n stats,\r\n };\r\n}\r\n\r\nfunction sanitizeMermaidId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n","/**\r\n * AI Insight Engine\r\n *\r\n * Multi-perspective analysis powered by LLM. Generates:\r\n * - Risk reports (security, performance, data integrity, logic)\r\n * - Impact analysis (change blast radius)\r\n * - Multi-role reports (developer, architect, tester, product, student, executive)\r\n * - Digital twin simulation (AI-predicted test outcomes)\r\n */\r\n\r\nimport type {\r\n KnowledgeGraph,\r\n RiskAnnotation,\r\n RiskCategory,\r\n RiskSeverity,\r\n ImpactAnalysis,\r\n PerspectiveReport,\r\n ReportPerspective,\r\n ReportSection,\r\n SimulationScenario,\r\n SimulationResult,\r\n} from '../graph/types.js';\r\nimport { bfsTraversal, getNeighbors, toMermaid } from '../graph/index.js';\r\nimport type { LlmProvider } from '../types.js';\r\n\r\nexport interface InsightOptions {\r\n /** LLM provider for AI-enhanced analysis */\r\n llm?: LlmProvider;\r\n /** Enable LLM-based analysis (requires llm provider) */\r\n useLlm?: boolean;\r\n /** Progress callback */\r\n onProgress?: (phase: string, percent: number, detail?: string) => void;\r\n}\r\n\r\n// ===================================================================\r\n// Risk Analysis\r\n// ===================================================================\r\n\r\n/**\r\n * Analyze a knowledge graph for risks across all categories.\r\n * Combines rule-based static analysis with optional LLM enhancement.\r\n */\r\nexport async function analyzeRisks(\r\n graph: KnowledgeGraph,\r\n options?: InsightOptions,\r\n): Promise<RiskAnnotation[]> {\r\n const risks: RiskAnnotation[] = [];\r\n let riskCounter = 0;\r\n\r\n options?.onProgress?.('risk-analysis', 0, 'Starting risk analysis...');\r\n\r\n // --- Rule-based risk detection ---\r\n\r\n // 1. Security: Unprotected API endpoints\r\n const apis = graph.nodes.filter(n => n.type === 'api');\r\n const middlewares = graph.nodes.filter(n => n.type === 'middleware');\r\n const hasAuthMiddleware = middlewares.some(m =>\r\n m.label.toLowerCase().includes('auth') || m.label.toLowerCase().includes('jwt') || m.label.toLowerCase().includes('session')\r\n );\r\n\r\n for (const api of apis) {\r\n const incoming = graph.edges.filter(e => e.target === api.id);\r\n const hasAuth = incoming.some(e => {\r\n const sourceNode = graph.nodes.find(n => n.id === e.source);\r\n return sourceNode?.type === 'middleware' &&\r\n (sourceNode.label.toLowerCase().includes('auth') || e.relation === 'middleware-of');\r\n });\r\n\r\n if (!hasAuth && !hasAuthMiddleware) {\r\n const apiPath = (api.metadata.path as string) || api.label;\r\n const isSensitive = /user|admin|password|token|secret|key|delete|payment/i.test(apiPath);\r\n if (isSensitive) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'security',\r\n severity: 'high',\r\n title: `Potentially unprotected sensitive endpoint: ${api.label}`,\r\n description: `The endpoint ${api.label} appears to handle sensitive data but no authentication middleware was detected in the graph.`,\r\n affectedNodes: [api.id],\r\n suggestion: 'Add authentication middleware to protect this endpoint.',\r\n confidence: 0.6,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 20, 'Checking data integrity...');\r\n\r\n // 2. Data Integrity: Models without validation\r\n const models = graph.nodes.filter(n => n.type === 'model');\r\n for (const model of models) {\r\n const writeEdges = graph.edges.filter(e => e.target === model.id && e.relation === 'writes');\r\n if (writeEdges.length > 3) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'data-integrity',\r\n severity: 'medium',\r\n title: `High write fan-in on model: ${model.label}`,\r\n description: `Model \"${model.label}\" is written to by ${writeEdges.length} different endpoints. This increases risk of data conflicts and race conditions.`,\r\n affectedNodes: [model.id, ...writeEdges.map(e => e.source)],\r\n suggestion: 'Consider adding transaction boundaries or an optimistic locking strategy.',\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n\r\n // 3. Data Integrity: Cascade delete risk\r\n const foreignKeyEdges = graph.edges.filter(e => e.relation === 'foreign-key' || e.relation === 'cascade-delete');\r\n for (const fk of foreignKeyEdges) {\r\n const sourceNode = graph.nodes.find(n => n.id === fk.source);\r\n const targetNode = graph.nodes.find(n => n.id === fk.target);\r\n if (sourceNode && targetNode) {\r\n // Check how many other tables reference the target\r\n const dependents = graph.edges.filter(e =>\r\n (e.relation === 'foreign-key' || e.relation === 'cascade-delete') && e.target === fk.target\r\n );\r\n if (dependents.length >= 3) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'data-integrity',\r\n severity: 'high',\r\n title: `Cascade risk: ${targetNode.label} has ${dependents.length} dependent tables`,\r\n description: `Deleting records from \"${targetNode.label}\" could cascade to ${dependents.length} other tables.`,\r\n affectedNodes: [fk.target, ...dependents.map(d => d.source)],\r\n suggestion: 'Implement soft deletes or add cascade protection.',\r\n confidence: 0.85,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 40, 'Checking performance...');\r\n\r\n // 4. Performance: Large modules (God-module smell)\r\n const moduleNodes = graph.nodes.filter(n => n.type === 'module');\r\n for (const mod of moduleNodes) {\r\n const children = graph.edges.filter(e => e.target === mod.id && e.relation === 'belongs-to');\r\n if (children.length > 50) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'maintainability',\r\n severity: 'medium',\r\n title: `Large module: ${mod.label} (${children.length} entities)`,\r\n description: `Module \"${mod.label}\" contains ${children.length} entities. Consider splitting for better maintainability.`,\r\n affectedNodes: [mod.id],\r\n suggestion: 'Split into smaller, focused sub-modules.',\r\n confidence: 0.75,\r\n });\r\n }\r\n }\r\n\r\n // 5. Reliability: Circular dependencies\r\n const cycles = detectCycles(graph);\r\n for (const cycle of cycles) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'logic',\r\n severity: 'high',\r\n title: `Circular dependency detected: ${cycle.map(id => graph.nodes.find(n => n.id === id)?.label || id).join(' → ')}`,\r\n description: `A circular dependency was found involving ${cycle.length} entities. This can cause initialization issues and makes testing harder.`,\r\n affectedNodes: cycle,\r\n suggestion: 'Break the cycle by introducing an interface or Event-based decoupling.',\r\n confidence: 0.9,\r\n });\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 60, 'Checking maintainability...');\r\n\r\n // 6. Maintainability: High coupling\r\n for (const node of graph.nodes) {\r\n if (node.type === 'file' || node.type === 'dependency') continue;\r\n const outgoing = graph.edges.filter(e => e.source === node.id);\r\n const incoming = graph.edges.filter(e => e.target === node.id);\r\n const coupling = outgoing.length + incoming.length;\r\n if (coupling > 15) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'maintainability',\r\n severity: 'medium',\r\n title: `High coupling: ${node.label} (${coupling} connections)`,\r\n description: `\"${node.label}\" has ${coupling} connections (${outgoing.length} outgoing, ${incoming.length} incoming). Changes here will have wide impact.`,\r\n affectedNodes: [node.id],\r\n suggestion: 'Consider extracting shared logic or adding an abstraction layer.',\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n\r\n // 7. Security: Potential injection points (APIs with dynamic path params)\r\n for (const api of apis) {\r\n const apiPath = (api.metadata.path as string) || api.label;\r\n if (apiPath.includes(':') || apiPath.includes('{')) {\r\n const method = (api.metadata.method as string) || '';\r\n if (['DELETE', 'PUT', 'PATCH'].includes(method)) {\r\n risks.push({\r\n id: `risk-${++riskCounter}`,\r\n category: 'security',\r\n severity: 'low',\r\n title: `Verify input validation: ${api.label}`,\r\n description: `Endpoint ${api.label} accepts path parameters. Ensure proper input validation and authorization checks.`,\r\n affectedNodes: [api.id],\r\n suggestion: 'Add input validation middleware and verify the user has permission to modify the specified resource.',\r\n confidence: 0.5,\r\n });\r\n }\r\n }\r\n }\r\n\r\n options?.onProgress?.('risk-analysis', 80, `Found ${risks.length} risks`);\r\n\r\n // --- LLM-enhanced risk detection (optional) ---\r\n if (options?.useLlm && options.llm) {\r\n try {\r\n const llmRisks = await getLlmRisks(graph, risks, options.llm);\r\n risks.push(...llmRisks);\r\n } catch {\r\n // LLM enhancement failed — rule-based results are still valid\r\n }\r\n }\r\n\r\n // Sort by severity\r\n const severityOrder: Record<RiskSeverity, number> = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };\r\n risks.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);\r\n\r\n options?.onProgress?.('risk-analysis', 100, `Analysis complete: ${risks.length} risks found`);\r\n\r\n return risks;\r\n}\r\n\r\n// ===================================================================\r\n// Impact Analysis\r\n// ===================================================================\r\n\r\n/**\r\n * Analyze the impact of changing a specific node.\r\n */\r\nexport function analyzeImpact(graph: KnowledgeGraph, nodeId: string): ImpactAnalysis {\r\n const node = graph.nodes.find(n => n.id === nodeId);\r\n if (!node) {\r\n return {\r\n sourceNode: nodeId,\r\n directImpact: [],\r\n transitiveImpact: [],\r\n riskLevel: 'low',\r\n summary: `Node \"${nodeId}\" not found in the graph.`,\r\n mermaidText: '',\r\n };\r\n }\r\n\r\n // Direct neighbors\r\n const { incoming, outgoing } = getNeighbors(graph, nodeId);\r\n const directNodes = new Set([\r\n ...incoming.map(e => e.source),\r\n ...outgoing.map(e => e.target),\r\n ]);\r\n directNodes.delete(nodeId);\r\n\r\n // Transitive impact (BFS depth 3)\r\n const transitiveNodes = bfsTraversal(graph, nodeId, 3);\r\n\r\n // Calculate risk level\r\n const totalImpact = transitiveNodes.length;\r\n let riskLevel: RiskSeverity;\r\n if (totalImpact > 20) riskLevel = 'critical';\r\n else if (totalImpact > 10) riskLevel = 'high';\r\n else if (totalImpact > 5) riskLevel = 'medium';\r\n else riskLevel = 'low';\r\n\r\n // Generate summary\r\n const summary = `Changing \"${node.label}\" directly affects ${directNodes.size} entities and transitively impacts ${transitiveNodes.length} entities (risk: ${riskLevel}).`;\r\n\r\n // Generate Mermaid diagram\r\n const impactNodeIds = new Set([nodeId, ...directNodes, ...transitiveNodes.slice(0, 20)]);\r\n const impactNodes = graph.nodes.filter(n => impactNodeIds.has(n.id));\r\n const impactEdges = graph.edges.filter(e => impactNodeIds.has(e.source) && impactNodeIds.has(e.target));\r\n\r\n let mermaidText = 'graph TD\\n';\r\n mermaidText += ` style ${sanitizeId(nodeId)} fill:#e94560,color:#fff\\n`;\r\n for (const dn of directNodes) {\r\n mermaidText += ` style ${sanitizeId(dn)} fill:#f39c12,color:#000\\n`;\r\n }\r\n for (const n of impactNodes) {\r\n mermaidText += ` ${sanitizeId(n.id)}[\"${n.label.replace(/\"/g, \"'\")}\"]\\n`;\r\n }\r\n for (const e of impactEdges) {\r\n mermaidText += ` ${sanitizeId(e.source)} -->|${e.relation}| ${sanitizeId(e.target)}\\n`;\r\n }\r\n\r\n return {\r\n sourceNode: nodeId,\r\n directImpact: [...directNodes],\r\n transitiveImpact: transitiveNodes,\r\n riskLevel,\r\n summary,\r\n mermaidText,\r\n };\r\n}\r\n\r\n// ===================================================================\r\n// Multi-Perspective Reports\r\n// ===================================================================\r\n\r\n/**\r\n * Generate a report from a specific perspective.\r\n */\r\nexport async function generateReport(\r\n graph: KnowledgeGraph,\r\n perspective: ReportPerspective,\r\n risks: RiskAnnotation[],\r\n options?: InsightOptions,\r\n): Promise<PerspectiveReport> {\r\n // If LLM available, use it for rich narrative\r\n if (options?.useLlm && options.llm) {\r\n return generateLlmReport(graph, perspective, risks, options.llm);\r\n }\r\n\r\n // Fallback: rule-based report generation\r\n switch (perspective) {\r\n case 'developer':\r\n return buildDeveloperReport(graph, risks);\r\n case 'architect':\r\n return buildArchitectReport(graph, risks);\r\n case 'tester':\r\n return buildTesterReport(graph, risks);\r\n case 'product':\r\n return buildProductReport(graph, risks);\r\n case 'student':\r\n return buildStudentReport(graph, risks);\r\n case 'executive':\r\n return buildExecutiveReport(graph, risks);\r\n default:\r\n return buildDeveloperReport(graph, risks);\r\n }\r\n}\r\n\r\nfunction buildDeveloperReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const stats = projectInfo.stats;\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Project Overview',\r\n content: `**${projectInfo.name}** is a ${projectInfo.projectType} project using ${projectInfo.frameworks.join(', ') || 'unknown frameworks'}.\\n\\n` +\r\n `- **Files**: ${stats.totalFiles} | **Lines**: ${stats.totalLines.toLocaleString()}\\n` +\r\n `- **Languages**: ${Object.entries(projectInfo.languages).map(([k, v]) => `${k}(${v})`).join(', ')}\\n` +\r\n `- **APIs**: ${stats.apiEndpoints} | **Models**: ${stats.dataModels} | **Functions**: ${stats.functions}`,\r\n },\r\n {\r\n heading: 'Architecture Map',\r\n content: 'Module-level dependency graph:',\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module', 'model', 'api'], maxNodes: 30 }),\r\n },\r\n },\r\n {\r\n heading: 'API Endpoints',\r\n content: graph.nodes\r\n .filter(n => n.type === 'api')\r\n .map(a => `- \\`${a.label}\\` (${a.filePath || 'unknown'})`)\r\n .join('\\n') || 'No API endpoints detected.',\r\n },\r\n {\r\n heading: 'Data Models',\r\n content: graph.nodes\r\n .filter(n => n.type === 'model')\r\n .map(m => `- **${m.label}** (${m.filePath || 'unknown'})`)\r\n .join('\\n') || 'No data models detected.',\r\n },\r\n {\r\n heading: 'Risk Report',\r\n content: risks.length === 0\r\n ? 'No significant risks detected.'\r\n : risks.slice(0, 10).map(r =>\r\n `- **[${r.severity.toUpperCase()}]** ${r.title}\\n ${r.description}`\r\n ).join('\\n\\n'),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'developer',\r\n title: `Developer Report: ${projectInfo.name}`,\r\n summary: `${projectInfo.name} — ${stats.apiEndpoints} APIs, ${stats.dataModels} models, ${risks.length} risks detected.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildArchitectReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const modules = graph.nodes.filter(n => n.type === 'module');\r\n const criticalRisks = risks.filter(r => r.severity === 'critical' || r.severity === 'high');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'System Architecture',\r\n content: `**Type**: ${projectInfo.projectType}\\n**Frameworks**: ${projectInfo.frameworks.join(', ')}\\n**Modules**: ${modules.length}\\n\\n` +\r\n `The system is organized into ${modules.length} modules with ${graph.edges.length} relationships.`,\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module'], maxNodes: 20 }),\r\n },\r\n },\r\n {\r\n heading: 'Module Coupling Analysis',\r\n content: modules.map(m => {\r\n const edges = graph.edges.filter(e => e.source === m.id || e.target === m.id);\r\n return `- **${m.label}**: ${edges.length} connections`;\r\n }).join('\\n'),\r\n },\r\n {\r\n heading: 'Technical Debt & Risk',\r\n content: criticalRisks.length === 0\r\n ? 'No critical or high-severity risks.'\r\n : criticalRisks.map(r => `- **[${r.severity}]** ${r.title}\\n _Suggestion_: ${r.suggestion || 'N/A'}`).join('\\n\\n'),\r\n },\r\n {\r\n heading: 'Recommendations',\r\n content: generateArchitectRecommendations(graph, risks),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'architect',\r\n title: `Architecture Report: ${projectInfo.name}`,\r\n summary: `${modules.length} modules, ${graph.edges.length} relationships, ${criticalRisks.length} critical/high risks.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildTesterReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const apis = graph.nodes.filter(n => n.type === 'api');\r\n const tests = graph.nodes.filter(n => n.type === 'test');\r\n const riskyApis = risks.filter(r => r.category === 'security' || r.category === 'data-integrity');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Test Coverage Overview',\r\n content: `- **API Endpoints**: ${apis.length}\\n- **Test Files Found**: ${tests.length}\\n- **Estimated Coverage**: ${tests.length > 0 ? Math.min(Math.round(tests.length / Math.max(apis.length, 1) * 100), 100) : 0}%`,\r\n },\r\n {\r\n heading: 'Priority Test Targets',\r\n content: 'Endpoints with highest risk that need testing first:\\n\\n' +\r\n riskyApis.slice(0, 10).map((r, i) => `${i + 1}. **${r.title}** (${r.severity})\\n ${r.description}`).join('\\n\\n'),\r\n },\r\n {\r\n heading: 'Edge Cases to Consider',\r\n content: apis.slice(0, 10).map(api => {\r\n const method = (api.metadata.method as string) || 'ANY';\r\n const suggestions: string[] = [];\r\n if (method === 'POST' || method === 'PUT') suggestions.push('Empty body', 'Invalid types', 'Missing required fields', 'Extremely long strings');\r\n if (method === 'DELETE') suggestions.push('Non-existent ID', 'Already deleted', 'ID with dependencies');\r\n if (method === 'GET') suggestions.push('Invalid query params', 'Large pagination', 'Non-existent ID');\r\n return `- **${api.label}**: ${suggestions.join(', ')}`;\r\n }).join('\\n'),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'tester',\r\n title: `Testing Report: ${graph.projectInfo.name}`,\r\n summary: `${apis.length} endpoints to test, ${riskyApis.length} high-risk areas identified.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildProductReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const modules = graph.nodes.filter(n => n.type === 'module');\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'What Does This System Do?',\r\n content: `This is a **${projectInfo.projectType}** system built with ${projectInfo.frameworks.join(', ')}. ` +\r\n `It contains ${modules.length} functional modules and ${projectInfo.stats.apiEndpoints} service interfaces.`,\r\n },\r\n {\r\n heading: 'Feature Map',\r\n content: modules.map(m => {\r\n const children = graph.edges.filter(e => e.target === m.id).length;\r\n return `- **${m.label}** — ${children} components`;\r\n }).join('\\n'),\r\n },\r\n {\r\n heading: 'Health Status',\r\n content: (() => {\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n if (critical > 0) return `⚠️ **Needs Attention**: ${critical} critical issues found that could affect users.`;\r\n if (high > 3) return `⚡ **Minor Concerns**: ${high} areas that should be improved.`;\r\n return '✅ **Healthy**: No critical issues detected. System is in good shape.';\r\n })(),\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'product',\r\n title: `Product Overview: ${projectInfo.name}`,\r\n summary: `${modules.length} feature modules, ${risks.filter(r => r.severity === 'critical').length} critical issues.`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildStudentReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'What is this project?',\r\n content: `This is a **${projectInfo.projectType}** project. Let\\'s break it down step by step!\\n\\n` +\r\n `**Languages used**: ${Object.keys(projectInfo.languages).join(', ')}\\n` +\r\n `**Frameworks**: ${projectInfo.frameworks.join(', ') || 'None detected'}\\n\\n` +\r\n `Think of this project like a building:\\n` +\r\n `- The **frameworks** are the building\\'s foundation\\n` +\r\n `- The **modules** are different rooms\\n` +\r\n `- The **APIs** are the doors and windows (interfaces to the outside world)\\n` +\r\n `- The **models** are the furniture and storage (data structures)`,\r\n },\r\n {\r\n heading: 'How is it organized?',\r\n content: `The project has **${projectInfo.stats.modules}** modules (think: folders of related code).\\n\\n` +\r\n `Each module typically contains:\\n` +\r\n `1. **Controllers/Routes** — Handle incoming requests (like a receptionist)\\n` +\r\n `2. **Services** — Business logic (like the workers)\\n` +\r\n `3. **Models** — Data structures (like forms and documents)\\n\\n` +\r\n 'Here\\'s a simplified view:',\r\n visualization: {\r\n type: 'mermaid',\r\n data: toMermaid(graph, { nodeTypes: ['module', 'model'], maxNodes: 15 }),\r\n },\r\n },\r\n {\r\n heading: 'Key Concepts to Learn',\r\n content: `Based on this project, you should study:\\n\\n` +\r\n (projectInfo.frameworks.includes('Express') ? '- **Express.js** — Node.js web framework for building APIs\\n' : '') +\r\n (projectInfo.frameworks.includes('React') ? '- **React** — Frontend UI library for building user interfaces\\n' : '') +\r\n (projectInfo.frameworks.includes('Sequelize') ? '- **Sequelize** — ORM for database operations\\n' : '') +\r\n `- **REST APIs** — How the frontend talks to the backend\\n` +\r\n `- **MVC Pattern** — Model-View-Controller architecture\\n` +\r\n `- **Authentication** — How users log in and stay logged in`,\r\n },\r\n {\r\n heading: 'Things to Watch Out For',\r\n content: risks.length > 0\r\n ? `Here are ${Math.min(risks.length, 5)} interesting issues found:\\n\\n` +\r\n risks.slice(0, 5).map((r, i) => `${i + 1}. **${r.title}**\\n _Why it matters_: ${r.description}\\n _How to fix_: ${r.suggestion || 'Research this topic!'}`).join('\\n\\n')\r\n : 'This project looks clean! No major issues found.',\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'student',\r\n title: `Learning Guide: ${projectInfo.name}`,\r\n summary: `A ${projectInfo.projectType} project — great for learning ${Object.keys(projectInfo.languages).join(', ')}!`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\nfunction buildExecutiveReport(graph: KnowledgeGraph, risks: RiskAnnotation[]): PerspectiveReport {\r\n const { projectInfo } = graph;\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n\r\n // Health score: 100 - (critical * 20 + high * 10 + medium * 3)\r\n const medium = risks.filter(r => r.severity === 'medium').length;\r\n const healthScore = Math.max(0, 100 - (critical * 20 + high * 10 + medium * 3));\r\n\r\n const sections: ReportSection[] = [\r\n {\r\n heading: 'Health Score',\r\n content: `# ${healthScore}/100\\n\\n` +\r\n (healthScore >= 80 ? '✅ System is healthy and well-maintained.' :\r\n healthScore >= 60 ? '⚡ System needs some attention. Address high-priority items.' :\r\n '⚠️ System has significant issues that need immediate attention.'),\r\n },\r\n {\r\n heading: 'Key Metrics',\r\n content: `| Metric | Value |\\n|--------|-------|\\n` +\r\n `| Codebase Size | ${projectInfo.stats.totalLines.toLocaleString()} lines |\\n` +\r\n `| Technologies | ${projectInfo.frameworks.length} frameworks |\\n` +\r\n `| API Surface | ${projectInfo.stats.apiEndpoints} endpoints |\\n` +\r\n `| Data Models | ${projectInfo.stats.dataModels} tables |\\n` +\r\n `| Critical Issues | ${critical} |\\n` +\r\n `| High Issues | ${high} |`,\r\n },\r\n {\r\n heading: 'Top 3 Risks Needing Action',\r\n content: risks.slice(0, 3).map((r, i) =>\r\n `${i + 1}. **${r.title}** (${r.severity})`\r\n ).join('\\n') || 'No significant risks.',\r\n },\r\n ];\r\n\r\n return {\r\n perspective: 'executive',\r\n title: `Executive Summary: ${projectInfo.name}`,\r\n summary: `Health: ${healthScore}/100 | ${critical} critical, ${high} high risks | ${projectInfo.stats.apiEndpoints} APIs`,\r\n sections,\r\n generatedAt: new Date().toISOString(),\r\n };\r\n}\r\n\r\n// ===================================================================\r\n// Digital Twin Simulation\r\n// ===================================================================\r\n\r\n/**\r\n * Run AI-powered simulation on a scenario (requires LLM).\r\n */\r\nexport async function simulateScenario(\r\n graph: KnowledgeGraph,\r\n scenario: SimulationScenario,\r\n llm: LlmProvider,\r\n): Promise<SimulationResult> {\r\n // Build context from graph\r\n const relatedNodes = scenario.steps\r\n .map(s => s.endpoint)\r\n .filter(Boolean)\r\n .flatMap(endpoint => graph.nodes.filter(n => n.type === 'api' && n.label.includes(endpoint!)))\r\n .map(n => n.id);\r\n\r\n const context = relatedNodes.flatMap(nodeId => {\r\n const neighbors = getNeighbors(graph, nodeId);\r\n return [\r\n ...neighbors.outgoing.map(e => {\r\n const target = graph.nodes.find(n => n.id === e.target);\r\n return `${e.relation}: ${target?.label || e.target}`;\r\n }),\r\n ];\r\n });\r\n\r\n const prompt = `You are an expert software engineer analyzing a system.\r\n\r\nProject: ${graph.projectInfo.name}\r\nFrameworks: ${graph.projectInfo.frameworks.join(', ')}\r\n\r\nScenario: ${scenario.name}\r\nDescription: ${scenario.description}\r\n\r\nSteps:\r\n${scenario.steps.map((s, i) => `${i + 1}. ${s.action} — ${s.endpoint || 'N/A'}`).join('\\n')}\r\n\r\nRelated context from knowledge graph:\r\n${context.join('\\n')}\r\n\r\nPredict:\r\n1. What would happen when executing this scenario?\r\n2. What anomalies or edge cases could occur?\r\n3. Rate the risk (0-100) of this scenario failing in production.\r\n\r\nRespond in JSON: { \"prediction\": \"...\", \"anomalies\": [\"...\"], \"riskScore\": N, \"confidence\": 0.X }`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n return {\r\n scenario,\r\n prediction: parsed.prediction || 'Unable to predict.',\r\n anomalies: parsed.anomalies || [],\r\n riskScore: parsed.riskScore || 50,\r\n confidence: parsed.confidence || 0.5,\r\n };\r\n } catch {\r\n return {\r\n scenario,\r\n prediction: response,\r\n anomalies: [],\r\n riskScore: 50,\r\n confidence: 0.3,\r\n };\r\n }\r\n}\r\n\r\n// ===================================================================\r\n// Helpers\r\n// ===================================================================\r\n\r\nfunction detectCycles(graph: KnowledgeGraph): string[][] {\r\n const cycles: string[][] = [];\r\n const adjacency = new Map<string, string[]>();\r\n\r\n // Build adjacency (only import/depends-on edges for cycle detection)\r\n for (const edge of graph.edges) {\r\n if (edge.relation !== 'imports' && edge.relation !== 'depends-on' && edge.relation !== 'calls') continue;\r\n if (!adjacency.has(edge.source)) adjacency.set(edge.source, []);\r\n adjacency.get(edge.source)!.push(edge.target);\r\n }\r\n\r\n const visited = new Set<string>();\r\n const inStack = new Set<string>();\r\n const path: string[] = [];\r\n\r\n function dfs(node: string): void {\r\n if (cycles.length >= 5) return; // Limit cycle count\r\n visited.add(node);\r\n inStack.add(node);\r\n path.push(node);\r\n\r\n for (const neighbor of adjacency.get(node) || []) {\r\n if (!visited.has(neighbor)) {\r\n dfs(neighbor);\r\n } else if (inStack.has(neighbor)) {\r\n // Found cycle\r\n const cycleStart = path.indexOf(neighbor);\r\n if (cycleStart >= 0) {\r\n cycles.push([...path.slice(cycleStart), neighbor]);\r\n }\r\n }\r\n }\r\n\r\n path.pop();\r\n inStack.delete(node);\r\n }\r\n\r\n for (const node of adjacency.keys()) {\r\n if (!visited.has(node)) {\r\n dfs(node);\r\n }\r\n }\r\n\r\n return cycles;\r\n}\r\n\r\nfunction generateArchitectRecommendations(_graph: KnowledgeGraph, risks: RiskAnnotation[]): string {\r\n const items: string[] = [];\r\n\r\n const securityRisks = risks.filter(r => r.category === 'security');\r\n if (securityRisks.length > 0) {\r\n items.push(`1. **Security Hardening**: Address ${securityRisks.length} security findings before next release.`);\r\n }\r\n\r\n const couplingRisks = risks.filter(r => r.category === 'maintainability');\r\n if (couplingRisks.length > 2) {\r\n items.push(`2. **Reduce Coupling**: ${couplingRisks.length} modules show high coupling. Consider introducing service boundaries.`);\r\n }\r\n\r\n const dataRisks = risks.filter(r => r.category === 'data-integrity');\r\n if (dataRisks.length > 0) {\r\n items.push(`3. **Data Protection**: ${dataRisks.length} data integrity concerns. Add transaction boundaries and cascade protections.`);\r\n }\r\n\r\n if (items.length === 0) {\r\n items.push('Architecture looks solid. Continue monitoring coupling metrics as the system grows.');\r\n }\r\n\r\n return items.join('\\n\\n');\r\n}\r\n\r\nasync function getLlmRisks(graph: KnowledgeGraph, existingRisks: RiskAnnotation[], llm: LlmProvider): Promise<RiskAnnotation[]> {\r\n const prompt = `Analyze this project knowledge graph for additional risks not already identified.\r\n\r\nProject: ${graph.projectInfo.name}\r\nType: ${graph.projectInfo.projectType}\r\nFrameworks: ${graph.projectInfo.frameworks.join(', ')}\r\nStats: ${graph.projectInfo.stats.apiEndpoints} APIs, ${graph.projectInfo.stats.dataModels} models\r\n\r\nAlready identified risks (${existingRisks.length}):\r\n${existingRisks.slice(0, 5).map(r => `- [${r.severity}] ${r.title}`).join('\\n')}\r\n\r\nAPI Endpoints: ${graph.nodes.filter(n => n.type === 'api').slice(0, 20).map(n => n.label).join(', ')}\r\nModels: ${graph.nodes.filter(n => n.type === 'model').slice(0, 20).map(n => n.label).join(', ')}\r\n\r\nReturn up to 3 additional risks in JSON array format:\r\n[{ \"category\": \"security|performance|data-integrity|logic|maintainability|reliability\", \"severity\": \"critical|high|medium|low\", \"title\": \"...\", \"description\": \"...\", \"suggestion\": \"...\" }]`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n if (!Array.isArray(parsed)) return [];\r\n return parsed.slice(0, 3).map((r: Record<string, string>, i: number) => ({\r\n id: `risk-llm-${i}`,\r\n category: (r.category || 'logic') as RiskCategory,\r\n severity: (r.severity || 'medium') as RiskSeverity,\r\n title: r.title || 'LLM-detected risk',\r\n description: r.description || '',\r\n affectedNodes: [],\r\n suggestion: r.suggestion,\r\n confidence: 0.6,\r\n }));\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nasync function generateLlmReport(\r\n graph: KnowledgeGraph,\r\n perspective: ReportPerspective,\r\n risks: RiskAnnotation[],\r\n llm: LlmProvider,\r\n): Promise<PerspectiveReport> {\r\n const perspectiveDescriptions: Record<ReportPerspective, string> = {\r\n developer: 'a software developer who wants technical details, code patterns, and API documentation',\r\n architect: 'a software architect who cares about modularity, coupling, tech debt, and system design',\r\n tester: 'a QA engineer who wants to know what to test, edge cases, and risk areas',\r\n product: 'a product manager who wants to understand features in business terms, not code',\r\n student: 'a computer science student learning from this codebase, explain concepts step by step',\r\n executive: 'a CTO/VP who wants a one-page health summary with actionable insights',\r\n };\r\n\r\n const prompt = `Generate a project analysis report for ${graph.projectInfo.name} from the perspective of ${perspectiveDescriptions[perspective]}.\r\n\r\nProject Info:\r\n- Type: ${graph.projectInfo.projectType}\r\n- Frameworks: ${graph.projectInfo.frameworks.join(', ')}\r\n- Stats: ${graph.projectInfo.stats.totalFiles} files, ${graph.projectInfo.stats.apiEndpoints} APIs, ${graph.projectInfo.stats.dataModels} models\r\n- Languages: ${Object.entries(graph.projectInfo.languages).map(([k, v]) => `${k}(${v} files)`).join(', ')}\r\n\r\nTop risks:\r\n${risks.slice(0, 5).map(r => `- [${r.severity}] ${r.title}`).join('\\n')}\r\n\r\nGenerate 3-5 report sections with clear headings and content. Use markdown formatting.\r\nRespond in JSON: { \"title\": \"...\", \"summary\": \"...\", \"sections\": [{ \"heading\": \"...\", \"content\": \"...\" }] }`;\r\n\r\n const response = await llm.chat([{ role: 'user', content: prompt }]);\r\n\r\n try {\r\n const parsed = JSON.parse(cleanJsonResponse(response));\r\n return {\r\n perspective,\r\n title: parsed.title || `${perspective} Report`,\r\n summary: parsed.summary || '',\r\n sections: (parsed.sections || []).map((s: Record<string, string>) => ({\r\n heading: s.heading || 'Section',\r\n content: s.content || '',\r\n })),\r\n generatedAt: new Date().toISOString(),\r\n };\r\n } catch {\r\n // Fallback to rule-based\r\n return buildDeveloperReport(graph, risks);\r\n }\r\n}\r\n\r\nfunction cleanJsonResponse(response: string): string {\r\n // Strip markdown code fences if present\r\n let cleaned = response.trim();\r\n if (cleaned.startsWith('```json')) cleaned = cleaned.slice(7);\r\n else if (cleaned.startsWith('```')) cleaned = cleaned.slice(3);\r\n if (cleaned.endsWith('```')) cleaned = cleaned.slice(0, -3);\r\n return cleaned.trim();\r\n}\r\n\r\nfunction sanitizeId(id: string): string {\r\n return id.replace(/[^a-zA-Z0-9_]/g, '_');\r\n}\r\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { dirname } from 'node:path';\r\nimport type { KnowledgeGraph, RiskAnnotation } from '../graph/types.js';\r\n\r\nfunction isSerializedSnapshotFile(value: SerializedSnapshotFile | StudioProjectStore): value is SerializedSnapshotFile {\r\n return 'snapshots' in value && Array.isArray(value.snapshots);\r\n}\r\n\r\nexport interface StudioProjectStore {\r\n graph: KnowledgeGraph | null;\r\n risks: RiskAnnotation[];\r\n scanTime: number;\r\n source: string;\r\n}\r\n\r\nexport interface StudioSnapshotStore {\r\n load(): StudioProjectStore | null;\r\n save(snapshot: StudioProjectStore): void;\r\n list(): StudioSnapshotSummary[];\r\n loadById(id: string): StudioProjectStore | null;\r\n rename(id: string, name: string): boolean;\r\n delete(id: string): boolean;\r\n pin(id: string, pinned: boolean): boolean;\r\n updateTags(id: string, tags: string[]): boolean;\r\n}\r\n\r\nexport interface StudioSnapshotRecord extends StudioProjectStore {\r\n id: string;\r\n name: string;\r\n pinned: boolean;\r\n tags: string[];\r\n}\r\n\r\nexport interface StudioSnapshotSummary {\r\n id: string;\r\n name: string;\r\n source: string;\r\n scanTime: number;\r\n nodeCount: number;\r\n riskCount: number;\r\n current: boolean;\r\n pinned: boolean;\r\n tags: string[];\r\n}\r\n\r\ninterface SerializedSnapshotFile {\r\n version: 2;\r\n currentSnapshotId: string | null;\r\n snapshots: StudioSnapshotRecord[];\r\n}\r\n\r\nexport const EMPTY_STUDIO_STORE: StudioProjectStore = {\r\n graph: null,\r\n risks: [],\r\n scanTime: 0,\r\n source: '',\r\n};\r\n\r\nexport class FileStudioSnapshotStore implements StudioSnapshotStore {\r\n private readonly filePath: string;\r\n private readonly maxSnapshots: number;\r\n\r\n constructor(filePath: string, maxSnapshots = 12) {\r\n this.filePath = filePath;\r\n this.maxSnapshots = maxSnapshots;\r\n }\r\n\r\n load(): StudioProjectStore | null {\r\n const data = this.readFile();\r\n if (!data || !data.currentSnapshotId) return null;\r\n const current = data.snapshots.find((snapshot) => snapshot.id === data.currentSnapshotId);\r\n return current ? this.toProjectStore(current) : null;\r\n }\r\n\r\n save(snapshot: StudioProjectStore): void {\r\n const data = this.readFile() ?? { version: 2, currentSnapshotId: null, snapshots: [] };\r\n const record = this.toSnapshotRecord(snapshot);\r\n data.currentSnapshotId = record.id;\r\n data.snapshots = [record, ...data.snapshots].slice(0, this.maxSnapshots);\r\n\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n }\r\n\r\n list(): StudioSnapshotSummary[] {\r\n const data = this.readFile();\r\n if (!data) return [];\r\n return data.snapshots.map((snapshot) => ({\r\n id: snapshot.id,\r\n name: snapshot.name,\r\n source: snapshot.source,\r\n scanTime: snapshot.scanTime,\r\n nodeCount: snapshot.graph?.nodes.length ?? 0,\r\n riskCount: snapshot.risks.length,\r\n current: snapshot.id === data.currentSnapshotId,\r\n pinned: Boolean(snapshot.pinned),\r\n tags: Array.isArray(snapshot.tags) ? snapshot.tags : [],\r\n })).sort((left, right) => {\r\n if (left.pinned !== right.pinned) return left.pinned ? -1 : 1;\r\n return right.scanTime - left.scanTime;\r\n });\r\n }\r\n\r\n loadById(id: string): StudioProjectStore | null {\r\n const data = this.readFile();\r\n if (!data) return null;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return null;\r\n\r\n data.currentSnapshotId = record.id;\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return this.toProjectStore(record);\r\n }\r\n\r\n rename(id: string, name: string): boolean {\r\n const nextName = name.trim();\r\n if (!nextName) return false;\r\n\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return false;\r\n\r\n record.name = nextName;\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n delete(id: string): boolean {\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const nextSnapshots = data.snapshots.filter((snapshot) => snapshot.id !== id);\r\n if (nextSnapshots.length === data.snapshots.length) return false;\r\n\r\n data.snapshots = nextSnapshots;\r\n if (data.currentSnapshotId === id) {\r\n data.currentSnapshotId = nextSnapshots[0]?.id ?? null;\r\n }\r\n\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n pin(id: string, pinned: boolean): boolean {\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return false;\r\n\r\n record.pinned = pinned;\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n updateTags(id: string, tags: string[]): boolean {\r\n const data = this.readFile();\r\n if (!data) return false;\r\n\r\n const record = data.snapshots.find((snapshot) => snapshot.id === id);\r\n if (!record) return false;\r\n\r\n record.tags = this.normalizeTags(tags);\r\n mkdirSync(dirname(this.filePath), { recursive: true });\r\n writeFileSync(this.filePath, JSON.stringify(data, null, 2), 'utf-8');\r\n return true;\r\n }\r\n\r\n private readFile(): SerializedSnapshotFile | null {\r\n if (!existsSync(this.filePath)) return null;\r\n\r\n try {\r\n const raw = readFileSync(this.filePath, 'utf-8');\r\n const parsed = JSON.parse(raw) as SerializedSnapshotFile | StudioProjectStore;\r\n return this.normalize(parsed);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n private normalize(parsed: SerializedSnapshotFile | StudioProjectStore): SerializedSnapshotFile {\r\n if (isSerializedSnapshotFile(parsed)) {\r\n return {\r\n version: 2,\r\n currentSnapshotId: typeof parsed.currentSnapshotId === 'string' ? parsed.currentSnapshotId : null,\r\n snapshots: parsed.snapshots.map((snapshot) => ({\r\n id: snapshot.id,\r\n name: snapshot.name,\r\n pinned: Boolean(snapshot.pinned),\r\n tags: this.normalizeTags(snapshot.tags),\r\n graph: snapshot.graph ?? null,\r\n risks: Array.isArray(snapshot.risks) ? snapshot.risks : [],\r\n scanTime: typeof snapshot.scanTime === 'number' ? snapshot.scanTime : 0,\r\n source: typeof snapshot.source === 'string' ? snapshot.source : '',\r\n })),\r\n };\r\n }\r\n\r\n const legacyStore = parsed as StudioProjectStore;\r\n const legacy = this.toSnapshotRecord({\r\n graph: legacyStore.graph ?? null,\r\n risks: Array.isArray(legacyStore.risks) ? legacyStore.risks : [],\r\n scanTime: typeof legacyStore.scanTime === 'number' ? legacyStore.scanTime : 0,\r\n source: typeof legacyStore.source === 'string' ? legacyStore.source : '',\r\n });\r\n\r\n return {\r\n version: 2,\r\n currentSnapshotId: legacy.id,\r\n snapshots: [legacy],\r\n };\r\n }\r\n\r\n private toSnapshotRecord(snapshot: StudioProjectStore): StudioSnapshotRecord {\r\n const name = snapshot.graph?.projectInfo?.name || this.deriveName(snapshot.source);\r\n return {\r\n id: `${snapshot.scanTime || Date.now()}-${Math.random().toString(16).slice(2, 8)}`,\r\n name,\r\n pinned: false,\r\n tags: [],\r\n graph: snapshot.graph ?? null,\r\n risks: Array.isArray(snapshot.risks) ? snapshot.risks : [],\r\n scanTime: typeof snapshot.scanTime === 'number' ? snapshot.scanTime : Date.now(),\r\n source: typeof snapshot.source === 'string' ? snapshot.source : '',\r\n };\r\n }\r\n\r\n private toProjectStore(snapshot: StudioSnapshotRecord): StudioProjectStore {\r\n return {\r\n graph: snapshot.graph ?? null,\r\n risks: Array.isArray(snapshot.risks) ? snapshot.risks : [],\r\n scanTime: typeof snapshot.scanTime === 'number' ? snapshot.scanTime : 0,\r\n source: typeof snapshot.source === 'string' ? snapshot.source : '',\r\n };\r\n }\r\n\r\n private deriveName(source: string): string {\r\n if (!source) return 'unknown-project';\r\n const parts = source.split(/[\\\\/]/).filter(Boolean);\r\n return parts[parts.length - 1] || source;\r\n }\r\n\r\n private normalizeTags(tags: unknown): string[] {\r\n if (!Array.isArray(tags)) return [];\r\n return [...new Set(tags\r\n .map((tag) => typeof tag === 'string' ? tag.trim() : '')\r\n .filter(Boolean)\r\n )];\r\n }\r\n}","/**\r\n * OpenCroc Dynamic Role Registry\r\n *\r\n * Manages an extensible pool of croc expert roles that can be\r\n * dynamically summoned based on project characteristics.\r\n *\r\n * Architecture:\r\n * RoleDefinition → what a croc CAN do (template)\r\n * CrocAgent → a live instance doing work (runtime)\r\n * TaskRouter → decides WHICH roles to summon for a project\r\n */\r\n\r\n// ─── Role Definition ─────────────────────────────────────────────────────────\r\n\r\nexport type RoleCategory =\r\n | 'core' // 官方核心角色 (always available)\r\n | 'language' // 语言专家鳄\r\n | 'framework' // 框架专家鳄\r\n | 'domain' // 领域专家鳄 (security, performance, etc.)\r\n | 'community'; // 社区贡献角色\r\n\r\nexport interface RoleTrigger {\r\n /** Match against detected languages (e.g. \"python\", \"typescript\") */\r\n languages?: string[];\r\n /** Match against detected frameworks (e.g. \"Express\", \"Django\", \"React\") */\r\n frameworks?: string[];\r\n /** Match against project type */\r\n projectTypes?: string[];\r\n /** Match against file patterns (glob-style) */\r\n filePatterns?: string[];\r\n /** Match against entity count thresholds */\r\n minEntities?: number;\r\n /** Match against risk categories found */\r\n riskCategories?: string[];\r\n /** Custom predicate for advanced matching */\r\n custom?: (ctx: MatchContext) => boolean;\r\n}\r\n\r\nexport interface MatchContext {\r\n languages: Record<string, number>;\r\n frameworks: string[];\r\n projectType: string;\r\n fileCount: number;\r\n entityCount: number;\r\n riskCategories: string[];\r\n hasModels: boolean;\r\n hasAPIs: boolean;\r\n hasFrontend: boolean;\r\n hasDocker: boolean;\r\n hasCI: boolean;\r\n}\r\n\r\nexport interface RoleDefinition {\r\n /** Unique identifier, e.g. \"security-auditor\" */\r\n id: string;\r\n /** Display name in Chinese, e.g. \"安全审计鳄\" */\r\n name: string;\r\n /** English name for international display */\r\n nameEn: string;\r\n /** Role category */\r\n category: RoleCategory;\r\n /** Short description of expertise */\r\n description: string;\r\n /** Icon/sprite identifier for 3D rendering */\r\n sprite: string;\r\n /** Color theme (hex) for the croc's glow */\r\n color: string;\r\n /** Priority: lower = summoned first when multiple match (0-100) */\r\n priority: number;\r\n /** When should this role be summoned? */\r\n triggers: RoleTrigger;\r\n /** System prompt template for LLM analysis */\r\n systemPrompt: string;\r\n /** What this role outputs */\r\n outputType: 'report' | 'analysis' | 'fix' | 'review' | 'diagram';\r\n /** Tags for search/filtering */\r\n tags: string[];\r\n /** Author info (for community roles) */\r\n author?: string;\r\n /** Version string */\r\n version?: string;\r\n}\r\n\r\n// ─── Built-in Core Roles ─────────────────────────────────────────────────────\r\n\r\nconst CORE_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'parser-croc',\r\n name: '解析鳄',\r\n nameEn: 'Parser Croc',\r\n category: 'core',\r\n description: '解析项目结构、提取实体和关系',\r\n sprite: 'parser',\r\n color: '#34d399',\r\n priority: 0,\r\n triggers: { custom: () => true }, // Always summoned\r\n systemPrompt: 'You are an expert code parser. Analyze the project structure, extract all entities (classes, functions, APIs, models) and their relationships.',\r\n outputType: 'analysis',\r\n tags: ['core', 'parser', 'structure'],\r\n },\r\n {\r\n id: 'analyzer-croc',\r\n name: '分析鳄',\r\n nameEn: 'Analyzer Croc',\r\n category: 'core',\r\n description: '构建知识图谱、分析依赖关系',\r\n sprite: 'analyzer',\r\n color: '#60a5fa',\r\n priority: 1,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert software architect. Build a knowledge graph of the project, analyze dependencies, coupling, and cohesion.',\r\n outputType: 'diagram',\r\n tags: ['core', 'graph', 'architecture'],\r\n },\r\n {\r\n id: 'tester-croc',\r\n name: '测试鳄',\r\n nameEn: 'Tester Croc',\r\n category: 'core',\r\n description: '生成和执行 E2E 测试',\r\n sprite: 'tester',\r\n color: '#a78bfa',\r\n priority: 2,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert test engineer. Generate comprehensive E2E test cases covering all critical paths, edge cases, and error scenarios.',\r\n outputType: 'analysis',\r\n tags: ['core', 'testing', 'e2e'],\r\n },\r\n {\r\n id: 'healer-croc',\r\n name: '修复鳄',\r\n nameEn: 'Healer Croc',\r\n category: 'core',\r\n description: '自动修复测试失败和代码问题',\r\n sprite: 'healer',\r\n color: '#f87171',\r\n priority: 3,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert debugger and code fixer. Analyze test failures, diagnose root causes, and propose minimal targeted fixes.',\r\n outputType: 'fix',\r\n tags: ['core', 'healing', 'debug'],\r\n },\r\n {\r\n id: 'planner-croc',\r\n name: '规划鳄',\r\n nameEn: 'Planner Croc',\r\n category: 'core',\r\n description: '制定测试策略和执行计划',\r\n sprite: 'planner',\r\n color: '#fbbf24',\r\n priority: 4,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert project planner. Create test strategies, prioritize test execution order, and optimize the testing pipeline.',\r\n outputType: 'analysis',\r\n tags: ['core', 'planning', 'strategy'],\r\n },\r\n {\r\n id: 'reporter-croc',\r\n name: '汇报鳄',\r\n nameEn: 'Reporter Croc',\r\n category: 'core',\r\n description: '生成多视角分析报告',\r\n sprite: 'reporter',\r\n color: '#22d3ee',\r\n priority: 5,\r\n triggers: { custom: () => true },\r\n systemPrompt: 'You are an expert technical writer. Generate clear, actionable reports from multiple perspectives (developer, architect, tester, product, executive).',\r\n outputType: 'report',\r\n tags: ['core', 'reporting', 'documentation'],\r\n },\r\n];\r\n\r\n// ─── Language Expert Roles ───────────────────────────────────────────────────\r\n\r\nconst LANGUAGE_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'python-croc',\r\n name: 'Python专家鳄',\r\n nameEn: 'Python Expert Croc',\r\n category: 'language',\r\n description: 'Python 生态专家:Django/Flask/FastAPI/SQLAlchemy',\r\n sprite: 'language',\r\n color: '#3776ab',\r\n priority: 10,\r\n triggers: { languages: ['python'] },\r\n systemPrompt: 'You are a Python ecosystem expert. Analyze Python code for best practices, type safety, async patterns, Django/Flask/FastAPI conventions, SQLAlchemy usage, and Python-specific security issues.',\r\n outputType: 'review',\r\n tags: ['language', 'python', 'django', 'flask', 'fastapi'],\r\n },\r\n {\r\n id: 'go-croc',\r\n name: 'Go专家鳄',\r\n nameEn: 'Go Expert Croc',\r\n category: 'language',\r\n description: 'Go 生态专家:goroutine/channel/接口设计',\r\n sprite: 'language',\r\n color: '#00add8',\r\n priority: 10,\r\n triggers: { languages: ['go'] },\r\n systemPrompt: 'You are a Go ecosystem expert. Analyze Go code for goroutine safety, channel patterns, interface design, error handling, and Go-specific performance concerns.',\r\n outputType: 'review',\r\n tags: ['language', 'go', 'golang', 'concurrency'],\r\n },\r\n {\r\n id: 'java-croc',\r\n name: 'Java专家鳄',\r\n nameEn: 'Java Expert Croc',\r\n category: 'language',\r\n description: 'Java/Kotlin 生态专家:Spring Boot/JPA/微服务',\r\n sprite: 'language',\r\n color: '#ed8b00',\r\n priority: 10,\r\n triggers: { languages: ['java', 'kotlin'] },\r\n systemPrompt: 'You are a Java/Kotlin ecosystem expert. Analyze Spring Boot applications for bean lifecycle issues, JPA N+1 queries, transaction management, and microservice patterns.',\r\n outputType: 'review',\r\n tags: ['language', 'java', 'kotlin', 'spring'],\r\n },\r\n {\r\n id: 'rust-croc',\r\n name: 'Rust专家鳄',\r\n nameEn: 'Rust Expert Croc',\r\n category: 'language',\r\n description: 'Rust 生态专家:所有权/生命周期/unsafe',\r\n sprite: 'language',\r\n color: '#dea584',\r\n priority: 10,\r\n triggers: { languages: ['rust'] },\r\n systemPrompt: 'You are a Rust ecosystem expert. Analyze Rust code for ownership patterns, lifetime issues, unsafe code safety, and performance optimization.',\r\n outputType: 'review',\r\n tags: ['language', 'rust', 'ownership', 'safety'],\r\n },\r\n];\r\n\r\n// ─── Framework Expert Roles ──────────────────────────────────────────────────\r\n\r\nconst FRAMEWORK_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'react-croc',\r\n name: 'React专家鳄',\r\n nameEn: 'React Expert Croc',\r\n category: 'framework',\r\n description: 'React/Next.js 前端性能和架构专家',\r\n sprite: 'framework',\r\n color: '#61dafb',\r\n priority: 15,\r\n triggers: { frameworks: ['React', 'Next.js'] },\r\n systemPrompt: 'You are a React/Next.js expert. Analyze component architecture, render performance, state management, SSR/SSG patterns, and React-specific anti-patterns.',\r\n outputType: 'review',\r\n tags: ['framework', 'react', 'nextjs', 'frontend'],\r\n },\r\n {\r\n id: 'vue-croc',\r\n name: 'Vue专家鳄',\r\n nameEn: 'Vue Expert Croc',\r\n category: 'framework',\r\n description: 'Vue/Nuxt 专家:组合式API/响应式/SSR',\r\n sprite: 'framework',\r\n color: '#42b883',\r\n priority: 15,\r\n triggers: { frameworks: ['Vue', 'Nuxt'] },\r\n systemPrompt: 'You are a Vue/Nuxt expert. Analyze Composition API usage, reactivity patterns, Pinia stores, SSR hydration, and Vue-specific best practices.',\r\n outputType: 'review',\r\n tags: ['framework', 'vue', 'nuxt', 'frontend'],\r\n },\r\n {\r\n id: 'express-croc',\r\n name: 'Express专家鳄',\r\n nameEn: 'Express Expert Croc',\r\n category: 'framework',\r\n description: 'Express/Koa/Fastify 路由和中间件专家',\r\n sprite: 'framework',\r\n color: '#68a063',\r\n priority: 15,\r\n triggers: { frameworks: ['Express', 'Koa', 'Fastify'] },\r\n systemPrompt: 'You are a Node.js backend expert. Analyze Express/Koa/Fastify middleware chains, route organization, error handling, authentication patterns, and performance.',\r\n outputType: 'review',\r\n tags: ['framework', 'express', 'koa', 'fastify', 'nodejs'],\r\n },\r\n {\r\n id: 'django-croc',\r\n name: 'Django专家鳄',\r\n nameEn: 'Django Expert Croc',\r\n category: 'framework',\r\n description: 'Django/DRF 专家:ORM/序列化/权限',\r\n sprite: 'framework',\r\n color: '#092e20',\r\n priority: 15,\r\n triggers: { frameworks: ['Django', 'DRF'] },\r\n systemPrompt: 'You are a Django/DRF expert. Analyze ORM query efficiency, serializer design, view permissions, middleware, and Django-specific security practices.',\r\n outputType: 'review',\r\n tags: ['framework', 'django', 'drf', 'python'],\r\n },\r\n {\r\n id: 'spring-croc',\r\n name: 'SpringBoot专家鳄',\r\n nameEn: 'Spring Boot Expert Croc',\r\n category: 'framework',\r\n description: 'Spring Boot/Cloud 微服务架构专家',\r\n sprite: 'framework',\r\n color: '#6db33f',\r\n priority: 15,\r\n triggers: { frameworks: ['Spring Boot', 'Spring Cloud'] },\r\n systemPrompt: 'You are a Spring Boot/Cloud expert. Analyze bean configurations, transaction management, service discovery, circuit breakers, and microservice communication patterns.',\r\n outputType: 'review',\r\n tags: ['framework', 'spring', 'springboot', 'microservice'],\r\n },\r\n];\r\n\r\n// ─── Domain Expert Roles ─────────────────────────────────────────────────────\r\n\r\nconst DOMAIN_ROLES: RoleDefinition[] = [\r\n {\r\n id: 'security-croc',\r\n name: '安全审计鳄',\r\n nameEn: 'Security Auditor Croc',\r\n category: 'domain',\r\n description: '安全漏洞检测:注入/XSS/CSRF/认证/授权',\r\n sprite: 'security',\r\n color: '#ef4444',\r\n priority: 8,\r\n triggers: {\r\n riskCategories: ['security'],\r\n custom: (ctx) => ctx.hasAPIs,\r\n },\r\n systemPrompt: 'You are a security auditor. Scan for OWASP Top 10 vulnerabilities: SQL injection, XSS, CSRF, broken authentication, sensitive data exposure, insecure deserialization, and missing access controls.',\r\n outputType: 'report',\r\n tags: ['domain', 'security', 'owasp', 'audit'],\r\n },\r\n {\r\n id: 'performance-croc',\r\n name: '性能分析鳄',\r\n nameEn: 'Performance Analyst Croc',\r\n category: 'domain',\r\n description: '性能瓶颈检测:N+1查询/内存泄漏/慢接口',\r\n sprite: 'performance',\r\n color: '#f59e0b',\r\n priority: 9,\r\n triggers: {\r\n minEntities: 50,\r\n custom: (ctx) => ctx.hasModels && ctx.hasAPIs,\r\n },\r\n systemPrompt: 'You are a performance analyst. Detect N+1 queries, memory leaks, slow API endpoints, missing indexes, unnecessary data loading, and recommend caching strategies.',\r\n outputType: 'report',\r\n tags: ['domain', 'performance', 'optimization', 'n+1'],\r\n },\r\n {\r\n id: 'architecture-croc',\r\n name: '架构评审鳄',\r\n nameEn: 'Architecture Reviewer Croc',\r\n category: 'domain',\r\n description: '架构质量评审:耦合度/内聚性/分层/DDD',\r\n sprite: 'architecture',\r\n color: '#8b5cf6',\r\n priority: 7,\r\n triggers: {\r\n minEntities: 30,\r\n },\r\n systemPrompt: 'You are a software architect. Evaluate coupling, cohesion, layering, dependency injection, SOLID principles, DDD patterns, and recommend architectural improvements.',\r\n outputType: 'review',\r\n tags: ['domain', 'architecture', 'solid', 'ddd'],\r\n },\r\n {\r\n id: 'data-modeling-croc',\r\n name: '数据建模鳄',\r\n nameEn: 'Data Modeling Croc',\r\n category: 'domain',\r\n description: '数据模型评审:范式/索引/关联/迁移',\r\n sprite: 'database',\r\n color: '#06b6d4',\r\n priority: 9,\r\n triggers: {\r\n custom: (ctx) => ctx.hasModels,\r\n frameworks: ['Sequelize', 'Prisma', 'TypeORM', 'Drizzle', 'SQLAlchemy', 'Django'],\r\n },\r\n systemPrompt: 'You are a database expert. Review data models for normalization, index design, relationship integrity, migration safety, cascade delete risks, and query optimization.',\r\n outputType: 'review',\r\n tags: ['domain', 'database', 'modeling', 'orm'],\r\n },\r\n {\r\n id: 'devops-croc',\r\n name: '运维部署鳄',\r\n nameEn: 'DevOps Croc',\r\n category: 'domain',\r\n description: 'CI/CD、Docker、K8s 部署和运维专家',\r\n sprite: 'devops',\r\n color: '#2563eb',\r\n priority: 12,\r\n triggers: {\r\n custom: (ctx) => ctx.hasDocker || ctx.hasCI,\r\n filePatterns: ['Dockerfile', 'docker-compose*', '.github/workflows/*', '.gitlab-ci*', 'Jenkinsfile'],\r\n },\r\n systemPrompt: 'You are a DevOps expert. Analyze Dockerfile efficiency, compose orchestration, CI/CD pipeline design, secret management, health checks, and deployment strategies.',\r\n outputType: 'review',\r\n tags: ['domain', 'devops', 'docker', 'ci/cd', 'kubernetes'],\r\n },\r\n {\r\n id: 'api-design-croc',\r\n name: 'API设计鳄',\r\n nameEn: 'API Design Croc',\r\n category: 'domain',\r\n description: 'RESTful API 设计评审:命名/版本/分页/错误处理',\r\n sprite: 'api',\r\n color: '#10b981',\r\n priority: 11,\r\n triggers: {\r\n custom: (ctx) => ctx.hasAPIs,\r\n minEntities: 10,\r\n },\r\n systemPrompt: 'You are an API design expert. Review REST API naming conventions, versioning strategy, pagination, filtering, error response format, rate limiting, and documentation completeness.',\r\n outputType: 'review',\r\n tags: ['domain', 'api', 'rest', 'design'],\r\n },\r\n {\r\n id: 'refactor-croc',\r\n name: '重构建议鳄',\r\n nameEn: 'Refactoring Croc',\r\n category: 'domain',\r\n description: '代码质量评估:技术债/复杂度/重复代码',\r\n sprite: 'refactor',\r\n color: '#ec4899',\r\n priority: 13,\r\n triggers: {\r\n riskCategories: ['maintainability'],\r\n minEntities: 40,\r\n },\r\n systemPrompt: 'You are a refactoring expert. Identify code smells, duplicated logic, high cyclomatic complexity, god classes, feature envy, and suggest targeted refactoring strategies with minimal risk.',\r\n outputType: 'review',\r\n tags: ['domain', 'refactoring', 'quality', 'tech-debt'],\r\n },\r\n {\r\n id: 'microservice-croc',\r\n name: '服务治理鳄',\r\n nameEn: 'Microservice Governance Croc',\r\n category: 'domain',\r\n description: '微服务架构治理:服务边界/熔断/链路追踪',\r\n sprite: 'microservice',\r\n color: '#7c3aed',\r\n priority: 14,\r\n triggers: {\r\n projectTypes: ['microservice', 'monorepo'],\r\n custom: (ctx) => ctx.entityCount > 100,\r\n },\r\n systemPrompt: 'You are a microservice governance expert. Analyze service boundaries, inter-service communication, circuit breakers, distributed tracing, service mesh, and API gateway patterns.',\r\n outputType: 'review',\r\n tags: ['domain', 'microservice', 'governance', 'distributed'],\r\n },\r\n];\r\n\r\n// ─── Role Registry ───────────────────────────────────────────────────────────\r\n\r\nexport class RoleRegistry {\r\n private roles = new Map<string, RoleDefinition>();\r\n\r\n constructor() {\r\n // Register all built-in roles\r\n for (const role of [...CORE_ROLES, ...LANGUAGE_ROLES, ...FRAMEWORK_ROLES, ...DOMAIN_ROLES]) {\r\n this.roles.set(role.id, role);\r\n }\r\n }\r\n\r\n /** Register a new role (community or custom) */\r\n register(role: RoleDefinition): void {\r\n if (this.roles.has(role.id)) {\r\n throw new Error(`Role \"${role.id}\" is already registered`);\r\n }\r\n this.roles.set(role.id, role);\r\n }\r\n\r\n /** Unregister a role */\r\n unregister(id: string): boolean {\r\n return this.roles.delete(id);\r\n }\r\n\r\n /** Get a role by ID */\r\n get(id: string): RoleDefinition | undefined {\r\n return this.roles.get(id);\r\n }\r\n\r\n /** List all registered roles */\r\n list(): RoleDefinition[] {\r\n return Array.from(this.roles.values());\r\n }\r\n\r\n /** List roles by category */\r\n listByCategory(category: RoleCategory): RoleDefinition[] {\r\n return this.list().filter(r => r.category === category);\r\n }\r\n\r\n /** Search roles by tags */\r\n search(query: string): RoleDefinition[] {\r\n const q = query.toLowerCase();\r\n return this.list().filter(r =>\r\n r.name.toLowerCase().includes(q) ||\r\n r.nameEn.toLowerCase().includes(q) ||\r\n r.description.toLowerCase().includes(q) ||\r\n r.tags.some(t => t.includes(q))\r\n );\r\n }\r\n\r\n /** Total number of registered roles */\r\n get size(): number {\r\n return this.roles.size;\r\n }\r\n}\r\n\r\n// ─── Singleton instance ──────────────────────────────────────────────────────\r\n\r\nlet _registry: RoleRegistry | null = null;\r\n\r\nexport function getRoleRegistry(): RoleRegistry {\r\n if (!_registry) {\r\n _registry = new RoleRegistry();\r\n }\r\n return _registry;\r\n}\r\n","/**\r\n * Studio Routes — Universal Project Analysis\r\n *\r\n * New routes for the upgraded OpenCroc Studio that supports\r\n * scanning any project (local or GitHub URL), building knowledge\r\n * graphs, analyzing risks, and generating multi-perspective reports.\r\n */\r\n\r\nimport type { FastifyInstance } from 'fastify';\r\nimport { cloneAndScan } from '../../scanner/github-cloner.js';\r\nimport { buildKnowledgeGraph, getGraphStats, toMermaid } from '../../graph/index.js';\r\nimport { analyzeRisks, analyzeImpact, generateReport } from '../../insight/index.js';\r\nimport type {\r\n ReportPerspective,\r\n ScanResult,\r\n} from '../../graph/types.js';\r\nimport type { CrocOffice } from '../croc-office.js';\r\nimport {\r\n EMPTY_STUDIO_STORE,\r\n type StudioProjectStore,\r\n type StudioSnapshotStore,\r\n} from '../studio-store.js';\r\n\r\nfunction restoreStore(snapshotStore?: StudioSnapshotStore): StudioProjectStore {\r\n return snapshotStore?.load() ?? { ...EMPTY_STUDIO_STORE };\r\n}\r\n\r\nexport function registerStudioRoutes(\r\n app: FastifyInstance,\r\n office: CrocOffice,\r\n snapshotStore?: StudioSnapshotStore,\r\n): void {\r\n const store = restoreStore(snapshotStore);\r\n // Transient — not persisted in snapshots\r\n let lastScanResult: ScanResult | null = null;\r\n\r\n if (store.graph) {\r\n office.log(`♻️ Restored Studio snapshot: ${store.graph.nodes.length} nodes, ${store.risks.length} risks`, 'info');\r\n }\r\n\r\n const persistStore = () => {\r\n snapshotStore?.save(store);\r\n };\r\n\r\n const broadcastGraph = () => {\r\n if (!store.graph) return;\r\n\r\n office.broadcast('graph:update', {\r\n nodes: store.graph.nodes.map(n => ({\r\n id: n.id,\r\n label: n.label,\r\n type: n.type,\r\n module: n.module,\r\n status: n.status,\r\n })),\r\n edges: store.graph.edges.map(e => ({\r\n source: e.source,\r\n target: e.target,\r\n relation: e.relation,\r\n })),\r\n });\r\n };\r\n\r\n // ===== POST /api/studio/scan — Scan a project (local path or GitHub URL) =====\r\n app.post<{\r\n Body: {\r\n target: string; // Local path or GitHub URL or user/repo\r\n branch?: string;\r\n useLlm?: boolean;\r\n };\r\n }>('/api/studio/scan', async (req, reply) => {\r\n const { target, branch, useLlm } = req.body || {};\r\n\r\n if (!target || typeof target !== 'string') {\r\n reply.code(400).send({ error: 'Missing \"target\" field. Provide a local path or GitHub URL.' });\r\n return;\r\n }\r\n\r\n office.log(`🔍 Starting scan: ${target}`, 'info');\r\n office.updateAgent('parser-croc', { status: 'working', currentTask: `Scanning ${target}...`, progress: 0 });\r\n\r\n try {\r\n const scanResult = await cloneAndScan({\r\n target,\r\n branch,\r\n useLlm,\r\n keepClone: true,\r\n onProgress: (phase, percent, detail) => {\r\n office.updateAgent('parser-croc', { currentTask: detail || phase, progress: percent });\r\n office.broadcast('scan:progress', { phase, percent, detail });\r\n },\r\n });\r\n\r\n office.updateAgent('parser-croc', { status: 'done', currentTask: 'Scan complete', progress: 100 });\r\n office.log(`✅ Scan complete: ${scanResult.entities.length} entities, ${scanResult.relationships.length} relationships`);\r\n\r\n // Build knowledge graph\r\n office.updateAgent('analyzer-croc', { status: 'working', currentTask: 'Building knowledge graph...', progress: 0 });\r\n\r\n const projectName = target.includes('/') ? target.split('/').pop()!.replace('.git', '') : target.split(/[\\\\/]/).pop()!;\r\n\r\n const graph = buildKnowledgeGraph(scanResult, {\r\n projectName,\r\n source: target.startsWith('http') || /^[\\w.-]+\\/[\\w.-]+$/.test(target) ? 'github' : 'local',\r\n sourceUrl: target,\r\n rootPath: target,\r\n });\r\n\r\n office.updateAgent('analyzer-croc', { status: 'done', currentTask: 'Graph built', progress: 100 });\r\n office.log(`📊 Knowledge graph: ${graph.nodes.length} nodes, ${graph.edges.length} edges`);\r\n\r\n // Analyze risks\r\n office.updateAgent('planner-croc', { status: 'working', currentTask: 'Analyzing risks...', progress: 0 });\r\n\r\n const risks = await analyzeRisks(graph);\r\n\r\n office.updateAgent('planner-croc', { status: 'done', currentTask: `${risks.length} risks found`, progress: 100 });\r\n\r\n // Store results\r\n store.graph = graph;\r\n store.risks = risks;\r\n store.scanTime = Date.now();\r\n store.source = target;\r\n lastScanResult = scanResult;\r\n persistStore();\r\n\r\n // Broadcast graph update\r\n broadcastGraph();\r\n\r\n return {\r\n ok: true,\r\n project: graph.projectInfo,\r\n stats: getGraphStats(graph),\r\n risks: risks.length,\r\n duration: graph.buildDuration + scanResult.duration,\r\n };\r\n } catch (err) {\r\n office.updateAgent('parser-croc', { status: 'error', currentTask: String(err) });\r\n office.log(`❌ Scan failed: ${err}`, 'error');\r\n reply.code(500).send({ error: `Scan failed: ${(err as Error).message}` });\r\n return;\r\n }\r\n });\r\n\r\n // ===== GET /api/studio/graph — Get current knowledge graph =====\r\n app.get('/api/studio/graph', async (_req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet. POST /api/studio/scan first.' });\r\n return;\r\n }\r\n\r\n return {\r\n nodes: store.graph.nodes,\r\n edges: store.graph.edges,\r\n projectInfo: store.graph.projectInfo,\r\n builtAt: store.graph.builtAt,\r\n stats: getGraphStats(store.graph),\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/graph/mermaid — Get Mermaid diagram =====\r\n app.get<{\r\n Querystring: { types?: string; maxNodes?: string };\r\n }>('/api/studio/graph/mermaid', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const nodeTypes = req.query.types?.split(',');\r\n const maxNodes = req.query.maxNodes ? parseInt(req.query.maxNodes, 10) : 50;\r\n\r\n return {\r\n mermaid: toMermaid(store.graph, { nodeTypes, maxNodes }),\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/risks — Get risk analysis =====\r\n app.get<{\r\n Querystring: { severity?: string; category?: string };\r\n }>('/api/studio/risks', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n let risks = store.risks;\r\n if (req.query.severity) {\r\n risks = risks.filter(r => r.severity === req.query.severity);\r\n }\r\n if (req.query.category) {\r\n risks = risks.filter(r => r.category === req.query.category);\r\n }\r\n\r\n return { total: risks.length, risks };\r\n });\r\n\r\n // ===== GET /api/studio/impact/:nodeId — Analyze impact of a node =====\r\n app.get<{\r\n Params: { nodeId: string };\r\n }>('/api/studio/impact/:nodeId', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n // URL-decode the nodeId (since it contains colons and slashes)\r\n const nodeId = decodeURIComponent(req.params.nodeId);\r\n const impact = analyzeImpact(store.graph, nodeId);\r\n return impact;\r\n });\r\n\r\n // ===== GET /api/studio/report/:perspective — Generate perspective report =====\r\n app.get<{\r\n Params: { perspective: string };\r\n }>('/api/studio/report/:perspective', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const validPerspectives = ['developer', 'architect', 'tester', 'product', 'student', 'executive'];\r\n const perspective = req.params.perspective;\r\n if (!validPerspectives.includes(perspective)) {\r\n reply.code(400).send({ error: `Invalid perspective. Valid: ${validPerspectives.join(', ')}` });\r\n return;\r\n }\r\n\r\n office.updateAgent('reporter-croc', { status: 'working', currentTask: `Generating ${perspective} report...` });\r\n\r\n const report = await generateReport(\r\n store.graph,\r\n perspective as ReportPerspective,\r\n store.risks,\r\n );\r\n\r\n office.updateAgent('reporter-croc', { status: 'done', currentTask: 'Report ready' });\r\n\r\n return report;\r\n });\r\n\r\n // ===== GET /api/studio/nodes — List nodes with filtering =====\r\n app.get<{\r\n Querystring: { type?: string; language?: string; module?: string; search?: string; limit?: string };\r\n }>('/api/studio/nodes', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n let nodes = store.graph.nodes;\r\n if (req.query.type) nodes = nodes.filter(n => n.type === req.query.type);\r\n if (req.query.language) nodes = nodes.filter(n => n.language === req.query.language);\r\n if (req.query.module) nodes = nodes.filter(n => n.module === req.query.module);\r\n if (req.query.search) {\r\n const q = req.query.search.toLowerCase();\r\n nodes = nodes.filter(n => n.label.toLowerCase().includes(q) || n.id.toLowerCase().includes(q));\r\n }\r\n\r\n const limit = req.query.limit ? parseInt(req.query.limit, 10) : 100;\r\n return { total: nodes.length, nodes: nodes.slice(0, limit) };\r\n });\r\n\r\n // ===== GET /api/studio/node/:nodeId — Get node detail with neighbors =====\r\n app.get<{\r\n Params: { nodeId: string };\r\n }>('/api/studio/node/:nodeId', async (req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const nodeId = decodeURIComponent(req.params.nodeId);\r\n const node = store.graph.nodes.find(n => n.id === nodeId);\r\n if (!node) {\r\n reply.code(404).send({ error: 'Node not found.' });\r\n return;\r\n }\r\n\r\n const incoming = store.graph.edges.filter(e => e.target === nodeId);\r\n const outgoing = store.graph.edges.filter(e => e.source === nodeId);\r\n const neighborIds = new Set([...incoming.map(e => e.source), ...outgoing.map(e => e.target)]);\r\n const neighbors = store.graph.nodes.filter(n => neighborIds.has(n.id));\r\n\r\n return { node, incoming, outgoing, neighbors };\r\n });\r\n\r\n // ===== GET /api/studio/summary — Quick one-line summary =====\r\n app.get('/api/studio/summary', async (_req, reply) => {\r\n if (!store.graph) {\r\n reply.code(404).send({ error: 'No project scanned yet.' });\r\n return;\r\n }\r\n\r\n const { projectInfo } = store.graph;\r\n const stats = getGraphStats(store.graph);\r\n const critical = store.risks.filter(r => r.severity === 'critical').length;\r\n const high = store.risks.filter(r => r.severity === 'high').length;\r\n const healthScore = Math.max(0, 100 - (critical * 20 + high * 10));\r\n\r\n return {\r\n name: projectInfo.name,\r\n oneLiner: `A ${projectInfo.projectType} project using ${projectInfo.frameworks.join(', ') || 'unknown'}, with ${stats.apiCount || 0} APIs and ${stats.modelCount || 0} data models.`,\r\n healthScore,\r\n stats,\r\n topRisks: store.risks.slice(0, 5).map(r => ({ severity: r.severity, title: r.title })),\r\n source: store.source,\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/snapshots — List available snapshots =====\r\n app.get('/api/studio/snapshots', async () => {\r\n const snapshots = snapshotStore?.list() ?? [];\r\n return {\r\n total: snapshots.length,\r\n snapshots,\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/load — Restore a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n }>('/api/studio/snapshots/:id/load', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const restored = snapshotStore.loadById(req.params.id);\r\n if (!restored) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n store.graph = restored.graph;\r\n store.risks = restored.risks;\r\n store.scanTime = restored.scanTime;\r\n store.source = restored.source;\r\n office.log(`♻️ Restored snapshot: ${store.source || 'unknown source'}`, 'info');\r\n broadcastGraph();\r\n\r\n return {\r\n ok: true,\r\n source: store.source,\r\n scanTime: store.scanTime,\r\n graph: store.graph ? {\r\n nodeCount: store.graph.nodes.length,\r\n edgeCount: store.graph.edges.length,\r\n } : null,\r\n risks: store.risks.length,\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/rename — Rename a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n Body: { name?: string };\r\n }>('/api/studio/snapshots/:id/rename', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const name = req.body?.name?.trim();\r\n if (!name) {\r\n reply.code(400).send({ error: 'Snapshot name is required.' });\r\n return;\r\n }\r\n\r\n const renamed = snapshotStore.rename(req.params.id, name);\r\n if (!renamed) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n return {\r\n ok: true,\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/pin — Pin or unpin a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n Body: { pinned?: boolean };\r\n }>('/api/studio/snapshots/:id/pin', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const pinned = Boolean(req.body?.pinned);\r\n const updated = snapshotStore.pin(req.params.id, pinned);\r\n if (!updated) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n return {\r\n ok: true,\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/tags — Replace snapshot tags =====\r\n app.post<{\r\n Params: { id: string };\r\n Body: { tags?: string[] };\r\n }>('/api/studio/snapshots/:id/tags', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const rawTags: string[] = Array.isArray(req.body?.tags) ? req.body.tags : [];\r\n const tags = [...new Set(rawTags\r\n .map((tag: string) => typeof tag === 'string' ? tag.trim() : '')\r\n .filter(Boolean)\r\n )];\r\n\r\n const updated = snapshotStore.updateTags(req.params.id, tags);\r\n if (!updated) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n return {\r\n ok: true,\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/snapshots/:id/delete — Delete a snapshot =====\r\n app.post<{\r\n Params: { id: string };\r\n }>('/api/studio/snapshots/:id/delete', async (req, reply) => {\r\n if (!snapshotStore) {\r\n reply.code(501).send({ error: 'Snapshot persistence is not configured.' });\r\n return;\r\n }\r\n\r\n const deleted = snapshotStore.delete(req.params.id);\r\n if (!deleted) {\r\n reply.code(404).send({ error: 'Snapshot not found.' });\r\n return;\r\n }\r\n\r\n const current = snapshotStore.load();\r\n store.graph = current?.graph ?? null;\r\n store.risks = current?.risks ?? [];\r\n store.scanTime = current?.scanTime ?? 0;\r\n store.source = current?.source ?? '';\r\n if (store.graph) {\r\n broadcastGraph();\r\n }\r\n\r\n return {\r\n ok: true,\r\n hasCurrent: Boolean(current?.graph),\r\n snapshots: snapshotStore.list(),\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/roles — List all registered croc roles =====\r\n app.get('/api/studio/roles', async (req) => {\r\n const { getRoleRegistry } = await import('../../agents/role-registry.js');\r\n const registry = getRoleRegistry();\r\n const category = (req.query as Record<string, string>).category;\r\n const search = (req.query as Record<string, string>).search;\r\n\r\n let roles = registry.list();\r\n if (category) roles = roles.filter(r => r.category === category);\r\n if (search) roles = registry.search(search);\r\n\r\n return {\r\n total: roles.length,\r\n categories: {\r\n core: roles.filter(r => r.category === 'core').length,\r\n language: roles.filter(r => r.category === 'language').length,\r\n framework: roles.filter(r => r.category === 'framework').length,\r\n domain: roles.filter(r => r.category === 'domain').length,\r\n community: roles.filter(r => r.category === 'community').length,\r\n },\r\n roles: roles.map(r => ({\r\n id: r.id,\r\n name: r.name,\r\n nameEn: r.nameEn,\r\n category: r.category,\r\n description: r.description,\r\n color: r.color,\r\n sprite: r.sprite,\r\n priority: r.priority,\r\n tags: r.tags,\r\n outputType: r.outputType,\r\n })),\r\n };\r\n });\r\n\r\n // ===== POST /api/studio/summon — Dynamically summon crocs for current project =====\r\n app.post('/api/studio/summon', async (_req, reply) => {\r\n if (!lastScanResult) {\r\n reply.code(400).send({ error: 'No project scanned. Run /api/studio/scan first.' });\r\n return;\r\n }\r\n\r\n const riskCategories = [...new Set(store.risks.map(r => r.category))];\r\n const plan = await office.summonForProject(lastScanResult, riskCategories);\r\n\r\n return {\r\n ok: true,\r\n totalAgents: office.getAgents().length,\r\n coreAgents: 6,\r\n dynamicAgents: office.getAgents().length - 6,\r\n reasoning: plan.reasoning,\r\n agents: office.getAgents().map(a => ({\r\n id: a.id,\r\n name: a.name,\r\n role: a.role,\r\n sprite: a.sprite,\r\n status: a.status,\r\n category: a.category,\r\n color: a.color,\r\n description: a.description,\r\n })),\r\n context: {\r\n languages: plan.context.languages,\r\n frameworks: plan.context.frameworks,\r\n projectType: plan.context.projectType,\r\n entityCount: plan.context.entityCount,\r\n hasAPIs: plan.context.hasAPIs,\r\n hasModels: plan.context.hasModels,\r\n hasFrontend: plan.context.hasFrontend,\r\n hasDocker: plan.context.hasDocker,\r\n hasCI: plan.context.hasCI,\r\n },\r\n };\r\n });\r\n\r\n // ===== GET /api/studio/agents — Current agent roster =====\r\n app.get('/api/studio/agents', async () => {\r\n const info = office.getSummonPlan();\r\n return {\r\n ...info,\r\n agents: info.agents.map(a => ({\r\n id: a.id,\r\n name: a.name,\r\n role: a.role,\r\n sprite: a.sprite,\r\n status: a.status,\r\n currentTask: a.currentTask,\r\n category: a.category,\r\n color: a.color,\r\n description: a.description,\r\n })),\r\n };\r\n });\r\n}\r\n","/**\r\n * OpenCroc Task Router\r\n *\r\n * Analyzes a scanned project and decides which croc roles to summon.\r\n * Returns a prioritized list of roles matching the project's characteristics.\r\n */\r\n\r\nimport type { ScanResult } from '../graph/types.js';\r\nimport type { RoleDefinition, MatchContext, RoleTrigger } from './role-registry.js';\r\nimport { getRoleRegistry } from './role-registry.js';\r\n\r\nexport interface SummonPlan {\r\n /** Roles to summon, sorted by priority (lower = first) */\r\n roles: SummonedRole[];\r\n /** Summary of why each role was picked */\r\n reasoning: string[];\r\n /** Project context used for matching */\r\n context: MatchContext;\r\n}\r\n\r\nexport interface SummonedRole {\r\n role: RoleDefinition;\r\n /** Why this role was summoned */\r\n reason: string;\r\n /** Match confidence 0-1 */\r\n confidence: number;\r\n}\r\n\r\n/**\r\n * Build a MatchContext from a ScanResult.\r\n */\r\nexport function buildMatchContext(scan: ScanResult): MatchContext {\r\n const languages = scan.languages;\r\n const frameworks = scan.frameworks.map(f => f.name);\r\n // Infer project type from frameworks/languages\r\n const frontendFrameworks = ['React', 'Vue', 'Angular', 'Svelte', 'Next.js', 'Nuxt'];\r\n const backendFrameworks = ['Express', 'Fastify', 'NestJS', 'Django', 'Flask', 'Spring Boot', 'Gin', 'Actix'];\r\n const hasFE = frameworks.some(f => frontendFrameworks.includes(f));\r\n const hasBE = frameworks.some(f => backendFrameworks.includes(f));\r\n const projectType = hasFE && hasBE ? 'fullstack' : hasFE ? 'frontend' : hasBE ? 'backend' : 'unknown';\r\n\r\n const entityTypes = new Set(scan.entities.map(e => e.type));\r\n const hasModels = entityTypes.has('model') || entityTypes.has('class');\r\n const hasAPIs = entityTypes.has('api') || entityTypes.has('route');\r\n\r\n const hasFrontend = hasFE ||\r\n (languages['html'] ?? 0) > 10 || (languages['css'] ?? 0) > 5;\r\n\r\n // Detect Docker/CI from file paths\r\n const allPaths = scan.files.map(f => f.path);\r\n const hasDocker = allPaths.some(p =>\r\n p.includes('Dockerfile') || p.includes('docker-compose')\r\n );\r\n const hasCI = allPaths.some(p =>\r\n p.includes('.github/workflows') ||\r\n p.includes('.gitlab-ci') ||\r\n p.includes('Jenkinsfile')\r\n );\r\n\r\n const riskCategories: string[] = [];\r\n\r\n return {\r\n languages,\r\n frameworks,\r\n projectType,\r\n fileCount: scan.files.length,\r\n entityCount: scan.entities.length,\r\n riskCategories,\r\n hasModels,\r\n hasAPIs,\r\n hasFrontend,\r\n hasDocker,\r\n hasCI,\r\n };\r\n}\r\n\r\n/**\r\n * Check if a role's triggers match the given context.\r\n */\r\nfunction matchesTriggers(trigger: RoleTrigger, ctx: MatchContext): { matches: boolean; reason: string; confidence: number } {\r\n const reasons: string[] = [];\r\n let score = 0;\r\n let checks = 0;\r\n\r\n // Language match\r\n if (trigger.languages && trigger.languages.length > 0) {\r\n checks++;\r\n const matched = trigger.languages.filter(l => (ctx.languages[l] ?? 0) > 0);\r\n if (matched.length > 0) {\r\n score++;\r\n reasons.push(`语言匹配: ${matched.join(', ')}`);\r\n }\r\n }\r\n\r\n // Framework match\r\n if (trigger.frameworks && trigger.frameworks.length > 0) {\r\n checks++;\r\n const matched = trigger.frameworks.filter(f =>\r\n ctx.frameworks.some(cf => cf.toLowerCase() === f.toLowerCase())\r\n );\r\n if (matched.length > 0) {\r\n score++;\r\n reasons.push(`框架匹配: ${matched.join(', ')}`);\r\n }\r\n }\r\n\r\n // Project type match\r\n if (trigger.projectTypes && trigger.projectTypes.length > 0) {\r\n checks++;\r\n if (trigger.projectTypes.includes(ctx.projectType)) {\r\n score++;\r\n reasons.push(`项目类型匹配: ${ctx.projectType}`);\r\n }\r\n }\r\n\r\n // Entity threshold\r\n if (trigger.minEntities !== undefined) {\r\n checks++;\r\n if (ctx.entityCount >= trigger.minEntities) {\r\n score++;\r\n reasons.push(`实体数量满足: ${ctx.entityCount} ≥ ${trigger.minEntities}`);\r\n }\r\n }\r\n\r\n // Risk categories\r\n if (trigger.riskCategories && trigger.riskCategories.length > 0) {\r\n checks++;\r\n const matched = trigger.riskCategories.filter(r => ctx.riskCategories.includes(r));\r\n if (matched.length > 0) {\r\n score++;\r\n reasons.push(`风险类别匹配: ${matched.join(', ')}`);\r\n }\r\n }\r\n\r\n // Custom predicate\r\n if (trigger.custom) {\r\n checks++;\r\n try {\r\n if (trigger.custom(ctx)) {\r\n score++;\r\n reasons.push('自定义条件满足');\r\n }\r\n } catch {\r\n // Custom predicate threw — treat as no match\r\n }\r\n }\r\n\r\n // A role matches if ALL specified trigger conditions pass\r\n // (OR logic: at least one condition must match if multiple are specified)\r\n const matches = checks === 0 ? false : score > 0;\r\n const confidence = checks > 0 ? score / checks : 0;\r\n\r\n return {\r\n matches,\r\n reason: reasons.join('; ') || '无匹配',\r\n confidence,\r\n };\r\n}\r\n\r\n/**\r\n * Given a scan result, determine which roles should be summoned.\r\n *\r\n * @param scan - The scan result from the project scanner\r\n * @param maxRoles - Maximum number of non-core roles to summon (default: 8)\r\n * @param riskCategories - Risk categories detected (from insight engine)\r\n * @returns A SummonPlan with prioritized roles\r\n */\r\nexport function planSummon(\r\n scan: ScanResult,\r\n maxRoles: number = 8,\r\n riskCategories: string[] = [],\r\n): SummonPlan {\r\n const registry = getRoleRegistry();\r\n const ctx = buildMatchContext(scan);\r\n ctx.riskCategories = riskCategories;\r\n\r\n const summoned: SummonedRole[] = [];\r\n const reasoning: string[] = [];\r\n\r\n const allRoles = registry.list();\r\n\r\n // Always include core roles\r\n const coreRoles = allRoles.filter(r => r.category === 'core');\r\n for (const role of coreRoles) {\r\n summoned.push({ role, reason: '核心角色(始终召唤)', confidence: 1.0 });\r\n reasoning.push(`✅ ${role.name} — 核心角色`);\r\n }\r\n\r\n // Match non-core roles\r\n const nonCore = allRoles.filter(r => r.category !== 'core');\r\n const candidates: SummonedRole[] = [];\r\n\r\n for (const role of nonCore) {\r\n const result = matchesTriggers(role.triggers, ctx);\r\n if (result.matches) {\r\n candidates.push({\r\n role,\r\n reason: result.reason,\r\n confidence: result.confidence,\r\n });\r\n }\r\n }\r\n\r\n // Sort by priority (lower first), then confidence (higher first)\r\n candidates.sort((a, b) => {\r\n if (a.role.priority !== b.role.priority) return a.role.priority - b.role.priority;\r\n return b.confidence - a.confidence;\r\n });\r\n\r\n // Take top N\r\n const selected = candidates.slice(0, maxRoles);\r\n for (const s of selected) {\r\n summoned.push(s);\r\n reasoning.push(`🐊 ${s.role.name} — ${s.reason} (置信度: ${(s.confidence * 100).toFixed(0)}%)`);\r\n }\r\n\r\n // Log skipped roles\r\n const skipped = candidates.slice(maxRoles);\r\n for (const s of skipped) {\r\n reasoning.push(`⏭️ ${s.role.name} — 匹配但超出限制 (置信度: ${(s.confidence * 100).toFixed(0)}%)`);\r\n }\r\n\r\n return { roles: summoned, reasoning, context: ctx };\r\n}\r\n","import { execSync as nodeExecSync } from 'node:child_process';\r\nimport type { ExecutionMetrics } from '../types.js';\r\nimport type {\r\n ExecutionCoordinator,\r\n ExecutionCoordinatorDeps,\r\n ExecutionRunMode,\r\n ExecutionRunRequest,\r\n ExecutionRunResult,\r\n} from './types.js';\r\n\r\nfunction parseMetrics(output: string): ExecutionMetrics {\r\n const metrics: ExecutionMetrics = { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n const passedMatch = output.match(/(\\d+)\\s+passed/);\r\n const failedMatch = output.match(/(\\d+)\\s+failed/);\r\n const skippedMatch = output.match(/(\\d+)\\s+skipped/);\r\n const timedOutMatch = output.match(/(\\d+)\\s+timed?\\s*out/i);\r\n if (passedMatch) metrics.passed = parseInt(passedMatch[1], 10);\r\n if (failedMatch) metrics.failed = parseInt(failedMatch[1], 10);\r\n if (skippedMatch) metrics.skipped = parseInt(skippedMatch[1], 10);\r\n if (timedOutMatch) metrics.timedOut = parseInt(timedOutMatch[1], 10);\r\n return metrics;\r\n}\r\n\r\nfunction getFailureLines(output: string): string[] {\r\n return output\r\n .split(/\\r?\\n/)\r\n .filter((line) => /fail|error|timeout/i.test(line))\r\n .slice(0, 5);\r\n}\r\n\r\nexport function createExecutionCoordinator(deps: ExecutionCoordinatorDeps = {}): ExecutionCoordinator {\r\n const execSync = deps.execSync ?? nodeExecSync;\r\n const categorizeFailure = deps.categorizeFailure;\r\n\r\n return {\r\n async run(request: ExecutionRunRequest): Promise<ExecutionRunResult> {\r\n const mode: ExecutionRunMode = request.mode ?? 'auto';\r\n const timeoutMs = request.timeoutMs ?? 300_000;\r\n const command = `npx playwright test ${request.testFiles.map((file) => `\"${file}\"`).join(' ')} --reporter=line 2>&1`;\r\n\r\n let output: string;\r\n try {\r\n output = String(execSync(command, {\r\n cwd: request.cwd,\r\n encoding: 'utf-8',\r\n timeout: timeoutMs,\r\n stdio: 'pipe',\r\n env: request.env,\r\n }));\r\n } catch (err: unknown) {\r\n const execErr = err as { stdout?: string; stderr?: string };\r\n output = `${execErr.stdout || ''}\\n${execErr.stderr || ''}`;\r\n }\r\n\r\n output = output.trim();\r\n const metrics = parseMetrics(output);\r\n if (metrics.passed === 0 && metrics.failed === 0 && metrics.skipped === 0 && metrics.timedOut === 0) {\r\n metrics.failed = request.testFiles.length;\r\n }\r\n\r\n const failureHints = getFailureLines(output).map((line) => {\r\n const analyzed = categorizeFailure ? categorizeFailure(line) : { category: 'unknown', confidence: 0.5 };\r\n return {\r\n line,\r\n category: analyzed.category,\r\n confidence: analyzed.confidence,\r\n };\r\n });\r\n\r\n return {\r\n mode,\r\n metrics,\r\n output,\r\n failureHints,\r\n };\r\n },\r\n };\r\n}\r\n","/**\r\n * Resilient HTTP fetch with exponential backoff retry.\r\n * Framework-level utility — no Playwright dependency required.\r\n */\r\n\r\nexport interface AttemptRecord {\r\n attempt: number;\r\n status: number;\r\n url: string;\r\n method: string;\r\n latencyMs: number;\r\n error?: string;\r\n}\r\n\r\nexport interface ResilientFetchOptions {\r\n /** HTTP method */\r\n method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\r\n /** Request body (will be JSON-stringified if object) */\r\n body?: string | Record<string, unknown>;\r\n /** Request headers */\r\n headers?: Record<string, string>;\r\n /** Max retry count (default: 3) */\r\n maxRetries?: number;\r\n /** Base delay in ms for exponential backoff (default: 1000) */\r\n baseDelayMs?: number;\r\n /** Per-request timeout in ms (default: 10000) */\r\n timeoutMs?: number;\r\n /** If true, throw on final failure; if false, return error result (default: false) */\r\n throwOnFailure?: boolean;\r\n}\r\n\r\nexport interface ResilientFetchResult {\r\n ok: boolean;\r\n status: number;\r\n data: unknown;\r\n attempts: AttemptRecord[];\r\n}\r\n\r\nconst RETRYABLE_STATUSES = new Set([408, 429, 500, 502, 503, 504]);\r\n\r\nfunction isRetryable(status: number): boolean {\r\n return RETRYABLE_STATUSES.has(status);\r\n}\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((r) => setTimeout(r, ms));\r\n}\r\n\r\nasync function safeJson(resp: Response): Promise<unknown> {\r\n try {\r\n return await resp.json();\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Make an HTTP request with automatic retry and exponential backoff.\r\n *\r\n * Retries on: network errors, 408, 429, 5xx.\r\n * Does NOT retry on: 4xx (except 408/429).\r\n */\r\nexport async function resilientFetch(\r\n url: string,\r\n options: ResilientFetchOptions = {},\r\n): Promise<ResilientFetchResult> {\r\n const {\r\n method = 'GET',\r\n body,\r\n headers = {},\r\n maxRetries = 3,\r\n baseDelayMs = 1000,\r\n timeoutMs = 10_000,\r\n throwOnFailure = false,\r\n } = options;\r\n\r\n const attempts: AttemptRecord[] = [];\r\n let lastStatus = 0;\r\n let lastBody: unknown = null;\r\n\r\n const requestHeaders: Record<string, string> = { ...headers };\r\n if (body && typeof body === 'object' && !requestHeaders['Content-Type']) {\r\n requestHeaders['Content-Type'] = 'application/json';\r\n }\r\n\r\n for (let i = 0; i <= maxRetries; i++) {\r\n const start = Date.now();\r\n\r\n try {\r\n const resp = await fetch(url, {\r\n method,\r\n headers: requestHeaders,\r\n body: body ? (typeof body === 'string' ? body : JSON.stringify(body)) : undefined,\r\n signal: AbortSignal.timeout(timeoutMs),\r\n });\r\n\r\n const latency = Date.now() - start;\r\n lastStatus = resp.status;\r\n lastBody = await safeJson(resp);\r\n\r\n attempts.push({ attempt: i + 1, status: lastStatus, url, method, latencyMs: latency });\r\n\r\n if (resp.ok) {\r\n return { ok: true, status: lastStatus, data: lastBody, attempts };\r\n }\r\n\r\n if (isRetryable(lastStatus) && i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n\r\n // Non-retryable error\r\n break;\r\n } catch (err) {\r\n const latency = Date.now() - start;\r\n const errMsg = err instanceof Error ? err.message : String(err);\r\n attempts.push({ attempt: i + 1, status: 0, url, method, latencyMs: latency, error: errMsg });\r\n\r\n if (i < maxRetries) {\r\n const delay = baseDelayMs * Math.pow(2, i);\r\n await sleep(delay);\r\n continue;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n const result: ResilientFetchResult = { ok: false, status: lastStatus, data: lastBody, attempts };\r\n\r\n if (throwOnFailure) {\r\n const summary = attempts.map((a) => `[${a.attempt}] ${a.status || 'ERR'} ${a.latencyMs}ms`).join(', ');\r\n throw new Error(`resilientFetch failed: ${method} ${url} (${attempts.length} attempts): ${summary}`);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Wait for a backend to become healthy by polling a health endpoint.\r\n */\r\nexport async function waitForBackend(\r\n baseUrl: string,\r\n options: { timeoutMs?: number; intervalMs?: number; healthPath?: string } = {},\r\n): Promise<void> {\r\n const { timeoutMs = 30_000, intervalMs = 1_000, healthPath = '/health' } = options;\r\n const healthUrl = new URL(healthPath, baseUrl).href;\r\n const start = Date.now();\r\n\r\n while (Date.now() - start < timeoutMs) {\r\n try {\r\n const resp = await fetch(healthUrl, { method: 'GET', signal: AbortSignal.timeout(3_000) });\r\n if (resp.ok) return;\r\n } catch {\r\n // not ready yet\r\n }\r\n await sleep(intervalMs);\r\n }\r\n\r\n throw new Error(`Backend not ready: ${healthUrl} timed out after ${timeoutMs}ms`);\r\n}\r\n","import { resolve } from 'node:path';\r\nimport { spawn as nodeSpawn } from 'node:child_process';\r\nimport { waitForBackend as runtimeWaitForBackend } from '../runtime/resilient-fetch.js';\r\nimport type {\r\n BackendEnsureRequest,\r\n BackendEnsureResult,\r\n BackendManager,\r\n BackendManagerDeps,\r\n BackendServerConfig,\r\n} from './types.js';\r\n\r\nfunction normalizeHealthUrl(server?: BackendServerConfig, baseURL?: string): string {\r\n if (server?.healthUrl) return server.healthUrl;\r\n if (baseURL) return new URL('/health', baseURL).href;\r\n return 'http://localhost:3000/health';\r\n}\r\n\r\nfunction splitHealthUrl(healthUrl: string): { baseUrl: string; healthPath: string } {\r\n const parsed = new URL(healthUrl);\r\n const baseUrl = `${parsed.protocol}//${parsed.host}`;\r\n const healthPath = `${parsed.pathname}${parsed.search}`;\r\n return { baseUrl, healthPath };\r\n}\r\n\r\nasync function waitReady(\r\n waitForBackend: NonNullable<BackendManagerDeps['waitForBackend']>,\r\n healthUrl: string,\r\n timeoutMs: number,\r\n intervalMs: number,\r\n): Promise<void> {\r\n const { baseUrl, healthPath } = splitHealthUrl(healthUrl);\r\n await waitForBackend(baseUrl, {\r\n timeoutMs,\r\n intervalMs,\r\n healthPath,\r\n });\r\n}\r\n\r\nexport function createBackendManager(deps: BackendManagerDeps = {}): BackendManager {\r\n const waitForBackend = deps.waitForBackend ?? runtimeWaitForBackend;\r\n const spawn = deps.spawn ?? nodeSpawn;\r\n\r\n return {\r\n async ensureReady(request: BackendEnsureRequest): Promise<BackendEnsureResult> {\r\n const server = request.server ?? {};\r\n const healthUrl = normalizeHealthUrl(server, request.baseURL);\r\n const quickTimeoutMs = 1_500;\r\n const startTimeoutMs = server.startTimeoutMs ?? 30_000;\r\n const pollIntervalMs = server.pollIntervalMs ?? 800;\r\n const tryReuse = request.mode !== 'managed' || server.reuseExisting !== false;\r\n\r\n if (tryReuse) {\r\n try {\r\n await waitReady(waitForBackend, healthUrl, quickTimeoutMs, 300);\r\n return {\r\n mode: request.mode,\r\n status: 'reused',\r\n healthUrl,\r\n cleanup: async () => {},\r\n };\r\n } catch (err) {\r\n void err;\r\n }\r\n }\r\n\r\n if (request.mode === 'reuse') {\r\n throw new Error(`HEALTH_FAIL: backend is not reachable at ${healthUrl} in reuse mode`);\r\n }\r\n\r\n if (!server.command) {\r\n if (request.mode === 'auto') {\r\n return {\r\n mode: request.mode,\r\n status: 'skipped',\r\n healthUrl,\r\n cleanup: async () => {},\r\n };\r\n }\r\n throw new Error('BOOT_CONFIG_MISSING: runtime.server.command is required for managed mode');\r\n }\r\n\r\n const child = spawn(server.command, server.args ?? [], {\r\n cwd: resolve(request.cwd, server.cwd ?? '.'),\r\n shell: true,\r\n stdio: 'pipe',\r\n env: process.env,\r\n });\r\n\r\n try {\r\n await waitReady(waitForBackend, healthUrl, startTimeoutMs, pollIntervalMs);\r\n } catch {\r\n if (child.exitCode === null) child.kill();\r\n throw new Error(`BOOT_TIMEOUT: backend did not become healthy at ${healthUrl}`);\r\n }\r\n\r\n return {\r\n mode: request.mode,\r\n status: 'started',\r\n healthUrl,\r\n cleanup: async () => {\r\n if (child.exitCode === null) child.kill();\r\n },\r\n };\r\n },\r\n };\r\n}\r\n","import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { dirname, join } from 'node:path';\r\nimport type { OpenCrocConfig } from '../types.js';\r\nimport { generatePlaywrightConfig } from '../runtime/playwright-config-generator.js';\r\nimport { generateGlobalSetup } from '../runtime/global-setup-generator.js';\r\nimport { generateGlobalTeardown } from '../runtime/global-teardown-generator.js';\r\nimport { generateAuthSetup } from '../runtime/auth-setup-generator.js';\r\nimport type { RuntimeBootstrap, RuntimeBootstrapRequest, RuntimeBootstrapResult } from './types.js';\r\n\r\nfunction ensureFile(filePath: string, content: string, force: boolean): boolean {\r\n if (existsSync(filePath) && !force) {\r\n return false;\r\n }\r\n mkdirSync(dirname(filePath), { recursive: true });\r\n writeFileSync(filePath, content, 'utf-8');\r\n return true;\r\n}\r\n\r\nexport function createRuntimeBootstrap(config: OpenCrocConfig): RuntimeBootstrap {\r\n return {\r\n async ensure(request: RuntimeBootstrapRequest): Promise<RuntimeBootstrapResult> {\r\n const force = request.force ?? false;\r\n const files = [\r\n {\r\n name: 'playwright.config.ts',\r\n content: generatePlaywrightConfig(config),\r\n },\r\n {\r\n name: 'global-setup.ts',\r\n content: generateGlobalSetup(config),\r\n },\r\n {\r\n name: 'global-teardown.ts',\r\n content: generateGlobalTeardown(config),\r\n },\r\n ];\r\n\r\n if (request.hasAuth) {\r\n files.push({\r\n name: 'auth.setup.ts',\r\n content: generateAuthSetup(config),\r\n });\r\n }\r\n\r\n const writtenFiles: string[] = [];\r\n const skippedFiles: string[] = [];\r\n for (const file of files) {\r\n const filePath = join(request.cwd, file.name);\r\n const written = ensureFile(filePath, file.content, force);\r\n if (written) writtenFiles.push(file.name);\r\n else skippedFiles.push(file.name);\r\n }\r\n\r\n return {\r\n writtenFiles,\r\n skippedFiles,\r\n };\r\n },\r\n };\r\n}\r\n","import type { OpenCrocConfig } from '../types.js';\r\nimport type { AuthProvisionResult, AuthProvisioner, AuthProvisionerDeps } from './types.js';\r\n\r\nfunction selectBaseUrl(configBaseUrl?: string): string {\r\n if (configBaseUrl && /^https?:\\/\\//i.test(configBaseUrl)) return configBaseUrl;\r\n const envBaseUrl = process.env.BASE_URL || '';\r\n if (/^https?:\\/\\//i.test(envBaseUrl)) return envBaseUrl;\r\n return '';\r\n}\r\n\r\nfunction resolveLoginUrl(loginUrl: string, baseUrl?: string): string {\r\n if (/^https?:\\/\\//i.test(loginUrl)) return loginUrl;\r\n if (!baseUrl) {\r\n throw new Error('AUTH_FAIL: playwright.baseURL or BASE_URL is required for relative runtime.auth.loginUrl');\r\n }\r\n try {\r\n return new URL(loginUrl, baseUrl).href;\r\n } catch {\r\n throw new Error('AUTH_FAIL: invalid login URL or base URL');\r\n }\r\n}\r\n\r\nexport function createAuthProvisioner(config: OpenCrocConfig, deps: AuthProvisionerDeps = {}): AuthProvisioner {\r\n const fetchFn = deps.fetchFn ?? fetch;\r\n\r\n return {\r\n async provision(): Promise<AuthProvisionResult> {\r\n const auth = config.runtime?.auth;\r\n const loginUrl = auth?.loginUrl;\r\n const baseURL = selectBaseUrl(config.playwright?.baseURL);\r\n\r\n if (!loginUrl) {\r\n return { status: 'skipped', env: {} };\r\n }\r\n\r\n const username = process.env.AUTH_USERNAME || auth?.username || 'admin';\r\n const password = process.env.AUTH_PASSWORD || auth?.password || '';\r\n if (!password) {\r\n throw new Error('AUTH_FAIL: runtime.auth.password or AUTH_PASSWORD is required');\r\n }\r\n\r\n const resolvedLoginUrl = resolveLoginUrl(loginUrl, baseURL);\r\n const response = await fetchFn(resolvedLoginUrl, {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n body: JSON.stringify({ username, password }),\r\n signal: AbortSignal.timeout(8_000),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`AUTH_FAIL: login request failed with status ${response.status}`);\r\n }\r\n\r\n const env: NodeJS.ProcessEnv = {\r\n AUTH_LOGIN_URL: resolvedLoginUrl,\r\n AUTH_USERNAME: username,\r\n AUTH_PASSWORD: password,\r\n };\r\n if (baseURL) env.BASE_URL = baseURL;\r\n\r\n return {\r\n status: 'ready',\r\n env,\r\n };\r\n },\r\n };\r\n}\r\n","import type { ExecutionMetrics } from '../types.js';\r\nimport type { AuthStatus, BackendStatus, ExecutionQualityGateResult } from './types.js';\r\n\r\nexport interface BuildQualityGateInput {\r\n metrics?: ExecutionMetrics | null;\r\n authStatus: AuthStatus;\r\n backendStatus: BackendStatus;\r\n}\r\n\r\nexport function buildExecutionQualityGate(input: BuildQualityGateInput): ExecutionQualityGateResult {\r\n const metrics = input.metrics ?? { passed: 0, failed: 0, skipped: 0, timedOut: 0 };\r\n const total = metrics.passed + metrics.failed + metrics.skipped + metrics.timedOut;\r\n const skipRatio = total > 0 ? metrics.skipped / total : 0;\r\n const effectiveExecutionRate = total > 0 ? metrics.passed / total : 0;\r\n const authFailRatio = input.authStatus === 'failed' ? 1 : 0;\r\n const setupFail =\r\n input.authStatus === 'failed' ||\r\n input.backendStatus === 'failed' ||\r\n (total === 0 && (input.authStatus !== 'skipped' || input.backendStatus !== 'skipped'));\r\n\r\n const reasons: string[] = [];\r\n if (setupFail) reasons.push('setup-failed');\r\n if (skipRatio >= 0.5) reasons.push('high-skip-ratio');\r\n if (metrics.failed > 0) reasons.push('tests-failed');\r\n if (metrics.timedOut > 0) reasons.push('tests-timeout');\r\n\r\n let level: ExecutionQualityGateResult['level'] = 'pass';\r\n if (setupFail || metrics.failed > 0) level = 'fail';\r\n else if (skipRatio >= 0.5 || metrics.timedOut > 0) level = 'warn';\r\n\r\n return {\r\n setupFail,\r\n skipRatio,\r\n authFailRatio,\r\n effectiveExecutionRate,\r\n level,\r\n reasons,\r\n authStatus: input.authStatus,\r\n backendStatus: input.backendStatus,\r\n };\r\n}\r\n","import type { WebSocket } from 'ws';\r\nimport type { OpenCrocConfig, PipelineRunResult, GeneratedTestFile, ExecutionMetrics, ReportOutput } from '../types.js';\r\nimport type { BackendStatus, ExecutionQualityGateResult, ExecutionRunMode, AuthStatus } from '../execution/types.js';\r\nimport type { ScanResult } from '../graph/types.js';\r\nimport type { SummonPlan } from '../agents/task-router.js';\r\n\r\nexport interface CrocAgent {\r\n id: string;\r\n name: string;\r\n role: string; // expanded from fixed union to allow dynamic roles\r\n sprite: string;\r\n status: 'idle' | 'working' | 'thinking' | 'done' | 'error';\r\n currentTask?: string;\r\n tokensUsed: number;\r\n progress?: number; // 0-100\r\n /** Dynamic role metadata */\r\n category?: string;\r\n color?: string;\r\n description?: string;\r\n}\r\n\r\nexport interface KnowledgeGraphNode {\r\n id: string;\r\n label: string;\r\n type: 'model' | 'controller' | 'api' | 'dto' | 'module';\r\n status: 'idle' | 'testing' | 'passed' | 'failed';\r\n fields?: string[];\r\n module?: string;\r\n}\r\n\r\nexport interface KnowledgeGraphEdge {\r\n source: string;\r\n target: string;\r\n relation: string;\r\n}\r\n\r\nexport interface KnowledgeGraph {\r\n nodes: KnowledgeGraphNode[];\r\n edges: KnowledgeGraphEdge[];\r\n}\r\n\r\nexport interface ProjectInfo {\r\n name: string;\r\n backendRoot: string;\r\n adapter: string;\r\n stats: {\r\n modules: number;\r\n models: number;\r\n endpoints: number;\r\n relations: number;\r\n };\r\n graph: KnowledgeGraph;\r\n agents: CrocAgent[];\r\n}\r\n\r\nexport interface TaskResult {\r\n ok: boolean;\r\n task: string;\r\n duration: number;\r\n details?: Record<string, unknown>;\r\n error?: string;\r\n}\r\n\r\nconst DEFAULT_AGENTS: CrocAgent[] = [\r\n { id: 'parser-croc', name: '解析鳄', role: 'parser', sprite: 'parser', status: 'idle', tokensUsed: 0 },\r\n { id: 'analyzer-croc', name: '分析鳄', role: 'analyzer', sprite: 'analyzer', status: 'idle', tokensUsed: 0 },\r\n { id: 'tester-croc', name: '测试鳄', role: 'tester', sprite: 'tester', status: 'idle', tokensUsed: 0 },\r\n { id: 'healer-croc', name: '修复鳄', role: 'healer', sprite: 'healer', status: 'idle', tokensUsed: 0 },\r\n { id: 'planner-croc', name: '规划鳄', role: 'planner', sprite: 'planner', status: 'idle', tokensUsed: 0 },\r\n { id: 'reporter-croc', name: '汇报鳄', role: 'reporter', sprite: 'reporter', status: 'idle', tokensUsed: 0 },\r\n];\r\n\r\nexport class CrocOffice {\r\n private config: OpenCrocConfig;\r\n private cwd: string;\r\n private clients: Set<WebSocket> = new Set();\r\n private agents: CrocAgent[];\r\n private cachedGraph: KnowledgeGraph | null = null;\r\n private running = false;\r\n private lastPipelineResult: PipelineRunResult | null = null;\r\n private lastGeneratedFiles: GeneratedTestFile[] = [];\r\n private lastExecutionMetrics: ExecutionMetrics | null = null;\r\n private lastExecutionQuality: ExecutionQualityGateResult | null = null;\r\n private lastReports: ReportOutput[] = [];\r\n\r\n private static readonly ACTIVE_AGENT_STATUSES = new Set<CrocAgent['status']>([\r\n 'working',\r\n 'thinking',\r\n ]);\r\n\r\n constructor(config: OpenCrocConfig, cwd: string) {\r\n this.config = config;\r\n this.cwd = cwd;\r\n this.agents = DEFAULT_AGENTS.map((a) => ({ ...a }));\r\n }\r\n\r\n addClient(ws: WebSocket): void {\r\n this.clients.add(ws);\r\n }\r\n\r\n removeClient(ws: WebSocket): void {\r\n this.clients.delete(ws);\r\n }\r\n\r\n broadcast(type: string, payload: unknown): void {\r\n const msg = JSON.stringify({ type, payload });\r\n for (const client of this.clients) {\r\n try {\r\n client.send(msg);\r\n } catch {\r\n this.clients.delete(client);\r\n }\r\n }\r\n }\r\n\r\n /** Send a log message to all clients */\r\n log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\r\n this.broadcast('log', { message, level, time: Date.now() });\r\n }\r\n\r\n getAgents(): CrocAgent[] {\r\n return this.agents;\r\n }\r\n\r\n getAgent(id: string): CrocAgent | undefined {\r\n return this.agents.find((a) => a.id === id);\r\n }\r\n\r\n updateAgent(id: string, update: Partial<CrocAgent>): void {\r\n const agent = this.agents.find((a) => a.id === id);\r\n if (agent) {\r\n const wasActive = this.isAgentActive(agent.status);\r\n Object.assign(agent, update);\r\n const isActive = this.isAgentActive(agent.status);\r\n this.broadcast('agent:update', this.agents);\r\n\r\n if (!wasActive && isActive) {\r\n this.broadcast('agent:assigned', {\r\n id: agent.id,\r\n name: agent.name,\r\n role: agent.role,\r\n status: agent.status,\r\n currentTask: agent.currentTask ?? null,\r\n at: Date.now(),\r\n });\r\n } else if (wasActive && !isActive) {\r\n this.broadcast('agent:released', {\r\n id: agent.id,\r\n name: agent.name,\r\n role: agent.role,\r\n status: agent.status,\r\n currentTask: agent.currentTask ?? null,\r\n at: Date.now(),\r\n });\r\n }\r\n }\r\n }\r\n\r\n private isAgentActive(status: CrocAgent['status']): boolean {\r\n return CrocOffice.ACTIVE_AGENT_STATUSES.has(status);\r\n }\r\n\r\n isRunning(): boolean {\r\n return this.running;\r\n }\r\n\r\n getConfig(): OpenCrocConfig {\r\n return this.config;\r\n }\r\n\r\n getCwd(): string {\r\n return this.cwd;\r\n }\r\n\r\n // ============ Real Task Dispatch ============\r\n\r\n /** Run the full scan → graph build pipeline */\r\n async runScan(): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'scan', duration: 0, error: 'Another task is running' };\r\n this.running = true;\r\n const start = Date.now();\r\n\r\n try {\r\n this.invalidateCache();\r\n this.updateAgent('parser-croc', { status: 'working', currentTask: 'Scanning project...', progress: 0 });\r\n this.log('🔍 Parser croc is scanning the project...');\r\n\r\n const graph = await this.buildKnowledgeGraph();\r\n\r\n const duration = Date.now() - start;\r\n this.log(`✅ Scan complete: ${graph.nodes.length} nodes, ${graph.edges.length} edges (${duration}ms)`);\r\n return { ok: true, task: 'scan', duration, details: { nodes: graph.nodes.length, edges: graph.edges.length } };\r\n } catch (err) {\r\n this.updateAgent('parser-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Scan failed: ${err}`, 'error');\r\n return { ok: false, task: 'scan', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n this.running = false;\r\n }\r\n }\r\n\r\n /** Run the real pipeline: scan → er-diagram → api-chain → plan → codegen → report */\r\n async runPipeline(): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'pipeline', duration: 0, error: 'Another task is running' };\r\n this.running = true;\r\n const start = Date.now();\r\n\r\n try {\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { createPipeline } = await import('../pipeline/index.js');\r\n\r\n const backendRoot = resolvePath(this.cwd, this.config.backendRoot);\r\n const pipelineConfig = { ...this.config, backendRoot };\r\n const pipeline = createPipeline(pipelineConfig);\r\n\r\n // Phase 1: Scan + ER Diagram (解析鳄)\r\n this.updateAgent('parser-croc', { status: 'working', currentTask: 'Scanning source code...', progress: 10 });\r\n this.log(`🐊 解析鳄 scanning from: ${backendRoot}`);\r\n this.invalidateCache();\r\n await this.buildKnowledgeGraph();\r\n this.updateNodeStatus('module', 'testing');\r\n\r\n // Run real pipeline: scan + er-diagram\r\n this.updateAgent('parser-croc', { currentTask: 'Parsing models & ER diagrams...', progress: 40 });\r\n const scanResult = await pipeline.run(['scan', 'er-diagram']);\r\n const moduleCount = scanResult.modules.length;\r\n const erCount = scanResult.erDiagrams.size;\r\n this.log(`📊 Found ${moduleCount} modules, ${erCount} ER diagrams`);\r\n this.updateAgent('parser-croc', { status: 'done', currentTask: `${moduleCount} modules parsed`, progress: 100 });\r\n\r\n // Phase 2: API Chain Analysis (分析鳄)\r\n this.updateAgent('analyzer-croc', { status: 'working', currentTask: 'Analyzing API chains...', progress: 0 });\r\n this.log('🐊 分析鳄 is analyzing API dependencies...');\r\n const analyzeResult = await pipeline.run(['api-chain']);\r\n const warnings = analyzeResult.validationErrors.filter(e => e.severity === 'warning');\r\n if (warnings.length > 0) {\r\n this.log(`⚠️ ${warnings.length} API chain warnings`, 'warn');\r\n }\r\n this.updateAgent('analyzer-croc', { status: 'done', currentTask: 'Analysis complete', progress: 100 });\r\n\r\n // Phase 3: Plan test chains (规划鳄)\r\n this.updateAgent('planner-croc', { status: 'thinking', currentTask: 'Planning test chains...', progress: 0 });\r\n this.log('🐊 规划鳄 is planning test chains...');\r\n const planResult = await pipeline.run(['plan']);\r\n let totalChains = 0, totalSteps = 0;\r\n for (const [, plan] of planResult.chainPlans) {\r\n totalChains += plan.chains.length;\r\n totalSteps += plan.totalSteps;\r\n }\r\n this.log(`📋 Planned ${totalChains} test chains with ${totalSteps} steps`);\r\n this.updateAgent('planner-croc', { status: 'done', currentTask: `${totalChains} chains planned`, progress: 100 });\r\n\r\n // Phase 4: Generate test code (测试鳄)\r\n this.updateAgent('tester-croc', { status: 'working', currentTask: 'Generating test code...', progress: 0 });\r\n this.log('🐊 测试鳄 is generating Playwright test code...');\r\n this.updateNodeStatus('controller', 'testing');\r\n\r\n // Full pipeline run for codegen (it needs prior steps' results internally)\r\n const fullResult = await pipeline.run(['scan', 'er-diagram', 'api-chain', 'plan', 'codegen']);\r\n this.lastPipelineResult = fullResult;\r\n this.lastGeneratedFiles = fullResult.generatedFiles;\r\n\r\n // Write generated files to disk\r\n const { writeFileSync, mkdirSync } = await import('node:fs');\r\n const { dirname } = await import('node:path');\r\n let filesWritten = 0;\r\n for (const file of fullResult.generatedFiles) {\r\n const fullPath = resolvePath(this.cwd, file.filePath);\r\n mkdirSync(dirname(fullPath), { recursive: true });\r\n writeFileSync(fullPath, file.content, 'utf-8');\r\n filesWritten++;\r\n }\r\n\r\n this.updateNodeStatus('controller', 'passed');\r\n this.log(`✅ Generated ${filesWritten} test files`);\r\n this.updateAgent('tester-croc', { status: 'done', currentTask: `${filesWritten} files generated`, progress: 100 });\r\n\r\n // Broadcast generated files to frontend\r\n this.broadcast('files:generated', fullResult.generatedFiles.map(f => ({\r\n filePath: f.filePath,\r\n module: f.module,\r\n chain: f.chain,\r\n lines: f.content.split('\\n').length,\r\n })));\r\n\r\n // Phase 5: Report (汇报鳄)\r\n this.updateAgent('reporter-croc', { status: 'working', currentTask: 'Compiling report...', progress: 0 });\r\n this.log('🐊 汇报鳄 is compiling results...');\r\n\r\n // Validation\r\n const validateResult = await pipeline.run(['validate']);\r\n const errors = validateResult.validationErrors.filter(e => e.severity === 'error');\r\n if (errors.length > 0) {\r\n this.log(`⚠️ ${errors.length} validation errors`, 'warn');\r\n }\r\n\r\n this.updateNodeStatus('module', 'passed');\r\n this.updateAgent('reporter-croc', { status: 'done', currentTask: 'Report ready', progress: 100 });\r\n\r\n const duration = Date.now() - start;\r\n this.log(`✅ Pipeline complete in ${duration}ms — ${moduleCount} modules, ${totalChains} chains, ${filesWritten} files`);\r\n this.broadcast('pipeline:complete', {\r\n duration, status: 'success',\r\n summary: { modules: moduleCount, chains: totalChains, steps: totalSteps, files: filesWritten },\r\n });\r\n return { ok: true, task: 'pipeline', duration, details: {\r\n modules: moduleCount, chains: totalChains, steps: totalSteps, files: filesWritten,\r\n }};\r\n } catch (err) {\r\n this.updateAgent('tester-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Pipeline failed: ${err}`, 'error');\r\n this.broadcast('pipeline:complete', { status: 'error', error: String(err) });\r\n return { ok: false, task: 'pipeline', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n this.running = false;\r\n }\r\n }\r\n\r\n /** Reset all agents to idle */\r\n resetAgents(): void {\r\n for (const agent of this.agents) {\r\n const wasActive = this.isAgentActive(agent.status);\r\n agent.status = 'idle';\r\n agent.currentTask = undefined;\r\n agent.progress = undefined;\r\n if (wasActive) {\r\n this.broadcast('agent:released', {\r\n id: agent.id,\r\n name: agent.name,\r\n role: agent.role,\r\n status: agent.status,\r\n currentTask: null,\r\n at: Date.now(),\r\n });\r\n }\r\n }\r\n this.broadcast('agent:update', this.agents);\r\n }\r\n\r\n /**\r\n * Dynamically summon crocs based on a project scan result.\r\n * Core 6 are always present; additional expert crocs are added based on project characteristics.\r\n */\r\n async summonForProject(scan: ScanResult, riskCategories: string[] = []): Promise<SummonPlan> {\r\n const { planSummon } = await import('../agents/task-router.js');\r\n const plan = planSummon(scan, 8, riskCategories);\r\n\r\n // Reset to core agents first\r\n const coreIds = new Set(DEFAULT_AGENTS.map(a => a.id));\r\n this.agents = DEFAULT_AGENTS.map((a) => ({ ...a }));\r\n\r\n // Add dynamic roles\r\n for (const summoned of plan.roles) {\r\n if (coreIds.has(summoned.role.id)) continue; // Skip core — already added\r\n\r\n const agent: CrocAgent = {\r\n id: summoned.role.id,\r\n name: summoned.role.name,\r\n role: summoned.role.id.replace(/-croc$/, ''),\r\n sprite: summoned.role.sprite,\r\n status: 'idle',\r\n tokensUsed: 0,\r\n category: summoned.role.category,\r\n color: summoned.role.color,\r\n description: summoned.role.description,\r\n };\r\n this.agents.push(agent);\r\n }\r\n\r\n // Broadcast the full agent list\r\n this.broadcast('agent:update', this.agents);\r\n\r\n // Log the summon plan\r\n for (const line of plan.reasoning) {\r\n this.log(line);\r\n }\r\n this.log(`🐊 共召唤 ${this.agents.length} 个鳄鱼专家 (${plan.roles.length - DEFAULT_AGENTS.length} 个动态角色)`);\r\n\r\n // Animate the summoning — stagger agent assignments\r\n const dynamicAgents = this.agents.filter(a => !coreIds.has(a.id));\r\n for (let i = 0; i < dynamicAgents.length; i++) {\r\n const agent = dynamicAgents[i]!;\r\n setTimeout(() => {\r\n this.updateAgent(agent.id, { status: 'working', currentTask: '分析项目中…' });\r\n setTimeout(() => {\r\n this.updateAgent(agent.id, { status: 'idle', currentTask: undefined });\r\n }, 2000 + Math.random() * 1000);\r\n }, 300 * i);\r\n }\r\n\r\n return plan;\r\n }\r\n\r\n /** Get the current summon plan context */\r\n getSummonPlan(): { agentCount: number; coreCount: number; dynamicCount: number; agents: CrocAgent[] } {\r\n const coreIds = new Set(DEFAULT_AGENTS.map(a => a.id));\r\n const coreCount = this.agents.filter(a => coreIds.has(a.id)).length;\r\n return {\r\n agentCount: this.agents.length,\r\n coreCount,\r\n dynamicCount: this.agents.length - coreCount,\r\n agents: this.agents,\r\n };\r\n }\r\n\r\n /** Get last pipeline result */\r\n getLastPipelineResult(): PipelineRunResult | null {\r\n return this.lastPipelineResult;\r\n }\r\n\r\n /** Get generated test files from last pipeline run */\r\n getGeneratedFiles(): GeneratedTestFile[] {\r\n return this.lastGeneratedFiles;\r\n }\r\n\r\n /** Get last execution metrics */\r\n getLastExecutionMetrics(): ExecutionMetrics | null {\r\n return this.lastExecutionMetrics;\r\n }\r\n\r\n getLastExecutionQuality(): ExecutionQualityGateResult | null {\r\n return this.lastExecutionQuality;\r\n }\r\n\r\n /** Get last generated reports */\r\n getLastReports(): ReportOutput[] {\r\n return this.lastReports;\r\n }\r\n\r\n /** Run generated tests with Playwright */\r\n async runTests(options: { mode?: ExecutionRunMode } = {}): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'execute', duration: 0, error: 'Another task is running' };\r\n if (this.lastGeneratedFiles.length === 0) {\r\n return { ok: false, task: 'execute', duration: 0, error: 'No test files — run Pipeline first' };\r\n }\r\n this.running = true;\r\n const start = Date.now();\r\n let cleanupBackend: (() => Promise<void>) | null = null;\r\n let authStatus: AuthStatus = 'skipped';\r\n let backendStatus!: BackendStatus;\r\n\r\n try {\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { existsSync } = await import('node:fs');\r\n const { createExecutionCoordinator } = await import('../execution/coordinator.js');\r\n const { createBackendManager } = await import('../execution/backend-manager.js');\r\n const { createRuntimeBootstrap } = await import('../execution/runtime-bootstrap.js');\r\n const { createAuthProvisioner } = await import('../execution/auth-provisioner.js');\r\n const { buildExecutionQualityGate } = await import('../execution/quality-gate.js');\r\n const { categorizeFailure } = await import('../self-healing/index.js');\r\n\r\n // Find test files on disk\r\n const testFiles = this.lastGeneratedFiles\r\n .map(f => resolvePath(this.cwd, f.filePath))\r\n .filter(f => existsSync(f));\r\n\r\n if (testFiles.length === 0) {\r\n this.log('⚠️ No test files found on disk', 'warn');\r\n return { ok: false, task: 'execute', duration: Date.now() - start, error: 'No test files found on disk' };\r\n }\r\n\r\n // Tester croc runs the tests\r\n const mode = options.mode ?? 'auto';\r\n this.updateAgent('tester-croc', { status: 'working', currentTask: `Running ${testFiles.length} test files (${mode})...`, progress: 0 });\r\n this.log(`🧪 测试鳄 is running ${testFiles.length} Playwright tests (${mode})...`);\r\n\r\n const runtimeBootstrap = createRuntimeBootstrap(this.config);\r\n const runtimeResult = await runtimeBootstrap.ensure({\r\n cwd: this.cwd,\r\n hasAuth: !!this.config.runtime?.auth?.loginUrl,\r\n });\r\n if (runtimeResult.writtenFiles.length > 0) {\r\n this.log(`🧩 Runtime assets prepared: ${runtimeResult.writtenFiles.join(', ')}`);\r\n }\r\n\r\n const backendManager = createBackendManager();\r\n try {\r\n const backendReady = await backendManager.ensureReady({\r\n mode,\r\n cwd: this.cwd,\r\n server: this.config.runtime?.server,\r\n baseURL: this.config.playwright?.baseURL,\r\n });\r\n backendStatus = backendReady.status;\r\n cleanupBackend = backendReady.cleanup;\r\n if (backendReady.status === 'started') {\r\n this.log(`🚀 Managed backend started (${backendReady.healthUrl})`);\r\n } else if (backendReady.status === 'reused') {\r\n this.log(`🔁 Reusing backend (${backendReady.healthUrl})`);\r\n }\r\n } catch (err) {\r\n backendStatus = 'failed';\r\n this.lastExecutionQuality = buildExecutionQualityGate({\r\n metrics: null,\r\n authStatus,\r\n backendStatus,\r\n });\r\n throw err;\r\n }\r\n\r\n const authProvisioner = createAuthProvisioner(this.config);\r\n let authResult;\r\n try {\r\n authResult = await authProvisioner.provision();\r\n authStatus = authResult.status;\r\n if (authResult.status === 'ready') {\r\n this.log('🔐 Auth environment prepared');\r\n }\r\n } catch (err) {\r\n authStatus = 'failed';\r\n this.lastExecutionQuality = buildExecutionQualityGate({\r\n metrics: null,\r\n authStatus,\r\n backendStatus,\r\n });\r\n throw err;\r\n }\r\n\r\n // Healer croc monitors\r\n this.updateAgent('healer-croc', { status: 'thinking', currentTask: 'Monitoring test run...', progress: 0 });\r\n\r\n const coordinator = createExecutionCoordinator({ categorizeFailure });\r\n const execResult = await coordinator.run({\r\n cwd: this.cwd,\r\n testFiles,\r\n mode,\r\n env: authResult.env,\r\n });\r\n const metrics = execResult.metrics;\r\n\r\n this.lastExecutionMetrics = metrics;\r\n this.lastExecutionQuality = buildExecutionQualityGate({\r\n metrics,\r\n authStatus,\r\n backendStatus,\r\n });\r\n const total = metrics.passed + metrics.failed + metrics.skipped + metrics.timedOut;\r\n\r\n // Update croc states\r\n if (metrics.failed > 0) {\r\n this.updateAgent('tester-croc', { status: 'error', currentTask: `${metrics.failed} tests failed`, progress: 100 });\r\n this.updateAgent('healer-croc', { status: 'working', currentTask: `Analyzing ${metrics.failed} failures...`, progress: 50 });\r\n this.log(`❌ Tests: ${metrics.passed} passed, ${metrics.failed} failed, ${metrics.skipped} skipped`, 'warn');\r\n for (const hint of execResult.failureHints) {\r\n this.log(` 🔍 ${hint.category} (${Math.round(hint.confidence * 100)}%): ${hint.line.substring(0, 100)}`, 'warn');\r\n }\r\n this.updateAgent('healer-croc', { status: 'done', currentTask: 'Failure analysis done', progress: 100 });\r\n } else {\r\n this.updateAgent('tester-croc', { status: 'done', currentTask: `All ${metrics.passed} tests passed!`, progress: 100 });\r\n this.updateAgent('healer-croc', { status: 'done', currentTask: 'No failures', progress: 100 });\r\n this.log(`✅ All ${metrics.passed} tests passed!`);\r\n }\r\n\r\n this.updateNodeStatus('controller', metrics.failed > 0 ? 'failed' : 'passed');\r\n\r\n // Broadcast results\r\n this.broadcast('test:complete', { metrics, total, quality: this.lastExecutionQuality });\r\n\r\n const duration = Date.now() - start;\r\n this.log(`🧪 Test execution complete in ${duration}ms`);\r\n return { ok: metrics.failed === 0, task: 'execute', duration, details: metrics as unknown as Record<string, unknown> };\r\n } catch (err) {\r\n this.updateAgent('tester-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Test execution failed: ${err}`, 'error');\r\n this.broadcast('test:complete', { metrics: null, total: 0, quality: this.lastExecutionQuality });\r\n return { ok: false, task: 'execute', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n if (cleanupBackend) {\r\n try {\r\n await cleanupBackend();\r\n this.log('🧹 Managed backend stopped');\r\n } catch (err) {\r\n this.log(`⚠️ Backend cleanup failed: ${err}`, 'warn');\r\n }\r\n }\r\n this.running = false;\r\n }\r\n }\r\n\r\n /** Generate reports (HTML/JSON/Markdown) */\r\n async generateReport(): Promise<TaskResult> {\r\n if (this.running) return { ok: false, task: 'report', duration: 0, error: 'Another task is running' };\r\n if (!this.lastPipelineResult) {\r\n return { ok: false, task: 'report', duration: 0, error: 'No pipeline result — run Pipeline first' };\r\n }\r\n this.running = true;\r\n const start = Date.now();\r\n\r\n try {\r\n this.updateAgent('reporter-croc', { status: 'working', currentTask: 'Generating reports...', progress: 0 });\r\n this.log('📊 汇报鳄 is generating reports...');\r\n\r\n const { generateReports } = await import('../reporters/index.js');\r\n const formats: ('html' | 'json' | 'markdown')[] = ['html', 'json', 'markdown'];\r\n const reports = generateReports(this.lastPipelineResult, formats, {\r\n metrics: this.lastExecutionMetrics,\r\n quality: this.lastExecutionQuality,\r\n });\r\n this.lastReports = reports;\r\n\r\n // Write reports to disk\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { writeFileSync, mkdirSync } = await import('node:fs');\r\n const outDir = resolvePath(this.cwd, this.config.outDir || './opencroc-output');\r\n mkdirSync(outDir, { recursive: true });\r\n\r\n for (const report of reports) {\r\n const fullPath = resolvePath(outDir, report.filename);\r\n writeFileSync(fullPath, report.content, 'utf-8');\r\n this.log(`📄 Generated ${report.format} report: ${report.filename}`);\r\n }\r\n\r\n this.updateAgent('reporter-croc', { status: 'done', currentTask: `${reports.length} reports generated`, progress: 100 });\r\n\r\n // Broadcast reports to frontend\r\n this.broadcast('reports:generated', reports.map(r => ({\r\n format: r.format,\r\n filename: r.filename,\r\n size: r.content.length,\r\n })));\r\n\r\n const duration = Date.now() - start;\r\n this.log(`✅ Reports generated in ${duration}ms`);\r\n return { ok: true, task: 'report', duration, details: { count: reports.length } };\r\n } catch (err) {\r\n this.updateAgent('reporter-croc', { status: 'error', currentTask: String(err) });\r\n this.log(`❌ Report generation failed: ${err}`, 'error');\r\n return { ok: false, task: 'report', duration: Date.now() - start, error: String(err) };\r\n } finally {\r\n this.running = false;\r\n }\r\n }\r\n\r\n // ============ Graph Helpers ============\r\n\r\n private updateNodeStatus(type: KnowledgeGraphNode['type'], status: KnowledgeGraphNode['status']): void {\r\n if (!this.cachedGraph) return;\r\n for (const node of this.cachedGraph.nodes) {\r\n if (node.type === type) {\r\n node.status = status;\r\n }\r\n }\r\n this.broadcast('graph:update', this.cachedGraph);\r\n }\r\n\r\n /** Build knowledge graph from project source code */\r\n async buildKnowledgeGraph(): Promise<KnowledgeGraph> {\r\n if (this.cachedGraph) return this.cachedGraph;\r\n\r\n this.updateAgent('parser-croc', { status: 'working', currentTask: 'Scanning project structure...', progress: 20 });\r\n\r\n try {\r\n const { resolve: resolvePath } = await import('node:path');\r\n const { glob } = await import('glob');\r\n\r\n const backendRoot = resolvePath(this.cwd, this.config.backendRoot);\r\n const nodes: KnowledgeGraphNode[] = [];\r\n const edges: KnowledgeGraphEdge[] = [];\r\n const moduleSet = new Set<string>();\r\n\r\n // Helper: infer module from file path\r\n // 1) Subfolder: models/aigc/Foo.ts → \"aigc\"\r\n // 2) Longest known prefix match on filename: workflowTemplate → \"workflow\"\r\n // 3) CamelCase first word: DataModel → \"data\"\r\n\r\n // Known domain prefixes, longest first for greedy matching\r\n const KNOWN_PREFIXES = [\r\n 'notification', 'department', 'application', 'permission', 'computed',\r\n 'delegation', 'dictionary', 'validation', 'simulation', 'statistics',\r\n 'inference', 'panorama', 'designer', 'workflow', 'template', 'relation',\r\n 'recycle', 'monitor', 'timeout', 'column', 'export', 'import', 'batch',\r\n 'field', 'chain', 'tenant', 'model', 'data', 'user', 'role', 'menu',\r\n 'auth', 'dept', 'page', 'app', 'api', 'org', 'log', 'er',\r\n ];\r\n\r\n const DOMAIN_GROUPS: Record<string, string> = {\r\n app: 'app', api: 'api', data: 'data', auth: 'auth',\r\n user: 'user', role: 'user', menu: 'app', dept: 'org',\r\n department: 'org', org: 'org', chain: 'workflow',\r\n workflow: 'workflow', batch: 'batch', column: 'data',\r\n computed: 'data', designer: 'designer', monitor: 'monitor',\r\n notification: 'notification', permission: 'permission',\r\n template: 'template', validation: 'validation',\r\n field: 'data', delegation: 'workflow', import: 'data',\r\n export: 'data', dictionary: 'data', panorama: 'panorama',\r\n inference: 'inference', simulation: 'simulation', er: 'data',\r\n relation: 'data', recycle: 'data', statistics: 'statistics',\r\n operation: 'system', log: 'system', timeout: 'workflow',\r\n tenant: 'system', model: 'data', page: 'app',\r\n application: 'app',\r\n };\r\n\r\n const inferModule = (filePath: string, type: 'model' | 'controller'): string => {\r\n const parts = filePath.replace(/\\\\/g, '/').split('/');\r\n // Subfolder detection\r\n const typeDir = type === 'model' ? 'models' : 'controllers';\r\n const typeDirIdx = parts.indexOf(typeDir);\r\n if (typeDirIdx >= 0 && parts.length - typeDirIdx > 2) {\r\n return parts[typeDirIdx + 1];\r\n }\r\n // Filename-based: strip extension + \"Controller\" suffix\r\n const baseName = parts[parts.length - 1]\r\n .replace(/\\.(ts|js)$/, '')\r\n .replace(/Controller$/i, '');\r\n const lc = baseName.toLowerCase();\r\n // Try longest known prefix match\r\n for (const prefix of KNOWN_PREFIXES) {\r\n if (lc.startsWith(prefix)) {\r\n return DOMAIN_GROUPS[prefix] || prefix;\r\n }\r\n }\r\n // CamelCase first word fallback\r\n const camelMatch = baseName.match(/^([A-Z]?[a-z]+)/);\r\n if (camelMatch) {\r\n const w = camelMatch[1].toLowerCase();\r\n return DOMAIN_GROUPS[w] || w;\r\n }\r\n return 'other';\r\n };\r\n\r\n // Scan for models\r\n this.updateAgent('parser-croc', { progress: 40, currentTask: 'Scanning models...' });\r\n const modelFiles = await glob('**/models/**/*.{ts,js}', {\r\n cwd: backendRoot,\r\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*', '**/index.*', '**/dist/**'],\r\n });\r\n\r\n for (const file of modelFiles) {\r\n const parts = file.replace(/\\\\/g, '/').split('/');\r\n const moduleName = inferModule(file, 'model');\r\n const fileName = parts[parts.length - 1].replace(/\\.(ts|js)$/, '');\r\n const nodeId = `model:${fileName}`;\r\n\r\n moduleSet.add(moduleName);\r\n nodes.push({\r\n id: nodeId,\r\n label: fileName,\r\n type: 'model',\r\n status: 'idle',\r\n module: moduleName,\r\n });\r\n }\r\n\r\n // Scan for controllers\r\n this.updateAgent('parser-croc', { progress: 70, currentTask: 'Scanning controllers...' });\r\n const controllerFiles = await glob('**/controllers/**/*.{ts,js}', {\r\n cwd: backendRoot,\r\n ignore: ['**/node_modules/**', '**/*.test.*', '**/*.spec.*', '**/index.*', '**/dist/**'],\r\n });\r\n\r\n for (const file of controllerFiles) {\r\n const parts = file.replace(/\\\\/g, '/').split('/');\r\n const moduleName = inferModule(file, 'controller');\r\n const fileName = parts[parts.length - 1].replace(/\\.(ts|js)$/, '').replace(/Controller$/, '');\r\n const nodeId = `controller:${fileName}`;\r\n\r\n moduleSet.add(moduleName);\r\n nodes.push({\r\n id: nodeId,\r\n label: `${fileName} (ctrl)`,\r\n type: 'controller',\r\n status: 'idle',\r\n module: moduleName,\r\n });\r\n\r\n // Link controller to its model with fuzzy match\r\n const lcName = fileName.toLowerCase();\r\n const modelNode = nodes.find((n) => n.type === 'model' && n.label.toLowerCase() === lcName);\r\n if (modelNode) {\r\n edges.push({ source: nodeId, target: modelNode.id, relation: 'uses' });\r\n }\r\n }\r\n\r\n // Add module nodes\r\n this.updateAgent('parser-croc', { progress: 90, currentTask: 'Building graph...' });\r\n for (const mod of moduleSet) {\r\n const moduleNodeId = `module:${mod}`;\r\n nodes.push({\r\n id: moduleNodeId,\r\n label: mod,\r\n type: 'module',\r\n status: 'idle',\r\n });\r\n\r\n // Link models/controllers to their module\r\n for (const n of nodes) {\r\n if (n.module === mod && n.type !== 'module') {\r\n edges.push({ source: moduleNodeId, target: n.id, relation: 'contains' });\r\n }\r\n }\r\n }\r\n\r\n this.cachedGraph = { nodes, edges };\r\n this.updateAgent('parser-croc', { status: 'done', currentTask: `Found ${nodes.length} nodes`, progress: 100 });\r\n this.broadcast('graph:update', this.cachedGraph);\r\n return this.cachedGraph;\r\n\r\n } catch (err) {\r\n this.updateAgent('parser-croc', { status: 'error', currentTask: String(err) });\r\n return { nodes: [], edges: [] };\r\n }\r\n }\r\n\r\n invalidateCache(): void {\r\n this.cachedGraph = null;\r\n }\r\n\r\n async getProjectInfo(): Promise<ProjectInfo> {\r\n const graph = await this.buildKnowledgeGraph();\r\n const stats = {\r\n modules: graph.nodes.filter((n) => n.type === 'module').length,\r\n models: graph.nodes.filter((n) => n.type === 'model').length,\r\n endpoints: graph.nodes.filter((n) => n.type === 'api' || n.type === 'controller').length,\r\n relations: graph.edges.length,\r\n };\r\n\r\n return {\r\n name: this.config.backendRoot.split('/').pop() || 'project',\r\n backendRoot: this.config.backendRoot,\r\n adapter: typeof this.config.adapter === 'string' ? this.config.adapter : 'custom',\r\n stats,\r\n graph,\r\n agents: this.agents,\r\n };\r\n }\r\n}\r\n","import Fastify from 'fastify';\nimport fastifyStatic from '@fastify/static';\nimport fastifyWebsocket from '@fastify/websocket';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join, resolve } from 'node:path';\nimport { existsSync } from 'node:fs';\r\nimport { registerProjectRoutes } from './routes/project.js';\r\nimport { registerAgentRoutes } from './routes/agents.js';\r\nimport { registerStudioRoutes } from './routes/studio.js';\r\nimport { CrocOffice } from './croc-office.js';\r\nimport { FileStudioSnapshotStore } from './studio-store.js';\r\nimport type { OpenCrocConfig } from '../types.js';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\n\r\nexport interface ServeOptions {\r\n port: number;\r\n host: string;\r\n open: boolean;\r\n config: OpenCrocConfig;\r\n cwd: string;\r\n}\r\n\r\nexport async function startServer(opts: ServeOptions): Promise<void> {\n const app = Fastify({ logger: false });\n\r\n // --- WebSocket ---\r\n await app.register(fastifyWebsocket);\r\n\r\n // --- Static frontend assets ---\r\n const webDir = resolve(__dirname, '../web');\n const builtIndexPath = join(webDir, 'dist', 'index.html');\n\n function hasBuiltStudio(): boolean {\n return existsSync(builtIndexPath);\n }\n\n function sendSpaEntry(reply: { sendFile: (path: string) => unknown; code: (status: number) => any; header: (key: string, value: string) => any; send: (body: string) => unknown; }) {\n if (hasBuiltStudio()) {\n return reply.sendFile('dist/index.html');\n }\n\n return reply.code(200).header('content-type', 'text/html').send(getEmbeddedHtml());\n }\n\n function isAssetRequest(url: string): boolean {\n return /\\.[a-z0-9]+$/i.test(url) || url.startsWith('/dist/');\n }\n\n if (existsSync(webDir)) {\n await app.register(fastifyStatic, {\n root: webDir,\n prefix: '/',\n index: false,\n });\n }\n\r\n // --- Croc Office (Agent orchestrator) ---\r\n const office = new CrocOffice(opts.config, opts.cwd);\r\n const snapshotStore = new FileStudioSnapshotStore(resolve(opts.cwd, '.opencroc/studio-snapshot.json'));\r\n\r\n // --- REST API routes ---\r\n registerProjectRoutes(app, office);\r\n registerAgentRoutes(app, office);\r\n registerStudioRoutes(app, office, snapshotStore);\r\n\r\n // --- WebSocket endpoint for real-time updates ---\n app.register(async (fastify) => {\n fastify.get('/ws', { websocket: true }, (socket) => {\n office.addClient(socket);\n socket.on('close', () => office.removeClient(socket));\n });\n });\n\n app.get('/index-studio.html', (_req, reply) => {\n reply.redirect('/studio');\n });\n\n app.get('/index-v2-pixel.html', (_req, reply) => {\n reply.redirect('/pixel');\n });\n\n app.get('/', (_req, reply) => {\n return sendSpaEntry(reply);\n });\n\n app.get('/studio', (_req, reply) => {\n return sendSpaEntry(reply);\n });\n\n app.get('/pixel', (_req, reply) => {\n return sendSpaEntry(reply);\n });\n\n // --- SPA fallback: serve index.html for non-API, non-asset routes ---\n app.setNotFoundHandler((req, reply) => {\n if (req.url.startsWith('/api/') || req.url.startsWith('/ws') || isAssetRequest(req.url)) {\n reply.code(404).send({ error: 'Not found' });\n return;\n }\n\n return sendSpaEntry(reply);\n });\n\r\n try {\r\n await app.listen({ port: opts.port, host: opts.host });\r\n const url = `http://${opts.host === '0.0.0.0' ? 'localhost' : opts.host}:${opts.port}`;\r\n console.log(`\\n 🐊 OpenCroc Studio is running at ${url}\\n`);\r\n\r\n if (opts.open) {\r\n const { exec } = await import('node:child_process');\r\n const cmd = process.platform === 'win32' ? 'start' :\r\n process.platform === 'darwin' ? 'open' : 'xdg-open';\r\n exec(`${cmd} ${url}`);\r\n }\r\n } catch (err) {\r\n console.error('Failed to start server:', err);\r\n process.exit(1);\r\n }\r\n}\r\n\r\n/** Minimal embedded HTML when no web build is present */\r\nfunction getEmbeddedHtml(): string {\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n<title>OpenCroc Studio 🐊</title>\r\n<style>\r\n * { margin:0; padding:0; box-sizing:border-box; }\r\n body { background:#1a1a2e; color:#e0e0e0; font-family:'Courier New',monospace; display:flex; justify-content:center; align-items:center; min-height:100vh; }\r\n .container { text-align:center; }\r\n h1 { font-size:3rem; color:#4ecca3; margin-bottom:1rem; }\r\n .croc { font-size:6rem; animation: bounce 1s infinite alternate; }\r\n @keyframes bounce { from{transform:translateY(0)} to{transform:translateY(-20px)} }\r\n p { margin-top:1rem; color:#888; }\r\n .status { margin-top:2rem; padding:1rem; background:#16213e; border-radius:8px; }\r\n #graph-container { margin-top:2rem; min-height:400px; background:#0f3460; border-radius:8px; position:relative; }\r\n .loading { color:#4ecca3; padding:2rem; }\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"container\">\r\n <div class=\"croc\">🐊</div>\r\n <h1>OpenCroc Studio</h1>\r\n <p>AI-native E2E testing — Pixel Croc Office</p>\r\n <div class=\"status\" id=\"status\">Connecting...</div>\r\n <div id=\"graph-container\"><div class=\"loading\">Loading project graph...</div></div>\r\n</div>\r\n<script>\r\n(async () => {\r\n // Fetch project graph data\r\n try {\r\n const res = await fetch('/api/project');\r\n const data = await res.json();\r\n document.getElementById('status').innerHTML =\r\n '<b>Project:</b> ' + (data.name || 'unknown') +\r\n ' | <b>Modules:</b> ' + (data.stats?.modules || 0) +\r\n ' | <b>Models:</b> ' + (data.stats?.models || 0) +\r\n ' | <b>APIs:</b> ' + (data.stats?.endpoints || 0);\r\n\r\n renderGraph(data.graph);\r\n } catch(e) {\r\n document.getElementById('status').textContent = 'Error loading project: ' + e.message;\r\n }\r\n\r\n // WebSocket for live updates\r\n const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';\r\n const ws = new WebSocket(protocol + '//' + location.host + '/ws');\r\n ws.onmessage = (e) => {\r\n try {\r\n const msg = JSON.parse(e.data);\r\n if (msg.type === 'agent:update') {\r\n updateAgentStatus(msg.payload);\r\n } else if (msg.type === 'graph:update') {\r\n renderGraph(msg.payload);\r\n }\r\n } catch {}\r\n };\r\n ws.onclose = () => {\r\n document.getElementById('status').textContent += ' [disconnected]';\r\n };\r\n})();\r\n\r\nfunction renderGraph(graph) {\r\n if (!graph || (!graph.nodes?.length)) {\r\n document.getElementById('graph-container').innerHTML = '<div class=\"loading\">No modules found. Run opencroc init first.</div>';\r\n return;\r\n }\r\n\r\n const container = document.getElementById('graph-container');\r\n const w = container.clientWidth || 800;\r\n const h = 500;\r\n\r\n // Simple force-directed placement\r\n const nodes = graph.nodes.map((n, i) => ({\r\n ...n,\r\n x: w/2 + Math.cos(i * 2 * Math.PI / graph.nodes.length) * Math.min(w,h) * 0.35,\r\n y: h/2 + Math.sin(i * 2 * Math.PI / graph.nodes.length) * Math.min(w,h) * 0.35,\r\n vx: 0, vy: 0,\r\n }));\r\n\r\n const nodeMap = new Map(nodes.map(n => [n.id, n]));\r\n\r\n // Render SVG\r\n const colors = { model:'#4ecca3', controller:'#e94560', api:'#f39c12', dto:'#3498db', default:'#888' };\r\n\r\n let svg = '<svg width=\"'+w+'\" height=\"'+h+'\" xmlns=\"http://www.w3.org/2000/svg\">';\r\n\r\n // Edges\r\n for (const edge of (graph.edges || [])) {\r\n const s = nodeMap.get(edge.source);\r\n const t = nodeMap.get(edge.target);\r\n if (s && t) {\r\n svg += '<line x1=\"'+s.x+'\" y1=\"'+s.y+'\" x2=\"'+t.x+'\" y2=\"'+t.y+'\" stroke=\"#555\" stroke-width=\"1.5\" opacity=\"0.6\"/>';\r\n }\r\n }\r\n\r\n // Nodes\r\n for (const n of nodes) {\r\n const color = colors[n.type] || colors.default;\r\n const statusColor = n.status === 'passed' ? '#4ecca3' : n.status === 'failed' ? '#e94560' : n.status === 'testing' ? '#f39c12' : '#555';\r\n // Pixel-art style square nodes\r\n svg += '<rect x=\"'+(n.x-16)+'\" y=\"'+(n.y-16)+'\" width=\"32\" height=\"32\" fill=\"'+color+'\" rx=\"4\" stroke=\"'+statusColor+'\" stroke-width=\"2\"/>';\r\n svg += '<text x=\"'+n.x+'\" y=\"'+(n.y+32)+'\" text-anchor=\"middle\" fill=\"#ccc\" font-size=\"10\" font-family=\"Courier New\">'+escapeHtml(n.label || n.id)+'</text>';\r\n }\r\n\r\n svg += '</svg>';\r\n container.innerHTML = svg;\r\n}\r\n\r\nfunction escapeHtml(s) { return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }\r\n\r\nfunction updateAgentStatus(agents) {\r\n // Will be enhanced with pixel croc animations in M2\r\n console.log('Agent update:', agents);\r\n}\r\n</script>\r\n</body>\r\n</html>`;\r\n}\r\n","import chalk from 'chalk';\r\nimport { loadConfig } from '../load-config.js';\r\nimport type { OpenCrocConfig } from '../../types.js';\r\n\r\nexport interface ServeCommandOptions {\r\n port?: string;\r\n host?: string;\r\n open?: boolean;\r\n}\r\n\r\nexport async function serve(opts: ServeCommandOptions): Promise<void> {\r\n let config: OpenCrocConfig;\r\n let configPath: string;\r\n\r\n try {\r\n const loaded = await loadConfig();\r\n config = loaded.config;\r\n configPath = loaded.filepath;\r\n } catch {\r\n // No config file — use sensible defaults based on cwd\r\n config = { backendRoot: '.' };\r\n configPath = '(auto-detected)';\r\n console.log(chalk.yellow('⚠ No opencroc config found, using current directory as backend root.'));\r\n console.log(chalk.gray(' Tip: run `opencroc init` to create a config file.\\n'));\r\n }\r\n\r\n const port = parseInt(opts.port || '8765', 10);\r\n const host = opts.host || 'localhost';\r\n\r\n console.log(chalk.cyan('🐊 Starting OpenCroc Studio...'));\r\n console.log(chalk.gray(` Config: ${configPath}`));\r\n console.log(chalk.gray(` Backend: ${config.backendRoot}`));\r\n\r\n const { startServer } = await import('../../server/index.js');\r\n await startServer({\r\n port,\r\n host,\r\n open: opts.open ?? true,\r\n config,\r\n cwd: process.cwd(),\r\n });\r\n}\r\n","/**\r\n * CLI Command: scan\r\n *\r\n * Scan any project (local, GitHub URL, user/repo) and build knowledge graph.\r\n *\r\n * Usage:\r\n * opencroc scan ./my-project\r\n * opencroc scan https://github.com/expressjs/express\r\n * opencroc scan facebook/react\r\n * opencroc scan ./backend --risks --report developer --json\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport chalk from 'chalk';\r\nimport { cloneAndScan } from '../../scanner/github-cloner.js';\r\nimport { buildKnowledgeGraph, getGraphStats, toMermaid } from '../../graph/index.js';\r\nimport { analyzeRisks, generateReport } from '../../insight/index.js';\r\nimport type { ReportPerspective, RiskAnnotation } from '../../graph/types.js';\r\n\r\ninterface ScanOptions {\r\n branch?: string;\r\n output: string;\r\n json?: boolean;\r\n mermaid?: boolean;\r\n risks?: boolean;\r\n report?: string;\r\n}\r\n\r\nexport async function scan(target: string, opts: ScanOptions): Promise<void> {\r\n console.log('');\r\n console.log(chalk.green('🐊 OpenCroc Studio — Universal Project Scanner'));\r\n console.log(chalk.gray(` Target: ${target}`));\r\n console.log('');\r\n\r\n const startTime = Date.now();\r\n\r\n // Phase 1: Scan\r\n console.log(chalk.cyan('📡 Phase 1: Scanning project...'));\r\n\r\n const scanResult = await cloneAndScan({\r\n target,\r\n branch: opts.branch,\r\n keepClone: true,\r\n onProgress: (phase, percent, detail) => {\r\n if (percent % 25 === 0 || phase === 'clone') {\r\n console.log(chalk.gray(` [${phase}] ${percent}% ${detail || ''}`));\r\n }\r\n },\r\n });\r\n\r\n console.log(chalk.green(` ✅ Found ${scanResult.entities.length} entities, ${scanResult.relationships.length} relationships`));\r\n console.log(chalk.gray(` Languages: ${Object.entries(scanResult.languages).filter(([k]) => !['json','yaml','markdown'].includes(k)).map(([k, v]) => `${k}(${v})`).join(', ')}`));\r\n console.log(chalk.gray(` Frameworks: ${scanResult.frameworks.map(f => f.name).join(', ') || 'none detected'}`));\r\n console.log('');\r\n\r\n // Phase 2: Build knowledge graph\r\n console.log(chalk.cyan('🧠 Phase 2: Building knowledge graph...'));\r\n\r\n const projectName = target.includes('/') ? target.split('/').pop()!.replace('.git', '') : path.basename(path.resolve(target));\r\n const isRemote = target.startsWith('http') || /^[\\w.-]+\\/[\\w.-]+$/.test(target);\r\n\r\n const graph = buildKnowledgeGraph(scanResult, {\r\n projectName,\r\n source: isRemote ? 'github' : 'local',\r\n sourceUrl: target,\r\n rootPath: target,\r\n });\r\n\r\n const stats = getGraphStats(graph);\r\n console.log(chalk.green(` ✅ ${graph.nodes.length} nodes, ${graph.edges.length} edges`));\r\n printStats(stats);\r\n console.log('');\r\n\r\n // Phase 3: Risk analysis (optional)\r\n let risks: RiskAnnotation[] = [];\r\n if (opts.risks) {\r\n console.log(chalk.cyan('⚠️ Phase 3: Analyzing risks...'));\r\n risks = await analyzeRisks(graph);\r\n printRisks(risks);\r\n console.log('');\r\n }\r\n\r\n // Phase 4: Generate report (optional)\r\n if (opts.report) {\r\n console.log(chalk.cyan(`📋 Phase 4: Generating ${opts.report} report...`));\r\n const report = await generateReport(graph, opts.report as ReportPerspective, risks);\r\n printReport(report);\r\n console.log('');\r\n }\r\n\r\n // Phase 5: Output\r\n fs.mkdirSync(opts.output, { recursive: true });\r\n\r\n // Always save graph JSON\r\n const graphPath = path.join(opts.output, 'knowledge-graph.json');\r\n fs.writeFileSync(graphPath, JSON.stringify({\r\n projectInfo: graph.projectInfo,\r\n stats: getGraphStats(graph),\r\n nodes: graph.nodes.map(n => ({ id: n.id, label: n.label, type: n.type, module: n.module, filePath: n.filePath })),\r\n edges: graph.edges.map(e => ({ source: e.source, target: e.target, relation: e.relation })),\r\n risks: risks.length > 0 ? risks : undefined,\r\n builtAt: graph.builtAt,\r\n }, null, 2));\r\n console.log(chalk.gray(` 📁 Graph saved: ${graphPath}`));\r\n\r\n if (opts.json) {\r\n const jsonPath = path.join(opts.output, 'scan-result.json');\r\n fs.writeFileSync(jsonPath, JSON.stringify({\r\n project: graph.projectInfo,\r\n stats,\r\n risks: risks.length > 0 ? risks : undefined,\r\n }, null, 2));\r\n console.log(chalk.gray(` 📁 JSON saved: ${jsonPath}`));\r\n }\r\n\r\n if (opts.mermaid) {\r\n const mermaidPath = path.join(opts.output, 'graph.mmd');\r\n const mermaidText = toMermaid(graph, { nodeTypes: ['module', 'model', 'api', 'service'], maxNodes: 40 });\r\n fs.writeFileSync(mermaidPath, mermaidText);\r\n console.log(chalk.gray(` 📁 Mermaid saved: ${mermaidPath}`));\r\n }\r\n\r\n const duration = ((Date.now() - startTime) / 1000).toFixed(1);\r\n console.log('');\r\n console.log(chalk.green(`🐊 Done in ${duration}s`));\r\n console.log(chalk.gray(` Run ${chalk.white('opencroc serve')} to explore the knowledge graph in Studio UI`));\r\n console.log('');\r\n}\r\n\r\nfunction printStats(stats: Record<string, number>): void {\r\n const items: string[] = [];\r\n if (stats.moduleCount) items.push(`${stats.moduleCount} modules`);\r\n if (stats.apiCount) items.push(`${stats.apiCount} APIs`);\r\n if (stats.modelCount) items.push(`${stats.modelCount} models`);\r\n if (stats.classCount) items.push(`${stats.classCount} classes`);\r\n if (stats.functionCount) items.push(`${stats.functionCount} functions`);\r\n if (stats.dependencyCount) items.push(`${stats.dependencyCount} dependencies`);\r\n if (items.length > 0) {\r\n console.log(chalk.gray(` ${items.join(' | ')}`));\r\n }\r\n}\r\n\r\nfunction printRisks(risks: RiskAnnotation[]): void {\r\n if (risks.length === 0) {\r\n console.log(chalk.green(' ✅ No significant risks detected.'));\r\n return;\r\n }\r\n\r\n const critical = risks.filter(r => r.severity === 'critical').length;\r\n const high = risks.filter(r => r.severity === 'high').length;\r\n const medium = risks.filter(r => r.severity === 'medium').length;\r\n const low = risks.filter(r => r.severity === 'low').length;\r\n\r\n console.log(chalk.yellow(` Found ${risks.length} risks:`));\r\n if (critical) console.log(chalk.red(` 🔴 Critical: ${critical}`));\r\n if (high) console.log(chalk.hex('#e67e22')(` 🟠 High: ${high}`));\r\n if (medium) console.log(chalk.yellow(` 🟡 Medium: ${medium}`));\r\n if (low) console.log(chalk.blue(` 🔵 Low: ${low}`));\r\n\r\n console.log('');\r\n console.log(chalk.white(' Top risks:'));\r\n for (const r of risks.slice(0, 5)) {\r\n const color = r.severity === 'critical' ? chalk.red :\r\n r.severity === 'high' ? chalk.hex('#e67e22') :\r\n r.severity === 'medium' ? chalk.yellow : chalk.blue;\r\n console.log(` ${color(`[${r.severity.toUpperCase()}]`)} ${r.title}`);\r\n }\r\n}\r\n\r\nfunction printReport(report: { title: string; summary: string; sections: Array<{ heading: string; content: string }> }): void {\r\n console.log(chalk.green(` ✅ ${report.title}`));\r\n console.log(chalk.gray(` ${report.summary}`));\r\n for (const section of report.sections) {\r\n console.log(chalk.cyan(`\\n ── ${section.heading} ──`));\r\n // Print first 3 lines of content\r\n const lines = section.content.split('\\n').slice(0, 3);\r\n for (const line of lines) {\r\n console.log(chalk.gray(` ${line}`));\r\n }\r\n if (section.content.split('\\n').length > 3) {\r\n console.log(chalk.gray(' ...'));\r\n }\r\n }\r\n}\r\n","/**\r\n * CLI Command: analyze\r\n *\r\n * Deep analysis of a scanned project — risks, impact, multi-perspective reports.\r\n *\r\n * Usage:\r\n * opencroc analyze ./my-project\r\n * opencroc analyze --perspective architect --risks\r\n * opencroc analyze --impact \"api:GET:/users\"\r\n */\r\n\r\nimport * as fs from 'node:fs';\r\nimport * as path from 'node:path';\r\nimport chalk from 'chalk';\r\nimport { scanProject } from '../../scanner/project-scanner.js';\r\nimport { buildKnowledgeGraph } from '../../graph/index.js';\r\nimport { analyzeRisks, analyzeImpact, generateReport } from '../../insight/index.js';\r\nimport type { ReportPerspective } from '../../graph/types.js';\r\n\r\ninterface AnalyzeOptions {\r\n perspective: string;\r\n risks: boolean;\r\n impact?: string;\r\n output: string;\r\n}\r\n\r\nexport async function analyze(target: string, opts: AnalyzeOptions): Promise<void> {\r\n console.log('');\r\n console.log(chalk.green('🐊 OpenCroc Studio — Project Analysis'));\r\n console.log('');\r\n\r\n const absTarget = path.resolve(target);\r\n\r\n // Check for existing graph first\r\n const graphPath = path.join(opts.output, 'knowledge-graph.json');\r\n let graph;\r\n\r\n if (fs.existsSync(graphPath)) {\r\n console.log(chalk.gray(` Loading cached graph from ${graphPath}...`));\r\n // Need to re-scan for full graph (cached is simplified)\r\n }\r\n\r\n // Scan\r\n console.log(chalk.cyan('📡 Scanning project...'));\r\n const scanResult = await scanProject({\r\n rootDir: absTarget,\r\n onProgress: (phase, percent, detail) => {\r\n if (percent === 100) console.log(chalk.gray(` [${phase}] ${detail || 'done'}`));\r\n },\r\n });\r\n\r\n const projectName = path.basename(absTarget);\r\n graph = buildKnowledgeGraph(scanResult, {\r\n projectName,\r\n source: 'local',\r\n rootPath: absTarget,\r\n });\r\n\r\n console.log(chalk.green(` ✅ ${graph.nodes.length} nodes, ${graph.edges.length} edges`));\r\n console.log('');\r\n\r\n // Risk analysis\r\n if (opts.risks) {\r\n console.log(chalk.cyan('⚠️ Risk Analysis'));\r\n const risks = await analyzeRisks(graph);\r\n\r\n if (risks.length === 0) {\r\n console.log(chalk.green(' ✅ No significant risks detected.'));\r\n } else {\r\n for (const r of risks) {\r\n const icon = r.severity === 'critical' ? '🔴' : r.severity === 'high' ? '🟠' : r.severity === 'medium' ? '🟡' : '🔵';\r\n console.log(` ${icon} [${r.severity.toUpperCase()}] ${r.title}`);\r\n console.log(chalk.gray(` ${r.description}`));\r\n if (r.suggestion) {\r\n console.log(chalk.green(` 💡 ${r.suggestion}`));\r\n }\r\n console.log('');\r\n }\r\n }\r\n }\r\n\r\n // Impact analysis\r\n if (opts.impact) {\r\n console.log(chalk.cyan(`🎯 Impact Analysis: ${opts.impact}`));\r\n const impact = analyzeImpact(graph, opts.impact);\r\n console.log(` ${impact.summary}`);\r\n console.log(` Direct impact: ${impact.directImpact.length} entities`);\r\n console.log(` Transitive impact: ${impact.transitiveImpact.length} entities`);\r\n console.log(` Risk level: ${impact.riskLevel}`);\r\n console.log('');\r\n\r\n if (impact.mermaidText) {\r\n const mermaidPath = path.join(opts.output, 'impact.mmd');\r\n fs.mkdirSync(opts.output, { recursive: true });\r\n fs.writeFileSync(mermaidPath, impact.mermaidText);\r\n console.log(chalk.gray(` 📁 Impact diagram saved: ${mermaidPath}`));\r\n }\r\n }\r\n\r\n // Perspective report\r\n const perspective = opts.perspective as ReportPerspective;\r\n console.log(chalk.cyan(`📋 ${perspective.charAt(0).toUpperCase() + perspective.slice(1)} Report`));\r\n console.log('');\r\n\r\n const risks = await analyzeRisks(graph);\r\n const report = await generateReport(graph, perspective, risks);\r\n\r\n console.log(chalk.bold.green(` ${report.title}`));\r\n console.log(chalk.gray(` ${report.summary}`));\r\n console.log('');\r\n\r\n for (const section of report.sections) {\r\n console.log(chalk.cyan(` ━━ ${section.heading} ━━`));\r\n const lines = section.content.split('\\n');\r\n for (const line of lines) {\r\n console.log(` ${line}`);\r\n }\r\n console.log('');\r\n }\r\n\r\n // Save report\r\n fs.mkdirSync(opts.output, { recursive: true });\r\n const reportPath = path.join(opts.output, `report-${perspective}.json`);\r\n fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));\r\n console.log(chalk.gray(` 📁 Report saved: ${reportPath}`));\r\n console.log('');\r\n}\r\n","#!/usr/bin/env node\r\n\r\nimport { Command } from 'commander';\r\n\r\nconst program = new Command();\r\n\r\nprogram\r\n .name('opencroc')\r\n .description('AI-native E2E testing framework')\r\n .version('1.0.0');\r\n\r\nprogram\r\n .command('init')\r\n .description('Initialize OpenCroc in the current project')\r\n .option('-y, --yes', 'Skip prompts and use defaults')\r\n .action(async (opts) => {\r\n const { initProject } = await import('./commands/init.js');\r\n await initProject(opts);\r\n });\r\n\r\nprogram\r\n .command('generate')\r\n .description('Generate E2E test cases from source code')\r\n .option('-m, --module <name>', 'Generate for a specific module')\r\n .option('-a, --all', 'Generate for all discovered modules')\r\n .option('--steps <steps>', 'Run specific pipeline steps (comma-separated)')\r\n .option('--dry-run', 'Preview without writing files')\r\n .action(async (opts) => {\r\n const { generate } = await import('./commands/generate.js');\r\n await generate(opts);\r\n });\r\n\r\nprogram\r\n .command('test')\r\n .description('Run generated E2E tests')\r\n .option('-m, --module <name>', 'Run tests for a specific module')\r\n .option('--headed', 'Run in headed browser mode')\r\n .option('--setup-hook <cmd>', 'Run setup hook command before test execution')\r\n .option('--auth-hook <cmd>', 'Run auth hook command before test execution')\r\n .option('--teardown-hook <cmd>', 'Run teardown hook command after test execution')\r\n .action(async (opts) => {\r\n const { runTests } = await import('./commands/test.js');\r\n await runTests(opts);\r\n });\r\n\r\nprogram\r\n .command('validate')\r\n .description('Validate module configurations and generated tests')\r\n .option('-m, --module <name>', 'Validate a specific module')\r\n .action(async (opts) => {\r\n const { validate } = await import('./commands/validate.js');\r\n await validate(opts);\r\n });\r\n\r\nprogram\r\n .command('heal')\r\n .description('Run self-healing loop on failed tests')\r\n .option('-m, --module <name>', 'Heal a specific module')\r\n .option('--max-iterations <n>', 'Maximum healing iterations', '3')\r\n .action(async (opts) => {\r\n const { heal } = await import('./commands/heal.js');\r\n await heal(opts);\r\n });\r\n\r\nprogram\r\n .command('ci')\r\n .description('Generate CI/CD pipeline template')\r\n .option('-p, --platform <name>', 'CI platform (github, gitlab)', 'github')\r\n .option('--self-heal', 'Include self-healing step')\r\n .option('--node <versions>', 'Node.js versions (comma-separated)', '20.x')\r\n .action(async (opts) => {\r\n const { ci } = await import('./commands/ci.js');\r\n await ci(opts);\r\n });\r\n\r\nprogram\r\n .command('report')\r\n .description('Generate pipeline report (HTML/JSON/Markdown)')\r\n .option('-f, --format <formats>', 'Report formats (comma-separated)', 'html')\r\n .option('-o, --output <dir>', 'Output directory')\r\n .action(async (opts) => {\r\n const { report } = await import('./commands/report.js');\r\n await report(opts);\r\n });\r\n\r\nprogram\r\n .command('dashboard')\r\n .description('Generate visual dashboard (opencroc-dashboard.html)')\r\n .option('-i, --input <file>', 'Build from existing opencroc-report.json file')\r\n .option('-o, --output <dir>', 'Output directory', './opencroc-output')\r\n .action(async (opts) => {\r\n const { dashboard } = await import('./commands/dashboard.js');\r\n await dashboard(opts);\r\n });\r\n\r\nprogram\r\n .command('init-runtime')\r\n .description('Generate Playwright runtime infrastructure (config, setup, teardown, auth)')\r\n .option('-o, --output <dir>', 'Output directory for generated files', '.')\r\n .option('--force', 'Overwrite existing files')\r\n .action(async (opts) => {\r\n const { initRuntime } = await import('./commands/init-runtime.js');\r\n await initRuntime(opts);\r\n });\r\n\r\nprogram\r\n .command('run')\r\n .description('Full orchestration: generate → execute → analyze → heal → report')\r\n .option('-m, --module <name>', 'Run for a specific module')\r\n .option('--phases <phases>', 'Phases to run (comma-separated: generate,execute,analyze,heal,report)')\r\n .option('--self-heal', 'Enable self-healing on test failures')\r\n .option('--headed', 'Run Playwright in headed mode')\r\n .option('--report <formats>', 'Report formats (comma-separated)', 'html,json')\r\n .option('--token-budget <n>', 'LLM token budget (0 = unlimited)')\r\n .option('--abort-on-error', 'Abort pipeline on first phase error')\r\n .action(async (opts) => {\r\n const { run } = await import('./commands/run.js');\r\n await run(opts);\r\n });\r\n\r\nprogram\r\n .command('serve')\r\n .description('Start OpenCroc Studio — pixel croc office + knowledge graph UI')\r\n .option('-p, --port <port>', 'Server port', '8765')\r\n .option('-H, --host <host>', 'Server host', 'localhost')\r\n .option('--no-open', 'Do not auto-open browser')\r\n .action(async (opts) => {\r\n const { serve } = await import('./commands/serve.js');\r\n await serve(opts);\r\n });\r\n\r\n// ===== Studio Commands — Universal Project Analysis =====\r\n\r\nprogram\r\n .command('scan')\r\n .description('Scan any project and build knowledge graph (local path, GitHub URL, or user/repo)')\r\n .argument('<target>', 'Local path, GitHub URL (https://github.com/user/repo), or shorthand (user/repo)')\r\n .option('-b, --branch <branch>', 'Git branch to clone')\r\n .option('-o, --output <dir>', 'Output directory for results', './opencroc-output')\r\n .option('--json', 'Output as JSON')\r\n .option('--mermaid', 'Output Mermaid diagram')\r\n .option('--risks', 'Include risk analysis')\r\n .option('--report <perspective>', 'Generate perspective report (developer/architect/tester/product/student/executive)')\r\n .action(async (target, opts) => {\r\n const { scan } = await import('./commands/scan.js');\r\n await scan(target, opts);\r\n });\r\n\r\nprogram\r\n .command('analyze')\r\n .description('Analyze a scanned project for risks and generate reports')\r\n .argument('[target]', 'Project path (default: current directory)', '.')\r\n .option('--perspective <role>', 'Report perspective (developer/architect/tester/product/student/executive)', 'developer')\r\n .option('--risks', 'Show risk analysis', true)\r\n .option('--impact <nodeId>', 'Analyze impact of a specific node')\r\n .option('-o, --output <dir>', 'Output directory', './opencroc-output')\r\n .action(async (target, opts) => {\r\n const { analyze } = await import('./commands/analyze.js');\r\n await analyze(target, opts);\r\n });\r\n\r\nprogram.parse();\r\n"],"mappings":"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","names":["path","fs","path","Project","SyntaxKind","fullPath","fs","path","Project","SyntaxKind","producer","path","Project","report","fs","path","backendRoot","chalk","writeFileSync","mkdirSync","existsSync","VALID_STEPS","chalk","readdirSync","existsSync","join","resolve","chalk","stdout","DEFAULTS","existsSync","readFileSync","writeFileSync","mkdirSync","dirname","fs","chalk","ci_exports","fs","path","chalk","init_ci","fs","path","chalk","escapeHtml","fs","path","chalk","init_dashboard","chalk","existsSync","mkdirSync","writeFileSync","join","resolve","writeFileSync","mkdirSync","existsSync","readdirSync","dirname","join","execFileSync","discoverTestFiles","writeFileSync","mkdirSync","existsSync","join","chalk","report","generateGitHubActionsTemplate","generateGitLabCITemplate","fs","path","fs","path","fs","path","detectCycles","path","prompt","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","report","getRoleRegistry","scan","execSync","categorizeFailure","resolve","waitForBackend","existsSync","mkdirSync","writeFileSync","dirname","join","createPipeline","writeFileSync","mkdirSync","dirname","scan","planSummon","existsSync","createExecutionCoordinator","createBackendManager","createRuntimeBootstrap","createAuthProvisioner","buildExecutionQualityGate","categorizeFailure","generateReports","report","inferModule","fileURLToPath","dirname","join","resolve","existsSync","__dirname","__filename","chalk","startServer","fs","path","chalk","report","fs","path","chalk","risks","report","initProject","generate","runTests","validate","heal","ci","report","dashboard","initRuntime","run","serve","scan","analyze"]}
|