opencroc 0.6.0 → 0.6.1
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.en.md +23 -0
- package/README.md +23 -0
- package/README.zh-CN.md +23 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +5 -4
package/README.en.md
CHANGED
|
@@ -297,6 +297,29 @@ export default defineConfig({
|
|
|
297
297
|
- [x] Visual dashboard (opencroc.com)
|
|
298
298
|
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
|
+
## Release Snapshot
|
|
301
|
+
|
|
302
|
+
- Current stable release: `0.6.1`
|
|
303
|
+
- npm dist-tag `latest`: `0.6.1`
|
|
304
|
+
- Roadmap status: fully completed
|
|
305
|
+
- Full-suite quality gate: 23 test files / 184 tests passing on Windows with stable Vitest config
|
|
306
|
+
|
|
307
|
+
### Version Rhythm
|
|
308
|
+
|
|
309
|
+
- `0.3.x`: plugin system, CI templates, reporters, VS Code scaffold, CI hardening
|
|
310
|
+
- `0.4.x`: NestJS controller parser
|
|
311
|
+
- `0.5.x`: Drizzle ORM adapter
|
|
312
|
+
- `0.6.x`: visual dashboard + Windows Vitest stability hardening
|
|
313
|
+
|
|
314
|
+
### Release Verification
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npm run lint
|
|
318
|
+
npm run typecheck
|
|
319
|
+
npm test
|
|
320
|
+
npm view opencroc version dist-tags --json
|
|
321
|
+
```
|
|
322
|
+
|
|
300
323
|
## Documentation
|
|
301
324
|
|
|
302
325
|
Visit **[opencroc.com](https://opencroc.com)** for full documentation, or browse:
|
package/README.md
CHANGED
|
@@ -297,6 +297,29 @@ export default defineConfig({
|
|
|
297
297
|
- [x] Visual dashboard (opencroc.com)
|
|
298
298
|
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
|
+
## Release Snapshot
|
|
301
|
+
|
|
302
|
+
- Current stable release: `0.6.1`
|
|
303
|
+
- npm dist-tag `latest`: `0.6.1`
|
|
304
|
+
- Roadmap status: fully completed
|
|
305
|
+
- Full-suite quality gate: 23 test files / 184 tests passing on Windows with stable Vitest config
|
|
306
|
+
|
|
307
|
+
### Version Rhythm
|
|
308
|
+
|
|
309
|
+
- `0.3.x`: plugin system, CI templates, reporters, VS Code scaffold, CI hardening
|
|
310
|
+
- `0.4.x`: NestJS controller parser
|
|
311
|
+
- `0.5.x`: Drizzle ORM adapter
|
|
312
|
+
- `0.6.x`: visual dashboard + Windows Vitest stability hardening
|
|
313
|
+
|
|
314
|
+
### Release Verification
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npm run lint
|
|
318
|
+
npm run typecheck
|
|
319
|
+
npm test
|
|
320
|
+
npm view opencroc version dist-tags --json
|
|
321
|
+
```
|
|
322
|
+
|
|
300
323
|
## Documentation
|
|
301
324
|
|
|
302
325
|
Visit **[opencroc.com](https://opencroc.com)** for full documentation, or browse:
|
package/README.zh-CN.md
CHANGED
|
@@ -297,6 +297,29 @@ export default defineConfig({
|
|
|
297
297
|
- [x] Visual dashboard (opencroc.com)
|
|
298
298
|
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
|
+
## 发布快照
|
|
301
|
+
|
|
302
|
+
- 当前稳定版本:`0.6.1`
|
|
303
|
+
- npm `latest` 标签:`0.6.1`
|
|
304
|
+
- Roadmap 状态:已全部完成
|
|
305
|
+
- 全量质量门禁:Windows 下 23 个测试文件 / 184 个测试稳定通过
|
|
306
|
+
|
|
307
|
+
### 版本节奏
|
|
308
|
+
|
|
309
|
+
- `0.3.x`:插件系统、CI 模板、报告系统、VS Code 脚手架、CI 稳定化
|
|
310
|
+
- `0.4.x`:NestJS 控制器解析
|
|
311
|
+
- `0.5.x`:Drizzle ORM 适配器
|
|
312
|
+
- `0.6.x`:可视化 dashboard 与 Windows 下 Vitest 稳定性收口
|
|
313
|
+
|
|
314
|
+
### 发布验证
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
npm run lint
|
|
318
|
+
npm run typecheck
|
|
319
|
+
npm test
|
|
320
|
+
npm view opencroc version dist-tags --json
|
|
321
|
+
```
|
|
322
|
+
|
|
300
323
|
## 文档
|
|
301
324
|
|
|
302
325
|
访问 **[opencroc.com](https://opencroc.com)** 查看完整文档,或阅读:
|
package/dist/cli/index.js
CHANGED
|
@@ -2489,7 +2489,7 @@ var init_dashboard2 = __esm({
|
|
|
2489
2489
|
init_esm_shims();
|
|
2490
2490
|
import { Command } from "commander";
|
|
2491
2491
|
var program = new Command();
|
|
2492
|
-
program.name("opencroc").description("AI-native E2E testing framework").version("0.6.
|
|
2492
|
+
program.name("opencroc").description("AI-native E2E testing framework").version("0.6.1");
|
|
2493
2493
|
program.command("init").description("Initialize OpenCroc in the current project").option("-y, --yes", "Skip prompts and use defaults").action(async (opts) => {
|
|
2494
2494
|
const { initProject: initProject2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2495
2495
|
await initProject2(opts);
|
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/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/index.ts","../../src/cli/commands/heal.ts","../../src/ci/index.ts","../../src/cli/commands/ci.ts","../../src/reporters/index.ts","../../src/cli/commands/report.ts","../../src/dashboard/index.ts","../../src/cli/commands/dashboard.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';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\nimport { stdin, stdout } from 'node:process';\n\nconst ADAPTERS = ['sequelize', 'typeorm', 'prisma'] as const;\nconst LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'none'] as const;\n\nexport interface InitAnswers {\n backendRoot: string;\n adapter: string;\n llmProvider: string;\n outDir: string;\n}\n\nconst DEFAULTS: InitAnswers = {\n backendRoot: './backend',\n adapter: 'sequelize',\n llmProvider: 'openai',\n outDir: './opencroc-output',\n};\n\nexport function buildConfigContent(answers: InitAnswers): string {\n const llmBlock =\n answers.llmProvider === 'none'\n ? ''\n : `\n llm: {\n provider: '${answers.llmProvider}',${answers.llmProvider === 'ollama' ? '' : \"\\n // apiKey: process.env.OPENCROC_LLM_API_KEY,\"}\n model: '${answers.llmProvider === 'zhipu' ? 'glm-4' : answers.llmProvider === 'ollama' ? 'llama3' : 'gpt-4o-mini'}',\n },`;\n\n return `import { defineConfig } from 'opencroc';\n\nexport default defineConfig({\n backendRoot: '${answers.backendRoot}',\n adapter: '${answers.adapter}',${llmBlock}\n outDir: '${answers.outDir}',\n selfHealing: {\n enabled: true,\n maxIterations: 3,\n },\n});\n`;\n}\n\nasync function prompt(\n rl: ReturnType<typeof createInterface>,\n question: string,\n defaultValue: string,\n): Promise<string> {\n const answer = await rl.question(` ${question} ${chalk.gray(`(${defaultValue})`)}: `);\n return answer.trim() || defaultValue;\n}\n\nasync function promptChoice(\n rl: ReturnType<typeof createInterface>,\n question: string,\n choices: readonly string[],\n defaultValue: string,\n): Promise<string> {\n const list = choices\n .map((c) => (c === defaultValue ? chalk.underline(c) : c))\n .join(' / ');\n const answer = await rl.question(` ${question} [${list}]: `);\n const trimmed = answer.trim().toLowerCase();\n if (!trimmed) return defaultValue;\n return choices.find((c) => c.toLowerCase() === trimmed) || defaultValue;\n}\n\nasync function collectAnswers(): Promise<InitAnswers> {\n const rl = createInterface({ input: stdin, output: stdout });\n try {\n const backendRoot = await prompt(rl, 'Backend source root', DEFAULTS.backendRoot);\n const adapter = await promptChoice(rl, 'ORM adapter', ADAPTERS, DEFAULTS.adapter);\n const llmProvider = await promptChoice(rl, 'LLM provider', LLM_PROVIDERS, DEFAULTS.llmProvider);\n const outDir = await prompt(rl, 'Test output directory', DEFAULTS.outDir);\n return { backendRoot, adapter, llmProvider, outDir };\n } finally {\n rl.close();\n }\n}\n\nfunction writeProject(cwd: string, answers: InitAnswers): void {\n const configPath = join(cwd, 'opencroc.config.ts');\n writeFileSync(configPath, buildConfigContent(answers), 'utf-8');\n console.log(chalk.green(' ✓ Created opencroc.config.ts'));\n\n const outputDir = join(cwd, answers.outDir);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n console.log(chalk.green(` ✓ Created ${answers.outDir}/`));\n }\n}\n\nfunction printNextSteps(answers: InitAnswers): void {\n const needsKey = answers.llmProvider !== 'none' && answers.llmProvider !== 'ollama';\n console.log('');\n console.log(chalk.cyan(' Next steps:'));\n let step = 1;\n console.log(` ${step++}. Review opencroc.config.ts`);\n if (needsKey) {\n console.log(` ${step++}. Set OPENCROC_LLM_API_KEY environment variable`);\n }\n console.log(` ${step++}. npx opencroc generate --all`);\n console.log(` ${step}. npx opencroc test`);\n}\n\nexport async function initProject(opts?: { yes?: boolean }): Promise<void> {\n const cwd = process.cwd();\n const configPath = join(cwd, 'opencroc.config.ts');\n\n if (existsSync(configPath)) {\n console.log(chalk.yellow('\\n ⚠ opencroc.config.ts already exists. Skipping.\\n'));\n return;\n }\n\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Project Setup\\n'));\n\n const answers = opts?.yes ? { ...DEFAULTS } : await collectAnswers();\n\n console.log('');\n writeProject(cwd, answers);\n printNextSteps(answers);\n console.log('');\n}\n","import { cosmiconfig } from 'cosmiconfig';\nimport type { OpenCrocConfig } from '../types.js';\n\nconst MODULE_NAME = 'opencroc';\n\nconst SEARCH_PLACES = [\n 'opencroc.config.ts',\n 'opencroc.config.js',\n 'opencroc.config.json',\n '.opencrocrc.json',\n 'package.json',\n];\n\nexport interface LoadConfigResult {\n config: OpenCrocConfig;\n filepath: string;\n}\n\nexport async function loadConfig(cwd?: string): Promise<LoadConfigResult> {\n const explorer = cosmiconfig(MODULE_NAME, {\n searchPlaces: SEARCH_PLACES,\n ...(cwd ? { stopDir: cwd } : {}),\n });\n\n const result = cwd ? await explorer.search(cwd) : await explorer.search();\n\n if (!result || result.isEmpty) {\n throw new Error(\n 'No opencroc config found. Run `opencroc init` to create one.',\n );\n }\n\n const config: OpenCrocConfig =\n result.config?.default ?? result.config;\n\n if (!config.backendRoot) {\n throw new Error(\n `Invalid config in ${result.filepath}: \"backendRoot\" is required.`,\n );\n }\n\n return { config, filepath: result.filepath };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n Project,\n SyntaxKind,\n type CallExpression,\n type ObjectLiteralExpression,\n type PropertyAssignment,\n type Node,\n} from 'ts-morph';\nimport type { TableSchema, FieldSchema, IndexSchema } from '../types.js';\n\nexport interface ModelParser {\n parseFile(filePath: string): Promise<TableSchema | null>;\n parseDirectory(dirPath: string): Promise<TableSchema[]>;\n}\n\n/**\n * Parse a single Sequelize Model file and extract TableSchema.\n */\nexport function parseModelFile(filePath: string): TableSchema | null {\n const absolutePath = path.resolve(filePath);\n if (!fs.existsSync(absolutePath)) return null;\n\n const project = new Project({ compilerOptions: { strict: false } });\n const sourceFile = project.addSourceFileAtPath(absolutePath);\n\n const initCall = findInitCall(sourceFile);\n if (!initCall) return null;\n\n const args = initCall.getArguments();\n if (args.length < 2) return null;\n\n const fields = parseFieldDefinitions(args[0]);\n const { tableName, indexes } = parseOptions(args[1]);\n\n if (!tableName) return null;\n\n return { tableName, fields, indexes };\n}\n\n/**\n * Batch parse all Model files in a directory.\n */\nexport function parseModuleModels(modelDir: string): TableSchema[] {\n const absoluteDir = path.resolve(modelDir);\n if (!fs.existsSync(absoluteDir)) return [];\n\n const files = fs.readdirSync(absoluteDir).filter((f) =>\n f.endsWith('.ts') &&\n !f.endsWith('.test.ts') &&\n !f.endsWith('.spec.ts') &&\n f !== 'index.ts' &&\n f !== 'associations.ts',\n );\n\n const schemas: TableSchema[] = [];\n for (const file of files) {\n try {\n const schema = parseModelFile(path.join(absoluteDir, file));\n if (schema) schemas.push(schema);\n } catch {\n // skip unparseable files\n }\n }\n return schemas;\n}\n\nfunction findInitCall(sourceFile: Node): CallExpression | null {\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n for (const call of calls) {\n const expr = call.getExpression();\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\n if (propAccess.getName() === 'init') return call;\n }\n }\n return null;\n}\n\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\n const fields: FieldSchema[] = [];\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\n\n const objLiteral = fieldsNode as ObjectLiteralExpression;\n for (const prop of objLiteral.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const propAssign = prop as PropertyAssignment;\n const initializer = propAssign.getInitializer();\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\n fields.push(parseFieldObject(propAssign.getName(), initializer as ObjectLiteralExpression));\n }\n return fields;\n}\n\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\n\n for (const prop of fieldObj.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const propAssign = prop as PropertyAssignment;\n const key = propAssign.getName();\n const init = propAssign.getInitializer();\n if (!init) continue;\n\n switch (key) {\n case 'type': field.type = extractDataType(init); break;\n case 'allowNull': field.allowNull = init.getText().trim() === 'true'; break;\n case 'primaryKey': field.primaryKey = init.getText().trim() === 'true'; break;\n case 'defaultValue': field.defaultValue = extractDefaultValue(init); break;\n }\n }\n return field;\n}\n\nfunction extractDataType(node: Node): string {\n const text = node.getText().trim();\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\n if (propMatch) return propMatch[1];\n return text;\n}\n\nfunction extractDefaultValue(node: Node): unknown {\n const text = node.getText().trim();\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\n return text.slice(1, -1);\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\n if (text === 'true') return true;\n if (text === 'false') return false;\n if (text === 'null') return null;\n return text;\n}\n\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\n let tableName: string | null = null;\n let indexes: IndexSchema[] = [];\n\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\n\n const objLiteral = optionsNode as ObjectLiteralExpression;\n for (const prop of objLiteral.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const propAssign = prop as PropertyAssignment;\n const key = propAssign.getName();\n const init = propAssign.getInitializer();\n if (!init) continue;\n\n if (key === 'tableName') tableName = extractStringValue(init);\n if (key === 'indexes') indexes = parseIndexes(init);\n }\n return { tableName, indexes };\n}\n\nfunction extractStringValue(node: Node): string | null {\n const text = node.getText().trim();\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\n return text.slice(1, -1);\n return null;\n}\n\nfunction parseIndexes(node: Node): IndexSchema[] {\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\n const indexes: IndexSchema[] = [];\n for (const el of arr.getElements()) {\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\n const idx = parseIndexObject(el as ObjectLiteralExpression);\n if (idx) indexes.push(idx);\n }\n return indexes;\n}\n\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\n let name = '';\n let fields: string[] = [];\n let unique = false;\n\n for (const prop of obj.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const pa = prop as PropertyAssignment;\n const init = pa.getInitializer();\n if (!init) continue;\n switch (pa.getName()) {\n case 'name': name = extractStringValue(init) || ''; break;\n case 'fields': fields = extractStringArray(init); break;\n case 'unique': unique = init.getText().trim() === 'true'; break;\n }\n }\n if (!name || fields.length === 0) return null;\n return { name, fields, unique };\n}\n\nfunction extractStringArray(node: Node): string[] {\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\n return arr.getElements()\n .map((el) => el.getText().trim())\n .filter((t) => (t.startsWith(\"'\") || t.startsWith('\"')))\n .map((t) => t.slice(1, -1));\n}\n\nexport function createModelParser(): ModelParser {\n return {\n async parseFile(filePath: string) {\n return parseModelFile(filePath);\n },\n async parseDirectory(dirPath: string) {\n return parseModuleModels(dirPath);\n },\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n Project,\n SyntaxKind,\n type CallExpression,\n type SourceFile,\n Node,\n type PropertyAccessExpression,\n type Decorator,\n type MethodDeclaration,\n type ObjectLiteralExpression,\n} from 'ts-morph';\nimport type { ApiEndpoint } from '../types.js';\n\nexport interface ControllerParser {\n parseFile(filePath: string): Promise<ApiEndpoint[]>;\n parseDirectory(dirPath: string): Promise<ApiEndpoint[]>;\n}\n\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\n\nconst METHOD_MAP: Record<string, string> = {\n get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH',\n};\n\nconst NEST_HTTP_DECORATORS = new Set(['get', 'post', 'put', 'delete', 'patch']);\n\n/**\n * Parse a single Controller file and extract API endpoints.\n */\nexport function parseControllerFile(filePath: string): ApiEndpoint[] {\n const absolutePath = path.resolve(filePath);\n if (!fs.existsSync(absolutePath)) return [];\n\n try {\n const project = new Project({ compilerOptions: { strict: false } });\n const sourceFile = project.addSourceFileAtPath(absolutePath);\n\n const endpoints: ApiEndpoint[] = [];\n endpoints.push(...extractRouterCalls(sourceFile));\n endpoints.push(...extractBaseCrudRoutes(sourceFile));\n endpoints.push(...extractNestControllerRoutes(sourceFile));\n\n return deduplicateEndpoints(endpoints);\n } catch {\n return [];\n }\n}\n\n/**\n * Parse all Controller files in a directory.\n */\nexport function parseControllerDirectory(dirPath: string): ApiEndpoint[] {\n const absoluteDir = path.resolve(dirPath);\n if (!fs.existsSync(absoluteDir)) return [];\n\n const files = fs.readdirSync(absoluteDir).filter((f) =>\n f.endsWith('.ts') &&\n !f.endsWith('.test.ts') &&\n !f.endsWith('.spec.ts') &&\n f !== 'index.ts',\n );\n\n const endpoints: ApiEndpoint[] = [];\n for (const file of files) {\n endpoints.push(...parseControllerFile(path.join(absoluteDir, file)));\n }\n return deduplicateEndpoints(endpoints);\n}\n\nfunction extractRouterCalls(sourceFile: SourceFile): ApiEndpoint[] {\n const endpoints: ApiEndpoint[] = [];\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n\n for (const call of calls) {\n const expr = call.getExpression();\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\n\n const propAccess = expr as PropertyAccessExpression;\n const methodName = propAccess.getName().toLowerCase();\n if (!HTTP_METHODS.has(methodName)) continue;\n\n const objectText = propAccess.getExpression().getText().trim();\n if (!isRouterLike(objectText)) continue;\n\n const args = call.getArguments();\n if (args.length === 0) continue;\n\n const routePath = resolveRoutePath(args[0], sourceFile);\n if (!routePath) continue;\n\n endpoints.push({\n method: METHOD_MAP[methodName],\n path: routePath,\n pathParams: extractPathParams(routePath),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: extractDescription(call),\n });\n }\n return endpoints;\n}\n\nfunction isRouterLike(text: string): boolean {\n return text === 'router' || text === 'this.router';\n}\n\nfunction extractBaseCrudRoutes(sourceFile: SourceFile): ApiEndpoint[] {\n const endpoints: ApiEndpoint[] = [];\n\n let isBaseCrud = false;\n for (const cls of sourceFile.getClasses()) {\n const heritage = cls.getExtends();\n if (heritage?.getText().includes('BaseCrudController')) {\n isBaseCrud = true;\n break;\n }\n }\n if (!isBaseCrud) return endpoints;\n\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n let resourcePath: string | null = null;\n\n for (const call of calls) {\n const exprText = call.getExpression().getText();\n if (\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\n !exprText.includes('Custom')\n ) {\n const args = call.getArguments();\n if (args.length >= 2) resourcePath = extractStringLiteral(args[1]);\n }\n }\n if (!resourcePath) return endpoints;\n\n const basePath = `/v1/:tenantId/${resourcePath}`;\n const crudRoutes: Array<{ method: string; path: string; desc: string }> = [\n { method: 'GET', path: basePath, desc: `List ${resourcePath}` },\n { method: 'GET', path: `${basePath}/:id`, desc: `Get ${resourcePath} by ID` },\n { method: 'POST', path: basePath, desc: `Create ${resourcePath}` },\n { method: 'PUT', path: `${basePath}/:id`, desc: `Update ${resourcePath}` },\n { method: 'DELETE', path: `${basePath}/:id`, desc: `Delete ${resourcePath}` },\n { method: 'POST', path: `${basePath}/batch-delete`, desc: `Batch delete ${resourcePath}` },\n ];\n\n for (const route of crudRoutes) {\n endpoints.push({\n method: route.method,\n path: route.path,\n pathParams: extractPathParams(route.path),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: route.desc,\n });\n }\n return endpoints;\n}\n\nfunction extractNestControllerRoutes(sourceFile: SourceFile): ApiEndpoint[] {\n const endpoints: ApiEndpoint[] = [];\n\n for (const cls of sourceFile.getClasses()) {\n const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === 'controller');\n if (!controllerDecorator) continue;\n\n const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? '');\n\n for (const methodDecl of cls.getMethods()) {\n const requestMapping = extractRequestMapping(methodDecl, sourceFile);\n if (requestMapping) {\n const fullPath = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));\n endpoints.push({\n method: requestMapping.method,\n path: fullPath,\n pathParams: extractPathParams(fullPath),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: extractMethodDescription(methodDecl),\n });\n continue;\n }\n\n const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));\n if (!httpDecorator) continue;\n\n const methodName = httpDecorator.getName().toLowerCase();\n const method = METHOD_MAP[methodName];\n if (!method) continue;\n\n const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? '');\n const fullPath = joinRoutePath(controllerBasePath, methodPath);\n\n endpoints.push({\n method,\n path: fullPath,\n pathParams: extractPathParams(fullPath),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: extractMethodDescription(methodDecl),\n });\n }\n }\n\n return endpoints;\n}\n\n/**\n * Infer related database table names from Service file imports.\n */\nexport function inferRelatedTables(servicePaths: string[]): string[] {\n const tables = new Set<string>();\n for (const sp of servicePaths) {\n const absolutePath = path.resolve(sp);\n if (!fs.existsSync(absolutePath)) continue;\n try {\n const content = fs.readFileSync(absolutePath, 'utf-8');\n const importRegex = /import\\s*\\{([^}]+)\\}\\s*from\\s*['\"][^'\"]*models[^'\"]*['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n const names = match[1].split(',').map((s) => s.trim());\n for (const name of names) {\n const cleanName = name.replace(/\\s+as\\s+\\w+/, '').trim();\n if (cleanName) tables.add(pascalToSnake(cleanName));\n }\n }\n } catch {\n // skip\n }\n }\n return Array.from(tables);\n}\n\nfunction resolveRoutePath(node: Node, sourceFile: SourceFile): string | null {\n const kind = node.getKind();\n if (kind === SyntaxKind.StringLiteral) return node.getText().slice(1, -1);\n if (kind === SyntaxKind.TemplateExpression || kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\n return resolveTemplateLiteral(node, sourceFile);\n }\n if (kind === SyntaxKind.Identifier) {\n return resolveVariableValue(sourceFile, node.getText().trim());\n }\n return null;\n}\n\nfunction extractDecoratorPath(decorator: Decorator, sourceFile: SourceFile): string | null {\n const args = decorator.getArguments();\n if (args.length === 0) return '';\n\n const firstArg = args[0];\n if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {\n return extractPathFromObjectLiteral(firstArg as ObjectLiteralExpression, sourceFile);\n }\n\n return resolveRoutePath(firstArg, sourceFile);\n}\n\nfunction extractPathFromObjectLiteral(node: ObjectLiteralExpression, sourceFile: SourceFile): string | null {\n const pathProp = node.getProperty('path');\n if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;\n const initializer = pathProp.getInitializer();\n if (!initializer) return null;\n return resolveRoutePath(initializer, sourceFile);\n}\n\nfunction extractRequestMapping(\n methodDecl: MethodDeclaration,\n sourceFile: SourceFile,\n): { method: string; path: string } | null {\n const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === 'requestmapping');\n if (!decorator) return null;\n\n const args = decorator.getArguments();\n if (args.length === 0) return null;\n const firstArg = args[0];\n if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return null;\n\n const obj = firstArg as ObjectLiteralExpression;\n const methodProp = obj.getProperty('method');\n let method = 'GET';\n if (methodProp && Node.isPropertyAssignment(methodProp)) {\n const init = methodProp.getInitializer();\n const methodText = init?.getText() || '';\n const normalized = methodText\n .replace(/['\"`]/g, '')\n .split('.')\n .pop()\n ?.toUpperCase();\n if (normalized && ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) {\n method = normalized;\n }\n }\n\n const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? '';\n return { method, path: pathValue };\n}\n\nfunction normalizeRoutePath(routePath: string): string {\n const cleaned = routePath.trim();\n if (!cleaned || cleaned === '/') return '';\n return `/${cleaned.replace(/^\\/+|\\/+$/g, '')}`;\n}\n\nfunction joinRoutePath(basePath: string, childPath: string): string {\n const joined = `${basePath}${childPath}`.replace(/\\/+/g, '/');\n return joined || '/';\n}\n\nfunction extractMethodDescription(methodDecl: MethodDeclaration): string {\n const docs = methodDecl.getJsDocs();\n if (docs.length > 0) {\n const desc = docs[0].getDescription().trim();\n if (desc) return desc;\n }\n return '';\n}\n\nfunction resolveTemplateLiteral(node: Node, sourceFile: SourceFile): string {\n let result = node.getText().slice(1, -1);\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\n const resolved = resolveVariableValue(sourceFile, expr.trim());\n return resolved || `{${expr.trim()}}`;\n });\n return result;\n}\n\nfunction resolveVariableValue(sourceFile: SourceFile, varName: string): string | null {\n for (const decl of sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\n if (decl.getName() === varName) {\n const init = decl.getInitializer();\n if (!init) continue;\n const t = init.getText().trim();\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\n return t.slice(1, -1);\n if (t.startsWith('`') && t.endsWith('`'))\n return resolveTemplateLiteral(init, sourceFile);\n }\n }\n return null;\n}\n\nfunction extractPathParams(routePath: string): string[] {\n const params: string[] = [];\n const regex = /:(\\w+)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\n return params;\n}\n\nfunction extractDescription(call: CallExpression): string {\n let current: Node = call;\n while (\n current.getParent() &&\n current.getParent()!.getKind() !== SyntaxKind.SourceFile &&\n current.getParent()!.getKind() !== SyntaxKind.Block\n ) {\n current = current.getParent()!;\n }\n const fullText = current.getFullText();\n const leadingText = fullText.substring(0, fullText.indexOf(current.getText()));\n const jsdocMatch = leadingText.match(/\\/\\*\\*[\\s\\S]*?\\*\\s+(.+?)(?:\\n|\\*\\/)/);\n if (jsdocMatch) return jsdocMatch[1].replace(/^\\*\\s*/, '').trim();\n const lineMatch = leadingText.match(/\\/\\/\\s*(.+)/);\n if (lineMatch) return lineMatch[1].trim();\n return '';\n}\n\nfunction extractStringLiteral(node: Node): string | null {\n const t = node.getText().trim();\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\n return t.slice(1, -1);\n return null;\n}\n\nfunction pascalToSnake(name: string): string {\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n}\n\nfunction deduplicateEndpoints(endpoints: ApiEndpoint[]): ApiEndpoint[] {\n const seen = new Map<string, ApiEndpoint>();\n for (const ep of endpoints) {\n const key = `${ep.method}:${ep.path}`;\n if (!seen.has(key)) {\n seen.set(key, ep);\n } else {\n const existing = seen.get(key)!;\n const merged = new Set([...existing.relatedTables, ...ep.relatedTables]);\n existing.relatedTables = Array.from(merged);\n if (!existing.description && ep.description) existing.description = ep.description;\n }\n }\n return Array.from(seen.values());\n}\n\nexport function createControllerParser(): ControllerParser {\n return {\n async parseFile(filePath: string) {\n return parseControllerFile(filePath);\n },\n async parseDirectory(dirPath: string) {\n return parseControllerDirectory(dirPath);\n },\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n Project,\n SyntaxKind,\n type ObjectLiteralExpression,\n type PropertyAssignment,\n type SourceFile,\n} from 'ts-morph';\nimport type { ForeignKeyRelation } from '../types.js';\nimport { parseModelFile } from './model-parser.js';\n\nexport interface AssociationParser {\n parseFile(filePath: string): Promise<ForeignKeyRelation[]>;\n}\n\ninterface RawAssociation {\n sourceClass: string;\n targetClass: string;\n foreignKey: string;\n type: 'hasMany' | 'belongsTo' | 'hasOne';\n importPath?: string;\n}\n\n/**\n * Parse an associations.ts file to extract all foreign key relations.\n */\nexport function parseAssociationFile(\n filePath: string,\n classToTableMap?: Map<string, string>,\n moduleTablePrefix?: string,\n): ForeignKeyRelation[] {\n const absolutePath = path.resolve(filePath);\n if (!fs.existsSync(absolutePath)) return [];\n\n const project = new Project({ compilerOptions: { strict: false } });\n const sourceFile = project.addSourceFileAtPath(absolutePath);\n\n const importPathMap = collectImportPaths(sourceFile);\n const rawAssociations = extractAssociationCalls(sourceFile, importPathMap);\n if (rawAssociations.length === 0) return [];\n\n return deduplicateRelations(rawAssociations, classToTableMap, moduleTablePrefix);\n}\n\n/**\n * Build className → tableName map from Model files in a directory.\n */\nexport function buildClassToTableMap(modelDir: string): Map<string, string> {\n const map = new Map<string, string>();\n const absoluteDir = path.resolve(modelDir);\n if (!fs.existsSync(absoluteDir)) return map;\n\n const files = fs.readdirSync(absoluteDir).filter((f) =>\n f.endsWith('.ts') &&\n !f.endsWith('.test.ts') &&\n !f.endsWith('.spec.ts') &&\n f !== 'index.ts' &&\n f !== 'associations.ts',\n );\n\n for (const file of files) {\n try {\n const schema = parseModelFile(path.join(absoluteDir, file));\n if (schema) {\n const className = file.replace('.ts', '');\n map.set(className, schema.tableName);\n }\n } catch {\n // skip\n }\n }\n return map;\n}\n\nfunction collectImportPaths(sourceFile: SourceFile): Map<string, string> {\n const map = new Map<string, string>();\n for (const decl of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = decl.getModuleSpecifierValue();\n for (const named of decl.getNamedImports()) {\n map.set(named.getName(), moduleSpecifier);\n }\n }\n return map;\n}\n\nfunction extractAssociationCalls(\n sourceFile: SourceFile,\n importPathMap: Map<string, string>,\n): RawAssociation[] {\n const associations: RawAssociation[] = [];\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n\n for (const call of calls) {\n const expr = call.getExpression();\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\n\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\n const methodName = propAccess.getName();\n if (methodName !== 'hasMany' && methodName !== 'belongsTo' && methodName !== 'hasOne') continue;\n\n const sourceClass = propAccess.getExpression().getText().trim();\n const args = call.getArguments();\n if (args.length < 1) continue;\n\n const targetClass = args[0].getText().trim();\n let foreignKey = '';\n\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\n foreignKey = extractStringProperty(args[1] as ObjectLiteralExpression, 'foreignKey');\n }\n\n associations.push({\n sourceClass,\n targetClass,\n foreignKey,\n type: methodName as RawAssociation['type'],\n importPath: importPathMap.get(targetClass),\n });\n }\n return associations;\n}\n\nfunction extractStringProperty(obj: ObjectLiteralExpression, propertyName: string): string {\n for (const prop of obj.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const pa = prop as PropertyAssignment;\n if (pa.getName() !== propertyName) continue;\n const init = pa.getInitializer();\n if (!init) continue;\n const text = init.getText().trim();\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\n return text.slice(1, -1);\n return text;\n }\n return '';\n}\n\nexport function classNameToTableName(className: string): string {\n return className.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n}\n\nfunction resolveTableName(className: string, classToTableMap?: Map<string, string>): string {\n if (classToTableMap?.has(className)) return classToTableMap.get(className)!;\n return classNameToTableName(className);\n}\n\nfunction isCrossModuleRef(\n targetTableName: string,\n importPath: string | undefined,\n moduleTablePrefix?: string,\n): boolean {\n if (moduleTablePrefix) return !targetTableName.startsWith(moduleTablePrefix);\n if (importPath) {\n const upLevels = (importPath.match(/\\.\\.\\//g) || []).length;\n return upLevels >= 2;\n }\n return false;\n}\n\nfunction deduplicateRelations(\n rawAssociations: RawAssociation[],\n classToTableMap?: Map<string, string>,\n moduleTablePrefix?: string,\n): ForeignKeyRelation[] {\n const seen = new Map<string, ForeignKeyRelation>();\n\n for (const raw of rawAssociations) {\n const sourceTable = resolveTableName(raw.sourceClass, classToTableMap);\n const targetTable = resolveTableName(raw.targetClass, classToTableMap);\n const crossModule = isCrossModuleRef(targetTable, raw.importPath, moduleTablePrefix);\n\n let parentTable: string;\n let childTable: string;\n let cardinality: ForeignKeyRelation['cardinality'];\n\n switch (raw.type) {\n case 'hasMany':\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:N'; break;\n case 'belongsTo':\n parentTable = targetTable; childTable = sourceTable; cardinality = 'N:1'; break;\n case 'hasOne':\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:1'; break;\n }\n\n const dedupeKey = `${parentTable}|${childTable}|${raw.foreignKey}`;\n if (seen.has(dedupeKey)) {\n const existing = seen.get(dedupeKey)!;\n if (existing.cardinality === 'N:1' && (cardinality === '1:N' || cardinality === '1:1')) {\n seen.set(dedupeKey, {\n sourceTable: parentTable, sourceField: 'id',\n targetTable: childTable, targetField: raw.foreignKey,\n cardinality, isCrossModule: crossModule || existing.isCrossModule,\n });\n }\n } else {\n seen.set(dedupeKey, {\n sourceTable: parentTable, sourceField: 'id',\n targetTable: childTable, targetField: raw.foreignKey,\n cardinality, isCrossModule: crossModule,\n });\n }\n }\n return Array.from(seen.values());\n}\n\nexport function createAssociationParser(): AssociationParser {\n return {\n async parseFile(filePath: string) {\n return parseAssociationFile(filePath);\n },\n };\n}\n","import type {\n ApiEndpoint,\n ApiDependency,\n ApiChainAnalysisResult,\n DirectedAcyclicGraph,\n} from '../types.js';\n\nconst EXCLUDED_PARAMS = new Set(['tenantId']);\n\nconst enum Color { WHITE = 0, GRAY = 1, BLACK = 2 }\n\nfunction toNodeKey(endpoint: ApiEndpoint): string {\n return `${endpoint.method} ${endpoint.path}`;\n}\n\nfunction paramToResourceHint(param: string): string {\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\n return stripped.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\n}\n\nfunction postProducesResource(postEndpoint: ApiEndpoint, resourceHint: string): boolean {\n const segments = postEndpoint.path.split('/').filter((s) => s && !s.startsWith(':'));\n if (segments.length === 0) return false;\n\n const lastSegment = segments[segments.length - 1].toLowerCase();\n if (lastSegment.includes(resourceHint)) return true;\n\n const parts = lastSegment.split('-');\n if (parts.some((p) => p === resourceHint || p.startsWith(resourceHint))) return true;\n\n if (resourceHint.length <= 4) {\n const abbreviation = parts.map((p) => p[0]).join('');\n if (abbreviation.startsWith(resourceHint)) return true;\n }\n return false;\n}\n\n/**\n * Infer API dependencies via path parameter matching.\n * POST endpoints produce IDs; GET/PUT/DELETE endpoints consume them.\n */\nexport function inferDependencies(endpoints: ApiEndpoint[]): ApiDependency[] {\n const dependencies: ApiDependency[] = [];\n const postEndpoints = endpoints.filter((ep) => ep.method === 'POST');\n\n for (const consumer of endpoints) {\n const consumedParams = consumer.pathParams.filter((p) => !EXCLUDED_PARAMS.has(p));\n if (consumedParams.length === 0) continue;\n\n for (const param of consumedParams) {\n if (param === 'id') {\n const basePath = consumer.path.replace(/\\/:id(\\/.*)?$/, '');\n const producer = postEndpoints.find((ep) => ep.path === basePath);\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\n }\n continue;\n }\n\n const resourceHint = paramToResourceHint(param);\n if (!resourceHint) continue;\n\n const producer = postEndpoints.find((ep) => postProducesResource(ep, resourceHint));\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\n }\n }\n }\n return deduplicateDependencies(dependencies);\n}\n\nfunction deduplicateDependencies(deps: ApiDependency[]): ApiDependency[] {\n const map = new Map<string, ApiDependency>();\n for (const dep of deps) {\n const key = `${toNodeKey(dep.from)}→${toNodeKey(dep.to)}`;\n if (map.has(key)) {\n Object.assign(map.get(key)!.paramMapping, dep.paramMapping);\n } else {\n map.set(key, { ...dep, paramMapping: { ...dep.paramMapping } });\n }\n }\n return Array.from(map.values());\n}\n\n/**\n * Build a directed graph from endpoints and their dependencies.\n */\nexport function buildGraph(\n endpoints: ApiEndpoint[],\n dependencies: ApiDependency[],\n): DirectedAcyclicGraph {\n const nodeSet = new Set<string>();\n for (const ep of endpoints) nodeSet.add(toNodeKey(ep));\n\n const edges: Array<{ from: string; to: string; label?: string }> = [];\n for (const dep of dependencies) {\n edges.push({\n from: toNodeKey(dep.from),\n to: toNodeKey(dep.to),\n label: Object.keys(dep.paramMapping).join(', ') || undefined,\n });\n }\n return { nodes: Array.from(nodeSet), edges };\n}\n\n/**\n * Detect cycles in a directed graph using DFS coloring.\n */\nexport function detectCycles(dag: DirectedAcyclicGraph): string[] {\n const adjacency = new Map<string, string[]>();\n for (const node of dag.nodes) adjacency.set(node, []);\n for (const edge of dag.edges) adjacency.get(edge.from)?.push(edge.to);\n\n const color = new Map<string, Color>();\n for (const node of dag.nodes) color.set(node, Color.WHITE);\n\n const warnings: string[] = [];\n const path: string[] = [];\n\n function dfs(node: string): void {\n color.set(node, Color.GRAY);\n path.push(node);\n for (const neighbor of adjacency.get(node) || []) {\n const nc = color.get(neighbor);\n if (nc === Color.GRAY) {\n const cycleStart = path.indexOf(neighbor);\n warnings.push(`Cycle detected: ${path.slice(cycleStart).concat(neighbor).join(' → ')}`);\n } else if (nc === Color.WHITE) {\n dfs(neighbor);\n }\n }\n path.pop();\n color.set(node, Color.BLACK);\n }\n\n for (const node of dag.nodes) {\n if (color.get(node) === Color.WHITE) dfs(node);\n }\n return warnings;\n}\n\n/**\n * Topological sort using Kahn's algorithm.\n */\nexport function topologicalSort(dag: DirectedAcyclicGraph): string[] {\n const inDegree = new Map<string, number>();\n const adjacency = new Map<string, string[]>();\n\n for (const node of dag.nodes) { inDegree.set(node, 0); adjacency.set(node, []); }\n for (const edge of dag.edges) {\n adjacency.get(edge.from)?.push(edge.to);\n inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);\n }\n\n const queue: string[] = [];\n for (const [node, degree] of inDegree) {\n if (degree === 0) queue.push(node);\n }\n\n const sorted: string[] = [];\n while (queue.length > 0) {\n const node = queue.shift()!;\n sorted.push(node);\n for (const neighbor of adjacency.get(node) || []) {\n const nd = (inDegree.get(neighbor) || 1) - 1;\n inDegree.set(neighbor, nd);\n if (nd === 0) queue.push(neighbor);\n }\n }\n return sorted;\n}\n\nexport interface ApiChainAnalyzer {\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult;\n}\n\n/**\n * Analyze API endpoints: infer dependencies, build DAG, detect cycles, topological sort.\n */\nexport function createApiChainAnalyzer(): ApiChainAnalyzer {\n return {\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult {\n const dependencies = inferDependencies(endpoints);\n const dag = buildGraph(endpoints, dependencies);\n const cycleWarnings = detectCycles(dag);\n\n return {\n moduleName: '',\n endpoints,\n dependencies,\n dag,\n hasCycles: cycleWarnings.length > 0,\n cycleWarnings,\n };\n },\n };\n}\n","import type { ERDiagramResult, TableSchema, ForeignKeyRelation } from '../types.js';\n\nexport interface ERDiagramGenerator {\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult;\n}\n\n/**\n * Map field type string to a short Mermaid ER type label.\n */\nfunction toMermaidType(fieldType: string): string {\n const upper = fieldType.toUpperCase();\n if (upper.startsWith('STRING')) return 'string';\n if (upper === 'BIGINT' || upper === 'INTEGER') return 'bigint';\n if (upper === 'BOOLEAN') return 'boolean';\n if (upper.startsWith('DATE') || upper === 'NOW') return 'datetime';\n if (upper === 'JSON' || upper === 'JSONB') return 'json';\n if (upper === 'TEXT') return 'text';\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return 'float';\n if (upper === 'UUID') return 'uuid';\n if (upper.startsWith('ENUM')) return 'enum';\n return 'string';\n}\n\n/**\n * Mermaid requires entity names without special characters.\n */\nfunction sanitizeEntityName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\n}\n\n/**\n * Generate Mermaid ER diagram syntax from parsed schemas and relations.\n */\nfunction generateMermaidER(tables: TableSchema[], relations: ForeignKeyRelation[]): string {\n const lines: string[] = ['erDiagram'];\n\n // Entity blocks\n for (const table of tables) {\n const entityName = sanitizeEntityName(table.tableName);\n lines.push(` ${entityName} {`);\n for (const field of table.fields) {\n const mType = toMermaidType(field.type);\n const pk = field.primaryKey ? 'PK' : '';\n const comment = field.comment ? ` \"${field.comment}\"` : '';\n lines.push(` ${mType} ${field.name}${pk ? ' ' + pk : ''}${comment}`);\n }\n lines.push(' }');\n }\n\n // Relationships\n const tableNames = new Set(tables.map((t) => t.tableName));\n for (const rel of relations) {\n if (!tableNames.has(rel.sourceTable) || !tableNames.has(rel.targetTable)) continue;\n\n const src = sanitizeEntityName(rel.sourceTable);\n const tgt = sanitizeEntityName(rel.targetTable);\n const linkStyle = rel.isCrossModule ? '..' : '--';\n\n let cardinality: string;\n switch (rel.cardinality) {\n case '1:N': cardinality = `||${linkStyle}o{`; break;\n case 'N:1': cardinality = `}o${linkStyle}||`; break;\n case '1:1': cardinality = `||${linkStyle}||`; break;\n default: cardinality = `||${linkStyle}o{`;\n }\n\n lines.push(` ${src} ${cardinality} ${tgt} : \"${rel.targetField}\"`);\n }\n\n return lines.join('\\n');\n}\n\nexport function createERDiagramGenerator(): ERDiagramGenerator {\n return {\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult {\n const mermaidText = generateMermaidER(tables, relations);\n return { tables, relations, mermaidText };\n },\n };\n}\n","import type { GeneratedTestFile, TestChain, TestStep } from '../types.js';\n\nexport interface TestCodeGenerator {\n generate(chains: TestChain[]): GeneratedTestFile[];\n}\n\n/**\n * Resolve a path parameter from the available createdIds.\n */\nfunction resolvePathParam(param: string, ids: string[]): string {\n // Try direct match (e.g., 'kbId' → look for 'kbId' in ids)\n if (ids.includes(param)) return `createdIds['${param}']`;\n // Try with 'Id' suffix stripped\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\n if (ids.includes(stripped)) return `createdIds['${stripped}']`;\n // Generic id\n if (param === 'id') return `createdIds['id']`;\n return `createdIds['${param}'] || '1'`;\n}\n\n/**\n * Generate URL building code for a test step.\n */\nfunction buildUrlCode(step: TestStep): string {\n const pathParams = step.endpoint.pathParams;\n if (pathParams.length === 0) return `const url = '${step.endpoint.path}';`;\n\n let urlTemplate = step.endpoint.path;\n const replacements: string[] = [];\n for (const param of pathParams) {\n urlTemplate = urlTemplate.replace(`:${param}`, `\\${${resolvePathParam(param, pathParams)}}`);\n replacements.push(param);\n }\n return `const url = \\`${urlTemplate}\\`;`;\n}\n\n/**\n * Generate assertion code for a test step.\n */\nfunction generateAssertions(step: TestStep): string[] {\n const lines: string[] = [];\n if (step.assertions.length > 0) {\n for (const assertion of step.assertions) {\n lines.push(` expect(${assertion}).toBeTruthy();`);\n }\n } else {\n // Default assertions\n if (step.endpoint.method === 'POST') {\n lines.push(' expect(response.status()).toBeLessThan(400);');\n lines.push(' const body = await response.json();');\n lines.push(\" if (body.data?.id) createdIds['id'] = body.data.id;\");\n } else if (step.endpoint.method === 'GET') {\n lines.push(' expect(response.ok()).toBeTruthy();');\n } else if (step.endpoint.method === 'DELETE') {\n lines.push(' expect(response.status()).toBeLessThan(400);');\n } else {\n lines.push(' expect(response.status()).toBeLessThan(400);');\n }\n }\n return lines;\n}\n\n/**\n * Generate a single Playwright test file from a test chain.\n */\nfunction generateTestFile(chain: TestChain): string {\n const lines: string[] = [];\n\n lines.push(`import { test, expect } from '@playwright/test';`);\n lines.push('');\n lines.push(`test.describe('${chain.name}', () => {`);\n lines.push(\" const createdIds: Record<string, string> = {};\");\n lines.push('');\n\n for (const step of chain.steps) {\n lines.push(` test('Step ${step.order}: ${step.description}', async ({ request }) => {`);\n lines.push(` // ${step.action}: ${step.endpoint.method} ${step.endpoint.path}`);\n lines.push(` ${buildUrlCode(step)}`);\n lines.push('');\n\n if (step.endpoint.method === 'GET') {\n lines.push(' const response = await request.get(url);');\n } else if (step.endpoint.method === 'POST') {\n lines.push(' const response = await request.post(url, { data: {} });');\n } else if (step.endpoint.method === 'PUT') {\n lines.push(' const response = await request.put(url, { data: {} });');\n } else if (step.endpoint.method === 'DELETE') {\n lines.push(' const response = await request.delete(url);');\n } else if (step.endpoint.method === 'PATCH') {\n lines.push(' const response = await request.patch(url, { data: {} });');\n }\n\n lines.push('');\n lines.push(...generateAssertions(step));\n lines.push(' });');\n lines.push('');\n }\n\n lines.push('});');\n return lines.join('\\n');\n}\n\nexport function createTestCodeGenerator(): TestCodeGenerator {\n return {\n generate(chains: TestChain[]): GeneratedTestFile[] {\n return chains.map((chain) => ({\n filePath: `${chain.module}/${chain.name.replace(/\\s+/g, '-').toLowerCase()}.spec.ts`,\n content: generateTestFile(chain),\n module: chain.module,\n chain: chain.name,\n }));\n },\n };\n}\n","import type { ValidationError } from '../types.js';\n\nconst REQUIRED_FIELDS = ['backendRoot'];\n\nconst VALID_ADAPTERS = ['sequelize', 'typeorm', 'prisma'];\nconst VALID_STEPS = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\nconst VALID_LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'custom'];\nconst VALID_REPORT_FORMATS = ['html', 'json', 'markdown'];\nconst VALID_HEAL_MODES = ['config-only', 'config-and-source'];\n\n/**\n * Validate an OpenCroc configuration object.\n * Returns an array of ValidationErrors (empty = valid).\n */\nexport function validateConfig(config: Record<string, unknown>): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // Required fields\n for (const field of REQUIRED_FIELDS) {\n if (!config[field]) {\n errors.push({\n module: 'config',\n field,\n message: `Missing required field: ${field}`,\n severity: 'error',\n });\n }\n }\n\n // backendRoot must be a string\n if (config.backendRoot && typeof config.backendRoot !== 'string') {\n errors.push({\n module: 'config',\n field: 'backendRoot',\n message: 'backendRoot must be a string path',\n severity: 'error',\n });\n }\n\n // adapter validation\n if (config.adapter && typeof config.adapter === 'string') {\n if (!VALID_ADAPTERS.includes(config.adapter)) {\n errors.push({\n module: 'config',\n field: 'adapter',\n message: `Invalid adapter: ${config.adapter}. Must be one of: ${VALID_ADAPTERS.join(', ')}`,\n severity: 'error',\n });\n }\n }\n\n // steps validation\n if (config.steps && Array.isArray(config.steps)) {\n for (const step of config.steps) {\n if (!VALID_STEPS.includes(step as string)) {\n errors.push({\n module: 'config',\n field: 'steps',\n message: `Invalid pipeline step: ${step}. Must be one of: ${VALID_STEPS.join(', ')}`,\n severity: 'error',\n });\n }\n }\n }\n\n // LLM config validation\n if (config.llm && typeof config.llm === 'object') {\n const llm = config.llm as Record<string, unknown>;\n if (llm.provider && !VALID_LLM_PROVIDERS.includes(llm.provider as string)) {\n errors.push({\n module: 'config',\n field: 'llm.provider',\n message: `Invalid LLM provider: ${llm.provider}. Must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,\n severity: 'error',\n });\n }\n if (llm.provider && llm.provider !== 'ollama' && !llm.apiKey) {\n errors.push({\n module: 'config',\n field: 'llm.apiKey',\n message: 'LLM apiKey is required for cloud providers',\n severity: 'warning',\n });\n }\n }\n\n // Report config validation\n if (config.report && typeof config.report === 'object') {\n const report = config.report as Record<string, unknown>;\n if (report.format && Array.isArray(report.format)) {\n for (const fmt of report.format) {\n if (!VALID_REPORT_FORMATS.includes(fmt as string)) {\n errors.push({\n module: 'config',\n field: 'report.format',\n message: `Invalid report format: ${fmt}. Must be one of: ${VALID_REPORT_FORMATS.join(', ')}`,\n severity: 'error',\n });\n }\n }\n }\n }\n\n // Self-healing config validation\n if (config.selfHealing && typeof config.selfHealing === 'object') {\n const sh = config.selfHealing as Record<string, unknown>;\n if (sh.mode && !VALID_HEAL_MODES.includes(sh.mode as string)) {\n errors.push({\n module: 'config',\n field: 'selfHealing.mode',\n message: `Invalid self-healing mode: ${sh.mode}. Must be one of: ${VALID_HEAL_MODES.join(', ')}`,\n severity: 'error',\n });\n }\n if (sh.maxIterations && (typeof sh.maxIterations !== 'number' || sh.maxIterations < 1)) {\n errors.push({\n module: 'config',\n field: 'selfHealing.maxIterations',\n message: 'maxIterations must be a positive number',\n severity: 'error',\n });\n }\n }\n\n return errors;\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport type {\n OpenCrocConfig,\n PipelineRunResult,\n PipelineStep,\n ERDiagramResult,\n ChainPlanResult,\n} from '../types.js';\nimport { parseModuleModels } from '../parsers/model-parser.js';\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\nimport { parseAssociationFile } from '../parsers/association-parser.js';\nimport { createApiChainAnalyzer, topologicalSort } from '../analyzers/api-chain-analyzer.js';\nimport { createERDiagramGenerator } from '../generators/er-diagram-generator.js';\nimport { createTestCodeGenerator } from '../generators/test-code-generator.js';\nimport { validateConfig } from '../validators/config-validator.js';\n\nexport interface Pipeline {\n run(steps?: PipelineStep[]): Promise<PipelineRunResult>;\n}\n\nconst ALL_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\n\nexport function createPipeline(config: OpenCrocConfig): Pipeline {\n return {\n async run(steps) {\n const startTime = Date.now();\n const activeSteps = steps || config.steps || ALL_STEPS;\n\n const result: PipelineRunResult = {\n modules: [],\n erDiagrams: new Map(),\n chainPlans: new Map(),\n generatedFiles: [],\n validationErrors: [],\n duration: 0,\n };\n\n // Step 1: Scan — discover modules\n if (activeSteps.includes('scan')) {\n const backendRoot = path.resolve(config.backendRoot);\n const modelsDir = path.join(backendRoot, 'models');\n\n if (fs.existsSync(modelsDir)) {\n // Discover modules from subdirectories\n const dirs = fs.readdirSync(modelsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n const moduleFilter = config.modules;\n for (const dir of dirs) {\n if (moduleFilter && !moduleFilter.includes(dir)) continue;\n result.modules.push(dir);\n }\n\n // If no subdirectories, treat root as single \"default\" module\n if (result.modules.length === 0) {\n result.modules.push('default');\n } else {\n // Also include root-level model files as \"default\" module\n const rootFiles = fs.readdirSync(modelsDir)\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts');\n if (rootFiles.length > 0) {\n result.modules.unshift('default');\n }\n }\n }\n }\n\n // Helper: resolve model dir for a module\n const resolveModelDir = (backendRoot: string, mod: string): string =>\n mod === 'default'\n ? path.join(backendRoot, 'models')\n : path.join(backendRoot, 'models', mod);\n\n // Helper: resolve controller dir for a module\n const resolveControllerDir = (backendRoot: string, mod: string): string =>\n mod === 'default'\n ? path.join(backendRoot, 'controllers')\n : path.join(backendRoot, 'controllers', mod);\n\n // Step 2: ER Diagram — parse models and generate relationship graphs\n if (activeSteps.includes('er-diagram')) {\n const erGen = createERDiagramGenerator();\n const backendRoot = path.resolve(config.backendRoot);\n\n for (const mod of result.modules) {\n const modelDir = resolveModelDir(backendRoot, mod);\n\n // For flat layouts, scan all model files for embedded associations\n const tables = fs.existsSync(modelDir) ? parseModuleModels(modelDir) : [];\n const relations: import('../types.js').ForeignKeyRelation[] = [];\n\n // Check for dedicated associations.ts first\n const assocFile = path.join(modelDir, 'associations.ts');\n if (fs.existsSync(assocFile)) {\n relations.push(...parseAssociationFile(assocFile));\n }\n\n // Also scan model files for embedded associations (belongsTo/hasMany at end of file)\n if (fs.existsSync(modelDir)) {\n const modelFiles = fs.readdirSync(modelDir)\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts');\n for (const file of modelFiles) {\n try {\n const embedded = parseAssociationFile(path.join(modelDir, file));\n relations.push(...embedded);\n } catch {\n // skip files that fail to parse\n }\n }\n }\n\n const erResult: ERDiagramResult = erGen.generate(tables, relations);\n result.erDiagrams.set(mod, erResult);\n }\n }\n\n // Step 3: API Chain — analyze controller routes and build dependency DAG\n if (activeSteps.includes('api-chain')) {\n const chainAnalyzer = createApiChainAnalyzer();\n const backendRoot = path.resolve(config.backendRoot);\n\n for (const mod of result.modules) {\n const controllerDir = resolveControllerDir(backendRoot, mod);\n const endpoints = fs.existsSync(controllerDir)\n ? parseControllerDirectory(controllerDir)\n : [];\n\n const analysis = chainAnalyzer.analyze(endpoints);\n analysis.moduleName = mod;\n\n if (analysis.hasCycles) {\n for (const warning of analysis.cycleWarnings) {\n result.validationErrors.push({\n module: mod,\n field: 'api-chain',\n message: warning,\n severity: 'warning',\n });\n }\n }\n }\n }\n\n // Step 4: Plan — generate test chains from dependency analysis\n if (activeSteps.includes('plan')) {\n const backendRoot = path.resolve(config.backendRoot);\n const chainAnalyzer = createApiChainAnalyzer();\n\n for (const mod of result.modules) {\n const controllerDir = resolveControllerDir(backendRoot, mod);\n const endpoints = fs.existsSync(controllerDir)\n ? parseControllerDirectory(controllerDir)\n : [];\n\n const analysis = chainAnalyzer.analyze(endpoints);\n const topoOrder = topologicalSort(analysis.dag);\n\n // Group by resource to create chains\n const chains = generateChainPlan(mod, endpoints, topoOrder);\n result.chainPlans.set(mod, chains);\n }\n }\n\n // Step 5: Codegen — emit Playwright test files from chain plans\n if (activeSteps.includes('codegen')) {\n const testGen = createTestCodeGenerator();\n const outDir = config.outDir || './opencroc-output';\n\n for (const [_mod, plan] of result.chainPlans) {\n const files = testGen.generate(plan.chains);\n for (const file of files) {\n file.filePath = path.join(outDir, file.filePath);\n }\n result.generatedFiles.push(...files);\n }\n }\n\n // Step 6: Validate — run validation on generated configs\n if (activeSteps.includes('validate')) {\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\n result.validationErrors.push(...configErrors);\n }\n\n result.duration = Date.now() - startTime;\n return result;\n },\n };\n}\n\n/**\n * Generate a basic chain plan from endpoints and topological order.\n */\nfunction generateChainPlan(\n moduleName: string,\n endpoints: import('../types.js').ApiEndpoint[],\n _topoOrder: string[],\n): ChainPlanResult {\n // Group endpoints by resource (first non-param path segment)\n const groups = new Map<string, import('../types.js').ApiEndpoint[]>();\n\n for (const ep of endpoints) {\n const segments = ep.path.split('/').filter((s) => s && !s.startsWith(':'));\n const resource = segments[segments.length - 1] || 'default';\n if (!groups.has(resource)) groups.set(resource, []);\n groups.get(resource)!.push(ep);\n }\n\n const chains: import('../types.js').TestChain[] = [];\n let totalSteps = 0;\n\n for (const [resource, eps] of groups) {\n const steps: import('../types.js').TestStep[] = eps.map((ep, i) => ({\n order: i + 1,\n action: ep.method,\n endpoint: ep,\n description: ep.description || `${ep.method} ${ep.path}`,\n assertions: [],\n }));\n\n chains.push({ name: `${resource} CRUD chain`, module: moduleName, steps });\n totalSteps += steps.length;\n }\n\n return { chains, totalSteps };\n}\n","import chalk from 'chalk';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { loadConfig } from '../load-config.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport type { PipelineStep, PipelineRunResult } from '../../types.js';\n\nconst VALID_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\n\nexport interface GenerateOptions {\n module?: string;\n all?: boolean;\n steps?: string;\n dryRun?: boolean;\n}\n\nfunction parseSteps(raw?: string): PipelineStep[] | undefined {\n if (!raw) return undefined;\n const names = raw.split(',').map((s) => s.trim());\n for (const name of names) {\n if (!VALID_STEPS.includes(name as PipelineStep)) {\n throw new Error(`Unknown pipeline step \"${name}\". Valid steps: ${VALID_STEPS.join(', ')}`);\n }\n }\n return names as PipelineStep[];\n}\n\nfunction writeGeneratedFiles(result: PipelineRunResult): number {\n let written = 0;\n for (const file of result.generatedFiles) {\n const dir = dirname(file.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(file.filePath, file.content, 'utf-8');\n written++;\n console.log(chalk.green(` ✓ ${file.filePath}`));\n }\n return written;\n}\n\nfunction printSummary(result: PipelineRunResult, dryRun: boolean): void {\n console.log('');\n console.log(chalk.cyan.bold(' Summary'));\n console.log(` Modules discovered : ${result.modules.length}`);\n console.log(` ER diagrams : ${result.erDiagrams.size}`);\n console.log(` Chain plans : ${result.chainPlans.size}`);\n console.log(` Generated files : ${result.generatedFiles.length}${dryRun ? ' (dry-run, not written)' : ''}`);\n\n if (result.validationErrors.length > 0) {\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\n if (errors.length > 0) console.log(chalk.red(` Errors : ${errors.length}`));\n if (warnings.length > 0) console.log(chalk.yellow(` Warnings : ${warnings.length}`));\n\n for (const err of result.validationErrors) {\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\n console.log(` ${icon} [${err.module}] ${err.message}`);\n }\n }\n\n console.log(chalk.gray(` Duration : ${result.duration}ms`));\n console.log('');\n}\n\nexport async function generate(opts: GenerateOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Generate E2E Tests\\n'));\n\n // Load config\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n // Apply --module filter\n if (opts.module) {\n config.modules = [opts.module];\n }\n\n // Parse --steps\n const steps = parseSteps(opts.steps);\n\n // Create and run pipeline\n const pipeline = createPipeline(config);\n const result = await pipeline.run(steps);\n\n // Write files (unless dry-run)\n if (!opts.dryRun && result.generatedFiles.length > 0) {\n console.log('');\n console.log(chalk.cyan(' Generated files:'));\n writeGeneratedFiles(result);\n } else if (opts.dryRun && result.generatedFiles.length > 0) {\n console.log('');\n console.log(chalk.yellow(' Dry-run — files that would be generated:'));\n for (const file of result.generatedFiles) {\n console.log(chalk.gray(` ${file.filePath}`));\n }\n }\n\n printSummary(result, !!opts.dryRun);\n}\n","import chalk from 'chalk';\nimport { readdirSync, existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { execFileSync } from 'node:child_process';\nimport { loadConfig } from '../load-config.js';\n\nexport interface TestOptions {\n module?: string;\n headed?: boolean;\n}\n\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\n const absDir = resolve(outDir);\n if (!existsSync(absDir)) return [];\n\n const files: string[] = [];\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\n const fullPath = join(entry.parentPath || (entry as unknown as { path: string }).path || absDir, entry.name);\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\n files.push(fullPath);\n }\n return files;\n}\n\nexport async function runTests(opts: TestOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Run E2E Tests\\n'));\n\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n const outDir = config.outDir || './opencroc-output';\n const testFiles = discoverTestFiles(outDir, opts.module);\n\n if (testFiles.length === 0) {\n console.log(chalk.yellow(' No test files found. Run `opencroc generate` first.\\n'));\n return;\n }\n\n console.log(` Found ${testFiles.length} test file(s)`);\n for (const f of testFiles) {\n console.log(chalk.gray(` ${f}`));\n }\n console.log('');\n\n // Build Playwright args\n const args = ['test', ...testFiles];\n if (!opts.headed) {\n args.push('--reporter=list');\n } else {\n args.push('--headed');\n }\n\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n\n try {\n console.log(chalk.cyan(' Running Playwright...\\n'));\n execFileSync(npxCmd, ['playwright', ...args], {\n stdio: 'inherit',\n cwd: process.cwd(),\n });\n console.log(chalk.green('\\n ✓ All tests passed.\\n'));\n } catch {\n console.log(chalk.red('\\n ✗ Some tests failed.\\n'));\n process.exitCode = 1;\n }\n}\n","import chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { validateConfig } from '../../validators/config-validator.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport type { ValidationError } from '../../types.js';\n\nexport interface ValidateOptions {\n module?: string;\n}\n\nfunction printErrors(errors: ValidationError[]): void {\n for (const err of errors) {\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\n const scope = err.module === 'config' ? '' : ` [${err.module}]`;\n console.log(` ${icon}${scope} ${err.field}: ${err.message}`);\n }\n}\n\nexport async function validate(opts: ValidateOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Validate\\n'));\n\n // Load and validate config\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\n\n // Apply module filter\n if (opts.module) {\n config.modules = [opts.module];\n }\n\n // Run pipeline in scan + validate mode to discover module-level issues\n const pipeline = createPipeline(config);\n const result = await pipeline.run(['scan', 'validate']);\n\n const allErrors = [...configErrors, ...result.validationErrors];\n const errors = allErrors.filter((e) => e.severity === 'error');\n const warnings = allErrors.filter((e) => e.severity === 'warning');\n\n if (allErrors.length === 0) {\n console.log(chalk.green(' ✓ Configuration is valid.'));\n console.log(chalk.gray(` Modules: ${result.modules.join(', ') || '(none)'}\\n`));\n return;\n }\n\n if (errors.length > 0) {\n console.log(chalk.red(` ${errors.length} error(s):`));\n printErrors(errors);\n }\n if (warnings.length > 0) {\n console.log(chalk.yellow(` ${warnings.length} warning(s):`));\n printErrors(warnings);\n }\n\n console.log('');\n\n if (errors.length > 0) {\n process.exitCode = 1;\n }\n}\n","import type { LlmProvider, LlmConfig } from '../types.js';\n\nexport interface ChatMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\ninterface OpenAIResponse {\n choices: Array<{ message: { content: string } }>;\n usage?: { total_tokens: number };\n}\n\nconst DEFAULT_MODELS: Record<string, string> = {\n openai: 'gpt-4o-mini',\n zhipu: 'glm-4',\n};\n\nconst DEFAULT_BASE_URLS: Record<string, string> = {\n openai: 'https://api.openai.com/v1',\n zhipu: 'https://open.bigmodel.cn/api/paas/v4',\n};\n\n/**\n * Create an OpenAI-compatible LLM provider.\n * Works with OpenAI, Zhipu (GLM), and any OpenAI-compatible API.\n */\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\n const provider = config.provider === 'zhipu' ? 'zhipu' : 'openai';\n const baseUrl = config.baseUrl || DEFAULT_BASE_URLS[provider];\n const model = config.model || DEFAULT_MODELS[provider];\n const maxTokens = config.maxTokens || 2048;\n const temperature = config.temperature ?? 0.3;\n\n if (!config.apiKey) {\n throw new Error(\n `API key is required for ${provider}. Set it in config or via OPENCROC_LLM_API_KEY env variable.`,\n );\n }\n\n return {\n name: provider,\n\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\n const url = `${baseUrl}/chat/completions`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model,\n messages,\n max_tokens: maxTokens,\n temperature,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`LLM API error (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as OpenAIResponse;\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error('LLM returned empty response');\n }\n return content;\n },\n\n estimateTokens(text: string): number {\n // Rough estimate: ~4 chars per token for English, ~2 for CJK\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(otherChars / 4 + cjkChars / 2);\n },\n };\n}\n","import type { LlmProvider, LlmConfig } from '../types.js';\n\ninterface OllamaResponse {\n message: { content: string };\n}\n\n/**\n * Create an Ollama LLM provider for local model inference.\n */\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\n const baseUrl = config.baseUrl || 'http://localhost:11434';\n const model = config.model || 'llama3';\n\n return {\n name: 'ollama',\n\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\n const url = `${baseUrl}/api/chat`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model,\n messages,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as OllamaResponse;\n const content = data.message?.content;\n if (!content) {\n throw new Error('Ollama returned empty response');\n }\n return content;\n },\n\n estimateTokens(text: string): number {\n // Same rough estimate as OpenAI provider\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(otherChars / 4 + cjkChars / 2);\n },\n };\n}\n","import type { LlmProvider, LlmConfig } from '../types.js';\nimport { createOpenAIProvider } from './openai.js';\nimport { createOllamaProvider } from './ollama.js';\n\nexport { createOpenAIProvider } from './openai.js';\nexport { createOllamaProvider } from './ollama.js';\n\n/**\n * Create an LLM provider from config.\n * Resolves apiKey from config or OPENCROC_LLM_API_KEY env variable.\n */\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\n const resolved: LlmConfig = {\n ...config,\n apiKey: config.apiKey || process.env.OPENCROC_LLM_API_KEY,\n };\n\n switch (config.provider) {\n case 'openai':\n case 'zhipu':\n return createOpenAIProvider(resolved);\n case 'ollama':\n return createOllamaProvider(resolved);\n default:\n throw new Error(\n `Unknown LLM provider: \"${config.provider}\". Available: openai, zhipu, ollama`,\n );\n }\n}\n\n/**\n * Token usage tracker — accumulates tokens across multiple LLM calls.\n */\nexport interface TokenTracker {\n track(text: string): void;\n trackChat(messages: Array<{ role: string; content: string }>, response: string): void;\n total: number;\n reset(): void;\n}\n\nexport function createTokenTracker(provider: LlmProvider): TokenTracker {\n let total = 0;\n\n return {\n track(text: string) {\n total += provider.estimateTokens(text);\n },\n\n trackChat(messages: Array<{ role: string; content: string }>, response: string) {\n for (const msg of messages) {\n total += provider.estimateTokens(msg.content);\n }\n total += provider.estimateTokens(response);\n },\n\n get total() {\n return total;\n },\n\n reset() {\n total = 0;\n },\n };\n}\n\n/**\n * System prompts for different LLM use cases in OpenCroc.\n */\nexport const SYSTEM_PROMPTS = {\n failureAnalysis: `You are an expert test failure analyst for an E2E testing framework.\nGiven a test failure error message and its context, analyze the root cause and suggest a fix.\nRespond in JSON format: { \"rootCause\": string, \"category\": string, \"suggestedFix\": string, \"confidence\": number }\nCategories: backend-5xx, timeout, endpoint-not-found, data-constraint, network, frontend-render, test-script, unknown.`,\n\n chainPlanning: `You are an API test chain planner.\nGiven a list of API endpoints and their dependencies, generate an optimal test execution order.\nConsider data dependencies, authentication requirements, and cleanup steps.\nRespond in JSON format: { \"chains\": [{ \"name\": string, \"steps\": [{ \"endpoint\": string, \"method\": string, \"description\": string }] }] }`,\n} as const;\n","import type { SelfHealingConfig, SelfHealingResult, FixOutcome, LlmProvider } from '../types.js';\nimport { SYSTEM_PROMPTS } from '../llm/index.js';\n\nexport type { SelfHealingResult, FixOutcome };\n\nexport interface SelfHealingLoop {\n run(testResultsDir: string): Promise<SelfHealingResult>;\n}\n\nexport interface SelfHealingOptions {\n config: SelfHealingConfig;\n llm?: LlmProvider;\n}\n\n/**\n * Categorize a test failure by heuristic rules.\n */\nexport function categorizeFailure(errorMessage: string): {\n category: string;\n confidence: number;\n} {\n const msg = errorMessage.toLowerCase();\n\n if (/5\\d{2}|internal server error/.test(msg))\n return { category: 'backend-5xx', confidence: 0.9 };\n if (/timeout|timed?\\s*out/.test(msg))\n return { category: 'timeout', confidence: 0.8 };\n if (/404|not found/.test(msg))\n return { category: 'endpoint-not-found', confidence: 0.85 };\n if (/4[0-2]\\d|validation|constraint/.test(msg))\n return { category: 'data-constraint', confidence: 0.75 };\n if (/econnrefused|enotfound|network/.test(msg))\n return { category: 'network', confidence: 0.9 };\n if (/selector|locator|element/.test(msg))\n return { category: 'frontend-render', confidence: 0.7 };\n if (/storage\\s*state|auth|login/.test(msg))\n return { category: 'test-script', confidence: 0.8 };\n\n return { category: 'unknown', confidence: 0.5 };\n}\n\n/**\n * LLM-enhanced failure analysis with heuristic fallback.\n */\nexport async function analyzeFailureWithLLM(\n errorMessage: string,\n llm?: LlmProvider,\n): Promise<{ rootCause: string; category: string; suggestedFix: string; confidence: number }> {\n // Always get heuristic result as fallback\n const heuristic = categorizeFailure(errorMessage);\n\n if (!llm) {\n return {\n rootCause: errorMessage,\n category: heuristic.category,\n suggestedFix: '',\n confidence: heuristic.confidence,\n };\n }\n\n try {\n const response = await llm.chat([\n { role: 'system', content: SYSTEM_PROMPTS.failureAnalysis },\n { role: 'user', content: `Analyze this test failure:\\n\\n${errorMessage}` },\n ]);\n\n const parsed = JSON.parse(response) as {\n rootCause?: string;\n category?: string;\n suggestedFix?: string;\n confidence?: number;\n };\n\n return {\n rootCause: parsed.rootCause || errorMessage,\n category: parsed.category || heuristic.category,\n suggestedFix: parsed.suggestedFix || '',\n confidence: parsed.confidence || heuristic.confidence,\n };\n } catch {\n // LLM failed — fall back to heuristic\n return {\n rootCause: errorMessage,\n category: heuristic.category,\n suggestedFix: '',\n confidence: heuristic.confidence,\n };\n }\n}\n\n/**\n * Attempt a config-only fix: validate and write corrected config JSON.\n */\nasync function attemptConfigFix(\n _testResultsDir: string,\n _mode: SelfHealingConfig['mode'],\n _llm?: LlmProvider,\n): Promise<FixOutcome> {\n // TODO: Load module config → run autoFix validation → write corrected JSON\n // For now, return a no-op outcome\n return {\n success: false,\n scope: 'config-only',\n fixedItems: [],\n rolledBack: false,\n };\n}\n\n/**\n * Create a self-healing loop. Accepts an optional LLM provider for AI-enhanced analysis.\n */\nexport function createSelfHealingLoop(config: SelfHealingConfig, llm?: LlmProvider): SelfHealingLoop {\n return {\n async run(testResultsDir: string): Promise<SelfHealingResult> {\n const maxIterations = config.maxIterations || 3;\n const mode = config.mode || 'config-only';\n const fixed: string[] = [];\n const remaining: string[] = [];\n let iterations = 0;\n let totalTokensUsed = 0;\n\n for (let i = 0; i < maxIterations; i++) {\n iterations = i + 1;\n\n const outcome = await attemptConfigFix(testResultsDir, mode, llm);\n if (outcome.success) {\n fixed.push(...outcome.fixedItems);\n } else {\n remaining.push(`iteration-${i + 1}: no fix applied`);\n }\n\n // Track token usage if LLM is available\n if (llm) {\n totalTokensUsed += llm.estimateTokens(`iteration-${i + 1}`);\n }\n\n // If all fixed, stop early\n if (outcome.success && outcome.fixedItems.length > 0) break;\n }\n\n return {\n iterations,\n fixed,\n remaining,\n totalTokensUsed,\n };\n },\n };\n}\n","import chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { createSelfHealingLoop } from '../../self-healing/index.js';\nimport type { SelfHealingConfig } from '../../types.js';\n\nexport interface HealOptions {\n module?: string;\n maxIterations?: string;\n}\n\nexport async function heal(opts: HealOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Self-Healing\\n'));\n\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n const outDir = config.outDir || './opencroc-output';\n const maxIterations = opts.maxIterations ? parseInt(opts.maxIterations, 10) : 3;\n\n const healingConfig: SelfHealingConfig = {\n enabled: true,\n maxIterations,\n mode: config.selfHealing?.mode || 'config-only',\n };\n\n console.log(chalk.gray(` Mode: ${healingConfig.mode}`));\n console.log(chalk.gray(` Max iterations: ${maxIterations}`));\n\n if (opts.module) {\n console.log(chalk.gray(` Module: ${opts.module}`));\n }\n console.log('');\n\n const loop = createSelfHealingLoop(healingConfig);\n const result = await loop.run(outDir);\n\n // Report results\n console.log(chalk.cyan(' Results:'));\n console.log(` Iterations : ${result.iterations}`);\n console.log(` Fixed : ${result.fixed.length > 0 ? chalk.green(result.fixed.join(', ')) : chalk.gray('(none)')}`);\n console.log(` Remaining : ${result.remaining.length > 0 ? chalk.yellow(result.remaining.join(', ')) : chalk.gray('(none)')}`);\n if (result.totalTokensUsed > 0) {\n console.log(` Tokens used : ${result.totalTokensUsed}`);\n }\n\n console.log('');\n\n if (result.remaining.length > 0) {\n console.log(chalk.yellow(' Some issues could not be auto-fixed. Manual review needed.\\n'));\n } else if (result.fixed.length > 0) {\n console.log(chalk.green(' ✓ All issues resolved.\\n'));\n } else {\n console.log(chalk.gray(' No issues detected.\\n'));\n }\n}\n","/**\n * CI template generators for popular CI/CD platforms.\n *\n * Usage:\n * npx opencroc ci --platform=github\n * npx opencroc ci --platform=gitlab\n */\n\nexport interface CiTemplateOptions {\n /** Node.js version(s). Default: ['20.x'] */\n nodeVersions?: string[];\n /** Install command. Default: 'npm ci' */\n installCommand?: string;\n /** Whether to run self-healing. Default: false */\n selfHeal?: boolean;\n /** Custom opencroc generate args */\n generateArgs?: string;\n /** Custom opencroc test args */\n testArgs?: string;\n}\n\nexport function generateGitHubActionsTemplate(opts: CiTemplateOptions = {}): string {\n const nodeVersions = opts.nodeVersions ?? ['20.x'];\n const install = opts.installCommand ?? 'npm ci';\n const genArgs = opts.generateArgs ?? '--all';\n const testArgs = opts.testArgs ?? '';\n const healStep = opts.selfHeal\n ? `\n - name: Self-heal failures\n if: failure()\n run: npx opencroc heal --max-iterations 3`\n : '';\n\n const matrix =\n nodeVersions.length > 1\n ? `\n strategy:\n matrix:\n node-version: [${nodeVersions.join(', ')}]`\n : '';\n\n const nodeSetup =\n nodeVersions.length > 1\n ? '${{ matrix.node-version }}'\n : nodeVersions[0];\n\n return `# Generated by OpenCroc — AI-native E2E testing\n# https://github.com/opencroc/opencroc\n\nname: OpenCroc E2E\n\non:\n push:\n branches: [main]\n pull_request:\n branches: [main]\n\njobs:\n e2e:\n runs-on: ubuntu-latest${matrix}\n steps:\n - uses: actions/checkout@v4\n\n - uses: actions/setup-node@v4\n with:\n node-version: '${nodeSetup}'\n\n - name: Install dependencies\n run: ${install}\n\n - name: Install Playwright browsers\n run: npx playwright install --with-deps chromium\n\n - name: Generate E2E tests\n run: npx opencroc generate ${genArgs}\n\n - name: Run E2E tests\n run: npx opencroc test ${testArgs}\n${healStep}\n - name: Upload test report\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: opencroc-report\n path: opencroc-output/\n retention-days: 14\n`;\n}\n\nexport function generateGitLabCITemplate(opts: CiTemplateOptions = {}): string {\n const install = opts.installCommand ?? 'npm ci';\n const genArgs = opts.generateArgs ?? '--all';\n const testArgs = opts.testArgs ?? '';\n const nodeVersion = opts.nodeVersions?.[0] ?? '20';\n\n return `# Generated by OpenCroc — AI-native E2E testing\n# https://github.com/opencroc/opencroc\n\nimage: node:${nodeVersion}\n\nstages:\n - generate\n - test\n\nvariables:\n PLAYWRIGHT_BROWSERS_PATH: \\${CI_PROJECT_DIR}/.cache/ms-playwright\n\ncache:\n key: \\${CI_COMMIT_REF_SLUG}\n paths:\n - node_modules/\n - .cache/ms-playwright/\n\ngenerate:\n stage: generate\n script:\n - ${install}\n - npx opencroc generate ${genArgs}\n artifacts:\n paths:\n - opencroc-output/\n expire_in: 1 day\n\ne2e:\n stage: test\n needs: [generate]\n before_script:\n - ${install}\n - npx playwright install --with-deps chromium\n script:\n - npx opencroc test ${testArgs}\n artifacts:\n when: always\n paths:\n - opencroc-output/\n expire_in: 14 days\n`;\n}\n\nconst TEMPLATES: Record<string, (opts: CiTemplateOptions) => string> = {\n github: generateGitHubActionsTemplate,\n gitlab: generateGitLabCITemplate,\n};\n\n/**\n * Get available CI platform names.\n */\nexport function listCiPlatforms(): string[] {\n return Object.keys(TEMPLATES);\n}\n\n/**\n * Generate a CI template for the given platform.\n */\nexport function generateCiTemplate(\n platform: string,\n opts: CiTemplateOptions = {},\n): string {\n const generator = TEMPLATES[platform];\n if (!generator) {\n throw new Error(\n `Unknown CI platform: \"${platform}\". Available: ${Object.keys(TEMPLATES).join(', ')}`,\n );\n }\n return generator(opts);\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { generateCiTemplate, listCiPlatforms } from '../../ci/index.js';\nimport type { CiTemplateOptions } from '../../ci/index.js';\n\nexport interface CiCommandOptions {\n platform?: string;\n selfHeal?: boolean;\n node?: string;\n}\n\nexport async function ci(opts: CiCommandOptions): Promise<void> {\n const platform = opts.platform ?? 'github';\n const available = listCiPlatforms();\n\n if (!available.includes(platform)) {\n console.error(chalk.red(`Unknown platform: \"${platform}\". Available: ${available.join(', ')}`));\n process.exitCode = 1;\n return;\n }\n\n const templateOpts: CiTemplateOptions = {\n selfHeal: opts.selfHeal ?? false,\n };\n if (opts.node) {\n templateOpts.nodeVersions = opts.node.split(',').map((s) => s.trim());\n }\n\n const content = generateCiTemplate(platform, templateOpts);\n\n let outputPath: string;\n if (platform === 'github') {\n outputPath = path.join('.github', 'workflows', 'opencroc.yml');\n } else if (platform === 'gitlab') {\n outputPath = '.gitlab-ci.yml';\n } else {\n outputPath = `opencroc-ci-${platform}.yml`;\n }\n\n const dir = path.dirname(outputPath);\n if (dir !== '.' && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, content, 'utf-8');\n console.log(chalk.green(`✔ CI template written to ${outputPath}`));\n console.log(chalk.dim(` Platform: ${platform}`));\n}\n","import type {\n PipelineRunResult,\n ERDiagramResult,\n ChainPlanResult,\n GeneratedTestFile,\n ValidationError,\n} from '../types.js';\n\n// ===== Reporter Types =====\n\nexport interface ReportOutput {\n format: 'html' | 'json' | 'markdown';\n content: string;\n filename: string;\n}\n\n// ===== JSON Reporter =====\n\nexport function generateJsonReport(result: PipelineRunResult): ReportOutput {\n const serializable = {\n modules: result.modules,\n erDiagrams: Object.fromEntries(\n Array.from(result.erDiagrams.entries()).map(([k, v]) => [\n k,\n { tables: v.tables.length, relations: v.relations.length, mermaidText: v.mermaidText },\n ]),\n ),\n chainPlans: Object.fromEntries(\n Array.from(result.chainPlans.entries()).map(([k, v]) => [\n k,\n { chains: v.chains.length, totalSteps: v.totalSteps },\n ]),\n ),\n generatedFiles: result.generatedFiles.map((f) => ({\n filePath: f.filePath,\n module: f.module,\n chain: f.chain,\n })),\n validationErrors: result.validationErrors,\n duration: result.duration,\n };\n\n return {\n format: 'json',\n content: JSON.stringify(serializable, null, 2),\n filename: 'opencroc-report.json',\n };\n}\n\n// ===== Markdown Reporter =====\n\nexport function generateMarkdownReport(result: PipelineRunResult): ReportOutput {\n const lines: string[] = [\n '# OpenCroc Report',\n '',\n `**Duration**: ${result.duration}ms`,\n `**Modules**: ${result.modules.length} (${result.modules.join(', ')})`,\n '',\n '## ER Diagrams',\n '',\n ];\n\n for (const [mod, er] of result.erDiagrams) {\n lines.push(`### ${mod}`);\n lines.push(`- Tables: ${er.tables.length}`);\n lines.push(`- Relations: ${er.relations.length}`);\n lines.push('');\n }\n\n lines.push('## Chain Plans', '');\n for (const [mod, plan] of result.chainPlans) {\n lines.push(`### ${mod}`);\n lines.push(`- Chains: ${plan.chains.length}`);\n lines.push(`- Total Steps: ${plan.totalSteps}`);\n lines.push('');\n }\n\n lines.push(`## Generated Files (${result.generatedFiles.length})`, '');\n for (const f of result.generatedFiles) {\n lines.push(`- \\`${f.filePath}\\` (${f.module} / ${f.chain})`);\n }\n\n if (result.validationErrors.length > 0) {\n lines.push('', '## Validation Issues', '');\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\n if (errors.length > 0) {\n lines.push(`### Errors (${errors.length})`, '');\n for (const e of errors) {\n lines.push(`- **[${e.module}]** ${e.field}: ${e.message}`);\n }\n }\n if (warnings.length > 0) {\n lines.push(`### Warnings (${warnings.length})`, '');\n for (const w of warnings) {\n lines.push(`- **[${w.module}]** ${w.field}: ${w.message}`);\n }\n }\n }\n\n lines.push('', '---', '*Generated by [OpenCroc](https://github.com/opencroc/opencroc)*');\n\n return {\n format: 'markdown',\n content: lines.join('\\n'),\n filename: 'opencroc-report.md',\n };\n}\n\n// ===== HTML Reporter =====\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nfunction erSummaryRows(erDiagrams: Map<string, ERDiagramResult>): string {\n const rows: string[] = [];\n for (const [mod, er] of erDiagrams) {\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${er.tables.length}</td><td>${er.relations.length}</td></tr>`);\n }\n return rows.join('\\n');\n}\n\nfunction chainSummaryRows(chainPlans: Map<string, ChainPlanResult>): string {\n const rows: string[] = [];\n for (const [mod, plan] of chainPlans) {\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${plan.chains.length}</td><td>${plan.totalSteps}</td></tr>`);\n }\n return rows.join('\\n');\n}\n\nfunction fileListRows(files: GeneratedTestFile[]): string {\n return files\n .map((f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`)\n .join('\\n');\n}\n\nfunction validationRows(errors: ValidationError[]): string {\n return errors\n .map(\n (e) =>\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>`,\n )\n .join('\\n');\n}\n\nexport function generateHtmlReport(result: PipelineRunResult): ReportOutput {\n const totalTables = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.tables.length, 0);\n const totalRelations = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.relations.length, 0);\n const totalChains = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.chains.length, 0);\n const totalSteps = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.totalSteps, 0);\n const errorCount = result.validationErrors.filter((e) => e.severity === 'error').length;\n const warnCount = result.validationErrors.filter((e) => e.severity === 'warning').length;\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>OpenCroc Report</title>\n<style>\n :root { --bg: #0d1117; --fg: #c9d1d9; --card: #161b22; --border: #30363d; --accent: #58a6ff; --green: #3fb950; --yellow: #d29922; --red: #f85149; }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--fg); padding: 2rem; }\n h1 { color: var(--accent); margin-bottom: 0.25rem; }\n .subtitle { color: #8b949e; margin-bottom: 2rem; }\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\n .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }\n .card .label { font-size: 0.85rem; color: #8b949e; }\n .card .value { font-size: 2rem; font-weight: 700; color: var(--accent); }\n .card .value.green { color: var(--green); }\n .card .value.yellow { color: var(--yellow); }\n .card .value.red { color: var(--red); }\n section { margin-bottom: 2rem; }\n h2 { color: var(--fg); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }\n table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 8px; overflow: hidden; }\n th, td { text-align: left; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }\n th { background: #21262d; color: #8b949e; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; }\n tr:last-child td { border-bottom: none; }\n code { background: #21262d; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; }\n .badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }\n .badge.error { background: rgba(248,81,73,0.15); color: var(--red); }\n .badge.warning { background: rgba(210,153,34,0.15); color: var(--yellow); }\n footer { margin-top: 3rem; text-align: center; color: #484f58; font-size: 0.85rem; }\n footer a { color: var(--accent); text-decoration: none; }\n</style>\n</head>\n<body>\n<h1>OpenCroc Report</h1>\n<p class=\"subtitle\">Generated in ${result.duration}ms · ${result.modules.length} module(s)</p>\n\n<div class=\"grid\">\n <div class=\"card\"><div class=\"label\">Modules</div><div class=\"value\">${result.modules.length}</div></div>\n <div class=\"card\"><div class=\"label\">Tables</div><div class=\"value\">${totalTables}</div></div>\n <div class=\"card\"><div class=\"label\">Relations</div><div class=\"value\">${totalRelations}</div></div>\n <div class=\"card\"><div class=\"label\">Chains</div><div class=\"value\">${totalChains}</div></div>\n <div class=\"card\"><div class=\"label\">Steps</div><div class=\"value\">${totalSteps}</div></div>\n <div class=\"card\"><div class=\"label\">Files</div><div class=\"value green\">${result.generatedFiles.length}</div></div>\n <div class=\"card\"><div class=\"label\">Errors</div><div class=\"value${errorCount > 0 ? ' red' : ''}\">${errorCount}</div></div>\n <div class=\"card\"><div class=\"label\">Warnings</div><div class=\"value${warnCount > 0 ? ' yellow' : ''}\">${warnCount}</div></div>\n</div>\n\n<section>\n<h2>ER Diagrams</h2>\n<table>\n<thead><tr><th>Module</th><th>Tables</th><th>Relations</th></tr></thead>\n<tbody>${erSummaryRows(result.erDiagrams)}</tbody>\n</table>\n</section>\n\n<section>\n<h2>Chain Plans</h2>\n<table>\n<thead><tr><th>Module</th><th>Chains</th><th>Steps</th></tr></thead>\n<tbody>${chainSummaryRows(result.chainPlans)}</tbody>\n</table>\n</section>\n\n<section>\n<h2>Generated Files (${result.generatedFiles.length})</h2>\n<table>\n<thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\n<tbody>${fileListRows(result.generatedFiles)}</tbody>\n</table>\n</section>\n\n${\n result.validationErrors.length > 0\n ? `<section>\n<h2>Validation Issues (${result.validationErrors.length})</h2>\n<table>\n<thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\n<tbody>${validationRows(result.validationErrors)}</tbody>\n</table>\n</section>`\n : ''\n}\n\n<footer>\n Generated by <a href=\"https://github.com/opencroc/opencroc\">OpenCroc</a>\n</footer>\n</body>\n</html>`;\n\n return {\n format: 'html',\n content: html,\n filename: 'opencroc-report.html',\n };\n}\n\n// ===== Report Orchestrator =====\n\nconst REPORTERS: Record<string, (result: PipelineRunResult) => ReportOutput> = {\n html: generateHtmlReport,\n json: generateJsonReport,\n markdown: generateMarkdownReport,\n};\n\n/**\n * Generate reports in the specified formats.\n */\nexport function generateReports(\n result: PipelineRunResult,\n formats: ('html' | 'json' | 'markdown')[] = ['html'],\n): ReportOutput[] {\n return formats.map((fmt) => {\n const gen = REPORTERS[fmt];\n if (!gen) throw new Error(`Unknown report format: \"${fmt}\". Available: ${Object.keys(REPORTERS).join(', ')}`);\n return gen(result);\n });\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport { generateReports } from '../../reporters/index.js';\n\nexport interface ReportCommandOptions {\n format?: string;\n output?: string;\n}\n\nexport async function report(opts: ReportCommandOptions): Promise<void> {\n let loaded;\n try {\n loaded = await loadConfig();\n } catch {\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\n process.exitCode = 1;\n return;\n }\n\n const { config } = loaded;\n\n console.log(chalk.cyan('Running pipeline to generate report...'));\n const pipeline = createPipeline(config);\n const result = await pipeline.run();\n\n const formats = (opts.format ?? 'html').split(',').map((s) => s.trim()) as ('html' | 'json' | 'markdown')[];\n const reports = generateReports(result, formats);\n\n const outDir = opts.output ?? config.outDir ?? './opencroc-output';\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n\n for (const r of reports) {\n const filePath = path.join(outDir, r.filename);\n fs.writeFileSync(filePath, r.content, 'utf-8');\n console.log(chalk.green(`✔ ${r.format} report → ${filePath}`));\n }\n\n console.log(chalk.dim(` ${result.modules.length} modules, ${result.generatedFiles.length} files, ${result.duration}ms`));\n}\n","import type { PipelineRunResult } from '../types.js';\n\nexport interface DashboardData {\n generatedAt: string;\n durationMs: number;\n modules: string[];\n totals: {\n modules: number;\n tables: number;\n relations: number;\n chains: number;\n steps: number;\n files: number;\n errors: number;\n warnings: number;\n };\n moduleCards: Array<{\n module: string;\n tables: number;\n relations: number;\n chains: number;\n steps: number;\n }>;\n files: Array<{ filePath: string; module: string; chain: string }>;\n issues: Array<{ severity: string; module: string; field: string; message: string }>;\n}\n\nexport interface DashboardOutput {\n filename: string;\n content: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction number(v: unknown): number {\n return typeof v === 'number' && Number.isFinite(v) ? v : 0;\n}\n\nexport function buildDashboardDataFromPipeline(result: PipelineRunResult): DashboardData {\n const moduleCards = result.modules.map((mod) => {\n const er = result.erDiagrams.get(mod);\n const plan = result.chainPlans.get(mod);\n return {\n module: mod,\n tables: er?.tables.length ?? 0,\n relations: er?.relations.length ?? 0,\n chains: plan?.chains.length ?? 0,\n steps: plan?.totalSteps ?? 0,\n };\n });\n\n const totals = {\n modules: result.modules.length,\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\n files: result.generatedFiles.length,\n errors: result.validationErrors.filter((e) => e.severity === 'error').length,\n warnings: result.validationErrors.filter((e) => e.severity === 'warning').length,\n };\n\n return {\n generatedAt: new Date().toISOString(),\n durationMs: result.duration,\n modules: [...result.modules],\n totals,\n moduleCards,\n files: result.generatedFiles.map((f) => ({ filePath: f.filePath, module: f.module, chain: f.chain })),\n issues: result.validationErrors.map((e) => ({\n severity: e.severity,\n module: e.module,\n field: e.field,\n message: e.message,\n })),\n };\n}\n\nexport function buildDashboardDataFromReportJson(input: unknown): DashboardData {\n const src = (input ?? {}) as Record<string, unknown>;\n const modules = Array.isArray(src.modules) ? src.modules.map((m) => String(m)) : [];\n const er = (src.erDiagrams ?? {}) as Record<string, { tables?: unknown; relations?: unknown }>;\n const plans = (src.chainPlans ?? {}) as Record<string, { chains?: unknown; totalSteps?: unknown }>;\n const files = Array.isArray(src.generatedFiles)\n ? src.generatedFiles.map((f) => {\n const row = f as Record<string, unknown>;\n return {\n filePath: String(row.filePath ?? ''),\n module: String(row.module ?? ''),\n chain: String(row.chain ?? ''),\n };\n })\n : [];\n\n const rawIssues = Array.isArray(src.validationErrors) ? src.validationErrors : [];\n const issues = rawIssues.map((item) => {\n const row = item as Record<string, unknown>;\n return {\n severity: String(row.severity ?? 'warning'),\n module: String(row.module ?? 'unknown'),\n field: String(row.field ?? 'unknown'),\n message: String(row.message ?? ''),\n };\n });\n\n const moduleCards = modules.map((mod) => ({\n module: mod,\n tables: number(er[mod]?.tables),\n relations: number(er[mod]?.relations),\n chains: number(plans[mod]?.chains),\n steps: number(plans[mod]?.totalSteps),\n }));\n\n return {\n generatedAt: new Date().toISOString(),\n durationMs: number(src.duration),\n modules,\n totals: {\n modules: modules.length,\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\n files: files.length,\n errors: issues.filter((i) => i.severity === 'error').length,\n warnings: issues.filter((i) => i.severity === 'warning').length,\n },\n moduleCards,\n files,\n issues,\n };\n}\n\nexport function generateVisualDashboardHtml(data: DashboardData): string {\n const moduleCardHtml = data.moduleCards\n .map(\n (m) => `<article class=\"module-card reveal\">\n <h3>${escapeHtml(m.module)}</h3>\n <div class=\"meta\">${m.tables} tables · ${m.relations} relations</div>\n <div class=\"bars\">\n <div class=\"bar\"><span>Chains</span><strong>${m.chains}</strong></div>\n <div class=\"bar\"><span>Steps</span><strong>${m.steps}</strong></div>\n </div>\n</article>`,\n )\n .join('\\n');\n\n const fileRows = data.files\n .slice(0, 20)\n .map(\n (f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`,\n )\n .join('\\n');\n\n const issueRows = data.issues\n .map(\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>`,\n )\n .join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>OpenCroc Visual Dashboard</title>\n <style>\n @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');\n :root {\n --bg: #f4efe6;\n --ink: #18222c;\n --card: #fff8ef;\n --line: #d8c7b4;\n --accent: #0b7a75;\n --accent-2: #f26a2e;\n --ok: #2f7d32;\n --warn: #b7791f;\n --err: #c0392b;\n }\n * { box-sizing: border-box; }\n body {\n margin: 0;\n font-family: 'Space Grotesk', 'Segoe UI', sans-serif;\n color: var(--ink);\n background:\n radial-gradient(circle at 15% 10%, #f9e2c5 0%, transparent 32%),\n radial-gradient(circle at 85% 0%, #d3efe4 0%, transparent 28%),\n var(--bg);\n min-height: 100vh;\n }\n .wrap { max-width: 1160px; margin: 0 auto; padding: 24px 18px 40px; }\n .hero {\n border: 2px solid var(--line);\n border-radius: 18px;\n background: linear-gradient(130deg, #fff8ef 0%, #f8f2ea 45%, #f3ece3 100%);\n padding: 22px;\n box-shadow: 0 12px 24px rgba(24, 34, 44, 0.08);\n position: relative;\n overflow: hidden;\n }\n .hero::after {\n content: '';\n position: absolute;\n right: -42px;\n top: -38px;\n width: 160px;\n height: 160px;\n border-radius: 50%;\n background: conic-gradient(from 50deg, #f26a2e 0deg, #f7a35a 90deg, #0b7a75 220deg, #f26a2e 360deg);\n opacity: 0.14;\n }\n h1 { margin: 0; font-size: clamp(1.6rem, 3vw, 2.5rem); letter-spacing: -0.03em; }\n .subtitle { margin-top: 8px; font-size: 0.95rem; opacity: 0.82; }\n .kpi-grid {\n margin-top: 16px;\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 10px;\n }\n .kpi {\n border: 1px solid var(--line);\n border-radius: 12px;\n padding: 10px 12px;\n background: #fffdf9;\n }\n .kpi .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }\n .kpi .value { font-size: 1.45rem; font-weight: 700; margin-top: 4px; }\n .kpi.error .value { color: var(--err); }\n .kpi.warning .value { color: var(--warn); }\n .kpi.files .value { color: var(--accent); }\n\n .section-title {\n margin: 24px 0 10px;\n font-size: 1rem;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: #344250;\n }\n\n .module-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 12px;\n }\n .module-card {\n border: 1px solid var(--line);\n border-radius: 14px;\n padding: 14px;\n background: var(--card);\n box-shadow: 0 8px 16px rgba(24, 34, 44, 0.06);\n }\n .module-card h3 { margin: 0 0 6px; font-size: 1.05rem; }\n .module-card .meta { font-size: 0.85rem; opacity: 0.78; }\n .bars { margin-top: 10px; display: grid; gap: 8px; }\n .bar { display: flex; justify-content: space-between; border-top: 1px dashed var(--line); padding-top: 7px; }\n\n table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--line);\n border-radius: 12px;\n overflow: hidden;\n background: #fffdf9;\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\n font-size: 0.82rem;\n }\n thead { background: #efe5d8; }\n th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eadfce; }\n tbody tr:last-child td { border-bottom: none; }\n tr.error td:first-child { color: var(--err); font-weight: 700; }\n tr.warning td:first-child { color: var(--warn); font-weight: 700; }\n\n code {\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\n background: #f5ece0;\n border: 1px solid #eadfce;\n border-radius: 6px;\n padding: 1px 5px;\n }\n\n .reveal { opacity: 0; transform: translateY(12px); animation: rise .55s ease forwards; }\n .module-card.reveal:nth-child(2) { animation-delay: .06s; }\n .module-card.reveal:nth-child(3) { animation-delay: .12s; }\n .module-card.reveal:nth-child(4) { animation-delay: .18s; }\n .module-card.reveal:nth-child(5) { animation-delay: .24s; }\n @keyframes rise {\n to { opacity: 1; transform: translateY(0); }\n }\n\n @media (max-width: 700px) {\n .wrap { padding: 14px 12px 28px; }\n .hero { padding: 16px; }\n table { font-size: 0.76rem; }\n th, td { padding: 7px 8px; }\n }\n </style>\n</head>\n<body>\n <main class=\"wrap\">\n <section class=\"hero reveal\">\n <h1>OpenCroc Visual Dashboard</h1>\n <p class=\"subtitle\">Pipeline finished in ${data.durationMs}ms · Generated ${escapeHtml(data.generatedAt)}</p>\n <div class=\"kpi-grid\">\n <div class=\"kpi\"><div class=\"label\">Modules</div><div class=\"value\">${data.totals.modules}</div></div>\n <div class=\"kpi\"><div class=\"label\">Tables</div><div class=\"value\">${data.totals.tables}</div></div>\n <div class=\"kpi\"><div class=\"label\">Relations</div><div class=\"value\">${data.totals.relations}</div></div>\n <div class=\"kpi\"><div class=\"label\">Chains</div><div class=\"value\">${data.totals.chains}</div></div>\n <div class=\"kpi\"><div class=\"label\">Steps</div><div class=\"value\">${data.totals.steps}</div></div>\n <div class=\"kpi files\"><div class=\"label\">Files</div><div class=\"value\">${data.totals.files}</div></div>\n <div class=\"kpi error\"><div class=\"label\">Errors</div><div class=\"value\">${data.totals.errors}</div></div>\n <div class=\"kpi warning\"><div class=\"label\">Warnings</div><div class=\"value\">${data.totals.warnings}</div></div>\n </div>\n </section>\n\n <h2 class=\"section-title\">Module Health</h2>\n <section class=\"module-grid\">\n ${moduleCardHtml || '<article class=\"module-card\">No module data</article>'}\n </section>\n\n <h2 class=\"section-title\">Generated Files (Top 20)</h2>\n <section>\n <table>\n <thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\n <tbody>${fileRows || '<tr><td colspan=\"3\">No files generated</td></tr>'}</tbody>\n </table>\n </section>\n\n <h2 class=\"section-title\">Validation Issues</h2>\n <section>\n <table>\n <thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\n <tbody>${issueRows || '<tr><td colspan=\"4\">No validation issues</td></tr>'}</tbody>\n </table>\n </section>\n </main>\n</body>\n</html>`;\n}\n\nexport function generateVisualDashboard(result: PipelineRunResult): DashboardOutput {\n const data = buildDashboardDataFromPipeline(result);\n return {\n filename: 'opencroc-dashboard.html',\n content: generateVisualDashboardHtml(data),\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport {\n buildDashboardDataFromReportJson,\n buildDashboardDataFromPipeline,\n generateVisualDashboardHtml,\n} from '../../dashboard/index.js';\n\nexport interface DashboardCommandOptions {\n output?: string;\n input?: string;\n}\n\nexport async function dashboard(opts: DashboardCommandOptions): Promise<void> {\n let dashboardHtml: string;\n\n if (opts.input) {\n const inputPath = path.resolve(opts.input);\n if (!fs.existsSync(inputPath)) {\n console.error(chalk.red(`Input report not found: ${inputPath}`));\n process.exitCode = 1;\n return;\n }\n\n const raw = fs.readFileSync(inputPath, 'utf-8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n console.error(chalk.red('Invalid JSON input. Please provide opencroc-report.json output.'));\n process.exitCode = 1;\n return;\n }\n\n const data = buildDashboardDataFromReportJson(parsed);\n dashboardHtml = generateVisualDashboardHtml(data);\n console.log(chalk.cyan(`Building visual dashboard from ${inputPath}...`));\n } else {\n let loaded;\n try {\n loaded = await loadConfig();\n } catch {\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\n process.exitCode = 1;\n return;\n }\n\n const { config } = loaded;\n console.log(chalk.cyan('Running pipeline to build visual dashboard...'));\n const pipeline = createPipeline(config);\n const result = await pipeline.run();\n\n const data = buildDashboardDataFromPipeline(result);\n dashboardHtml = generateVisualDashboardHtml(data);\n }\n\n const outDir = opts.output ? path.resolve(opts.output) : path.resolve('./opencroc-output');\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n\n const outPath = path.join(outDir, 'opencroc-dashboard.html');\n fs.writeFileSync(outPath, dashboardHtml, 'utf-8');\n console.log(chalk.green(`✔ visual dashboard → ${outPath}`));\n}\n","#!/usr/bin/env node\n\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n .name('opencroc')\n .description('AI-native E2E testing framework')\n .version('0.6.0');\n\nprogram\n .command('init')\n .description('Initialize OpenCroc in the current project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .action(async (opts) => {\n const { initProject } = await import('./commands/init.js');\n await initProject(opts);\n });\n\nprogram\n .command('generate')\n .description('Generate E2E test cases from source code')\n .option('-m, --module <name>', 'Generate for a specific module')\n .option('-a, --all', 'Generate for all discovered modules')\n .option('--steps <steps>', 'Run specific pipeline steps (comma-separated)')\n .option('--dry-run', 'Preview without writing files')\n .action(async (opts) => {\n const { generate } = await import('./commands/generate.js');\n await generate(opts);\n });\n\nprogram\n .command('test')\n .description('Run generated E2E tests')\n .option('-m, --module <name>', 'Run tests for a specific module')\n .option('--headed', 'Run in headed browser mode')\n .action(async (opts) => {\n const { runTests } = await import('./commands/test.js');\n await runTests(opts);\n });\n\nprogram\n .command('validate')\n .description('Validate module configurations and generated tests')\n .option('-m, --module <name>', 'Validate a specific module')\n .action(async (opts) => {\n const { validate } = await import('./commands/validate.js');\n await validate(opts);\n });\n\nprogram\n .command('heal')\n .description('Run self-healing loop on failed tests')\n .option('-m, --module <name>', 'Heal a specific module')\n .option('--max-iterations <n>', 'Maximum healing iterations', '3')\n .action(async (opts) => {\n const { heal } = await import('./commands/heal.js');\n await heal(opts);\n });\n\nprogram\n .command('ci')\n .description('Generate CI/CD pipeline template')\n .option('-p, --platform <name>', 'CI platform (github, gitlab)', 'github')\n .option('--self-heal', 'Include self-healing step')\n .option('--node <versions>', 'Node.js versions (comma-separated)', '20.x')\n .action(async (opts) => {\n const { ci } = await import('./commands/ci.js');\n await ci(opts);\n });\n\nprogram\n .command('report')\n .description('Generate pipeline report (HTML/JSON/Markdown)')\n .option('-f, --format <formats>', 'Report formats (comma-separated)', 'html')\n .option('-o, --output <dir>', 'Output directory')\n .action(async (opts) => {\n const { report } = await import('./commands/report.js');\n await report(opts);\n });\n\nprogram\n .command('dashboard')\n .description('Generate visual dashboard (opencroc-dashboard.html)')\n .option('-i, --input <file>', 'Build from existing opencroc-report.json file')\n .option('-o, --output <dir>', 'Output directory', './opencroc-output')\n .action(async (opts) => {\n const { dashboard } = await import('./commands/dashboard.js');\n await dashboard(opts);\n });\n\nprogram.parse();\n"],"mappings":"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","names":["path","fs","path","Project","SyntaxKind","fullPath","fs","path","Project","SyntaxKind","producer","path","report","fs","path","chalk","writeFileSync","mkdirSync","existsSync","VALID_STEPS","chalk","readdirSync","existsSync","join","resolve","chalk","chalk","fs","path","chalk","init_ci","fs","path","chalk","escapeHtml","fs","path","chalk","init_dashboard","initProject","generate","runTests","validate","heal","ci","report","dashboard"]}
|
|
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/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/index.ts","../../src/cli/commands/heal.ts","../../src/ci/index.ts","../../src/cli/commands/ci.ts","../../src/reporters/index.ts","../../src/cli/commands/report.ts","../../src/dashboard/index.ts","../../src/cli/commands/dashboard.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';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createInterface } from 'node:readline/promises';\nimport { stdin, stdout } from 'node:process';\n\nconst ADAPTERS = ['sequelize', 'typeorm', 'prisma'] as const;\nconst LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'none'] as const;\n\nexport interface InitAnswers {\n backendRoot: string;\n adapter: string;\n llmProvider: string;\n outDir: string;\n}\n\nconst DEFAULTS: InitAnswers = {\n backendRoot: './backend',\n adapter: 'sequelize',\n llmProvider: 'openai',\n outDir: './opencroc-output',\n};\n\nexport function buildConfigContent(answers: InitAnswers): string {\n const llmBlock =\n answers.llmProvider === 'none'\n ? ''\n : `\n llm: {\n provider: '${answers.llmProvider}',${answers.llmProvider === 'ollama' ? '' : \"\\n // apiKey: process.env.OPENCROC_LLM_API_KEY,\"}\n model: '${answers.llmProvider === 'zhipu' ? 'glm-4' : answers.llmProvider === 'ollama' ? 'llama3' : 'gpt-4o-mini'}',\n },`;\n\n return `import { defineConfig } from 'opencroc';\n\nexport default defineConfig({\n backendRoot: '${answers.backendRoot}',\n adapter: '${answers.adapter}',${llmBlock}\n outDir: '${answers.outDir}',\n selfHealing: {\n enabled: true,\n maxIterations: 3,\n },\n});\n`;\n}\n\nasync function prompt(\n rl: ReturnType<typeof createInterface>,\n question: string,\n defaultValue: string,\n): Promise<string> {\n const answer = await rl.question(` ${question} ${chalk.gray(`(${defaultValue})`)}: `);\n return answer.trim() || defaultValue;\n}\n\nasync function promptChoice(\n rl: ReturnType<typeof createInterface>,\n question: string,\n choices: readonly string[],\n defaultValue: string,\n): Promise<string> {\n const list = choices\n .map((c) => (c === defaultValue ? chalk.underline(c) : c))\n .join(' / ');\n const answer = await rl.question(` ${question} [${list}]: `);\n const trimmed = answer.trim().toLowerCase();\n if (!trimmed) return defaultValue;\n return choices.find((c) => c.toLowerCase() === trimmed) || defaultValue;\n}\n\nasync function collectAnswers(): Promise<InitAnswers> {\n const rl = createInterface({ input: stdin, output: stdout });\n try {\n const backendRoot = await prompt(rl, 'Backend source root', DEFAULTS.backendRoot);\n const adapter = await promptChoice(rl, 'ORM adapter', ADAPTERS, DEFAULTS.adapter);\n const llmProvider = await promptChoice(rl, 'LLM provider', LLM_PROVIDERS, DEFAULTS.llmProvider);\n const outDir = await prompt(rl, 'Test output directory', DEFAULTS.outDir);\n return { backendRoot, adapter, llmProvider, outDir };\n } finally {\n rl.close();\n }\n}\n\nfunction writeProject(cwd: string, answers: InitAnswers): void {\n const configPath = join(cwd, 'opencroc.config.ts');\n writeFileSync(configPath, buildConfigContent(answers), 'utf-8');\n console.log(chalk.green(' ✓ Created opencroc.config.ts'));\n\n const outputDir = join(cwd, answers.outDir);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { recursive: true });\n console.log(chalk.green(` ✓ Created ${answers.outDir}/`));\n }\n}\n\nfunction printNextSteps(answers: InitAnswers): void {\n const needsKey = answers.llmProvider !== 'none' && answers.llmProvider !== 'ollama';\n console.log('');\n console.log(chalk.cyan(' Next steps:'));\n let step = 1;\n console.log(` ${step++}. Review opencroc.config.ts`);\n if (needsKey) {\n console.log(` ${step++}. Set OPENCROC_LLM_API_KEY environment variable`);\n }\n console.log(` ${step++}. npx opencroc generate --all`);\n console.log(` ${step}. npx opencroc test`);\n}\n\nexport async function initProject(opts?: { yes?: boolean }): Promise<void> {\n const cwd = process.cwd();\n const configPath = join(cwd, 'opencroc.config.ts');\n\n if (existsSync(configPath)) {\n console.log(chalk.yellow('\\n ⚠ opencroc.config.ts already exists. Skipping.\\n'));\n return;\n }\n\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Project Setup\\n'));\n\n const answers = opts?.yes ? { ...DEFAULTS } : await collectAnswers();\n\n console.log('');\n writeProject(cwd, answers);\n printNextSteps(answers);\n console.log('');\n}\n","import { cosmiconfig } from 'cosmiconfig';\nimport type { OpenCrocConfig } from '../types.js';\n\nconst MODULE_NAME = 'opencroc';\n\nconst SEARCH_PLACES = [\n 'opencroc.config.ts',\n 'opencroc.config.js',\n 'opencroc.config.json',\n '.opencrocrc.json',\n 'package.json',\n];\n\nexport interface LoadConfigResult {\n config: OpenCrocConfig;\n filepath: string;\n}\n\nexport async function loadConfig(cwd?: string): Promise<LoadConfigResult> {\n const explorer = cosmiconfig(MODULE_NAME, {\n searchPlaces: SEARCH_PLACES,\n ...(cwd ? { stopDir: cwd } : {}),\n });\n\n const result = cwd ? await explorer.search(cwd) : await explorer.search();\n\n if (!result || result.isEmpty) {\n throw new Error(\n 'No opencroc config found. Run `opencroc init` to create one.',\n );\n }\n\n const config: OpenCrocConfig =\n result.config?.default ?? result.config;\n\n if (!config.backendRoot) {\n throw new Error(\n `Invalid config in ${result.filepath}: \"backendRoot\" is required.`,\n );\n }\n\n return { config, filepath: result.filepath };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n Project,\n SyntaxKind,\n type CallExpression,\n type ObjectLiteralExpression,\n type PropertyAssignment,\n type Node,\n} from 'ts-morph';\nimport type { TableSchema, FieldSchema, IndexSchema } from '../types.js';\n\nexport interface ModelParser {\n parseFile(filePath: string): Promise<TableSchema | null>;\n parseDirectory(dirPath: string): Promise<TableSchema[]>;\n}\n\n/**\n * Parse a single Sequelize Model file and extract TableSchema.\n */\nexport function parseModelFile(filePath: string): TableSchema | null {\n const absolutePath = path.resolve(filePath);\n if (!fs.existsSync(absolutePath)) return null;\n\n const project = new Project({ compilerOptions: { strict: false } });\n const sourceFile = project.addSourceFileAtPath(absolutePath);\n\n const initCall = findInitCall(sourceFile);\n if (!initCall) return null;\n\n const args = initCall.getArguments();\n if (args.length < 2) return null;\n\n const fields = parseFieldDefinitions(args[0]);\n const { tableName, indexes } = parseOptions(args[1]);\n\n if (!tableName) return null;\n\n return { tableName, fields, indexes };\n}\n\n/**\n * Batch parse all Model files in a directory.\n */\nexport function parseModuleModels(modelDir: string): TableSchema[] {\n const absoluteDir = path.resolve(modelDir);\n if (!fs.existsSync(absoluteDir)) return [];\n\n const files = fs.readdirSync(absoluteDir).filter((f) =>\n f.endsWith('.ts') &&\n !f.endsWith('.test.ts') &&\n !f.endsWith('.spec.ts') &&\n f !== 'index.ts' &&\n f !== 'associations.ts',\n );\n\n const schemas: TableSchema[] = [];\n for (const file of files) {\n try {\n const schema = parseModelFile(path.join(absoluteDir, file));\n if (schema) schemas.push(schema);\n } catch {\n // skip unparseable files\n }\n }\n return schemas;\n}\n\nfunction findInitCall(sourceFile: Node): CallExpression | null {\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n for (const call of calls) {\n const expr = call.getExpression();\n if (expr.getKind() === SyntaxKind.PropertyAccessExpression) {\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\n if (propAccess.getName() === 'init') return call;\n }\n }\n return null;\n}\n\nfunction parseFieldDefinitions(fieldsNode: Node): FieldSchema[] {\n const fields: FieldSchema[] = [];\n if (fieldsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return fields;\n\n const objLiteral = fieldsNode as ObjectLiteralExpression;\n for (const prop of objLiteral.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const propAssign = prop as PropertyAssignment;\n const initializer = propAssign.getInitializer();\n if (!initializer || initializer.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\n fields.push(parseFieldObject(propAssign.getName(), initializer as ObjectLiteralExpression));\n }\n return fields;\n}\n\nfunction parseFieldObject(fieldName: string, fieldObj: ObjectLiteralExpression): FieldSchema {\n const field: FieldSchema = { name: fieldName, type: 'STRING', allowNull: true, primaryKey: false };\n\n for (const prop of fieldObj.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const propAssign = prop as PropertyAssignment;\n const key = propAssign.getName();\n const init = propAssign.getInitializer();\n if (!init) continue;\n\n switch (key) {\n case 'type': field.type = extractDataType(init); break;\n case 'allowNull': field.allowNull = init.getText().trim() === 'true'; break;\n case 'primaryKey': field.primaryKey = init.getText().trim() === 'true'; break;\n case 'defaultValue': field.defaultValue = extractDefaultValue(init); break;\n }\n }\n return field;\n}\n\nfunction extractDataType(node: Node): string {\n const text = node.getText().trim();\n const callMatch = text.match(/^DataTypes\\.(\\w+)\\((.+)\\)$/);\n if (callMatch) return `${callMatch[1]}(${callMatch[2]})`;\n const propMatch = text.match(/^DataTypes\\.(\\w+)$/);\n if (propMatch) return propMatch[1];\n return text;\n}\n\nfunction extractDefaultValue(node: Node): unknown {\n const text = node.getText().trim();\n if (text === 'DataTypes.NOW') return 'DataTypes.NOW';\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\n return text.slice(1, -1);\n if (/^-?\\d+(\\.\\d+)?$/.test(text)) return Number(text);\n if (text === 'true') return true;\n if (text === 'false') return false;\n if (text === 'null') return null;\n return text;\n}\n\nfunction parseOptions(optionsNode: Node): { tableName: string | null; indexes: IndexSchema[] } {\n let tableName: string | null = null;\n let indexes: IndexSchema[] = [];\n\n if (optionsNode.getKind() !== SyntaxKind.ObjectLiteralExpression) return { tableName, indexes };\n\n const objLiteral = optionsNode as ObjectLiteralExpression;\n for (const prop of objLiteral.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const propAssign = prop as PropertyAssignment;\n const key = propAssign.getName();\n const init = propAssign.getInitializer();\n if (!init) continue;\n\n if (key === 'tableName') tableName = extractStringValue(init);\n if (key === 'indexes') indexes = parseIndexes(init);\n }\n return { tableName, indexes };\n}\n\nfunction extractStringValue(node: Node): string | null {\n const text = node.getText().trim();\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\n return text.slice(1, -1);\n return null;\n}\n\nfunction parseIndexes(node: Node): IndexSchema[] {\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\n const indexes: IndexSchema[] = [];\n for (const el of arr.getElements()) {\n if (el.getKind() !== SyntaxKind.ObjectLiteralExpression) continue;\n const idx = parseIndexObject(el as ObjectLiteralExpression);\n if (idx) indexes.push(idx);\n }\n return indexes;\n}\n\nfunction parseIndexObject(obj: ObjectLiteralExpression): IndexSchema | null {\n let name = '';\n let fields: string[] = [];\n let unique = false;\n\n for (const prop of obj.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const pa = prop as PropertyAssignment;\n const init = pa.getInitializer();\n if (!init) continue;\n switch (pa.getName()) {\n case 'name': name = extractStringValue(init) || ''; break;\n case 'fields': fields = extractStringArray(init); break;\n case 'unique': unique = init.getText().trim() === 'true'; break;\n }\n }\n if (!name || fields.length === 0) return null;\n return { name, fields, unique };\n}\n\nfunction extractStringArray(node: Node): string[] {\n if (node.getKind() !== SyntaxKind.ArrayLiteralExpression) return [];\n const arr = node.asKindOrThrow(SyntaxKind.ArrayLiteralExpression);\n return arr.getElements()\n .map((el) => el.getText().trim())\n .filter((t) => (t.startsWith(\"'\") || t.startsWith('\"')))\n .map((t) => t.slice(1, -1));\n}\n\nexport function createModelParser(): ModelParser {\n return {\n async parseFile(filePath: string) {\n return parseModelFile(filePath);\n },\n async parseDirectory(dirPath: string) {\n return parseModuleModels(dirPath);\n },\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n Project,\n SyntaxKind,\n type CallExpression,\n type SourceFile,\n Node,\n type PropertyAccessExpression,\n type Decorator,\n type MethodDeclaration,\n type ObjectLiteralExpression,\n} from 'ts-morph';\nimport type { ApiEndpoint } from '../types.js';\n\nexport interface ControllerParser {\n parseFile(filePath: string): Promise<ApiEndpoint[]>;\n parseDirectory(dirPath: string): Promise<ApiEndpoint[]>;\n}\n\nconst HTTP_METHODS = new Set(['get', 'post', 'put', 'delete', 'patch']);\n\nconst METHOD_MAP: Record<string, string> = {\n get: 'GET', post: 'POST', put: 'PUT', delete: 'DELETE', patch: 'PATCH',\n};\n\nconst NEST_HTTP_DECORATORS = new Set(['get', 'post', 'put', 'delete', 'patch']);\n\n/**\n * Parse a single Controller file and extract API endpoints.\n */\nexport function parseControllerFile(filePath: string): ApiEndpoint[] {\n const absolutePath = path.resolve(filePath);\n if (!fs.existsSync(absolutePath)) return [];\n\n try {\n const project = new Project({ compilerOptions: { strict: false } });\n const sourceFile = project.addSourceFileAtPath(absolutePath);\n\n const endpoints: ApiEndpoint[] = [];\n endpoints.push(...extractRouterCalls(sourceFile));\n endpoints.push(...extractBaseCrudRoutes(sourceFile));\n endpoints.push(...extractNestControllerRoutes(sourceFile));\n\n return deduplicateEndpoints(endpoints);\n } catch {\n return [];\n }\n}\n\n/**\n * Parse all Controller files in a directory.\n */\nexport function parseControllerDirectory(dirPath: string): ApiEndpoint[] {\n const absoluteDir = path.resolve(dirPath);\n if (!fs.existsSync(absoluteDir)) return [];\n\n const files = fs.readdirSync(absoluteDir).filter((f) =>\n f.endsWith('.ts') &&\n !f.endsWith('.test.ts') &&\n !f.endsWith('.spec.ts') &&\n f !== 'index.ts',\n );\n\n const endpoints: ApiEndpoint[] = [];\n for (const file of files) {\n endpoints.push(...parseControllerFile(path.join(absoluteDir, file)));\n }\n return deduplicateEndpoints(endpoints);\n}\n\nfunction extractRouterCalls(sourceFile: SourceFile): ApiEndpoint[] {\n const endpoints: ApiEndpoint[] = [];\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n\n for (const call of calls) {\n const expr = call.getExpression();\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\n\n const propAccess = expr as PropertyAccessExpression;\n const methodName = propAccess.getName().toLowerCase();\n if (!HTTP_METHODS.has(methodName)) continue;\n\n const objectText = propAccess.getExpression().getText().trim();\n if (!isRouterLike(objectText)) continue;\n\n const args = call.getArguments();\n if (args.length === 0) continue;\n\n const routePath = resolveRoutePath(args[0], sourceFile);\n if (!routePath) continue;\n\n endpoints.push({\n method: METHOD_MAP[methodName],\n path: routePath,\n pathParams: extractPathParams(routePath),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: extractDescription(call),\n });\n }\n return endpoints;\n}\n\nfunction isRouterLike(text: string): boolean {\n return text === 'router' || text === 'this.router';\n}\n\nfunction extractBaseCrudRoutes(sourceFile: SourceFile): ApiEndpoint[] {\n const endpoints: ApiEndpoint[] = [];\n\n let isBaseCrud = false;\n for (const cls of sourceFile.getClasses()) {\n const heritage = cls.getExtends();\n if (heritage?.getText().includes('BaseCrudController')) {\n isBaseCrud = true;\n break;\n }\n }\n if (!isBaseCrud) return endpoints;\n\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n let resourcePath: string | null = null;\n\n for (const call of calls) {\n const exprText = call.getExpression().getText();\n if (\n (exprText === 'super.registerRoutes' || exprText.endsWith('.registerRoutes')) &&\n !exprText.includes('Custom')\n ) {\n const args = call.getArguments();\n if (args.length >= 2) resourcePath = extractStringLiteral(args[1]);\n }\n }\n if (!resourcePath) return endpoints;\n\n const basePath = `/v1/:tenantId/${resourcePath}`;\n const crudRoutes: Array<{ method: string; path: string; desc: string }> = [\n { method: 'GET', path: basePath, desc: `List ${resourcePath}` },\n { method: 'GET', path: `${basePath}/:id`, desc: `Get ${resourcePath} by ID` },\n { method: 'POST', path: basePath, desc: `Create ${resourcePath}` },\n { method: 'PUT', path: `${basePath}/:id`, desc: `Update ${resourcePath}` },\n { method: 'DELETE', path: `${basePath}/:id`, desc: `Delete ${resourcePath}` },\n { method: 'POST', path: `${basePath}/batch-delete`, desc: `Batch delete ${resourcePath}` },\n ];\n\n for (const route of crudRoutes) {\n endpoints.push({\n method: route.method,\n path: route.path,\n pathParams: extractPathParams(route.path),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: route.desc,\n });\n }\n return endpoints;\n}\n\nfunction extractNestControllerRoutes(sourceFile: SourceFile): ApiEndpoint[] {\n const endpoints: ApiEndpoint[] = [];\n\n for (const cls of sourceFile.getClasses()) {\n const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === 'controller');\n if (!controllerDecorator) continue;\n\n const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? '');\n\n for (const methodDecl of cls.getMethods()) {\n const requestMapping = extractRequestMapping(methodDecl, sourceFile);\n if (requestMapping) {\n const fullPath = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));\n endpoints.push({\n method: requestMapping.method,\n path: fullPath,\n pathParams: extractPathParams(fullPath),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: extractMethodDescription(methodDecl),\n });\n continue;\n }\n\n const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));\n if (!httpDecorator) continue;\n\n const methodName = httpDecorator.getName().toLowerCase();\n const method = METHOD_MAP[methodName];\n if (!method) continue;\n\n const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? '');\n const fullPath = joinRoutePath(controllerBasePath, methodPath);\n\n endpoints.push({\n method,\n path: fullPath,\n pathParams: extractPathParams(fullPath),\n queryParams: [],\n bodyFields: [],\n responseFields: [],\n relatedTables: [],\n description: extractMethodDescription(methodDecl),\n });\n }\n }\n\n return endpoints;\n}\n\n/**\n * Infer related database table names from Service file imports.\n */\nexport function inferRelatedTables(servicePaths: string[]): string[] {\n const tables = new Set<string>();\n for (const sp of servicePaths) {\n const absolutePath = path.resolve(sp);\n if (!fs.existsSync(absolutePath)) continue;\n try {\n const content = fs.readFileSync(absolutePath, 'utf-8');\n const importRegex = /import\\s*\\{([^}]+)\\}\\s*from\\s*['\"][^'\"]*models[^'\"]*['\"]/g;\n let match: RegExpExecArray | null;\n while ((match = importRegex.exec(content)) !== null) {\n const names = match[1].split(',').map((s) => s.trim());\n for (const name of names) {\n const cleanName = name.replace(/\\s+as\\s+\\w+/, '').trim();\n if (cleanName) tables.add(pascalToSnake(cleanName));\n }\n }\n } catch {\n // skip\n }\n }\n return Array.from(tables);\n}\n\nfunction resolveRoutePath(node: Node, sourceFile: SourceFile): string | null {\n const kind = node.getKind();\n if (kind === SyntaxKind.StringLiteral) return node.getText().slice(1, -1);\n if (kind === SyntaxKind.TemplateExpression || kind === SyntaxKind.NoSubstitutionTemplateLiteral) {\n return resolveTemplateLiteral(node, sourceFile);\n }\n if (kind === SyntaxKind.Identifier) {\n return resolveVariableValue(sourceFile, node.getText().trim());\n }\n return null;\n}\n\nfunction extractDecoratorPath(decorator: Decorator, sourceFile: SourceFile): string | null {\n const args = decorator.getArguments();\n if (args.length === 0) return '';\n\n const firstArg = args[0];\n if (firstArg.getKind() === SyntaxKind.ObjectLiteralExpression) {\n return extractPathFromObjectLiteral(firstArg as ObjectLiteralExpression, sourceFile);\n }\n\n return resolveRoutePath(firstArg, sourceFile);\n}\n\nfunction extractPathFromObjectLiteral(node: ObjectLiteralExpression, sourceFile: SourceFile): string | null {\n const pathProp = node.getProperty('path');\n if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;\n const initializer = pathProp.getInitializer();\n if (!initializer) return null;\n return resolveRoutePath(initializer, sourceFile);\n}\n\nfunction extractRequestMapping(\n methodDecl: MethodDeclaration,\n sourceFile: SourceFile,\n): { method: string; path: string } | null {\n const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === 'requestmapping');\n if (!decorator) return null;\n\n const args = decorator.getArguments();\n if (args.length === 0) return null;\n const firstArg = args[0];\n if (firstArg.getKind() !== SyntaxKind.ObjectLiteralExpression) return null;\n\n const obj = firstArg as ObjectLiteralExpression;\n const methodProp = obj.getProperty('method');\n let method = 'GET';\n if (methodProp && Node.isPropertyAssignment(methodProp)) {\n const init = methodProp.getInitializer();\n const methodText = init?.getText() || '';\n const normalized = methodText\n .replace(/['\"`]/g, '')\n .split('.')\n .pop()\n ?.toUpperCase();\n if (normalized && ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'].includes(normalized)) {\n method = normalized;\n }\n }\n\n const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? '';\n return { method, path: pathValue };\n}\n\nfunction normalizeRoutePath(routePath: string): string {\n const cleaned = routePath.trim();\n if (!cleaned || cleaned === '/') return '';\n return `/${cleaned.replace(/^\\/+|\\/+$/g, '')}`;\n}\n\nfunction joinRoutePath(basePath: string, childPath: string): string {\n const joined = `${basePath}${childPath}`.replace(/\\/+/g, '/');\n return joined || '/';\n}\n\nfunction extractMethodDescription(methodDecl: MethodDeclaration): string {\n const docs = methodDecl.getJsDocs();\n if (docs.length > 0) {\n const desc = docs[0].getDescription().trim();\n if (desc) return desc;\n }\n return '';\n}\n\nfunction resolveTemplateLiteral(node: Node, sourceFile: SourceFile): string {\n let result = node.getText().slice(1, -1);\n result = result.replace(/\\$\\{([^}]+)\\}/g, (_match, expr: string) => {\n const resolved = resolveVariableValue(sourceFile, expr.trim());\n return resolved || `{${expr.trim()}}`;\n });\n return result;\n}\n\nfunction resolveVariableValue(sourceFile: SourceFile, varName: string): string | null {\n for (const decl of sourceFile.getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {\n if (decl.getName() === varName) {\n const init = decl.getInitializer();\n if (!init) continue;\n const t = init.getText().trim();\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\n return t.slice(1, -1);\n if (t.startsWith('`') && t.endsWith('`'))\n return resolveTemplateLiteral(init, sourceFile);\n }\n }\n return null;\n}\n\nfunction extractPathParams(routePath: string): string[] {\n const params: string[] = [];\n const regex = /:(\\w+)/g;\n let match: RegExpExecArray | null;\n while ((match = regex.exec(routePath)) !== null) params.push(match[1]);\n return params;\n}\n\nfunction extractDescription(call: CallExpression): string {\n let current: Node = call;\n while (\n current.getParent() &&\n current.getParent()!.getKind() !== SyntaxKind.SourceFile &&\n current.getParent()!.getKind() !== SyntaxKind.Block\n ) {\n current = current.getParent()!;\n }\n const fullText = current.getFullText();\n const leadingText = fullText.substring(0, fullText.indexOf(current.getText()));\n const jsdocMatch = leadingText.match(/\\/\\*\\*[\\s\\S]*?\\*\\s+(.+?)(?:\\n|\\*\\/)/);\n if (jsdocMatch) return jsdocMatch[1].replace(/^\\*\\s*/, '').trim();\n const lineMatch = leadingText.match(/\\/\\/\\s*(.+)/);\n if (lineMatch) return lineMatch[1].trim();\n return '';\n}\n\nfunction extractStringLiteral(node: Node): string | null {\n const t = node.getText().trim();\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"')))\n return t.slice(1, -1);\n return null;\n}\n\nfunction pascalToSnake(name: string): string {\n return name.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n}\n\nfunction deduplicateEndpoints(endpoints: ApiEndpoint[]): ApiEndpoint[] {\n const seen = new Map<string, ApiEndpoint>();\n for (const ep of endpoints) {\n const key = `${ep.method}:${ep.path}`;\n if (!seen.has(key)) {\n seen.set(key, ep);\n } else {\n const existing = seen.get(key)!;\n const merged = new Set([...existing.relatedTables, ...ep.relatedTables]);\n existing.relatedTables = Array.from(merged);\n if (!existing.description && ep.description) existing.description = ep.description;\n }\n }\n return Array.from(seen.values());\n}\n\nexport function createControllerParser(): ControllerParser {\n return {\n async parseFile(filePath: string) {\n return parseControllerFile(filePath);\n },\n async parseDirectory(dirPath: string) {\n return parseControllerDirectory(dirPath);\n },\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport {\n Project,\n SyntaxKind,\n type ObjectLiteralExpression,\n type PropertyAssignment,\n type SourceFile,\n} from 'ts-morph';\nimport type { ForeignKeyRelation } from '../types.js';\nimport { parseModelFile } from './model-parser.js';\n\nexport interface AssociationParser {\n parseFile(filePath: string): Promise<ForeignKeyRelation[]>;\n}\n\ninterface RawAssociation {\n sourceClass: string;\n targetClass: string;\n foreignKey: string;\n type: 'hasMany' | 'belongsTo' | 'hasOne';\n importPath?: string;\n}\n\n/**\n * Parse an associations.ts file to extract all foreign key relations.\n */\nexport function parseAssociationFile(\n filePath: string,\n classToTableMap?: Map<string, string>,\n moduleTablePrefix?: string,\n): ForeignKeyRelation[] {\n const absolutePath = path.resolve(filePath);\n if (!fs.existsSync(absolutePath)) return [];\n\n const project = new Project({ compilerOptions: { strict: false } });\n const sourceFile = project.addSourceFileAtPath(absolutePath);\n\n const importPathMap = collectImportPaths(sourceFile);\n const rawAssociations = extractAssociationCalls(sourceFile, importPathMap);\n if (rawAssociations.length === 0) return [];\n\n return deduplicateRelations(rawAssociations, classToTableMap, moduleTablePrefix);\n}\n\n/**\n * Build className → tableName map from Model files in a directory.\n */\nexport function buildClassToTableMap(modelDir: string): Map<string, string> {\n const map = new Map<string, string>();\n const absoluteDir = path.resolve(modelDir);\n if (!fs.existsSync(absoluteDir)) return map;\n\n const files = fs.readdirSync(absoluteDir).filter((f) =>\n f.endsWith('.ts') &&\n !f.endsWith('.test.ts') &&\n !f.endsWith('.spec.ts') &&\n f !== 'index.ts' &&\n f !== 'associations.ts',\n );\n\n for (const file of files) {\n try {\n const schema = parseModelFile(path.join(absoluteDir, file));\n if (schema) {\n const className = file.replace('.ts', '');\n map.set(className, schema.tableName);\n }\n } catch {\n // skip\n }\n }\n return map;\n}\n\nfunction collectImportPaths(sourceFile: SourceFile): Map<string, string> {\n const map = new Map<string, string>();\n for (const decl of sourceFile.getImportDeclarations()) {\n const moduleSpecifier = decl.getModuleSpecifierValue();\n for (const named of decl.getNamedImports()) {\n map.set(named.getName(), moduleSpecifier);\n }\n }\n return map;\n}\n\nfunction extractAssociationCalls(\n sourceFile: SourceFile,\n importPathMap: Map<string, string>,\n): RawAssociation[] {\n const associations: RawAssociation[] = [];\n const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);\n\n for (const call of calls) {\n const expr = call.getExpression();\n if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) continue;\n\n const propAccess = expr.asKindOrThrow(SyntaxKind.PropertyAccessExpression);\n const methodName = propAccess.getName();\n if (methodName !== 'hasMany' && methodName !== 'belongsTo' && methodName !== 'hasOne') continue;\n\n const sourceClass = propAccess.getExpression().getText().trim();\n const args = call.getArguments();\n if (args.length < 1) continue;\n\n const targetClass = args[0].getText().trim();\n let foreignKey = '';\n\n if (args.length >= 2 && args[1].getKind() === SyntaxKind.ObjectLiteralExpression) {\n foreignKey = extractStringProperty(args[1] as ObjectLiteralExpression, 'foreignKey');\n }\n\n associations.push({\n sourceClass,\n targetClass,\n foreignKey,\n type: methodName as RawAssociation['type'],\n importPath: importPathMap.get(targetClass),\n });\n }\n return associations;\n}\n\nfunction extractStringProperty(obj: ObjectLiteralExpression, propertyName: string): string {\n for (const prop of obj.getProperties()) {\n if (prop.getKind() !== SyntaxKind.PropertyAssignment) continue;\n const pa = prop as PropertyAssignment;\n if (pa.getName() !== propertyName) continue;\n const init = pa.getInitializer();\n if (!init) continue;\n const text = init.getText().trim();\n if ((text.startsWith(\"'\") && text.endsWith(\"'\")) || (text.startsWith('\"') && text.endsWith('\"')))\n return text.slice(1, -1);\n return text;\n }\n return '';\n}\n\nexport function classNameToTableName(className: string): string {\n return className.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '');\n}\n\nfunction resolveTableName(className: string, classToTableMap?: Map<string, string>): string {\n if (classToTableMap?.has(className)) return classToTableMap.get(className)!;\n return classNameToTableName(className);\n}\n\nfunction isCrossModuleRef(\n targetTableName: string,\n importPath: string | undefined,\n moduleTablePrefix?: string,\n): boolean {\n if (moduleTablePrefix) return !targetTableName.startsWith(moduleTablePrefix);\n if (importPath) {\n const upLevels = (importPath.match(/\\.\\.\\//g) || []).length;\n return upLevels >= 2;\n }\n return false;\n}\n\nfunction deduplicateRelations(\n rawAssociations: RawAssociation[],\n classToTableMap?: Map<string, string>,\n moduleTablePrefix?: string,\n): ForeignKeyRelation[] {\n const seen = new Map<string, ForeignKeyRelation>();\n\n for (const raw of rawAssociations) {\n const sourceTable = resolveTableName(raw.sourceClass, classToTableMap);\n const targetTable = resolveTableName(raw.targetClass, classToTableMap);\n const crossModule = isCrossModuleRef(targetTable, raw.importPath, moduleTablePrefix);\n\n let parentTable: string;\n let childTable: string;\n let cardinality: ForeignKeyRelation['cardinality'];\n\n switch (raw.type) {\n case 'hasMany':\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:N'; break;\n case 'belongsTo':\n parentTable = targetTable; childTable = sourceTable; cardinality = 'N:1'; break;\n case 'hasOne':\n parentTable = sourceTable; childTable = targetTable; cardinality = '1:1'; break;\n }\n\n const dedupeKey = `${parentTable}|${childTable}|${raw.foreignKey}`;\n if (seen.has(dedupeKey)) {\n const existing = seen.get(dedupeKey)!;\n if (existing.cardinality === 'N:1' && (cardinality === '1:N' || cardinality === '1:1')) {\n seen.set(dedupeKey, {\n sourceTable: parentTable, sourceField: 'id',\n targetTable: childTable, targetField: raw.foreignKey,\n cardinality, isCrossModule: crossModule || existing.isCrossModule,\n });\n }\n } else {\n seen.set(dedupeKey, {\n sourceTable: parentTable, sourceField: 'id',\n targetTable: childTable, targetField: raw.foreignKey,\n cardinality, isCrossModule: crossModule,\n });\n }\n }\n return Array.from(seen.values());\n}\n\nexport function createAssociationParser(): AssociationParser {\n return {\n async parseFile(filePath: string) {\n return parseAssociationFile(filePath);\n },\n };\n}\n","import type {\n ApiEndpoint,\n ApiDependency,\n ApiChainAnalysisResult,\n DirectedAcyclicGraph,\n} from '../types.js';\n\nconst EXCLUDED_PARAMS = new Set(['tenantId']);\n\nconst enum Color { WHITE = 0, GRAY = 1, BLACK = 2 }\n\nfunction toNodeKey(endpoint: ApiEndpoint): string {\n return `${endpoint.method} ${endpoint.path}`;\n}\n\nfunction paramToResourceHint(param: string): string {\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\n return stripped.replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');\n}\n\nfunction postProducesResource(postEndpoint: ApiEndpoint, resourceHint: string): boolean {\n const segments = postEndpoint.path.split('/').filter((s) => s && !s.startsWith(':'));\n if (segments.length === 0) return false;\n\n const lastSegment = segments[segments.length - 1].toLowerCase();\n if (lastSegment.includes(resourceHint)) return true;\n\n const parts = lastSegment.split('-');\n if (parts.some((p) => p === resourceHint || p.startsWith(resourceHint))) return true;\n\n if (resourceHint.length <= 4) {\n const abbreviation = parts.map((p) => p[0]).join('');\n if (abbreviation.startsWith(resourceHint)) return true;\n }\n return false;\n}\n\n/**\n * Infer API dependencies via path parameter matching.\n * POST endpoints produce IDs; GET/PUT/DELETE endpoints consume them.\n */\nexport function inferDependencies(endpoints: ApiEndpoint[]): ApiDependency[] {\n const dependencies: ApiDependency[] = [];\n const postEndpoints = endpoints.filter((ep) => ep.method === 'POST');\n\n for (const consumer of endpoints) {\n const consumedParams = consumer.pathParams.filter((p) => !EXCLUDED_PARAMS.has(p));\n if (consumedParams.length === 0) continue;\n\n for (const param of consumedParams) {\n if (param === 'id') {\n const basePath = consumer.path.replace(/\\/:id(\\/.*)?$/, '');\n const producer = postEndpoints.find((ep) => ep.path === basePath);\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\n }\n continue;\n }\n\n const resourceHint = paramToResourceHint(param);\n if (!resourceHint) continue;\n\n const producer = postEndpoints.find((ep) => postProducesResource(ep, resourceHint));\n if (producer && toNodeKey(producer) !== toNodeKey(consumer)) {\n dependencies.push({ from: consumer, to: producer, paramMapping: { [`:${param}`]: 'response.data.id' } });\n }\n }\n }\n return deduplicateDependencies(dependencies);\n}\n\nfunction deduplicateDependencies(deps: ApiDependency[]): ApiDependency[] {\n const map = new Map<string, ApiDependency>();\n for (const dep of deps) {\n const key = `${toNodeKey(dep.from)}→${toNodeKey(dep.to)}`;\n if (map.has(key)) {\n Object.assign(map.get(key)!.paramMapping, dep.paramMapping);\n } else {\n map.set(key, { ...dep, paramMapping: { ...dep.paramMapping } });\n }\n }\n return Array.from(map.values());\n}\n\n/**\n * Build a directed graph from endpoints and their dependencies.\n */\nexport function buildGraph(\n endpoints: ApiEndpoint[],\n dependencies: ApiDependency[],\n): DirectedAcyclicGraph {\n const nodeSet = new Set<string>();\n for (const ep of endpoints) nodeSet.add(toNodeKey(ep));\n\n const edges: Array<{ from: string; to: string; label?: string }> = [];\n for (const dep of dependencies) {\n edges.push({\n from: toNodeKey(dep.from),\n to: toNodeKey(dep.to),\n label: Object.keys(dep.paramMapping).join(', ') || undefined,\n });\n }\n return { nodes: Array.from(nodeSet), edges };\n}\n\n/**\n * Detect cycles in a directed graph using DFS coloring.\n */\nexport function detectCycles(dag: DirectedAcyclicGraph): string[] {\n const adjacency = new Map<string, string[]>();\n for (const node of dag.nodes) adjacency.set(node, []);\n for (const edge of dag.edges) adjacency.get(edge.from)?.push(edge.to);\n\n const color = new Map<string, Color>();\n for (const node of dag.nodes) color.set(node, Color.WHITE);\n\n const warnings: string[] = [];\n const path: string[] = [];\n\n function dfs(node: string): void {\n color.set(node, Color.GRAY);\n path.push(node);\n for (const neighbor of adjacency.get(node) || []) {\n const nc = color.get(neighbor);\n if (nc === Color.GRAY) {\n const cycleStart = path.indexOf(neighbor);\n warnings.push(`Cycle detected: ${path.slice(cycleStart).concat(neighbor).join(' → ')}`);\n } else if (nc === Color.WHITE) {\n dfs(neighbor);\n }\n }\n path.pop();\n color.set(node, Color.BLACK);\n }\n\n for (const node of dag.nodes) {\n if (color.get(node) === Color.WHITE) dfs(node);\n }\n return warnings;\n}\n\n/**\n * Topological sort using Kahn's algorithm.\n */\nexport function topologicalSort(dag: DirectedAcyclicGraph): string[] {\n const inDegree = new Map<string, number>();\n const adjacency = new Map<string, string[]>();\n\n for (const node of dag.nodes) { inDegree.set(node, 0); adjacency.set(node, []); }\n for (const edge of dag.edges) {\n adjacency.get(edge.from)?.push(edge.to);\n inDegree.set(edge.to, (inDegree.get(edge.to) || 0) + 1);\n }\n\n const queue: string[] = [];\n for (const [node, degree] of inDegree) {\n if (degree === 0) queue.push(node);\n }\n\n const sorted: string[] = [];\n while (queue.length > 0) {\n const node = queue.shift()!;\n sorted.push(node);\n for (const neighbor of adjacency.get(node) || []) {\n const nd = (inDegree.get(neighbor) || 1) - 1;\n inDegree.set(neighbor, nd);\n if (nd === 0) queue.push(neighbor);\n }\n }\n return sorted;\n}\n\nexport interface ApiChainAnalyzer {\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult;\n}\n\n/**\n * Analyze API endpoints: infer dependencies, build DAG, detect cycles, topological sort.\n */\nexport function createApiChainAnalyzer(): ApiChainAnalyzer {\n return {\n analyze(endpoints: ApiEndpoint[]): ApiChainAnalysisResult {\n const dependencies = inferDependencies(endpoints);\n const dag = buildGraph(endpoints, dependencies);\n const cycleWarnings = detectCycles(dag);\n\n return {\n moduleName: '',\n endpoints,\n dependencies,\n dag,\n hasCycles: cycleWarnings.length > 0,\n cycleWarnings,\n };\n },\n };\n}\n","import type { ERDiagramResult, TableSchema, ForeignKeyRelation } from '../types.js';\n\nexport interface ERDiagramGenerator {\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult;\n}\n\n/**\n * Map field type string to a short Mermaid ER type label.\n */\nfunction toMermaidType(fieldType: string): string {\n const upper = fieldType.toUpperCase();\n if (upper.startsWith('STRING')) return 'string';\n if (upper === 'BIGINT' || upper === 'INTEGER') return 'bigint';\n if (upper === 'BOOLEAN') return 'boolean';\n if (upper.startsWith('DATE') || upper === 'NOW') return 'datetime';\n if (upper === 'JSON' || upper === 'JSONB') return 'json';\n if (upper === 'TEXT') return 'text';\n if (upper === 'FLOAT' || upper === 'DOUBLE' || upper === 'DECIMAL') return 'float';\n if (upper === 'UUID') return 'uuid';\n if (upper.startsWith('ENUM')) return 'enum';\n return 'string';\n}\n\n/**\n * Mermaid requires entity names without special characters.\n */\nfunction sanitizeEntityName(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\n}\n\n/**\n * Generate Mermaid ER diagram syntax from parsed schemas and relations.\n */\nfunction generateMermaidER(tables: TableSchema[], relations: ForeignKeyRelation[]): string {\n const lines: string[] = ['erDiagram'];\n\n // Entity blocks\n for (const table of tables) {\n const entityName = sanitizeEntityName(table.tableName);\n lines.push(` ${entityName} {`);\n for (const field of table.fields) {\n const mType = toMermaidType(field.type);\n const pk = field.primaryKey ? 'PK' : '';\n const comment = field.comment ? ` \"${field.comment}\"` : '';\n lines.push(` ${mType} ${field.name}${pk ? ' ' + pk : ''}${comment}`);\n }\n lines.push(' }');\n }\n\n // Relationships\n const tableNames = new Set(tables.map((t) => t.tableName));\n for (const rel of relations) {\n if (!tableNames.has(rel.sourceTable) || !tableNames.has(rel.targetTable)) continue;\n\n const src = sanitizeEntityName(rel.sourceTable);\n const tgt = sanitizeEntityName(rel.targetTable);\n const linkStyle = rel.isCrossModule ? '..' : '--';\n\n let cardinality: string;\n switch (rel.cardinality) {\n case '1:N': cardinality = `||${linkStyle}o{`; break;\n case 'N:1': cardinality = `}o${linkStyle}||`; break;\n case '1:1': cardinality = `||${linkStyle}||`; break;\n default: cardinality = `||${linkStyle}o{`;\n }\n\n lines.push(` ${src} ${cardinality} ${tgt} : \"${rel.targetField}\"`);\n }\n\n return lines.join('\\n');\n}\n\nexport function createERDiagramGenerator(): ERDiagramGenerator {\n return {\n generate(tables: TableSchema[], relations: ForeignKeyRelation[]): ERDiagramResult {\n const mermaidText = generateMermaidER(tables, relations);\n return { tables, relations, mermaidText };\n },\n };\n}\n","import type { GeneratedTestFile, TestChain, TestStep } from '../types.js';\n\nexport interface TestCodeGenerator {\n generate(chains: TestChain[]): GeneratedTestFile[];\n}\n\n/**\n * Resolve a path parameter from the available createdIds.\n */\nfunction resolvePathParam(param: string, ids: string[]): string {\n // Try direct match (e.g., 'kbId' → look for 'kbId' in ids)\n if (ids.includes(param)) return `createdIds['${param}']`;\n // Try with 'Id' suffix stripped\n const stripped = param.endsWith('Id') ? param.slice(0, -2) : param;\n if (ids.includes(stripped)) return `createdIds['${stripped}']`;\n // Generic id\n if (param === 'id') return `createdIds['id']`;\n return `createdIds['${param}'] || '1'`;\n}\n\n/**\n * Generate URL building code for a test step.\n */\nfunction buildUrlCode(step: TestStep): string {\n const pathParams = step.endpoint.pathParams;\n if (pathParams.length === 0) return `const url = '${step.endpoint.path}';`;\n\n let urlTemplate = step.endpoint.path;\n const replacements: string[] = [];\n for (const param of pathParams) {\n urlTemplate = urlTemplate.replace(`:${param}`, `\\${${resolvePathParam(param, pathParams)}}`);\n replacements.push(param);\n }\n return `const url = \\`${urlTemplate}\\`;`;\n}\n\n/**\n * Generate assertion code for a test step.\n */\nfunction generateAssertions(step: TestStep): string[] {\n const lines: string[] = [];\n if (step.assertions.length > 0) {\n for (const assertion of step.assertions) {\n lines.push(` expect(${assertion}).toBeTruthy();`);\n }\n } else {\n // Default assertions\n if (step.endpoint.method === 'POST') {\n lines.push(' expect(response.status()).toBeLessThan(400);');\n lines.push(' const body = await response.json();');\n lines.push(\" if (body.data?.id) createdIds['id'] = body.data.id;\");\n } else if (step.endpoint.method === 'GET') {\n lines.push(' expect(response.ok()).toBeTruthy();');\n } else if (step.endpoint.method === 'DELETE') {\n lines.push(' expect(response.status()).toBeLessThan(400);');\n } else {\n lines.push(' expect(response.status()).toBeLessThan(400);');\n }\n }\n return lines;\n}\n\n/**\n * Generate a single Playwright test file from a test chain.\n */\nfunction generateTestFile(chain: TestChain): string {\n const lines: string[] = [];\n\n lines.push(`import { test, expect } from '@playwright/test';`);\n lines.push('');\n lines.push(`test.describe('${chain.name}', () => {`);\n lines.push(\" const createdIds: Record<string, string> = {};\");\n lines.push('');\n\n for (const step of chain.steps) {\n lines.push(` test('Step ${step.order}: ${step.description}', async ({ request }) => {`);\n lines.push(` // ${step.action}: ${step.endpoint.method} ${step.endpoint.path}`);\n lines.push(` ${buildUrlCode(step)}`);\n lines.push('');\n\n if (step.endpoint.method === 'GET') {\n lines.push(' const response = await request.get(url);');\n } else if (step.endpoint.method === 'POST') {\n lines.push(' const response = await request.post(url, { data: {} });');\n } else if (step.endpoint.method === 'PUT') {\n lines.push(' const response = await request.put(url, { data: {} });');\n } else if (step.endpoint.method === 'DELETE') {\n lines.push(' const response = await request.delete(url);');\n } else if (step.endpoint.method === 'PATCH') {\n lines.push(' const response = await request.patch(url, { data: {} });');\n }\n\n lines.push('');\n lines.push(...generateAssertions(step));\n lines.push(' });');\n lines.push('');\n }\n\n lines.push('});');\n return lines.join('\\n');\n}\n\nexport function createTestCodeGenerator(): TestCodeGenerator {\n return {\n generate(chains: TestChain[]): GeneratedTestFile[] {\n return chains.map((chain) => ({\n filePath: `${chain.module}/${chain.name.replace(/\\s+/g, '-').toLowerCase()}.spec.ts`,\n content: generateTestFile(chain),\n module: chain.module,\n chain: chain.name,\n }));\n },\n };\n}\n","import type { ValidationError } from '../types.js';\n\nconst REQUIRED_FIELDS = ['backendRoot'];\n\nconst VALID_ADAPTERS = ['sequelize', 'typeorm', 'prisma'];\nconst VALID_STEPS = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\nconst VALID_LLM_PROVIDERS = ['openai', 'zhipu', 'ollama', 'custom'];\nconst VALID_REPORT_FORMATS = ['html', 'json', 'markdown'];\nconst VALID_HEAL_MODES = ['config-only', 'config-and-source'];\n\n/**\n * Validate an OpenCroc configuration object.\n * Returns an array of ValidationErrors (empty = valid).\n */\nexport function validateConfig(config: Record<string, unknown>): ValidationError[] {\n const errors: ValidationError[] = [];\n\n // Required fields\n for (const field of REQUIRED_FIELDS) {\n if (!config[field]) {\n errors.push({\n module: 'config',\n field,\n message: `Missing required field: ${field}`,\n severity: 'error',\n });\n }\n }\n\n // backendRoot must be a string\n if (config.backendRoot && typeof config.backendRoot !== 'string') {\n errors.push({\n module: 'config',\n field: 'backendRoot',\n message: 'backendRoot must be a string path',\n severity: 'error',\n });\n }\n\n // adapter validation\n if (config.adapter && typeof config.adapter === 'string') {\n if (!VALID_ADAPTERS.includes(config.adapter)) {\n errors.push({\n module: 'config',\n field: 'adapter',\n message: `Invalid adapter: ${config.adapter}. Must be one of: ${VALID_ADAPTERS.join(', ')}`,\n severity: 'error',\n });\n }\n }\n\n // steps validation\n if (config.steps && Array.isArray(config.steps)) {\n for (const step of config.steps) {\n if (!VALID_STEPS.includes(step as string)) {\n errors.push({\n module: 'config',\n field: 'steps',\n message: `Invalid pipeline step: ${step}. Must be one of: ${VALID_STEPS.join(', ')}`,\n severity: 'error',\n });\n }\n }\n }\n\n // LLM config validation\n if (config.llm && typeof config.llm === 'object') {\n const llm = config.llm as Record<string, unknown>;\n if (llm.provider && !VALID_LLM_PROVIDERS.includes(llm.provider as string)) {\n errors.push({\n module: 'config',\n field: 'llm.provider',\n message: `Invalid LLM provider: ${llm.provider}. Must be one of: ${VALID_LLM_PROVIDERS.join(', ')}`,\n severity: 'error',\n });\n }\n if (llm.provider && llm.provider !== 'ollama' && !llm.apiKey) {\n errors.push({\n module: 'config',\n field: 'llm.apiKey',\n message: 'LLM apiKey is required for cloud providers',\n severity: 'warning',\n });\n }\n }\n\n // Report config validation\n if (config.report && typeof config.report === 'object') {\n const report = config.report as Record<string, unknown>;\n if (report.format && Array.isArray(report.format)) {\n for (const fmt of report.format) {\n if (!VALID_REPORT_FORMATS.includes(fmt as string)) {\n errors.push({\n module: 'config',\n field: 'report.format',\n message: `Invalid report format: ${fmt}. Must be one of: ${VALID_REPORT_FORMATS.join(', ')}`,\n severity: 'error',\n });\n }\n }\n }\n }\n\n // Self-healing config validation\n if (config.selfHealing && typeof config.selfHealing === 'object') {\n const sh = config.selfHealing as Record<string, unknown>;\n if (sh.mode && !VALID_HEAL_MODES.includes(sh.mode as string)) {\n errors.push({\n module: 'config',\n field: 'selfHealing.mode',\n message: `Invalid self-healing mode: ${sh.mode}. Must be one of: ${VALID_HEAL_MODES.join(', ')}`,\n severity: 'error',\n });\n }\n if (sh.maxIterations && (typeof sh.maxIterations !== 'number' || sh.maxIterations < 1)) {\n errors.push({\n module: 'config',\n field: 'selfHealing.maxIterations',\n message: 'maxIterations must be a positive number',\n severity: 'error',\n });\n }\n }\n\n return errors;\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport type {\n OpenCrocConfig,\n PipelineRunResult,\n PipelineStep,\n ERDiagramResult,\n ChainPlanResult,\n} from '../types.js';\nimport { parseModuleModels } from '../parsers/model-parser.js';\nimport { parseControllerDirectory } from '../parsers/controller-parser.js';\nimport { parseAssociationFile } from '../parsers/association-parser.js';\nimport { createApiChainAnalyzer, topologicalSort } from '../analyzers/api-chain-analyzer.js';\nimport { createERDiagramGenerator } from '../generators/er-diagram-generator.js';\nimport { createTestCodeGenerator } from '../generators/test-code-generator.js';\nimport { validateConfig } from '../validators/config-validator.js';\n\nexport interface Pipeline {\n run(steps?: PipelineStep[]): Promise<PipelineRunResult>;\n}\n\nconst ALL_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\n\nexport function createPipeline(config: OpenCrocConfig): Pipeline {\n return {\n async run(steps) {\n const startTime = Date.now();\n const activeSteps = steps || config.steps || ALL_STEPS;\n\n const result: PipelineRunResult = {\n modules: [],\n erDiagrams: new Map(),\n chainPlans: new Map(),\n generatedFiles: [],\n validationErrors: [],\n duration: 0,\n };\n\n // Step 1: Scan — discover modules\n if (activeSteps.includes('scan')) {\n const backendRoot = path.resolve(config.backendRoot);\n const modelsDir = path.join(backendRoot, 'models');\n\n if (fs.existsSync(modelsDir)) {\n // Discover modules from subdirectories\n const dirs = fs.readdirSync(modelsDir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name);\n\n const moduleFilter = config.modules;\n for (const dir of dirs) {\n if (moduleFilter && !moduleFilter.includes(dir)) continue;\n result.modules.push(dir);\n }\n\n // If no subdirectories, treat root as single \"default\" module\n if (result.modules.length === 0) {\n result.modules.push('default');\n } else {\n // Also include root-level model files as \"default\" module\n const rootFiles = fs.readdirSync(modelsDir)\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts');\n if (rootFiles.length > 0) {\n result.modules.unshift('default');\n }\n }\n }\n }\n\n // Helper: resolve model dir for a module\n const resolveModelDir = (backendRoot: string, mod: string): string =>\n mod === 'default'\n ? path.join(backendRoot, 'models')\n : path.join(backendRoot, 'models', mod);\n\n // Helper: resolve controller dir for a module\n const resolveControllerDir = (backendRoot: string, mod: string): string =>\n mod === 'default'\n ? path.join(backendRoot, 'controllers')\n : path.join(backendRoot, 'controllers', mod);\n\n // Step 2: ER Diagram — parse models and generate relationship graphs\n if (activeSteps.includes('er-diagram')) {\n const erGen = createERDiagramGenerator();\n const backendRoot = path.resolve(config.backendRoot);\n\n for (const mod of result.modules) {\n const modelDir = resolveModelDir(backendRoot, mod);\n\n // For flat layouts, scan all model files for embedded associations\n const tables = fs.existsSync(modelDir) ? parseModuleModels(modelDir) : [];\n const relations: import('../types.js').ForeignKeyRelation[] = [];\n\n // Check for dedicated associations.ts first\n const assocFile = path.join(modelDir, 'associations.ts');\n if (fs.existsSync(assocFile)) {\n relations.push(...parseAssociationFile(assocFile));\n }\n\n // Also scan model files for embedded associations (belongsTo/hasMany at end of file)\n if (fs.existsSync(modelDir)) {\n const modelFiles = fs.readdirSync(modelDir)\n .filter((f) => f.endsWith('.ts') && !f.endsWith('.test.ts') && f !== 'index.ts' && f !== 'associations.ts');\n for (const file of modelFiles) {\n try {\n const embedded = parseAssociationFile(path.join(modelDir, file));\n relations.push(...embedded);\n } catch {\n // skip files that fail to parse\n }\n }\n }\n\n const erResult: ERDiagramResult = erGen.generate(tables, relations);\n result.erDiagrams.set(mod, erResult);\n }\n }\n\n // Step 3: API Chain — analyze controller routes and build dependency DAG\n if (activeSteps.includes('api-chain')) {\n const chainAnalyzer = createApiChainAnalyzer();\n const backendRoot = path.resolve(config.backendRoot);\n\n for (const mod of result.modules) {\n const controllerDir = resolveControllerDir(backendRoot, mod);\n const endpoints = fs.existsSync(controllerDir)\n ? parseControllerDirectory(controllerDir)\n : [];\n\n const analysis = chainAnalyzer.analyze(endpoints);\n analysis.moduleName = mod;\n\n if (analysis.hasCycles) {\n for (const warning of analysis.cycleWarnings) {\n result.validationErrors.push({\n module: mod,\n field: 'api-chain',\n message: warning,\n severity: 'warning',\n });\n }\n }\n }\n }\n\n // Step 4: Plan — generate test chains from dependency analysis\n if (activeSteps.includes('plan')) {\n const backendRoot = path.resolve(config.backendRoot);\n const chainAnalyzer = createApiChainAnalyzer();\n\n for (const mod of result.modules) {\n const controllerDir = resolveControllerDir(backendRoot, mod);\n const endpoints = fs.existsSync(controllerDir)\n ? parseControllerDirectory(controllerDir)\n : [];\n\n const analysis = chainAnalyzer.analyze(endpoints);\n const topoOrder = topologicalSort(analysis.dag);\n\n // Group by resource to create chains\n const chains = generateChainPlan(mod, endpoints, topoOrder);\n result.chainPlans.set(mod, chains);\n }\n }\n\n // Step 5: Codegen — emit Playwright test files from chain plans\n if (activeSteps.includes('codegen')) {\n const testGen = createTestCodeGenerator();\n const outDir = config.outDir || './opencroc-output';\n\n for (const [_mod, plan] of result.chainPlans) {\n const files = testGen.generate(plan.chains);\n for (const file of files) {\n file.filePath = path.join(outDir, file.filePath);\n }\n result.generatedFiles.push(...files);\n }\n }\n\n // Step 6: Validate — run validation on generated configs\n if (activeSteps.includes('validate')) {\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\n result.validationErrors.push(...configErrors);\n }\n\n result.duration = Date.now() - startTime;\n return result;\n },\n };\n}\n\n/**\n * Generate a basic chain plan from endpoints and topological order.\n */\nfunction generateChainPlan(\n moduleName: string,\n endpoints: import('../types.js').ApiEndpoint[],\n _topoOrder: string[],\n): ChainPlanResult {\n // Group endpoints by resource (first non-param path segment)\n const groups = new Map<string, import('../types.js').ApiEndpoint[]>();\n\n for (const ep of endpoints) {\n const segments = ep.path.split('/').filter((s) => s && !s.startsWith(':'));\n const resource = segments[segments.length - 1] || 'default';\n if (!groups.has(resource)) groups.set(resource, []);\n groups.get(resource)!.push(ep);\n }\n\n const chains: import('../types.js').TestChain[] = [];\n let totalSteps = 0;\n\n for (const [resource, eps] of groups) {\n const steps: import('../types.js').TestStep[] = eps.map((ep, i) => ({\n order: i + 1,\n action: ep.method,\n endpoint: ep,\n description: ep.description || `${ep.method} ${ep.path}`,\n assertions: [],\n }));\n\n chains.push({ name: `${resource} CRUD chain`, module: moduleName, steps });\n totalSteps += steps.length;\n }\n\n return { chains, totalSteps };\n}\n","import chalk from 'chalk';\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport { loadConfig } from '../load-config.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport type { PipelineStep, PipelineRunResult } from '../../types.js';\n\nconst VALID_STEPS: PipelineStep[] = ['scan', 'er-diagram', 'api-chain', 'plan', 'codegen', 'validate'];\n\nexport interface GenerateOptions {\n module?: string;\n all?: boolean;\n steps?: string;\n dryRun?: boolean;\n}\n\nfunction parseSteps(raw?: string): PipelineStep[] | undefined {\n if (!raw) return undefined;\n const names = raw.split(',').map((s) => s.trim());\n for (const name of names) {\n if (!VALID_STEPS.includes(name as PipelineStep)) {\n throw new Error(`Unknown pipeline step \"${name}\". Valid steps: ${VALID_STEPS.join(', ')}`);\n }\n }\n return names as PipelineStep[];\n}\n\nfunction writeGeneratedFiles(result: PipelineRunResult): number {\n let written = 0;\n for (const file of result.generatedFiles) {\n const dir = dirname(file.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(file.filePath, file.content, 'utf-8');\n written++;\n console.log(chalk.green(` ✓ ${file.filePath}`));\n }\n return written;\n}\n\nfunction printSummary(result: PipelineRunResult, dryRun: boolean): void {\n console.log('');\n console.log(chalk.cyan.bold(' Summary'));\n console.log(` Modules discovered : ${result.modules.length}`);\n console.log(` ER diagrams : ${result.erDiagrams.size}`);\n console.log(` Chain plans : ${result.chainPlans.size}`);\n console.log(` Generated files : ${result.generatedFiles.length}${dryRun ? ' (dry-run, not written)' : ''}`);\n\n if (result.validationErrors.length > 0) {\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\n if (errors.length > 0) console.log(chalk.red(` Errors : ${errors.length}`));\n if (warnings.length > 0) console.log(chalk.yellow(` Warnings : ${warnings.length}`));\n\n for (const err of result.validationErrors) {\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\n console.log(` ${icon} [${err.module}] ${err.message}`);\n }\n }\n\n console.log(chalk.gray(` Duration : ${result.duration}ms`));\n console.log('');\n}\n\nexport async function generate(opts: GenerateOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Generate E2E Tests\\n'));\n\n // Load config\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n // Apply --module filter\n if (opts.module) {\n config.modules = [opts.module];\n }\n\n // Parse --steps\n const steps = parseSteps(opts.steps);\n\n // Create and run pipeline\n const pipeline = createPipeline(config);\n const result = await pipeline.run(steps);\n\n // Write files (unless dry-run)\n if (!opts.dryRun && result.generatedFiles.length > 0) {\n console.log('');\n console.log(chalk.cyan(' Generated files:'));\n writeGeneratedFiles(result);\n } else if (opts.dryRun && result.generatedFiles.length > 0) {\n console.log('');\n console.log(chalk.yellow(' Dry-run — files that would be generated:'));\n for (const file of result.generatedFiles) {\n console.log(chalk.gray(` ${file.filePath}`));\n }\n }\n\n printSummary(result, !!opts.dryRun);\n}\n","import chalk from 'chalk';\nimport { readdirSync, existsSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { execFileSync } from 'node:child_process';\nimport { loadConfig } from '../load-config.js';\n\nexport interface TestOptions {\n module?: string;\n headed?: boolean;\n}\n\nfunction discoverTestFiles(outDir: string, moduleFilter?: string): string[] {\n const absDir = resolve(outDir);\n if (!existsSync(absDir)) return [];\n\n const files: string[] = [];\n const entries = readdirSync(absDir, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n if (!entry.name.endsWith('.spec.ts') && !entry.name.endsWith('.test.ts')) continue;\n const fullPath = join(entry.parentPath || (entry as unknown as { path: string }).path || absDir, entry.name);\n if (moduleFilter && !fullPath.includes(moduleFilter)) continue;\n files.push(fullPath);\n }\n return files;\n}\n\nexport async function runTests(opts: TestOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Run E2E Tests\\n'));\n\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n const outDir = config.outDir || './opencroc-output';\n const testFiles = discoverTestFiles(outDir, opts.module);\n\n if (testFiles.length === 0) {\n console.log(chalk.yellow(' No test files found. Run `opencroc generate` first.\\n'));\n return;\n }\n\n console.log(` Found ${testFiles.length} test file(s)`);\n for (const f of testFiles) {\n console.log(chalk.gray(` ${f}`));\n }\n console.log('');\n\n // Build Playwright args\n const args = ['test', ...testFiles];\n if (!opts.headed) {\n args.push('--reporter=list');\n } else {\n args.push('--headed');\n }\n\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n\n try {\n console.log(chalk.cyan(' Running Playwright...\\n'));\n execFileSync(npxCmd, ['playwright', ...args], {\n stdio: 'inherit',\n cwd: process.cwd(),\n });\n console.log(chalk.green('\\n ✓ All tests passed.\\n'));\n } catch {\n console.log(chalk.red('\\n ✗ Some tests failed.\\n'));\n process.exitCode = 1;\n }\n}\n","import chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { validateConfig } from '../../validators/config-validator.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport type { ValidationError } from '../../types.js';\n\nexport interface ValidateOptions {\n module?: string;\n}\n\nfunction printErrors(errors: ValidationError[]): void {\n for (const err of errors) {\n const icon = err.severity === 'error' ? chalk.red('✗') : chalk.yellow('⚠');\n const scope = err.module === 'config' ? '' : ` [${err.module}]`;\n console.log(` ${icon}${scope} ${err.field}: ${err.message}`);\n }\n}\n\nexport async function validate(opts: ValidateOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Validate\\n'));\n\n // Load and validate config\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n const configErrors = validateConfig(config as unknown as Record<string, unknown>);\n\n // Apply module filter\n if (opts.module) {\n config.modules = [opts.module];\n }\n\n // Run pipeline in scan + validate mode to discover module-level issues\n const pipeline = createPipeline(config);\n const result = await pipeline.run(['scan', 'validate']);\n\n const allErrors = [...configErrors, ...result.validationErrors];\n const errors = allErrors.filter((e) => e.severity === 'error');\n const warnings = allErrors.filter((e) => e.severity === 'warning');\n\n if (allErrors.length === 0) {\n console.log(chalk.green(' ✓ Configuration is valid.'));\n console.log(chalk.gray(` Modules: ${result.modules.join(', ') || '(none)'}\\n`));\n return;\n }\n\n if (errors.length > 0) {\n console.log(chalk.red(` ${errors.length} error(s):`));\n printErrors(errors);\n }\n if (warnings.length > 0) {\n console.log(chalk.yellow(` ${warnings.length} warning(s):`));\n printErrors(warnings);\n }\n\n console.log('');\n\n if (errors.length > 0) {\n process.exitCode = 1;\n }\n}\n","import type { LlmProvider, LlmConfig } from '../types.js';\n\nexport interface ChatMessage {\n role: 'system' | 'user' | 'assistant';\n content: string;\n}\n\ninterface OpenAIResponse {\n choices: Array<{ message: { content: string } }>;\n usage?: { total_tokens: number };\n}\n\nconst DEFAULT_MODELS: Record<string, string> = {\n openai: 'gpt-4o-mini',\n zhipu: 'glm-4',\n};\n\nconst DEFAULT_BASE_URLS: Record<string, string> = {\n openai: 'https://api.openai.com/v1',\n zhipu: 'https://open.bigmodel.cn/api/paas/v4',\n};\n\n/**\n * Create an OpenAI-compatible LLM provider.\n * Works with OpenAI, Zhipu (GLM), and any OpenAI-compatible API.\n */\nexport function createOpenAIProvider(config: LlmConfig): LlmProvider {\n const provider = config.provider === 'zhipu' ? 'zhipu' : 'openai';\n const baseUrl = config.baseUrl || DEFAULT_BASE_URLS[provider];\n const model = config.model || DEFAULT_MODELS[provider];\n const maxTokens = config.maxTokens || 2048;\n const temperature = config.temperature ?? 0.3;\n\n if (!config.apiKey) {\n throw new Error(\n `API key is required for ${provider}. Set it in config or via OPENCROC_LLM_API_KEY env variable.`,\n );\n }\n\n return {\n name: provider,\n\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\n const url = `${baseUrl}/chat/completions`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model,\n messages,\n max_tokens: maxTokens,\n temperature,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`LLM API error (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as OpenAIResponse;\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error('LLM returned empty response');\n }\n return content;\n },\n\n estimateTokens(text: string): number {\n // Rough estimate: ~4 chars per token for English, ~2 for CJK\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(otherChars / 4 + cjkChars / 2);\n },\n };\n}\n","import type { LlmProvider, LlmConfig } from '../types.js';\n\ninterface OllamaResponse {\n message: { content: string };\n}\n\n/**\n * Create an Ollama LLM provider for local model inference.\n */\nexport function createOllamaProvider(config: LlmConfig): LlmProvider {\n const baseUrl = config.baseUrl || 'http://localhost:11434';\n const model = config.model || 'llama3';\n\n return {\n name: 'ollama',\n\n async chat(messages: Array<{ role: string; content: string }>): Promise<string> {\n const url = `${baseUrl}/api/chat`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n model,\n messages,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`Ollama API error (${response.status}): ${errorText}`);\n }\n\n const data = (await response.json()) as OllamaResponse;\n const content = data.message?.content;\n if (!content) {\n throw new Error('Ollama returned empty response');\n }\n return content;\n },\n\n estimateTokens(text: string): number {\n // Same rough estimate as OpenAI provider\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3000-\\u303f]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(otherChars / 4 + cjkChars / 2);\n },\n };\n}\n","import type { LlmProvider, LlmConfig } from '../types.js';\nimport { createOpenAIProvider } from './openai.js';\nimport { createOllamaProvider } from './ollama.js';\n\nexport { createOpenAIProvider } from './openai.js';\nexport { createOllamaProvider } from './ollama.js';\n\n/**\n * Create an LLM provider from config.\n * Resolves apiKey from config or OPENCROC_LLM_API_KEY env variable.\n */\nexport function createLlmProvider(config: LlmConfig): LlmProvider {\n const resolved: LlmConfig = {\n ...config,\n apiKey: config.apiKey || process.env.OPENCROC_LLM_API_KEY,\n };\n\n switch (config.provider) {\n case 'openai':\n case 'zhipu':\n return createOpenAIProvider(resolved);\n case 'ollama':\n return createOllamaProvider(resolved);\n default:\n throw new Error(\n `Unknown LLM provider: \"${config.provider}\". Available: openai, zhipu, ollama`,\n );\n }\n}\n\n/**\n * Token usage tracker — accumulates tokens across multiple LLM calls.\n */\nexport interface TokenTracker {\n track(text: string): void;\n trackChat(messages: Array<{ role: string; content: string }>, response: string): void;\n total: number;\n reset(): void;\n}\n\nexport function createTokenTracker(provider: LlmProvider): TokenTracker {\n let total = 0;\n\n return {\n track(text: string) {\n total += provider.estimateTokens(text);\n },\n\n trackChat(messages: Array<{ role: string; content: string }>, response: string) {\n for (const msg of messages) {\n total += provider.estimateTokens(msg.content);\n }\n total += provider.estimateTokens(response);\n },\n\n get total() {\n return total;\n },\n\n reset() {\n total = 0;\n },\n };\n}\n\n/**\n * System prompts for different LLM use cases in OpenCroc.\n */\nexport const SYSTEM_PROMPTS = {\n failureAnalysis: `You are an expert test failure analyst for an E2E testing framework.\nGiven a test failure error message and its context, analyze the root cause and suggest a fix.\nRespond in JSON format: { \"rootCause\": string, \"category\": string, \"suggestedFix\": string, \"confidence\": number }\nCategories: backend-5xx, timeout, endpoint-not-found, data-constraint, network, frontend-render, test-script, unknown.`,\n\n chainPlanning: `You are an API test chain planner.\nGiven a list of API endpoints and their dependencies, generate an optimal test execution order.\nConsider data dependencies, authentication requirements, and cleanup steps.\nRespond in JSON format: { \"chains\": [{ \"name\": string, \"steps\": [{ \"endpoint\": string, \"method\": string, \"description\": string }] }] }`,\n} as const;\n","import type { SelfHealingConfig, SelfHealingResult, FixOutcome, LlmProvider } from '../types.js';\nimport { SYSTEM_PROMPTS } from '../llm/index.js';\n\nexport type { SelfHealingResult, FixOutcome };\n\nexport interface SelfHealingLoop {\n run(testResultsDir: string): Promise<SelfHealingResult>;\n}\n\nexport interface SelfHealingOptions {\n config: SelfHealingConfig;\n llm?: LlmProvider;\n}\n\n/**\n * Categorize a test failure by heuristic rules.\n */\nexport function categorizeFailure(errorMessage: string): {\n category: string;\n confidence: number;\n} {\n const msg = errorMessage.toLowerCase();\n\n if (/5\\d{2}|internal server error/.test(msg))\n return { category: 'backend-5xx', confidence: 0.9 };\n if (/timeout|timed?\\s*out/.test(msg))\n return { category: 'timeout', confidence: 0.8 };\n if (/404|not found/.test(msg))\n return { category: 'endpoint-not-found', confidence: 0.85 };\n if (/4[0-2]\\d|validation|constraint/.test(msg))\n return { category: 'data-constraint', confidence: 0.75 };\n if (/econnrefused|enotfound|network/.test(msg))\n return { category: 'network', confidence: 0.9 };\n if (/selector|locator|element/.test(msg))\n return { category: 'frontend-render', confidence: 0.7 };\n if (/storage\\s*state|auth|login/.test(msg))\n return { category: 'test-script', confidence: 0.8 };\n\n return { category: 'unknown', confidence: 0.5 };\n}\n\n/**\n * LLM-enhanced failure analysis with heuristic fallback.\n */\nexport async function analyzeFailureWithLLM(\n errorMessage: string,\n llm?: LlmProvider,\n): Promise<{ rootCause: string; category: string; suggestedFix: string; confidence: number }> {\n // Always get heuristic result as fallback\n const heuristic = categorizeFailure(errorMessage);\n\n if (!llm) {\n return {\n rootCause: errorMessage,\n category: heuristic.category,\n suggestedFix: '',\n confidence: heuristic.confidence,\n };\n }\n\n try {\n const response = await llm.chat([\n { role: 'system', content: SYSTEM_PROMPTS.failureAnalysis },\n { role: 'user', content: `Analyze this test failure:\\n\\n${errorMessage}` },\n ]);\n\n const parsed = JSON.parse(response) as {\n rootCause?: string;\n category?: string;\n suggestedFix?: string;\n confidence?: number;\n };\n\n return {\n rootCause: parsed.rootCause || errorMessage,\n category: parsed.category || heuristic.category,\n suggestedFix: parsed.suggestedFix || '',\n confidence: parsed.confidence || heuristic.confidence,\n };\n } catch {\n // LLM failed — fall back to heuristic\n return {\n rootCause: errorMessage,\n category: heuristic.category,\n suggestedFix: '',\n confidence: heuristic.confidence,\n };\n }\n}\n\n/**\n * Attempt a config-only fix: validate and write corrected config JSON.\n */\nasync function attemptConfigFix(\n _testResultsDir: string,\n _mode: SelfHealingConfig['mode'],\n _llm?: LlmProvider,\n): Promise<FixOutcome> {\n // TODO: Load module config → run autoFix validation → write corrected JSON\n // For now, return a no-op outcome\n return {\n success: false,\n scope: 'config-only',\n fixedItems: [],\n rolledBack: false,\n };\n}\n\n/**\n * Create a self-healing loop. Accepts an optional LLM provider for AI-enhanced analysis.\n */\nexport function createSelfHealingLoop(config: SelfHealingConfig, llm?: LlmProvider): SelfHealingLoop {\n return {\n async run(testResultsDir: string): Promise<SelfHealingResult> {\n const maxIterations = config.maxIterations || 3;\n const mode = config.mode || 'config-only';\n const fixed: string[] = [];\n const remaining: string[] = [];\n let iterations = 0;\n let totalTokensUsed = 0;\n\n for (let i = 0; i < maxIterations; i++) {\n iterations = i + 1;\n\n const outcome = await attemptConfigFix(testResultsDir, mode, llm);\n if (outcome.success) {\n fixed.push(...outcome.fixedItems);\n } else {\n remaining.push(`iteration-${i + 1}: no fix applied`);\n }\n\n // Track token usage if LLM is available\n if (llm) {\n totalTokensUsed += llm.estimateTokens(`iteration-${i + 1}`);\n }\n\n // If all fixed, stop early\n if (outcome.success && outcome.fixedItems.length > 0) break;\n }\n\n return {\n iterations,\n fixed,\n remaining,\n totalTokensUsed,\n };\n },\n };\n}\n","import chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { createSelfHealingLoop } from '../../self-healing/index.js';\nimport type { SelfHealingConfig } from '../../types.js';\n\nexport interface HealOptions {\n module?: string;\n maxIterations?: string;\n}\n\nexport async function heal(opts: HealOptions): Promise<void> {\n console.log(chalk.cyan.bold('\\n 🐊 OpenCroc — Self-Healing\\n'));\n\n const { config, filepath } = await loadConfig();\n console.log(chalk.gray(` Config: ${filepath}`));\n\n const outDir = config.outDir || './opencroc-output';\n const maxIterations = opts.maxIterations ? parseInt(opts.maxIterations, 10) : 3;\n\n const healingConfig: SelfHealingConfig = {\n enabled: true,\n maxIterations,\n mode: config.selfHealing?.mode || 'config-only',\n };\n\n console.log(chalk.gray(` Mode: ${healingConfig.mode}`));\n console.log(chalk.gray(` Max iterations: ${maxIterations}`));\n\n if (opts.module) {\n console.log(chalk.gray(` Module: ${opts.module}`));\n }\n console.log('');\n\n const loop = createSelfHealingLoop(healingConfig);\n const result = await loop.run(outDir);\n\n // Report results\n console.log(chalk.cyan(' Results:'));\n console.log(` Iterations : ${result.iterations}`);\n console.log(` Fixed : ${result.fixed.length > 0 ? chalk.green(result.fixed.join(', ')) : chalk.gray('(none)')}`);\n console.log(` Remaining : ${result.remaining.length > 0 ? chalk.yellow(result.remaining.join(', ')) : chalk.gray('(none)')}`);\n if (result.totalTokensUsed > 0) {\n console.log(` Tokens used : ${result.totalTokensUsed}`);\n }\n\n console.log('');\n\n if (result.remaining.length > 0) {\n console.log(chalk.yellow(' Some issues could not be auto-fixed. Manual review needed.\\n'));\n } else if (result.fixed.length > 0) {\n console.log(chalk.green(' ✓ All issues resolved.\\n'));\n } else {\n console.log(chalk.gray(' No issues detected.\\n'));\n }\n}\n","/**\n * CI template generators for popular CI/CD platforms.\n *\n * Usage:\n * npx opencroc ci --platform=github\n * npx opencroc ci --platform=gitlab\n */\n\nexport interface CiTemplateOptions {\n /** Node.js version(s). Default: ['20.x'] */\n nodeVersions?: string[];\n /** Install command. Default: 'npm ci' */\n installCommand?: string;\n /** Whether to run self-healing. Default: false */\n selfHeal?: boolean;\n /** Custom opencroc generate args */\n generateArgs?: string;\n /** Custom opencroc test args */\n testArgs?: string;\n}\n\nexport function generateGitHubActionsTemplate(opts: CiTemplateOptions = {}): string {\n const nodeVersions = opts.nodeVersions ?? ['20.x'];\n const install = opts.installCommand ?? 'npm ci';\n const genArgs = opts.generateArgs ?? '--all';\n const testArgs = opts.testArgs ?? '';\n const healStep = opts.selfHeal\n ? `\n - name: Self-heal failures\n if: failure()\n run: npx opencroc heal --max-iterations 3`\n : '';\n\n const matrix =\n nodeVersions.length > 1\n ? `\n strategy:\n matrix:\n node-version: [${nodeVersions.join(', ')}]`\n : '';\n\n const nodeSetup =\n nodeVersions.length > 1\n ? '${{ matrix.node-version }}'\n : nodeVersions[0];\n\n return `# Generated by OpenCroc — AI-native E2E testing\n# https://github.com/opencroc/opencroc\n\nname: OpenCroc E2E\n\non:\n push:\n branches: [main]\n pull_request:\n branches: [main]\n\njobs:\n e2e:\n runs-on: ubuntu-latest${matrix}\n steps:\n - uses: actions/checkout@v4\n\n - uses: actions/setup-node@v4\n with:\n node-version: '${nodeSetup}'\n\n - name: Install dependencies\n run: ${install}\n\n - name: Install Playwright browsers\n run: npx playwright install --with-deps chromium\n\n - name: Generate E2E tests\n run: npx opencroc generate ${genArgs}\n\n - name: Run E2E tests\n run: npx opencroc test ${testArgs}\n${healStep}\n - name: Upload test report\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: opencroc-report\n path: opencroc-output/\n retention-days: 14\n`;\n}\n\nexport function generateGitLabCITemplate(opts: CiTemplateOptions = {}): string {\n const install = opts.installCommand ?? 'npm ci';\n const genArgs = opts.generateArgs ?? '--all';\n const testArgs = opts.testArgs ?? '';\n const nodeVersion = opts.nodeVersions?.[0] ?? '20';\n\n return `# Generated by OpenCroc — AI-native E2E testing\n# https://github.com/opencroc/opencroc\n\nimage: node:${nodeVersion}\n\nstages:\n - generate\n - test\n\nvariables:\n PLAYWRIGHT_BROWSERS_PATH: \\${CI_PROJECT_DIR}/.cache/ms-playwright\n\ncache:\n key: \\${CI_COMMIT_REF_SLUG}\n paths:\n - node_modules/\n - .cache/ms-playwright/\n\ngenerate:\n stage: generate\n script:\n - ${install}\n - npx opencroc generate ${genArgs}\n artifacts:\n paths:\n - opencroc-output/\n expire_in: 1 day\n\ne2e:\n stage: test\n needs: [generate]\n before_script:\n - ${install}\n - npx playwright install --with-deps chromium\n script:\n - npx opencroc test ${testArgs}\n artifacts:\n when: always\n paths:\n - opencroc-output/\n expire_in: 14 days\n`;\n}\n\nconst TEMPLATES: Record<string, (opts: CiTemplateOptions) => string> = {\n github: generateGitHubActionsTemplate,\n gitlab: generateGitLabCITemplate,\n};\n\n/**\n * Get available CI platform names.\n */\nexport function listCiPlatforms(): string[] {\n return Object.keys(TEMPLATES);\n}\n\n/**\n * Generate a CI template for the given platform.\n */\nexport function generateCiTemplate(\n platform: string,\n opts: CiTemplateOptions = {},\n): string {\n const generator = TEMPLATES[platform];\n if (!generator) {\n throw new Error(\n `Unknown CI platform: \"${platform}\". Available: ${Object.keys(TEMPLATES).join(', ')}`,\n );\n }\n return generator(opts);\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { generateCiTemplate, listCiPlatforms } from '../../ci/index.js';\nimport type { CiTemplateOptions } from '../../ci/index.js';\n\nexport interface CiCommandOptions {\n platform?: string;\n selfHeal?: boolean;\n node?: string;\n}\n\nexport async function ci(opts: CiCommandOptions): Promise<void> {\n const platform = opts.platform ?? 'github';\n const available = listCiPlatforms();\n\n if (!available.includes(platform)) {\n console.error(chalk.red(`Unknown platform: \"${platform}\". Available: ${available.join(', ')}`));\n process.exitCode = 1;\n return;\n }\n\n const templateOpts: CiTemplateOptions = {\n selfHeal: opts.selfHeal ?? false,\n };\n if (opts.node) {\n templateOpts.nodeVersions = opts.node.split(',').map((s) => s.trim());\n }\n\n const content = generateCiTemplate(platform, templateOpts);\n\n let outputPath: string;\n if (platform === 'github') {\n outputPath = path.join('.github', 'workflows', 'opencroc.yml');\n } else if (platform === 'gitlab') {\n outputPath = '.gitlab-ci.yml';\n } else {\n outputPath = `opencroc-ci-${platform}.yml`;\n }\n\n const dir = path.dirname(outputPath);\n if (dir !== '.' && !fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, content, 'utf-8');\n console.log(chalk.green(`✔ CI template written to ${outputPath}`));\n console.log(chalk.dim(` Platform: ${platform}`));\n}\n","import type {\n PipelineRunResult,\n ERDiagramResult,\n ChainPlanResult,\n GeneratedTestFile,\n ValidationError,\n} from '../types.js';\n\n// ===== Reporter Types =====\n\nexport interface ReportOutput {\n format: 'html' | 'json' | 'markdown';\n content: string;\n filename: string;\n}\n\n// ===== JSON Reporter =====\n\nexport function generateJsonReport(result: PipelineRunResult): ReportOutput {\n const serializable = {\n modules: result.modules,\n erDiagrams: Object.fromEntries(\n Array.from(result.erDiagrams.entries()).map(([k, v]) => [\n k,\n { tables: v.tables.length, relations: v.relations.length, mermaidText: v.mermaidText },\n ]),\n ),\n chainPlans: Object.fromEntries(\n Array.from(result.chainPlans.entries()).map(([k, v]) => [\n k,\n { chains: v.chains.length, totalSteps: v.totalSteps },\n ]),\n ),\n generatedFiles: result.generatedFiles.map((f) => ({\n filePath: f.filePath,\n module: f.module,\n chain: f.chain,\n })),\n validationErrors: result.validationErrors,\n duration: result.duration,\n };\n\n return {\n format: 'json',\n content: JSON.stringify(serializable, null, 2),\n filename: 'opencroc-report.json',\n };\n}\n\n// ===== Markdown Reporter =====\n\nexport function generateMarkdownReport(result: PipelineRunResult): ReportOutput {\n const lines: string[] = [\n '# OpenCroc Report',\n '',\n `**Duration**: ${result.duration}ms`,\n `**Modules**: ${result.modules.length} (${result.modules.join(', ')})`,\n '',\n '## ER Diagrams',\n '',\n ];\n\n for (const [mod, er] of result.erDiagrams) {\n lines.push(`### ${mod}`);\n lines.push(`- Tables: ${er.tables.length}`);\n lines.push(`- Relations: ${er.relations.length}`);\n lines.push('');\n }\n\n lines.push('## Chain Plans', '');\n for (const [mod, plan] of result.chainPlans) {\n lines.push(`### ${mod}`);\n lines.push(`- Chains: ${plan.chains.length}`);\n lines.push(`- Total Steps: ${plan.totalSteps}`);\n lines.push('');\n }\n\n lines.push(`## Generated Files (${result.generatedFiles.length})`, '');\n for (const f of result.generatedFiles) {\n lines.push(`- \\`${f.filePath}\\` (${f.module} / ${f.chain})`);\n }\n\n if (result.validationErrors.length > 0) {\n lines.push('', '## Validation Issues', '');\n const errors = result.validationErrors.filter((e) => e.severity === 'error');\n const warnings = result.validationErrors.filter((e) => e.severity === 'warning');\n if (errors.length > 0) {\n lines.push(`### Errors (${errors.length})`, '');\n for (const e of errors) {\n lines.push(`- **[${e.module}]** ${e.field}: ${e.message}`);\n }\n }\n if (warnings.length > 0) {\n lines.push(`### Warnings (${warnings.length})`, '');\n for (const w of warnings) {\n lines.push(`- **[${w.module}]** ${w.field}: ${w.message}`);\n }\n }\n }\n\n lines.push('', '---', '*Generated by [OpenCroc](https://github.com/opencroc/opencroc)*');\n\n return {\n format: 'markdown',\n content: lines.join('\\n'),\n filename: 'opencroc-report.md',\n };\n}\n\n// ===== HTML Reporter =====\n\nfunction escapeHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\nfunction erSummaryRows(erDiagrams: Map<string, ERDiagramResult>): string {\n const rows: string[] = [];\n for (const [mod, er] of erDiagrams) {\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${er.tables.length}</td><td>${er.relations.length}</td></tr>`);\n }\n return rows.join('\\n');\n}\n\nfunction chainSummaryRows(chainPlans: Map<string, ChainPlanResult>): string {\n const rows: string[] = [];\n for (const [mod, plan] of chainPlans) {\n rows.push(`<tr><td>${escapeHtml(mod)}</td><td>${plan.chains.length}</td><td>${plan.totalSteps}</td></tr>`);\n }\n return rows.join('\\n');\n}\n\nfunction fileListRows(files: GeneratedTestFile[]): string {\n return files\n .map((f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`)\n .join('\\n');\n}\n\nfunction validationRows(errors: ValidationError[]): string {\n return errors\n .map(\n (e) =>\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>`,\n )\n .join('\\n');\n}\n\nexport function generateHtmlReport(result: PipelineRunResult): ReportOutput {\n const totalTables = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.tables.length, 0);\n const totalRelations = Array.from(result.erDiagrams.values()).reduce((s, e) => s + e.relations.length, 0);\n const totalChains = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.chains.length, 0);\n const totalSteps = Array.from(result.chainPlans.values()).reduce((s, p) => s + p.totalSteps, 0);\n const errorCount = result.validationErrors.filter((e) => e.severity === 'error').length;\n const warnCount = result.validationErrors.filter((e) => e.severity === 'warning').length;\n\n const html = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>OpenCroc Report</title>\n<style>\n :root { --bg: #0d1117; --fg: #c9d1d9; --card: #161b22; --border: #30363d; --accent: #58a6ff; --green: #3fb950; --yellow: #d29922; --red: #f85149; }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; background: var(--bg); color: var(--fg); padding: 2rem; }\n h1 { color: var(--accent); margin-bottom: 0.25rem; }\n .subtitle { color: #8b949e; margin-bottom: 2rem; }\n .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; }\n .card { background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 1.25rem; }\n .card .label { font-size: 0.85rem; color: #8b949e; }\n .card .value { font-size: 2rem; font-weight: 700; color: var(--accent); }\n .card .value.green { color: var(--green); }\n .card .value.yellow { color: var(--yellow); }\n .card .value.red { color: var(--red); }\n section { margin-bottom: 2rem; }\n h2 { color: var(--fg); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; margin-bottom: 1rem; }\n table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: 8px; overflow: hidden; }\n th, td { text-align: left; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }\n th { background: #21262d; color: #8b949e; font-weight: 600; font-size: 0.85rem; text-transform: uppercase; }\n tr:last-child td { border-bottom: none; }\n code { background: #21262d; padding: 0.15rem 0.4rem; border-radius: 4px; font-size: 0.85rem; }\n .badge { display: inline-block; padding: 0.15rem 0.5rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; text-transform: uppercase; }\n .badge.error { background: rgba(248,81,73,0.15); color: var(--red); }\n .badge.warning { background: rgba(210,153,34,0.15); color: var(--yellow); }\n footer { margin-top: 3rem; text-align: center; color: #484f58; font-size: 0.85rem; }\n footer a { color: var(--accent); text-decoration: none; }\n</style>\n</head>\n<body>\n<h1>OpenCroc Report</h1>\n<p class=\"subtitle\">Generated in ${result.duration}ms · ${result.modules.length} module(s)</p>\n\n<div class=\"grid\">\n <div class=\"card\"><div class=\"label\">Modules</div><div class=\"value\">${result.modules.length}</div></div>\n <div class=\"card\"><div class=\"label\">Tables</div><div class=\"value\">${totalTables}</div></div>\n <div class=\"card\"><div class=\"label\">Relations</div><div class=\"value\">${totalRelations}</div></div>\n <div class=\"card\"><div class=\"label\">Chains</div><div class=\"value\">${totalChains}</div></div>\n <div class=\"card\"><div class=\"label\">Steps</div><div class=\"value\">${totalSteps}</div></div>\n <div class=\"card\"><div class=\"label\">Files</div><div class=\"value green\">${result.generatedFiles.length}</div></div>\n <div class=\"card\"><div class=\"label\">Errors</div><div class=\"value${errorCount > 0 ? ' red' : ''}\">${errorCount}</div></div>\n <div class=\"card\"><div class=\"label\">Warnings</div><div class=\"value${warnCount > 0 ? ' yellow' : ''}\">${warnCount}</div></div>\n</div>\n\n<section>\n<h2>ER Diagrams</h2>\n<table>\n<thead><tr><th>Module</th><th>Tables</th><th>Relations</th></tr></thead>\n<tbody>${erSummaryRows(result.erDiagrams)}</tbody>\n</table>\n</section>\n\n<section>\n<h2>Chain Plans</h2>\n<table>\n<thead><tr><th>Module</th><th>Chains</th><th>Steps</th></tr></thead>\n<tbody>${chainSummaryRows(result.chainPlans)}</tbody>\n</table>\n</section>\n\n<section>\n<h2>Generated Files (${result.generatedFiles.length})</h2>\n<table>\n<thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\n<tbody>${fileListRows(result.generatedFiles)}</tbody>\n</table>\n</section>\n\n${\n result.validationErrors.length > 0\n ? `<section>\n<h2>Validation Issues (${result.validationErrors.length})</h2>\n<table>\n<thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\n<tbody>${validationRows(result.validationErrors)}</tbody>\n</table>\n</section>`\n : ''\n}\n\n<footer>\n Generated by <a href=\"https://github.com/opencroc/opencroc\">OpenCroc</a>\n</footer>\n</body>\n</html>`;\n\n return {\n format: 'html',\n content: html,\n filename: 'opencroc-report.html',\n };\n}\n\n// ===== Report Orchestrator =====\n\nconst REPORTERS: Record<string, (result: PipelineRunResult) => ReportOutput> = {\n html: generateHtmlReport,\n json: generateJsonReport,\n markdown: generateMarkdownReport,\n};\n\n/**\n * Generate reports in the specified formats.\n */\nexport function generateReports(\n result: PipelineRunResult,\n formats: ('html' | 'json' | 'markdown')[] = ['html'],\n): ReportOutput[] {\n return formats.map((fmt) => {\n const gen = REPORTERS[fmt];\n if (!gen) throw new Error(`Unknown report format: \"${fmt}\". Available: ${Object.keys(REPORTERS).join(', ')}`);\n return gen(result);\n });\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport { generateReports } from '../../reporters/index.js';\n\nexport interface ReportCommandOptions {\n format?: string;\n output?: string;\n}\n\nexport async function report(opts: ReportCommandOptions): Promise<void> {\n let loaded;\n try {\n loaded = await loadConfig();\n } catch {\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\n process.exitCode = 1;\n return;\n }\n\n const { config } = loaded;\n\n console.log(chalk.cyan('Running pipeline to generate report...'));\n const pipeline = createPipeline(config);\n const result = await pipeline.run();\n\n const formats = (opts.format ?? 'html').split(',').map((s) => s.trim()) as ('html' | 'json' | 'markdown')[];\n const reports = generateReports(result, formats);\n\n const outDir = opts.output ?? config.outDir ?? './opencroc-output';\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n\n for (const r of reports) {\n const filePath = path.join(outDir, r.filename);\n fs.writeFileSync(filePath, r.content, 'utf-8');\n console.log(chalk.green(`✔ ${r.format} report → ${filePath}`));\n }\n\n console.log(chalk.dim(` ${result.modules.length} modules, ${result.generatedFiles.length} files, ${result.duration}ms`));\n}\n","import type { PipelineRunResult } from '../types.js';\n\nexport interface DashboardData {\n generatedAt: string;\n durationMs: number;\n modules: string[];\n totals: {\n modules: number;\n tables: number;\n relations: number;\n chains: number;\n steps: number;\n files: number;\n errors: number;\n warnings: number;\n };\n moduleCards: Array<{\n module: string;\n tables: number;\n relations: number;\n chains: number;\n steps: number;\n }>;\n files: Array<{ filePath: string; module: string; chain: string }>;\n issues: Array<{ severity: string; module: string; field: string; message: string }>;\n}\n\nexport interface DashboardOutput {\n filename: string;\n content: string;\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\nfunction number(v: unknown): number {\n return typeof v === 'number' && Number.isFinite(v) ? v : 0;\n}\n\nexport function buildDashboardDataFromPipeline(result: PipelineRunResult): DashboardData {\n const moduleCards = result.modules.map((mod) => {\n const er = result.erDiagrams.get(mod);\n const plan = result.chainPlans.get(mod);\n return {\n module: mod,\n tables: er?.tables.length ?? 0,\n relations: er?.relations.length ?? 0,\n chains: plan?.chains.length ?? 0,\n steps: plan?.totalSteps ?? 0,\n };\n });\n\n const totals = {\n modules: result.modules.length,\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\n files: result.generatedFiles.length,\n errors: result.validationErrors.filter((e) => e.severity === 'error').length,\n warnings: result.validationErrors.filter((e) => e.severity === 'warning').length,\n };\n\n return {\n generatedAt: new Date().toISOString(),\n durationMs: result.duration,\n modules: [...result.modules],\n totals,\n moduleCards,\n files: result.generatedFiles.map((f) => ({ filePath: f.filePath, module: f.module, chain: f.chain })),\n issues: result.validationErrors.map((e) => ({\n severity: e.severity,\n module: e.module,\n field: e.field,\n message: e.message,\n })),\n };\n}\n\nexport function buildDashboardDataFromReportJson(input: unknown): DashboardData {\n const src = (input ?? {}) as Record<string, unknown>;\n const modules = Array.isArray(src.modules) ? src.modules.map((m) => String(m)) : [];\n const er = (src.erDiagrams ?? {}) as Record<string, { tables?: unknown; relations?: unknown }>;\n const plans = (src.chainPlans ?? {}) as Record<string, { chains?: unknown; totalSteps?: unknown }>;\n const files = Array.isArray(src.generatedFiles)\n ? src.generatedFiles.map((f) => {\n const row = f as Record<string, unknown>;\n return {\n filePath: String(row.filePath ?? ''),\n module: String(row.module ?? ''),\n chain: String(row.chain ?? ''),\n };\n })\n : [];\n\n const rawIssues = Array.isArray(src.validationErrors) ? src.validationErrors : [];\n const issues = rawIssues.map((item) => {\n const row = item as Record<string, unknown>;\n return {\n severity: String(row.severity ?? 'warning'),\n module: String(row.module ?? 'unknown'),\n field: String(row.field ?? 'unknown'),\n message: String(row.message ?? ''),\n };\n });\n\n const moduleCards = modules.map((mod) => ({\n module: mod,\n tables: number(er[mod]?.tables),\n relations: number(er[mod]?.relations),\n chains: number(plans[mod]?.chains),\n steps: number(plans[mod]?.totalSteps),\n }));\n\n return {\n generatedAt: new Date().toISOString(),\n durationMs: number(src.duration),\n modules,\n totals: {\n modules: modules.length,\n tables: moduleCards.reduce((s, m) => s + m.tables, 0),\n relations: moduleCards.reduce((s, m) => s + m.relations, 0),\n chains: moduleCards.reduce((s, m) => s + m.chains, 0),\n steps: moduleCards.reduce((s, m) => s + m.steps, 0),\n files: files.length,\n errors: issues.filter((i) => i.severity === 'error').length,\n warnings: issues.filter((i) => i.severity === 'warning').length,\n },\n moduleCards,\n files,\n issues,\n };\n}\n\nexport function generateVisualDashboardHtml(data: DashboardData): string {\n const moduleCardHtml = data.moduleCards\n .map(\n (m) => `<article class=\"module-card reveal\">\n <h3>${escapeHtml(m.module)}</h3>\n <div class=\"meta\">${m.tables} tables · ${m.relations} relations</div>\n <div class=\"bars\">\n <div class=\"bar\"><span>Chains</span><strong>${m.chains}</strong></div>\n <div class=\"bar\"><span>Steps</span><strong>${m.steps}</strong></div>\n </div>\n</article>`,\n )\n .join('\\n');\n\n const fileRows = data.files\n .slice(0, 20)\n .map(\n (f) => `<tr><td><code>${escapeHtml(f.filePath)}</code></td><td>${escapeHtml(f.module)}</td><td>${escapeHtml(f.chain)}</td></tr>`,\n )\n .join('\\n');\n\n const issueRows = data.issues\n .map(\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>`,\n )\n .join('\\n');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>OpenCroc Visual Dashboard</title>\n <style>\n @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap');\n :root {\n --bg: #f4efe6;\n --ink: #18222c;\n --card: #fff8ef;\n --line: #d8c7b4;\n --accent: #0b7a75;\n --accent-2: #f26a2e;\n --ok: #2f7d32;\n --warn: #b7791f;\n --err: #c0392b;\n }\n * { box-sizing: border-box; }\n body {\n margin: 0;\n font-family: 'Space Grotesk', 'Segoe UI', sans-serif;\n color: var(--ink);\n background:\n radial-gradient(circle at 15% 10%, #f9e2c5 0%, transparent 32%),\n radial-gradient(circle at 85% 0%, #d3efe4 0%, transparent 28%),\n var(--bg);\n min-height: 100vh;\n }\n .wrap { max-width: 1160px; margin: 0 auto; padding: 24px 18px 40px; }\n .hero {\n border: 2px solid var(--line);\n border-radius: 18px;\n background: linear-gradient(130deg, #fff8ef 0%, #f8f2ea 45%, #f3ece3 100%);\n padding: 22px;\n box-shadow: 0 12px 24px rgba(24, 34, 44, 0.08);\n position: relative;\n overflow: hidden;\n }\n .hero::after {\n content: '';\n position: absolute;\n right: -42px;\n top: -38px;\n width: 160px;\n height: 160px;\n border-radius: 50%;\n background: conic-gradient(from 50deg, #f26a2e 0deg, #f7a35a 90deg, #0b7a75 220deg, #f26a2e 360deg);\n opacity: 0.14;\n }\n h1 { margin: 0; font-size: clamp(1.6rem, 3vw, 2.5rem); letter-spacing: -0.03em; }\n .subtitle { margin-top: 8px; font-size: 0.95rem; opacity: 0.82; }\n .kpi-grid {\n margin-top: 16px;\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));\n gap: 10px;\n }\n .kpi {\n border: 1px solid var(--line);\n border-radius: 12px;\n padding: 10px 12px;\n background: #fffdf9;\n }\n .kpi .label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }\n .kpi .value { font-size: 1.45rem; font-weight: 700; margin-top: 4px; }\n .kpi.error .value { color: var(--err); }\n .kpi.warning .value { color: var(--warn); }\n .kpi.files .value { color: var(--accent); }\n\n .section-title {\n margin: 24px 0 10px;\n font-size: 1rem;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n color: #344250;\n }\n\n .module-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n gap: 12px;\n }\n .module-card {\n border: 1px solid var(--line);\n border-radius: 14px;\n padding: 14px;\n background: var(--card);\n box-shadow: 0 8px 16px rgba(24, 34, 44, 0.06);\n }\n .module-card h3 { margin: 0 0 6px; font-size: 1.05rem; }\n .module-card .meta { font-size: 0.85rem; opacity: 0.78; }\n .bars { margin-top: 10px; display: grid; gap: 8px; }\n .bar { display: flex; justify-content: space-between; border-top: 1px dashed var(--line); padding-top: 7px; }\n\n table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--line);\n border-radius: 12px;\n overflow: hidden;\n background: #fffdf9;\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\n font-size: 0.82rem;\n }\n thead { background: #efe5d8; }\n th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eadfce; }\n tbody tr:last-child td { border-bottom: none; }\n tr.error td:first-child { color: var(--err); font-weight: 700; }\n tr.warning td:first-child { color: var(--warn); font-weight: 700; }\n\n code {\n font-family: 'IBM Plex Mono', 'Consolas', monospace;\n background: #f5ece0;\n border: 1px solid #eadfce;\n border-radius: 6px;\n padding: 1px 5px;\n }\n\n .reveal { opacity: 0; transform: translateY(12px); animation: rise .55s ease forwards; }\n .module-card.reveal:nth-child(2) { animation-delay: .06s; }\n .module-card.reveal:nth-child(3) { animation-delay: .12s; }\n .module-card.reveal:nth-child(4) { animation-delay: .18s; }\n .module-card.reveal:nth-child(5) { animation-delay: .24s; }\n @keyframes rise {\n to { opacity: 1; transform: translateY(0); }\n }\n\n @media (max-width: 700px) {\n .wrap { padding: 14px 12px 28px; }\n .hero { padding: 16px; }\n table { font-size: 0.76rem; }\n th, td { padding: 7px 8px; }\n }\n </style>\n</head>\n<body>\n <main class=\"wrap\">\n <section class=\"hero reveal\">\n <h1>OpenCroc Visual Dashboard</h1>\n <p class=\"subtitle\">Pipeline finished in ${data.durationMs}ms · Generated ${escapeHtml(data.generatedAt)}</p>\n <div class=\"kpi-grid\">\n <div class=\"kpi\"><div class=\"label\">Modules</div><div class=\"value\">${data.totals.modules}</div></div>\n <div class=\"kpi\"><div class=\"label\">Tables</div><div class=\"value\">${data.totals.tables}</div></div>\n <div class=\"kpi\"><div class=\"label\">Relations</div><div class=\"value\">${data.totals.relations}</div></div>\n <div class=\"kpi\"><div class=\"label\">Chains</div><div class=\"value\">${data.totals.chains}</div></div>\n <div class=\"kpi\"><div class=\"label\">Steps</div><div class=\"value\">${data.totals.steps}</div></div>\n <div class=\"kpi files\"><div class=\"label\">Files</div><div class=\"value\">${data.totals.files}</div></div>\n <div class=\"kpi error\"><div class=\"label\">Errors</div><div class=\"value\">${data.totals.errors}</div></div>\n <div class=\"kpi warning\"><div class=\"label\">Warnings</div><div class=\"value\">${data.totals.warnings}</div></div>\n </div>\n </section>\n\n <h2 class=\"section-title\">Module Health</h2>\n <section class=\"module-grid\">\n ${moduleCardHtml || '<article class=\"module-card\">No module data</article>'}\n </section>\n\n <h2 class=\"section-title\">Generated Files (Top 20)</h2>\n <section>\n <table>\n <thead><tr><th>File</th><th>Module</th><th>Chain</th></tr></thead>\n <tbody>${fileRows || '<tr><td colspan=\"3\">No files generated</td></tr>'}</tbody>\n </table>\n </section>\n\n <h2 class=\"section-title\">Validation Issues</h2>\n <section>\n <table>\n <thead><tr><th>Severity</th><th>Module</th><th>Field</th><th>Message</th></tr></thead>\n <tbody>${issueRows || '<tr><td colspan=\"4\">No validation issues</td></tr>'}</tbody>\n </table>\n </section>\n </main>\n</body>\n</html>`;\n}\n\nexport function generateVisualDashboard(result: PipelineRunResult): DashboardOutput {\n const data = buildDashboardDataFromPipeline(result);\n return {\n filename: 'opencroc-dashboard.html',\n content: generateVisualDashboardHtml(data),\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport chalk from 'chalk';\nimport { loadConfig } from '../load-config.js';\nimport { createPipeline } from '../../pipeline/index.js';\nimport {\n buildDashboardDataFromReportJson,\n buildDashboardDataFromPipeline,\n generateVisualDashboardHtml,\n} from '../../dashboard/index.js';\n\nexport interface DashboardCommandOptions {\n output?: string;\n input?: string;\n}\n\nexport async function dashboard(opts: DashboardCommandOptions): Promise<void> {\n let dashboardHtml: string;\n\n if (opts.input) {\n const inputPath = path.resolve(opts.input);\n if (!fs.existsSync(inputPath)) {\n console.error(chalk.red(`Input report not found: ${inputPath}`));\n process.exitCode = 1;\n return;\n }\n\n const raw = fs.readFileSync(inputPath, 'utf-8');\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n console.error(chalk.red('Invalid JSON input. Please provide opencroc-report.json output.'));\n process.exitCode = 1;\n return;\n }\n\n const data = buildDashboardDataFromReportJson(parsed);\n dashboardHtml = generateVisualDashboardHtml(data);\n console.log(chalk.cyan(`Building visual dashboard from ${inputPath}...`));\n } else {\n let loaded;\n try {\n loaded = await loadConfig();\n } catch {\n console.error(chalk.red('No opencroc config found. Run `opencroc init` first.'));\n process.exitCode = 1;\n return;\n }\n\n const { config } = loaded;\n console.log(chalk.cyan('Running pipeline to build visual dashboard...'));\n const pipeline = createPipeline(config);\n const result = await pipeline.run();\n\n const data = buildDashboardDataFromPipeline(result);\n dashboardHtml = generateVisualDashboardHtml(data);\n }\n\n const outDir = opts.output ? path.resolve(opts.output) : path.resolve('./opencroc-output');\n if (!fs.existsSync(outDir)) {\n fs.mkdirSync(outDir, { recursive: true });\n }\n\n const outPath = path.join(outDir, 'opencroc-dashboard.html');\n fs.writeFileSync(outPath, dashboardHtml, 'utf-8');\n console.log(chalk.green(`✔ visual dashboard → ${outPath}`));\n}\n","#!/usr/bin/env node\n\nimport { Command } from 'commander';\n\nconst program = new Command();\n\nprogram\n .name('opencroc')\n .description('AI-native E2E testing framework')\n .version('0.6.1');\n\nprogram\n .command('init')\n .description('Initialize OpenCroc in the current project')\n .option('-y, --yes', 'Skip prompts and use defaults')\n .action(async (opts) => {\n const { initProject } = await import('./commands/init.js');\n await initProject(opts);\n });\n\nprogram\n .command('generate')\n .description('Generate E2E test cases from source code')\n .option('-m, --module <name>', 'Generate for a specific module')\n .option('-a, --all', 'Generate for all discovered modules')\n .option('--steps <steps>', 'Run specific pipeline steps (comma-separated)')\n .option('--dry-run', 'Preview without writing files')\n .action(async (opts) => {\n const { generate } = await import('./commands/generate.js');\n await generate(opts);\n });\n\nprogram\n .command('test')\n .description('Run generated E2E tests')\n .option('-m, --module <name>', 'Run tests for a specific module')\n .option('--headed', 'Run in headed browser mode')\n .action(async (opts) => {\n const { runTests } = await import('./commands/test.js');\n await runTests(opts);\n });\n\nprogram\n .command('validate')\n .description('Validate module configurations and generated tests')\n .option('-m, --module <name>', 'Validate a specific module')\n .action(async (opts) => {\n const { validate } = await import('./commands/validate.js');\n await validate(opts);\n });\n\nprogram\n .command('heal')\n .description('Run self-healing loop on failed tests')\n .option('-m, --module <name>', 'Heal a specific module')\n .option('--max-iterations <n>', 'Maximum healing iterations', '3')\n .action(async (opts) => {\n const { heal } = await import('./commands/heal.js');\n await heal(opts);\n });\n\nprogram\n .command('ci')\n .description('Generate CI/CD pipeline template')\n .option('-p, --platform <name>', 'CI platform (github, gitlab)', 'github')\n .option('--self-heal', 'Include self-healing step')\n .option('--node <versions>', 'Node.js versions (comma-separated)', '20.x')\n .action(async (opts) => {\n const { ci } = await import('./commands/ci.js');\n await ci(opts);\n });\n\nprogram\n .command('report')\n .description('Generate pipeline report (HTML/JSON/Markdown)')\n .option('-f, --format <formats>', 'Report formats (comma-separated)', 'html')\n .option('-o, --output <dir>', 'Output directory')\n .action(async (opts) => {\n const { report } = await import('./commands/report.js');\n await report(opts);\n });\n\nprogram\n .command('dashboard')\n .description('Generate visual dashboard (opencroc-dashboard.html)')\n .option('-i, --input <file>', 'Build from existing opencroc-report.json file')\n .option('-o, --output <dir>', 'Output directory', './opencroc-output')\n .action(async (opts) => {\n const { dashboard } = await import('./commands/dashboard.js');\n await dashboard(opts);\n });\n\nprogram.parse();\n"],"mappings":"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","names":["path","fs","path","Project","SyntaxKind","fullPath","fs","path","Project","SyntaxKind","producer","path","report","fs","path","chalk","writeFileSync","mkdirSync","existsSync","VALID_STEPS","chalk","readdirSync","existsSync","join","resolve","chalk","chalk","fs","path","chalk","init_ci","fs","path","chalk","escapeHtml","fs","path","chalk","init_dashboard","initProject","generate","runTests","validate","heal","ci","report","dashboard"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencroc",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "AI-native E2E testing framework — source-aware test generation, intelligent validation, and self-healing",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"e2e",
|
|
@@ -37,9 +37,10 @@
|
|
|
37
37
|
"dev": "tsup --watch",
|
|
38
38
|
"lint": "eslint src/",
|
|
39
39
|
"lint:fix": "eslint src/ --fix",
|
|
40
|
-
"test": "vitest run",
|
|
41
|
-
"test:
|
|
42
|
-
"test:
|
|
40
|
+
"test": "vitest run --config vitest.config.ts",
|
|
41
|
+
"test:stable": "vitest run --config vitest.config.ts",
|
|
42
|
+
"test:watch": "vitest --config vitest.config.ts",
|
|
43
|
+
"test:coverage": "vitest run --config vitest.config.ts --coverage",
|
|
43
44
|
"typecheck": "tsc --noEmit",
|
|
44
45
|
"prepublishOnly": "npm run build"
|
|
45
46
|
},
|