speclore 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/infra/logger.ts","../../src/types/config.ts","../../src/infra/config.ts","../../src/setup/detector.ts","../../src/version.ts","../../src/core/context-engine/config-reader.ts","../../src/infra/path-utils.ts","../../src/core/context-engine/graph-builder.ts","../../src/core/context-engine/context-writer.ts","../../src/core/context-engine/index.ts","../../src/ai/cost-tracker.ts","../../src/core/state-manager/index.ts","../../src/cli/commands/status.ts","../../src/plugins/builtin/md-reader.ts","../../src/plugins/builtin/docx-reader.ts","../../src/infra/excel-utils.ts","../../src/plugins/builtin/xlsx-reader.ts","../../src/plugins/builtin/pdf-reader.ts","../../src/ai/base-adapter.ts","../../src/ai/openai-adapter.ts","../../src/ai/claude-adapter.ts","../../src/ai/ollama-adapter.ts","../../src/ai/provider.ts","../../src/plugins/builtin/image-reader.ts","../../src/plugins/builtin/cursor-writer.ts","../../src/plugins/builtin/claude-writer.ts","../../src/plugins/builtin/qoder-writer.ts","../../src/plugins/builtin/junit-parser.ts","../../src/plugins/builtin/jest-parser.ts","../../src/plugins/builtin/vitest-parser.ts","../../src/plugins/registry.ts","../../src/core/requirement-reader/markdown-reader.ts","../../src/core/requirement-reader/docx-reader.ts","../../src/core/requirement-reader/xlsx-reader.ts","../../src/core/requirement-reader/pdf-reader.ts","../../src/core/requirement-reader/image-reader.ts","../../src/core/requirement-reader/url-reader.ts","../../src/core/requirement-reader/index.ts","../../src/ai/output-validator.ts","../../src/ai/token-counter.ts","../../src/ai/prompt-templates.ts","../../src/core/feature-generator/prompt-builder.ts","../../src/core/feature-generator/generator.ts","../../src/core/feature-generator/index.ts","../../src/core/constraint-coder/ai-tool-detector.ts","../../src/core/constraint-coder/constraint-writer.ts","../../src/core/constraint-coder/index.ts","../../src/core/test-scaffolder/framework-detector.ts","../../src/core/test-scaffolder/index.ts","../../src/core/verifier/mapping-resolver.ts","../../src/core/verifier/runner.ts","../../src/core/verifier/report-generator.ts","../../src/core/verifier/index.ts","../../src/core/analyzer/rdg-builder.ts","../../src/core/analyzer/cdg-builder.ts","../../src/core/analyzer/aligner.ts","../../src/core/analyzer/impact-analyzer.ts","../../src/core/analyzer/index.ts","../../src/infra/file-lock.ts","../../src/mcp/schemas.ts","../../src/mcp/tools.ts","../../src/mcp/status.ts","../../src/mcp/server.ts","../../src/cli/index.ts","../../src/cli/commands/setup.ts","../../src/setup/config-writer.ts","../../src/infra/install-detector.ts","../../src/setup/rule-writer.ts","../../src/cli/commands/init.ts","../../src/cli/commands/spec.ts","../../src/cli/commands/code.ts","../../src/cli/commands/verify.ts","../../src/cli/commands/teardown.ts","../../src/setup/cleanup.ts","../../src/cli/commands/migrate.ts","../../src/bin/cli.ts"],"sourcesContent":["/**\r\n * Structured logger powered by pino.\r\n *\r\n * - Development: pretty-printed colored output (via pino-pretty)\r\n * - Production: structured JSON (set SPECLORE_LOG_FORMAT=json or NODE_ENV=production)\r\n * - Enable debug via `--verbose` CLI flag or SPECLORE_LOG_LEVEL=debug env.\r\n *\r\n * Levels: debug < info < warn < error\r\n *\r\n * @module infra/logger\r\n */\r\n\r\nimport pino from 'pino';\r\nimport type { LogLevel } from '../types/index.js';\r\n\r\nlet currentLevel: LogLevel = 'info';\r\n\r\n/**\r\n * Determine if JSON output should be used.\r\n * JSON mode is enabled when:\r\n * - SPECLORE_LOG_FORMAT=json, or\r\n * - NODE_ENV=production (and no explicit format override)\r\n */\r\nfunction isJsonMode(): boolean {\r\n const format = process.env['SPECLORE_LOG_FORMAT'];\r\n if (format === 'json') return true;\r\n if (format === 'pretty') return false;\r\n return process.env['NODE_ENV'] === 'production';\r\n}\r\n\r\nfunction createPinoInstance(level: LogLevel): pino.Logger {\r\n const pinoLevel = toPinoLevel(level);\r\n\r\n if (isJsonMode()) {\r\n // Production: structured JSON to stdout\r\n return pino({\r\n level: pinoLevel,\r\n timestamp: pino.stdTimeFunctions.isoTime,\r\n formatters: {\r\n level(label) {\r\n return { level: label };\r\n },\r\n },\r\n });\r\n }\r\n\r\n // Development: pretty output via pino-pretty transport\r\n return pino({\r\n level: pinoLevel,\r\n transport: {\r\n target: 'pino-pretty',\r\n options: {\r\n colorize: true,\r\n translateTime: 'HH:MM:ss.l',\r\n ignore: 'pid,hostname',\r\n singleLine: true,\r\n },\r\n },\r\n });\r\n}\r\n\r\nfunction toPinoLevel(level: LogLevel): string {\r\n // pino levels: trace < debug < info < warn < error < fatal\r\n return level;\r\n}\r\n\r\nlet pinoInstance: pino.Logger = createPinoInstance(currentLevel);\r\n\r\n/**\r\n * Initialize the logger level.\r\n * Called once at CLI startup based on --verbose flag or env variable.\r\n */\r\nexport function initLogger(options?: { verbose?: boolean }): void {\r\n if (options?.verbose) {\r\n setLogLevel('debug');\r\n return;\r\n }\r\n\r\n const envLevel = process.env['SPECLORE_LOG_LEVEL'] as LogLevel | undefined;\r\n if (envLevel && ['debug', 'info', 'warn', 'error'].includes(envLevel)) {\r\n setLogLevel(envLevel);\r\n }\r\n}\r\n\r\n/**\r\n * Set the log level programmatically.\r\n */\r\nexport function setLogLevel(level: LogLevel): void {\r\n currentLevel = level;\r\n pinoInstance = createPinoInstance(level);\r\n}\r\n\r\n/**\r\n * Get the current log level.\r\n */\r\nexport function getLogLevel(): LogLevel {\r\n return currentLevel;\r\n}\r\n\r\nexport const logger = {\r\n debug(message: string, ...args: unknown[]): void {\r\n pinoInstance.debug({ args: args.length > 0 ? args : undefined }, message);\r\n },\r\n\r\n info(message: string, ...args: unknown[]): void {\r\n pinoInstance.info({ args: args.length > 0 ? args : undefined }, message);\r\n },\r\n\r\n warn(message: string, ...args: unknown[]): void {\r\n pinoInstance.warn({ args: args.length > 0 ? args : undefined }, message);\r\n },\r\n\r\n error(message: string, ...args: unknown[]): void {\r\n pinoInstance.error({ args: args.length > 0 ? args : undefined }, message);\r\n },\r\n\r\n /** Shortcut to set log level */\r\n setLevel(level: LogLevel): void {\r\n setLogLevel(level);\r\n },\r\n};\r\n","/**\r\n * SpecLore configuration type definitions.\r\n *\r\n * Maps to `.speclore/config.yaml` structure.\r\n * @module types/config\r\n */\r\n\r\nimport type { ProfileLevel } from './index.js';\r\n\r\n/** Root configuration — maps to config.yaml */\r\nexport interface SpecLoreConfig {\r\n project: ProjectConfig;\r\n ai?: AIConfig;\r\n spec: SpecConfig;\r\n verify: VerifyConfig;\r\n plugins?: PluginsConfig;\r\n}\r\n\r\n/** Project section */\r\nexport interface ProjectConfig {\r\n name: string;\r\n language: string;\r\n framework: string;\r\n /** Profile level: strict | normal | minimal (default: normal) */\r\n profile: ProfileLevel;\r\n /** Module declarations */\r\n modules: Record<string, ModuleConfig>;\r\n}\r\n\r\n/** Module declaration in config.yaml */\r\nexport interface ModuleConfig {\r\n path: string;\r\n responsibility: string;\r\n dependsOn?: string[];\r\n entities?: string[];\r\n apis?: string[];\r\n}\r\n\r\n/** AI provider section (optional — auto-detected when in AI client) */\r\nexport interface AIConfig {\r\n provider: 'openai-compatible' | 'claude' | 'ollama';\r\n baseUrl?: string;\r\n model?: string;\r\n /** API key from environment variable name, default: SPECLORE_API_KEY */\r\n apiKeyEnv?: string;\r\n /** Maximum budget in USD — calls are rejected when exceeded */\r\n maxBudgetUsd?: number;\r\n /** Fallback providers tried in order when the primary is unavailable */\r\n fallbackProviders?: AIConfig[];\r\n}\r\n\r\n/** Spec generation section */\r\nexport interface SpecConfig {\r\n /** Output directory for .feature files (default: \"specs\") */\r\n outputDir: string;\r\n /** Default language for generated features (default: \"zh-CN\") */\r\n defaultLanguage: string;\r\n /** Below this confidence, scenarios are flagged for review (default: 0.6) */\r\n confidenceThreshold: number;\r\n}\r\n\r\n/** Verification section */\r\nexport interface VerifyConfig {\r\n /** Test command to execute */\r\n command: string;\r\n /** Test timeout in seconds (default: 300) */\r\n timeout: number;\r\n /** Report formats to generate (default: [\"json\", \"html\"]) */\r\n reportFormat: ('json' | 'html')[];\r\n /** Test-to-feature mapping rules */\r\n mapping: MappingConfig;\r\n}\r\n\r\n/** Mapping configuration */\r\nexport interface MappingConfig {\r\n patterns: MappingPattern[];\r\n}\r\n\r\n/** Single mapping pattern */\r\nexport interface MappingPattern {\r\n /** Feature file pattern, e.g. \"specs/{module}/{name}.feature\" */\r\n feature: string;\r\n /** Test file pattern, e.g. \"tests/{module}/{Name}Test.*\" */\r\n test: string;\r\n}\r\n\r\n/** Plugin registration section */\r\nexport interface PluginsConfig {\r\n readers?: PluginRef[];\r\n writers?: PluginRef[];\r\n parsers?: PluginRef[];\r\n}\r\n\r\n/** Plugin reference in config.yaml */\r\nexport interface PluginRef {\r\n name: string;\r\n package: string;\r\n}\r\n\r\n/** Default configuration values */\r\nexport const DEFAULT_CONFIG: SpecLoreConfig = {\r\n project: {\r\n name: '',\r\n language: '',\r\n framework: '',\r\n profile: 'normal',\r\n modules: {},\r\n },\r\n spec: {\r\n outputDir: 'specs',\r\n defaultLanguage: 'zh-CN',\r\n confidenceThreshold: 0.6,\r\n },\r\n verify: {\r\n command: '',\r\n timeout: 300,\r\n reportFormat: ['json', 'html'],\r\n mapping: {\r\n patterns: [\r\n {\r\n feature: 'specs/{module}/{name}.feature',\r\n test: 'tests/{module}/{Name}Test.*',\r\n },\r\n {\r\n feature: 'specs/{module}/{name}.feature',\r\n test: 'tests/{module}/{name}.test.*',\r\n },\r\n {\r\n feature: 'specs/{module}/{name}.feature',\r\n test: 'tests/{module}/test_{name}.py',\r\n },\r\n ],\r\n },\r\n },\r\n};\r\n","/**\r\n * Configuration loader — reads, validates, and merges SpecLore config.\r\n *\r\n * Three-level merge order:\r\n * 1. Built-in defaults (DEFAULT_CONFIG)\r\n * 2. Global config: ~/.speclore/config.yaml\r\n * 3. Project config: .speclore/config.yaml (highest priority)\r\n *\r\n * @module infra/config\r\n */\r\n\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport yaml from 'js-yaml';\r\nimport type { ProfileLevel } from '../types/index.js';\r\nimport type { SpecLoreConfig } from '../types/config.js';\r\nimport { DEFAULT_CONFIG } from '../types/config.js';\r\n\r\nconst CONFIG_FILENAME = 'config.yaml';\r\nconst SPECLORE_DIR = '.speclore';\r\n\r\n/**\r\n * Load the merged configuration for the given project root.\r\n */\r\nexport function loadConfig(projectRoot: string): SpecLoreConfig {\r\n const globalConfig = loadGlobalConfig();\r\n const projectConfig = loadProjectConfig(projectRoot);\r\n\r\n return mergeConfigs(DEFAULT_CONFIG, globalConfig, projectConfig);\r\n}\r\n\r\n/**\r\n * Load global config from ~/.speclore/config.yaml\r\n */\r\nfunction loadGlobalConfig(): Partial<SpecLoreConfig> | null {\r\n const globalPath = join(homedir(), SPECLORE_DIR, CONFIG_FILENAME);\r\n return readYamlIfExists(globalPath);\r\n}\r\n\r\n/**\r\n * Load project config from {projectRoot}/.speclore/config.yaml\r\n */\r\nfunction loadProjectConfig(projectRoot: string): Partial<SpecLoreConfig> | null {\r\n const projectPath = join(projectRoot, SPECLORE_DIR, CONFIG_FILENAME);\r\n return readYamlIfExists(projectPath);\r\n}\r\n\r\n/**\r\n * Read and parse a YAML file if it exists, otherwise return null.\r\n */\r\nfunction readYamlIfExists(filePath: string): Record<string, unknown> | null {\r\n if (!existsSync(filePath)) {\r\n return null;\r\n }\r\n try {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });\r\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\r\n return parsed as Record<string, unknown>;\r\n }\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Deep-merge multiple partial configs. Later values override earlier ones.\r\n */\r\nfunction mergeConfigs(...configs: Array<Partial<SpecLoreConfig> | null>): SpecLoreConfig {\r\n const result = structuredClone(DEFAULT_CONFIG) as unknown as Record<string, unknown>;\r\n\r\n for (const config of configs) {\r\n if (!config) continue;\r\n deepMerge(result, config);\r\n }\r\n\r\n validateConfig(result as unknown as SpecLoreConfig);\r\n return result as unknown as SpecLoreConfig;\r\n}\r\n\r\n/**\r\n * Recursively merge `source` into `target`.\r\n */\r\nfunction deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {\r\n for (const key of Object.keys(source)) {\r\n const targetVal = target[key];\r\n const sourceVal = source[key];\r\n\r\n if (\r\n sourceVal !== null &&\r\n typeof sourceVal === 'object' &&\r\n !Array.isArray(sourceVal) &&\r\n targetVal !== null &&\r\n typeof targetVal === 'object' &&\r\n !Array.isArray(targetVal)\r\n ) {\r\n deepMerge(\r\n targetVal as Record<string, unknown>,\r\n sourceVal as Record<string, unknown>,\r\n );\r\n } else if (sourceVal !== undefined) {\r\n target[key] = sourceVal;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Validate the merged configuration.\r\n * Throws a descriptive error for invalid values.\r\n */\r\nfunction validateConfig(config: SpecLoreConfig): void {\r\n // Profile must be one of the allowed values\r\n const validProfiles: ProfileLevel[] = ['strict', 'normal', 'minimal'];\r\n if (!validProfiles.includes(config.project.profile)) {\r\n throw new ConfigError(\r\n `Invalid profile \"${config.project.profile}\". Must be one of: ${validProfiles.join(', ')}`,\r\n );\r\n }\r\n\r\n // Spec output dir must not be empty\r\n if (!config.spec.outputDir || config.spec.outputDir.trim() === '') {\r\n throw new ConfigError('spec.outputDir must not be empty');\r\n }\r\n\r\n // Confidence threshold must be between 0 and 1\r\n if (config.spec.confidenceThreshold < 0 || config.spec.confidenceThreshold > 1) {\r\n throw new ConfigError('spec.confidenceThreshold must be between 0 and 1');\r\n }\r\n\r\n // Verify timeout must be positive\r\n if (config.verify.timeout <= 0) {\r\n throw new ConfigError('verify.timeout must be a positive number (seconds)');\r\n }\r\n\r\n // AI provider validation\r\n if (config.ai) {\r\n const validProviders = ['openai-compatible', 'claude', 'ollama'] as const;\r\n if (!validProviders.includes(config.ai.provider)) {\r\n throw new ConfigError(\r\n `Invalid ai.provider \"${config.ai.provider}\". Must be one of: ${validProviders.join(', ')}`,\r\n );\r\n }\r\n }\r\n\r\n // Module dependency validation\r\n const moduleNames = Object.keys(config.project.modules);\r\n for (const [name, mod] of Object.entries(config.project.modules)) {\r\n if (!mod.path) {\r\n throw new ConfigError(`Module \"${name}\" must have a \"path\" field`);\r\n }\r\n if (!mod.responsibility) {\r\n throw new ConfigError(`Module \"${name}\" must have a \"responsibility\" field`);\r\n }\r\n if (mod.dependsOn) {\r\n for (const dep of mod.dependsOn) {\r\n if (!moduleNames.includes(dep)) {\r\n throw new ConfigError(\r\n `Module \"${name}\" depends on \"${dep}\", which is not declared in modules`,\r\n );\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get the path to the project's .speclore directory.\r\n */\r\nexport function getSpecLoreDir(projectRoot: string): string {\r\n return join(projectRoot, SPECLORE_DIR);\r\n}\r\n\r\n/**\r\n * Get the path to the global .speclore directory.\r\n */\r\nexport function getGlobalSpecLoreDir(): string {\r\n return join(homedir(), SPECLORE_DIR);\r\n}\r\n\r\n/** Configuration validation error */\r\nexport class ConfigError extends Error {\r\n constructor(message: string) {\r\n super(`[SpecLore Config] ${message}`);\r\n this.name = 'ConfigError';\r\n }\r\n}\r\n\r\n/** Generate default config.yaml content for a project */\r\nexport function generateDefaultConfigYaml(projectName: string): string {\r\n return `# SpecLore Configuration\r\n# See: https://github.com/cheneyzhang93/speclore#configuration\r\n\r\nproject:\r\n name: ${projectName}\r\n language: typescript\r\n framework: \"\"\r\n profile: normal\r\n modules: {}\r\n # Example:\r\n # order:\r\n # path: src/order\r\n # responsibility: Order management and processing\r\n # dependsOn: [inventory, payment]\r\n\r\nai:\r\n provider: openai-compatible\r\n # baseUrl: https://api.openai.com/v1\r\n # model: gpt-4\r\n\r\nspec:\r\n outputDir: specs\r\n defaultLanguage: zh-CN\r\n confidenceThreshold: 0.6\r\n\r\nverify:\r\n command: \"\"\r\n timeout: 300\r\n reportFormat:\r\n - json\r\n - html\r\n mapping:\r\n patterns:\r\n - feature: \"specs/{module}/{name}.feature\"\r\n test: \"tests/{module}/{name}.test.*\"\r\n`;\r\n}\r\n","/**\r\n * AI tool detector — scans project for Cursor, Claude Code, Qoder configurations.\r\n *\r\n * @module setup/detector\r\n */\r\n\r\nimport { existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { AIToolInfo } from '../types/index.js';\r\n\r\n/**\r\n * Detect which AI tools are present in the project.\r\n */\r\nexport function detectAITools(projectRoot: string): AIToolInfo[] {\r\n const tools: AIToolInfo[] = [];\r\n\r\n // Cursor\r\n const cursorFiles = ['.cursor/mcp.json', '.cursor/rules'];\r\n const cursorConfigs = cursorFiles.filter(f => existsSync(join(projectRoot, f)));\r\n tools.push({\r\n tool: 'cursor',\r\n detected: existsSync(join(projectRoot, '.cursor')),\r\n configFiles: cursorConfigs,\r\n });\r\n\r\n // Claude Code\r\n const claudeFiles = ['.claude/', '.mcp.json', 'CLAUDE.md'];\r\n const claudeConfigs = claudeFiles.filter(f => existsSync(join(projectRoot, f)));\r\n tools.push({\r\n tool: 'claude',\r\n detected: claudeConfigs.length > 0,\r\n configFiles: claudeConfigs,\r\n });\r\n\r\n // Qoder\r\n const qoderFiles = ['.qoder/mcp.json', '.qoder/rules'];\r\n const qoderConfigs = qoderFiles.filter(f => existsSync(join(projectRoot, f)));\r\n tools.push({\r\n tool: 'qoder',\r\n detected: existsSync(join(projectRoot, '.qoder')),\r\n configFiles: qoderConfigs,\r\n });\r\n\r\n return tools.filter(t => t.detected);\r\n}\r\n","/**\r\n * Single source of truth for SpecLore version.\r\n *\r\n * Reads version from package.json at runtime, working both in\r\n * source (src/version.ts) and built (dist/version.js) contexts.\r\n *\r\n * @module version\r\n */\r\n\r\nimport { readFileSync } from 'node:fs';\r\nimport { fileURLToPath } from 'node:url';\r\nimport { join, dirname } from 'node:path';\r\n\r\nfunction readVersion(): string {\r\n let currentDir = dirname(fileURLToPath(import.meta.url));\r\n\r\n // Walk up to find package.json (handles dist/, dist/cli/, dist/mcp/, src/)\r\n for (let depth = 0; depth < 4; depth++) {\r\n try {\r\n const pkgPath = join(currentDir, 'package.json');\r\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as Record<string, unknown>;\r\n if (typeof pkg.version === 'string') return pkg.version;\r\n } catch {\r\n // try parent\r\n }\r\n currentDir = join(currentDir, '..');\r\n }\r\n return '0.0.0';\r\n}\r\n\r\nexport const VERSION: string = readVersion();\r\n","/**\r\n * Config reader — parses module declarations from config.yaml.\r\n *\r\n * @module core/context-engine/config-reader\r\n */\r\n\r\nimport type { SpecLoreConfig, ModuleBoundary } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Read module declarations from the project config and build ModuleBoundary objects.\r\n */\r\nexport function readModuleConfig(config: SpecLoreConfig): ModuleBoundary[] {\r\n const boundaries: ModuleBoundary[] = [];\r\n\r\n for (const [name, mod] of Object.entries(config.project.modules)) {\r\n logger.debug(`Reading module config: ${name} → ${mod.path}`);\r\n\r\n boundaries.push({\r\n name,\r\n responsibility: mod.responsibility,\r\n publicApis: mod.apis ?? [],\r\n internalObjects: mod.entities ?? [],\r\n dependsOn: mod.dependsOn ?? [],\r\n });\r\n }\r\n\r\n return boundaries;\r\n}\r\n","/**\r\n * Cross-platform path utilities.\r\n *\r\n * Handles Windows / POSIX path normalization, relative path computation,\r\n * and glob pattern matching for SpecLore's file operations.\r\n *\r\n * @module infra/path-utils\r\n */\r\n\r\nimport { posix, sep, relative, resolve, isAbsolute, join } from 'node:path';\r\nimport { glob, globSync } from 'glob';\r\n\r\n/**\r\n * Normalize a path to use forward slashes (POSIX-style).\r\n * SpecLore stores all paths internally as POSIX for consistency.\r\n */\r\nexport function toPosixPath(p: string): string {\r\n return p.split(/[/\\\\]/).join(posix.sep);\r\n}\r\n\r\n/**\r\n * Normalize a path to the current platform's separator.\r\n */\r\nexport function toPlatformPath(p: string): string {\r\n if (sep === posix.sep) {\r\n return p;\r\n }\r\n return p.split(posix.sep).join(sep);\r\n}\r\n\r\n/**\r\n * Compute a relative path from `from` to `to`, returning POSIX-style result.\r\n */\r\nexport function relativePosix(from: string, to: string): string {\r\n return toPosixPath(relative(from, to));\r\n}\r\n\r\n/**\r\n * Resolve a path relative to a base directory, returning POSIX-style result.\r\n */\r\nexport function resolvePosix(base: string, ...segments: string[]): string {\r\n return toPosixPath(resolve(base, ...segments));\r\n}\r\n\r\n/**\r\n * Join path segments, returning POSIX-style result.\r\n */\r\nexport function joinPosix(...segments: string[]): string {\r\n return toPosixPath(join(...segments));\r\n}\r\n\r\n/**\r\n * Check if a path is absolute (platform-aware).\r\n */\r\nexport { isAbsolute };\r\n\r\n/**\r\n * Expand a glob pattern and return matching file paths (POSIX-style).\r\n */\r\nexport async function expandGlob(pattern: string, cwd?: string): Promise<string[]> {\r\n const matches = await glob(pattern, {\r\n cwd: cwd ?? process.cwd(),\r\n absolute: true,\r\n nodir: true,\r\n });\r\n return matches.map(toPosixPath);\r\n}\r\n\r\n/**\r\n * Expand a glob pattern synchronously.\r\n */\r\nexport function expandGlobSync(pattern: string, cwd?: string): string[] {\r\n const matches = globSync(pattern, {\r\n cwd: cwd ?? process.cwd(),\r\n absolute: true,\r\n nodir: true,\r\n });\r\n return matches.map(toPosixPath);\r\n}\r\n\r\n/**\r\n * Apply a mapping pattern to derive a test path from a feature path.\r\n *\r\n * Pattern variables:\r\n * {module} — module name (directory segment)\r\n * {name} — file name without extension\r\n * {Name} — file name without extension, first letter capitalized\r\n *\r\n * Example:\r\n * feature: \"specs/order/create.feature\"\r\n * pattern: \"tests/{module}/{Name}Test.*\"\r\n * result: \"tests/order/CreateTest.*\" (glob-ready)\r\n */\r\nexport function applyMappingPattern(\r\n featurePath: string,\r\n featurePattern: string,\r\n testPattern: string,\r\n): string | null {\r\n // Extract variables from the feature pattern\r\n const vars = extractPatternVars(featurePath, featurePattern);\r\n if (!vars) return null;\r\n\r\n // Apply variables to the test pattern\r\n let result = testPattern;\r\n for (const [key, value] of Object.entries(vars)) {\r\n result = result.replaceAll(`{${key}}`, value);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Extract pattern variables ({module}, {name}, {Name}) from a concrete path\r\n * by matching it against a pattern template.\r\n */\r\nfunction extractPatternVars(\r\n concretePath: string,\r\n pattern: string,\r\n): Record<string, string> | null {\r\n // Convert pattern to regex, capturing variable segments\r\n const vars: string[] = [];\r\n const regexStr = pattern\r\n .replace(/\\{(\\w+)}/g, (_, varName: string) => {\r\n vars.push(varName);\r\n return '([^/]+)';\r\n })\r\n // Escape dots for regex\r\n .replace(/\\./g, '\\\\.')\r\n // Handle * wildcard in patterns like \"Test.*\"\r\n .replace(/\\*/g, '.*');\r\n\r\n const regex = new RegExp(`^${regexStr}$`);\r\n const match = concretePath.match(regex);\r\n if (!match) return null;\r\n\r\n const result: Record<string, string> = {};\r\n for (let i = 0; i < vars.length; i++) {\r\n const varName = vars[i]!;\r\n const value = match[i + 1] ?? '';\r\n\r\n // Handle {Name} — capitalize first letter of {name}\r\n if (varName === 'Name' && result['name']) {\r\n result[varName] = result['name'].charAt(0).toUpperCase() + result['name'].slice(1);\r\n } else {\r\n result[varName] = value;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n","/**\r\n * Graph builder — scans project structure to build dependency graph and detect project info.\r\n *\r\n * @module core/context-engine/graph-builder\r\n */\r\n\r\nimport { existsSync, readdirSync, statSync, readFileSync } from 'node:fs';\r\nimport { join, basename, extname, relative } from 'node:path';\r\nimport type { GraphEdge, EntityInfo, ApiInfo } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { toPosixPath } from '../../infra/path-utils.js';\r\n\r\n/** Detected project information */\r\nexport interface ProjectInfo {\r\n language: string;\r\n framework: string;\r\n buildTool: string;\r\n testFramework: string;\r\n directoryStructure: string;\r\n}\r\n\r\n/**\r\n * Detect project language, framework, build tool, and test framework.\r\n */\r\nexport function detectProjectInfo(projectRoot: string): ProjectInfo {\r\n const info: ProjectInfo = {\r\n language: 'unknown',\r\n framework: 'unknown',\r\n buildTool: 'unknown',\r\n testFramework: 'unknown',\r\n directoryStructure: '',\r\n };\r\n\r\n // Language detection\r\n if (existsSync(join(projectRoot, 'package.json'))) {\r\n info.language = 'typescript';\r\n info.buildTool = 'npm';\r\n\r\n try {\r\n const pkg = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf-8')) as Record<string, Record<string, string> | undefined>;\r\n const deps: Record<string, string> = { ...pkg.dependencies, ...pkg.devDependencies };\r\n\r\n if ('next' in deps) info.framework = 'next.js';\r\n else if ('@nestjs/core' in deps) info.framework = 'nestjs';\r\n else if ('express' in deps) info.framework = 'express';\r\n else if ('react' in deps) info.framework = 'react';\r\n else if ('vue' in deps) info.framework = 'vue';\r\n else if ('nuxt' in deps) info.framework = 'nuxt';\r\n\r\n if ('vitest' in deps || 'jest' in deps) info.testFramework = 'vitest' in deps ? 'vitest' : 'jest';\r\n } catch {\r\n logger.debug('Failed to parse package.json, using default project info');\r\n }\r\n } else if (existsSync(join(projectRoot, 'pom.xml'))) {\r\n info.language = 'java';\r\n info.buildTool = 'maven';\r\n info.testFramework = 'junit';\r\n\r\n // Try to detect Spring Boot from pom.xml\r\n try {\r\n const pom = readFileSync(join(projectRoot, 'pom.xml'), 'utf-8');\r\n if (pom.includes('spring-boot')) info.framework = 'spring-boot';\r\n } catch { /* ignore */ }\r\n } else if (existsSync(join(projectRoot, 'build.gradle')) || existsSync(join(projectRoot, 'build.gradle.kts'))) {\r\n info.language = 'java';\r\n info.buildTool = 'gradle';\r\n info.testFramework = 'junit';\r\n } else if (existsSync(join(projectRoot, 'go.mod'))) {\r\n info.language = 'go';\r\n info.buildTool = 'go';\r\n info.testFramework = 'go-test';\r\n } else if (existsSync(join(projectRoot, 'Cargo.toml'))) {\r\n info.language = 'rust';\r\n info.buildTool = 'cargo';\r\n info.testFramework = 'cargo-test';\r\n } else if (existsSync(join(projectRoot, 'requirements.txt')) || existsSync(join(projectRoot, 'pyproject.toml'))) {\r\n info.language = 'python';\r\n info.buildTool = 'pip';\r\n info.testFramework = 'pytest';\r\n\r\n try {\r\n const reqs = existsSync(join(projectRoot, 'requirements.txt'))\r\n ? readFileSync(join(projectRoot, 'requirements.txt'), 'utf-8')\r\n : readFileSync(join(projectRoot, 'pyproject.toml'), 'utf-8');\r\n if (reqs.includes('django')) info.framework = 'django';\r\n else if (reqs.includes('flask')) info.framework = 'flask';\r\n else if (reqs.includes('fastapi')) info.framework = 'fastapi';\r\n } catch { /* ignore */ }\r\n }\r\n\r\n // Build directory structure summary (≤ 50 lines)\r\n info.directoryStructure = buildDirectorySummary(projectRoot, '', 2, 50);\r\n\r\n logger.debug(`Detected project: ${info.language} / ${info.framework} / ${info.buildTool}`);\r\n return info;\r\n}\r\n\r\n/**\r\n * Build a human-readable directory structure summary.\r\n */\r\nfunction buildDirectorySummary(\r\n root: string,\r\n _prefix: string,\r\n maxDepth: number,\r\n maxLines: number,\r\n): string {\r\n const lines: string[] = [];\r\n\r\n function walk(dir: string, indent: string, depth: number): void {\r\n if (depth > maxDepth || lines.length >= maxLines) return;\r\n\r\n let entries: string[];\r\n try {\r\n entries = readdirSync(dir)\r\n .filter(e => !e.startsWith('.') && e !== 'node_modules' && e !== '__pycache__')\r\n .sort();\r\n } catch {\r\n return;\r\n }\r\n\r\n for (const entry of entries) {\r\n if (lines.length >= maxLines) return;\r\n\r\n const fullPath = join(dir, entry);\r\n const isDir = statSync(fullPath).isDirectory();\r\n const display = isDir ? `${entry}/` : entry;\r\n lines.push(`${indent}${display}`);\r\n\r\n if (isDir) {\r\n walk(fullPath, indent + ' ', depth + 1);\r\n }\r\n }\r\n }\r\n\r\n walk(root, '', 0);\r\n return lines.slice(0, maxLines).join('\\n');\r\n}\r\n\r\n/**\r\n * Build dependency graph by scanning imports in source files.\r\n */\r\nexport function buildDependencyGraph(\r\n projectRoot: string,\r\n modules: Array<{ name: string; path: string; dependsOn: string[] }>,\r\n): GraphEdge[] {\r\n const edges: GraphEdge[] = [];\r\n\r\n // First, use declared dependencies from config\r\n for (const mod of modules) {\r\n for (const dep of mod.dependsOn) {\r\n edges.push({\r\n from: mod.name,\r\n to: dep,\r\n type: 'import',\r\n });\r\n }\r\n }\r\n\r\n // Then, try to detect additional dependencies from imports\r\n for (const mod of modules) {\r\n const modPath = join(projectRoot, mod.path);\r\n if (!existsSync(modPath)) continue;\r\n\r\n try {\r\n const imports = scanImports(modPath);\r\n for (const otherMod of modules) {\r\n if (otherMod.name === mod.name) continue;\r\n\r\n // Check if any import references the other module's path\r\n const otherPath = otherMod.path.replace(/\\\\/g, '/');\r\n const hasImport = imports.some(imp => imp.includes(otherPath) || imp.includes(otherMod.name));\r\n\r\n if (hasImport && !edges.some(e => e.from === mod.name && e.to === otherMod.name)) {\r\n edges.push({\r\n from: mod.name,\r\n to: otherMod.name,\r\n type: 'import',\r\n });\r\n }\r\n }\r\n } catch {\r\n // Skip module on scan error\r\n }\r\n }\r\n\r\n return edges;\r\n}\r\n\r\n/**\r\n * Scan a directory for import statements and return imported paths.\r\n */\r\nfunction scanImports(dir: string): string[] {\r\n const imports: string[] = [];\r\n\r\n function walk(d: string): void {\r\n let entries: string[];\r\n try {\r\n entries = readdirSync(d);\r\n } catch {\r\n return;\r\n }\r\n\r\n for (const entry of entries) {\r\n const fullPath = join(d, entry);\r\n const stat = statSync(fullPath);\r\n\r\n if (stat.isDirectory()) {\r\n walk(fullPath);\r\n continue;\r\n }\r\n\r\n const ext = extname(entry);\r\n if (!['.ts', '.tsx', '.js', '.jsx', '.java', '.py'].includes(ext)) continue;\r\n\r\n try {\r\n const content = readFileSync(fullPath, 'utf-8');\r\n // Match import/require patterns\r\n const importRegex = /(?:import\\s+.*?from\\s+['\"]([^'\"]+)['\"]|require\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\))/g;\r\n let match;\r\n while ((match = importRegex.exec(content)) !== null) {\r\n const imported = match[1] ?? match[2];\r\n if (imported) imports.push(imported);\r\n }\r\n } catch {\r\n // Skip unreadable files\r\n }\r\n }\r\n }\r\n\r\n walk(dir);\r\n return imports;\r\n}\r\n\r\n/**\r\n * Recursively read all files in a directory (Node 18 compatible).\r\n */\r\nfunction readDirRecursive(dir: string): string[] {\r\n const files: string[] = [];\r\n function walk(d: string): void {\r\n try {\r\n const entries = readdirSync(d, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const fullPath = join(d, entry.name);\r\n if (entry.isDirectory()) walk(fullPath);\r\n else files.push(fullPath);\r\n }\r\n } catch { /* skip unreadable dirs */ }\r\n }\r\n walk(dir);\r\n return files;\r\n}\r\n\r\n/** Supported source file extensions for heuristic analysis */\r\nconst ANALYZABLE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx', '.java', '.py']);\r\n\r\n/**\r\n * Analyze a single file for entity declarations (content-level heuristic).\r\n * Supports TypeScript/JavaScript, Java, and Python.\r\n */\r\nfunction analyzeFileForEntities(\r\n filePath: string,\r\n modName: string,\r\n modPath: string,\r\n modRelativePath: string,\r\n): EntityInfo[] {\r\n const entities: EntityInfo[] = [];\r\n const ext = extname(filePath);\r\n const name = basename(filePath, ext);\r\n\r\n if (!ANALYZABLE_EXTENSIONS.has(ext)) return entities;\r\n\r\n try {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const relFile = toPosixPath(join(modRelativePath, relative(modPath, filePath)));\r\n\r\n // Layer 1: File name suffix (fast path)\r\n if (/(?:Entity|Model|Domain|Schema)$/i.test(name)) {\r\n entities.push({ name, module: modName, file: relFile });\r\n return entities;\r\n }\r\n\r\n // Layer 2: Decorator/annotation-based detection\r\n if (ext === '.java') {\r\n // Java: @Entity annotation (JPA/Hibernate)\r\n const javaMatch = content.match(/@Entity(?:\\([^)]*\\))?\\s*(?:public\\s+)?(?:abstract\\s+)?class\\s+(\\w+)/);\r\n if (javaMatch?.[1]) {\r\n entities.push({ name: javaMatch[1], module: modName, file: relFile });\r\n return entities;\r\n }\r\n } else if (ext === '.py') {\r\n // Python: Django models.Model or SQLAlchemy Base\r\n const pyMatch = content.match(/class\\s+(\\w+)\\s*\\(\\s*(?:models\\.Model|Base|declarative_base\\(\\))\\s*\\)/);\r\n if (pyMatch?.[1]) {\r\n entities.push({ name: pyMatch[1], module: modName, file: relFile });\r\n return entities;\r\n }\r\n } else {\r\n // TypeScript/JavaScript: @Entity() / @Schema() decorators (TypeORM / Mongoose)\r\n // /s flag allows . to match newlines for multiline decorator args\r\n if (/@Entity\\(|@Schema\\(/.test(content)) {\r\n const classMatch = content.match(/@(?:Entity|Schema)\\([^)]*\\)\\s*(?:export\\s+)?(?:abstract\\s+)?class\\s+(\\w+)/s);\r\n if (classMatch?.[1]) {\r\n entities.push({ name: classMatch[1], module: modName, file: relFile });\r\n return entities;\r\n }\r\n }\r\n }\r\n\r\n // Layer 3: Class inheritance heuristic\r\n if (ext === '.java') {\r\n const extendsMatch = content.match(/class\\s+(\\w+)\\s+extends\\s+\\w*(?:Base)?(?:Entity|Model)\\b/);\r\n if (extendsMatch?.[1]) {\r\n entities.push({ name: extendsMatch[1], module: modName, file: relFile });\r\n }\r\n } else if (ext === '.py') {\r\n const extendsMatch = content.match(/class\\s+(\\w+)\\s*\\(\\s*\\w*(?:Base|Model)\\w*\\s*\\)/);\r\n if (extendsMatch?.[1] && !/Test|Mock|Fake/i.test(extendsMatch[1])) {\r\n entities.push({ name: extendsMatch[1], module: modName, file: relFile });\r\n }\r\n } else {\r\n const extendsMatch = content.match(/class\\s+(\\w+)\\s+extends\\s+\\w*(?:Base)?(?:Entity|Model|Document)\\b/);\r\n if (extendsMatch?.[1]) {\r\n entities.push({ name: extendsMatch[1], module: modName, file: relFile });\r\n }\r\n }\r\n } catch {\r\n // Skip unreadable files\r\n }\r\n\r\n return entities;\r\n}\r\n\r\n/**\r\n * Analyze a single file for API route declarations (content-level heuristic).\r\n * Supports Express, NestJS, Java Spring, and Python Flask/Django.\r\n */\r\nfunction analyzeFileForApis(\r\n filePath: string,\r\n modName: string,\r\n modPath: string,\r\n modRelativePath: string,\r\n): ApiInfo[] {\r\n const apis: ApiInfo[] = [];\r\n const ext = extname(filePath);\r\n const name = basename(filePath, ext);\r\n\r\n if (!ANALYZABLE_EXTENSIONS.has(ext)) return apis;\r\n\r\n try {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const relFile = toPosixPath(join(modRelativePath, relative(modPath, filePath)));\r\n\r\n // Layer 1: File name suffix (fast path) — default to GET\r\n if (/Controller|Resource|Handler|Route$/i.test(name)) {\r\n apis.push({\r\n method: 'GET',\r\n path: `/${modName}/${name.toLowerCase()}`,\r\n module: modName,\r\n file: relFile,\r\n });\r\n }\r\n\r\n // Layer 2: Express-style route definitions\r\n // Handles: router.get('/path', middleware, handler) and router.get('/path', handler)\r\n const expressRegex = /(?:router|app)\\.(get|post|put|patch|delete)\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*[,)]/gi;\r\n let match;\r\n while ((match = expressRegex.exec(content)) !== null) {\r\n const method = (match[1] ?? 'get').toUpperCase();\r\n const routePath = match[2]!;\r\n apis.push({\r\n method,\r\n path: routePath,\r\n module: modName,\r\n file: relFile,\r\n });\r\n }\r\n\r\n // Layer 3: NestJS decorator-based routes\r\n const nestjsRegex = /@(Get|Post|Put|Patch|Delete)\\s*\\(\\s*['\"`]([^'\"`]*)['\"`]\\s*\\)/g;\r\n while ((match = nestjsRegex.exec(content)) !== null) {\r\n const method = (match[1] ?? 'Get').toUpperCase();\r\n const routePath = match[2] ?? '';\r\n apis.push({\r\n method,\r\n path: routePath || `/${modName}`,\r\n module: modName,\r\n file: relFile,\r\n });\r\n }\r\n\r\n // Layer 4: Java Spring MVC annotations\r\n if (ext === '.java') {\r\n const springRegex = /@(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping)(?:\\s*\\(\\s*(?:value\\s*=\\s*)?['\"`]([^'\"`]*)['\"\"])?/g;\r\n while ((match = springRegex.exec(content)) !== null) {\r\n const annotation = match[1]!;\r\n const method = annotation.replace(/Mapping$/, '').toUpperCase() || 'GET';\r\n const routePath = match[2] ?? '';\r\n apis.push({\r\n method,\r\n path: routePath || `/${modName}`,\r\n module: modName,\r\n file: relFile,\r\n });\r\n }\r\n }\r\n\r\n // Layer 5: Python Flask/Django route decorators\r\n if (ext === '.py') {\r\n const flaskRegex = /@(\\w+)\\.route\\s*\\(\\s*['\"`]([^'\"`]+)['\"`]/g;\r\n while ((match = flaskRegex.exec(content)) !== null) {\r\n const routePath = match[2]!;\r\n // Flask defaults to GET unless methods= is specified\r\n const methodsMatch = content.slice(match.index).match(/methods\\s*=\\s*\\[([^\\]]+)\\]/);\r\n let method = 'GET';\r\n if (methodsMatch?.[1]) {\r\n // Take the first method from the list\r\n const firstMethod = methodsMatch[1].match(/['\"](\\w+)['\"]/)?.[1];\r\n if (firstMethod) method = firstMethod.toUpperCase();\r\n }\r\n apis.push({\r\n method,\r\n path: routePath,\r\n module: modName,\r\n file: relFile,\r\n });\r\n }\r\n }\r\n } catch {\r\n // Skip unreadable files\r\n }\r\n\r\n return apis;\r\n}\r\n\r\n/**\r\n * Extract entity info from source files.\r\n * Uses multi-layer heuristics: file name suffix, decorators, class inheritance.\r\n */\r\nexport function extractEntities(\r\n projectRoot: string,\r\n modules: Array<{ name: string; path: string }>,\r\n): EntityInfo[] {\r\n const entities: EntityInfo[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const mod of modules) {\r\n const modPath = join(projectRoot, mod.path);\r\n if (!existsSync(modPath)) continue;\r\n\r\n try {\r\n const files = readDirRecursive(modPath);\r\n for (const file of files) {\r\n const found = analyzeFileForEntities(file, mod.name, modPath, mod.path);\r\n for (const entity of found) {\r\n const key = `${entity.module}:${entity.name}`;\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n entities.push(entity);\r\n }\r\n }\r\n }\r\n } catch {\r\n // Skip module on error\r\n }\r\n }\r\n\r\n return entities;\r\n}\r\n\r\n/**\r\n * Extract API info from source files.\r\n * Uses multi-layer heuristics: file name suffix, Express routes, NestJS decorators.\r\n */\r\nexport function extractApis(\r\n projectRoot: string,\r\n modules: Array<{ name: string; path: string }>,\r\n): ApiInfo[] {\r\n const apis: ApiInfo[] = [];\r\n const seen = new Set<string>();\r\n\r\n for (const mod of modules) {\r\n const modPath = join(projectRoot, mod.path);\r\n if (!existsSync(modPath)) continue;\r\n\r\n try {\r\n const files = readDirRecursive(modPath);\r\n for (const file of files) {\r\n const found = analyzeFileForApis(file, mod.name, modPath, mod.path);\r\n for (const api of found) {\r\n const key = `${api.method}:${api.path}:${api.module}`;\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n apis.push(api);\r\n }\r\n }\r\n }\r\n } catch {\r\n // Skip module on error\r\n }\r\n }\r\n\r\n return apis;\r\n}\r\n","/**\r\n * Context writer — generates and caches context.json.\r\n *\r\n * @module core/context-engine/context-writer\r\n */\r\n\r\nimport { readFileSync, writeFileSync, existsSync, statSync, mkdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { execFileSync } from 'node:child_process';\r\nimport type { ContextFile, SpecLoreConfig } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { readModuleConfig } from './config-reader.js';\r\nimport { detectProjectInfo, buildDependencyGraph, extractEntities, extractApis } from './graph-builder.js';\r\nimport { VERSION } from '../../version.js';\r\n\r\nconst CONTEXT_FILENAME = 'context.json';\r\nconst CACHE_EXPIRY_MS = 60 * 60 * 1000; // 1 hour\r\nconst MAX_CONTEXT_SIZE = 50 * 1024; // 50KB\r\n\r\n/**\r\n * Build a complete project context from scratch.\r\n */\r\nexport function buildContext(projectRoot: string, config: SpecLoreConfig): ContextFile {\r\n logger.info('Building project context...');\r\n\r\n // Detect project info\r\n const projectInfo = detectProjectInfo(projectRoot);\r\n\r\n // Read module config\r\n const moduleBoundaries = readModuleConfig(config);\r\n\r\n // Build module list for scanning\r\n const moduleList = Object.entries(config.project.modules).map(([name, mod]) => ({\r\n name,\r\n path: mod.path,\r\n dependsOn: mod.dependsOn ?? [],\r\n }));\r\n\r\n // Build dependency graph\r\n const dependencyGraph = buildDependencyGraph(projectRoot, moduleList);\r\n\r\n // Extract entities and APIs\r\n const entities = extractEntities(projectRoot, moduleList);\r\n const apis = extractApis(projectRoot, moduleList);\r\n\r\n const contextFile: ContextFile = {\r\n version: '1.0',\r\n generatedAt: new Date().toISOString(),\r\n generatedBy: `speclore v${VERSION}`,\r\n projectSummary: {\r\n language: projectInfo.language,\r\n framework: projectInfo.framework,\r\n buildTool: projectInfo.buildTool,\r\n testFramework: projectInfo.testFramework,\r\n directoryStructure: projectInfo.directoryStructure,\r\n },\r\n moduleBoundaries,\r\n existingCode: {\r\n entities: entities.map(e => ({ name: e.name, module: e.module, file: e.file })),\r\n apis: apis.map(a => ({ method: a.method, path: a.path, module: a.module, file: a.file })),\r\n },\r\n dependencyGraph,\r\n };\r\n\r\n // Enforce size limit\r\n const json = JSON.stringify(contextFile, null, 2);\r\n if (json.length > MAX_CONTEXT_SIZE) {\r\n logger.warn(`Context file exceeds ${MAX_CONTEXT_SIZE} bytes, truncating...`);\r\n contextFile.projectSummary.directoryStructure = truncateTo(\r\n contextFile.projectSummary.directoryStructure,\r\n 20,\r\n );\r\n }\r\n\r\n return contextFile;\r\n}\r\n\r\n/**\r\n * Load context from cache (context.json).\r\n * Returns null if cache doesn't exist or is expired.\r\n */\r\nexport function loadContext(specLoreDir: string): ContextFile | null {\r\n const contextPath = join(specLoreDir, CONTEXT_FILENAME);\r\n\r\n if (!existsSync(contextPath)) {\r\n logger.debug('No cached context.json found');\r\n return null;\r\n }\r\n\r\n // Check expiry\r\n const stat = statSync(contextPath);\r\n const age = Date.now() - stat.mtimeMs;\r\n if (age > CACHE_EXPIRY_MS) {\r\n logger.debug(`Context cache expired (age: ${Math.round(age / 60000)}min)`);\r\n return null;\r\n }\r\n\r\n // Check git HEAD change\r\n if (hasGitHeadChanged(specLoreDir)) {\r\n logger.debug('Git HEAD changed since last context build');\r\n return null;\r\n }\r\n\r\n try {\r\n const content = readFileSync(contextPath, 'utf-8');\r\n const context = JSON.parse(content) as ContextFile;\r\n logger.debug('Loaded cached context.json');\r\n return context;\r\n } catch {\r\n logger.warn('Failed to parse cached context.json, will rebuild');\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Write context.json to disk.\r\n */\r\nexport function writeContextFile(specLoreDir: string, context: ContextFile): void {\r\n if (!existsSync(specLoreDir)) {\r\n mkdirSync(specLoreDir, { recursive: true });\r\n }\r\n\r\n const contextPath = join(specLoreDir, CONTEXT_FILENAME);\r\n writeFileSync(contextPath, JSON.stringify(context, null, 2), 'utf-8');\r\n logger.info(`Context written to ${contextPath}`);\r\n}\r\n\r\n/**\r\n * Refresh context: load from cache or rebuild.\r\n */\r\nexport function refreshContext(\r\n projectRoot: string,\r\n specLoreDir: string,\r\n config: SpecLoreConfig,\r\n): ContextFile {\r\n const cached = loadContext(specLoreDir);\r\n if (cached) return cached;\r\n\r\n const context = buildContext(projectRoot, config);\r\n writeContextFile(specLoreDir, context);\r\n return context;\r\n}\r\n\r\n/**\r\n * Check if git HEAD has changed since context was last built.\r\n */\r\nfunction hasGitHeadChanged(specLoreDir: string): boolean {\r\n try {\r\n const projectRoot = join(specLoreDir, '..');\r\n const head = execFileSync('git', ['rev-parse', 'HEAD'], {\r\n cwd: projectRoot,\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n }).trim();\r\n\r\n const headFile = join(specLoreDir, '.git-head');\r\n if (!existsSync(headFile)) return true;\r\n\r\n const savedHead = readFileSync(headFile, 'utf-8').trim();\r\n if (savedHead !== head) {\r\n // Update saved HEAD\r\n writeFileSync(headFile, head, 'utf-8');\r\n return true;\r\n }\r\n\r\n return false;\r\n } catch {\r\n // Not a git repo or git not available — don't use git-based expiry\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Truncate a string to a maximum number of lines.\r\n */\r\nfunction truncateTo(text: string, maxLines: number): string {\r\n const lines = text.split('\\n');\r\n if (lines.length <= maxLines) return text;\r\n return lines.slice(0, maxLines).join('\\n') + `\\n... (${lines.length - maxLines} more lines)`;\r\n}\r\n","/**\r\n * M5: Project Context Engine.\r\n *\r\n * Scans the target project to build a comprehensive context:\r\n * - Language / framework detection\r\n * - Module structure from config.yaml + directory scanning\r\n * - Dependency graph inference\r\n * - Entity and API extraction\r\n * - context.json generation and caching\r\n *\r\n * @module core/context-engine\r\n */\r\n\r\nexport { buildContext, loadContext, refreshContext } from './context-writer.js';\r\nexport { readModuleConfig } from './config-reader.js';\r\nexport { buildDependencyGraph, detectProjectInfo } from './graph-builder.js';\r\nexport { writeContextFile } from './context-writer.js';\r\n","/**\r\n * Cost tracker — tracks token usage and estimated costs across AI provider calls.\r\n *\r\n * Supports budget limits and per-model pricing for OpenAI and Anthropic.\r\n *\r\n * @module ai/cost-tracker\r\n */\r\n\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/** Per-model pricing in USD per 1K tokens (input/output) */\r\nconst MODEL_PRICING: Record<string, { inputPer1K: number; outputPer1K: number }> = {\r\n // OpenAI models\r\n 'gpt-4': { inputPer1K: 0.03, outputPer1K: 0.06 },\r\n 'gpt-4-turbo': { inputPer1K: 0.01, outputPer1K: 0.03 },\r\n 'gpt-4o': { inputPer1K: 0.005, outputPer1K: 0.015 },\r\n 'gpt-4o-mini': { inputPer1K: 0.00015, outputPer1K: 0.0006 },\r\n 'gpt-3.5-turbo': { inputPer1K: 0.0005, outputPer1K: 0.0015 },\r\n // Anthropic models\r\n 'claude-3-5-sonnet-20241022': { inputPer1K: 0.003, outputPer1K: 0.015 },\r\n 'claude-3-5-haiku-20241022': { inputPer1K: 0.001, outputPer1K: 0.005 },\r\n 'claude-3-opus-20240229': { inputPer1K: 0.015, outputPer1K: 0.075 },\r\n};\r\n\r\n/** Single usage record */\r\nexport interface UsageRecord {\r\n timestamp: string;\r\n model: string;\r\n promptTokens: number;\r\n completionTokens: number;\r\n totalTokens: number;\r\n estimatedCostUsd: number;\r\n}\r\n\r\n/** Aggregated usage summary */\r\nexport interface UsageSummary {\r\n totalCalls: number;\r\n totalPromptTokens: number;\r\n totalCompletionTokens: number;\r\n totalTokens: number;\r\n totalCostUsd: number;\r\n byModel: Record<string, { calls: number; tokens: number; costUsd: number }>;\r\n}\r\n\r\n/**\r\n * Tracks AI API usage and costs.\r\n */\r\nexport class CostTracker {\r\n private records: UsageRecord[] = [];\r\n private maxBudgetUsd: number;\r\n\r\n constructor(maxBudgetUsd?: number) {\r\n this.maxBudgetUsd = maxBudgetUsd ?? Infinity;\r\n }\r\n\r\n /**\r\n * Record a single API call's token usage.\r\n * Returns the estimated cost in USD.\r\n */\r\n recordUsage(model: string, promptTokens: number, completionTokens: number): number {\r\n const cost = this.estimateCost(model, promptTokens, completionTokens);\r\n\r\n const currentTotal = this.records.reduce((sum, r) => sum + r.estimatedCostUsd, 0);\r\n if (currentTotal + cost > this.maxBudgetUsd) {\r\n throw new Error(\r\n `Budget exceeded: $${(currentTotal + cost).toFixed(4)} would exceed limit of $${this.maxBudgetUsd.toFixed(2)}. ` +\r\n `Current spend: $${currentTotal.toFixed(4)}.`,\r\n );\r\n }\r\n\r\n this.records.push({\r\n timestamp: new Date().toISOString(),\r\n model,\r\n promptTokens,\r\n completionTokens,\r\n totalTokens: promptTokens + completionTokens,\r\n estimatedCostUsd: cost,\r\n });\r\n\r\n logger.debug(`AI usage: ${model} — ${promptTokens}+${completionTokens} tokens, ~$${cost.toFixed(4)}`);\r\n return cost;\r\n }\r\n\r\n /**\r\n * Estimate cost for a given model and token counts.\r\n */\r\n estimateCost(model: string, promptTokens: number, completionTokens: number): number {\r\n const pricing = MODEL_PRICING[model];\r\n if (!pricing) {\r\n // Unknown model — return 0 (can't estimate)\r\n logger.debug(`No pricing data for model: ${model}`);\r\n return 0;\r\n }\r\n\r\n const inputCost = (promptTokens / 1000) * pricing.inputPer1K;\r\n const outputCost = (completionTokens / 1000) * pricing.outputPer1K;\r\n return inputCost + outputCost;\r\n }\r\n\r\n /**\r\n * Get aggregated usage summary.\r\n */\r\n getUsageSummary(): UsageSummary {\r\n const summary: UsageSummary = {\r\n totalCalls: this.records.length,\r\n totalPromptTokens: 0,\r\n totalCompletionTokens: 0,\r\n totalTokens: 0,\r\n totalCostUsd: 0,\r\n byModel: {},\r\n };\r\n\r\n for (const record of this.records) {\r\n summary.totalPromptTokens += record.promptTokens;\r\n summary.totalCompletionTokens += record.completionTokens;\r\n summary.totalTokens += record.totalTokens;\r\n summary.totalCostUsd += record.estimatedCostUsd;\r\n\r\n if (!summary.byModel[record.model]) {\r\n summary.byModel[record.model] = { calls: 0, tokens: 0, costUsd: 0 };\r\n }\r\n const modelStats = summary.byModel[record.model]!;\r\n modelStats.calls++;\r\n modelStats.tokens += record.totalTokens;\r\n modelStats.costUsd += record.estimatedCostUsd;\r\n }\r\n\r\n return summary;\r\n }\r\n\r\n /**\r\n * Get all usage records.\r\n */\r\n getRecords(): UsageRecord[] {\r\n return [...this.records];\r\n }\r\n\r\n /**\r\n * Reset all tracking data.\r\n */\r\n reset(): void {\r\n this.records = [];\r\n }\r\n\r\n /**\r\n * Get the configured budget limit.\r\n */\r\n getBudgetLimit(): number {\r\n return this.maxBudgetUsd;\r\n }\r\n}\r\n\r\n/** Global cost tracker singleton */\r\nlet _tracker: CostTracker | null = null;\r\n\r\n/** Get or create the global cost tracker */\r\nexport function getCostTracker(maxBudgetUsd?: number): CostTracker {\r\n if (!_tracker) {\r\n _tracker = new CostTracker(maxBudgetUsd);\r\n }\r\n return _tracker;\r\n}\r\n\r\n/** Reset the global tracker (for testing) */\r\nexport function resetCostTracker(): void {\r\n _tracker = null;\r\n}\r\n","/**\r\n * State Manager — tracks project workflow state via .speclore/state.yaml.\r\n *\r\n * Provides state machine enforcement for MCP tools:\r\n * (none) → specified → constrained → coding → verified\r\n *\r\n * @module core/state-manager\r\n */\r\n\r\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport yaml from 'js-yaml';\r\nimport { globSync } from 'glob';\r\nimport type { FeatureState, FeatureStateEntry, ProjectState } from '../../types/index.js';\r\n\r\nconst STATE_FILENAME = 'state.yaml';\r\n\r\n/** Allowed state transitions */\r\nconst ALLOWED_TRANSITIONS: Record<FeatureState, FeatureState[]> = {\r\n specified: ['constrained'],\r\n constrained: ['coding'],\r\n coding: ['verified'],\r\n verified: ['constrained', 'specified'],\r\n};\r\n\r\nfunction createDefaultState(): ProjectState {\r\n return {\r\n schemaVersion: 1,\r\n initialized: true,\r\n initializedAt: new Date().toISOString(),\r\n features: {},\r\n };\r\n}\r\n\r\nexport class StateManager {\r\n private projectRoot: string;\r\n private statePath: string;\r\n\r\n constructor(projectRoot: string) {\r\n this.projectRoot = projectRoot;\r\n this.statePath = join(projectRoot, '.speclore', STATE_FILENAME);\r\n }\r\n\r\n /** Load state from disk, or return default if not exists */\r\n load(): ProjectState {\r\n if (!existsSync(this.statePath)) {\r\n return createDefaultState();\r\n }\r\n try {\r\n const content = readFileSync(this.statePath, 'utf-8');\r\n const parsed = yaml.load(content, { schema: yaml.JSON_SCHEMA });\r\n if (parsed && typeof parsed === 'object') {\r\n return parsed as ProjectState;\r\n }\r\n } catch {\r\n // Fall through to default\r\n }\r\n return createDefaultState();\r\n }\r\n\r\n /** Persist state to disk */\r\n save(state: ProjectState): void {\r\n const dir = join(this.projectRoot, '.speclore');\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n writeFileSync(this.statePath, yaml.dump(state, { lineWidth: 120 }), 'utf-8');\r\n }\r\n\r\n /** Ensure state file exists with default values */\r\n ensureInitialized(): ProjectState {\r\n if (!existsSync(this.statePath)) {\r\n // No state file — create and persist default\r\n const state = createDefaultState();\r\n this.save(state);\r\n return state;\r\n }\r\n const state = this.load();\r\n if (!state.initialized) {\r\n state.initialized = true;\r\n state.initializedAt = new Date().toISOString();\r\n this.save(state);\r\n }\r\n return state;\r\n }\r\n\r\n /** Get state entry for a specific feature */\r\n getFeatureState(featurePath: string): FeatureStateEntry | null {\r\n const state = this.load();\r\n return state.features[featurePath] ?? null;\r\n }\r\n\r\n /** Get project-level summary */\r\n getProjectSummary(): {\r\n initialized: boolean;\r\n featureCount: number;\r\n states: Record<FeatureState, number>;\r\n } {\r\n const state = this.load();\r\n const counts: Record<FeatureState, number> = {\r\n specified: 0,\r\n constrained: 0,\r\n coding: 0,\r\n verified: 0,\r\n };\r\n for (const entry of Object.values(state.features)) {\r\n counts[entry.state] = (counts[entry.state] ?? 0) + 1;\r\n }\r\n return {\r\n initialized: state.initialized,\r\n featureCount: Object.keys(state.features).length,\r\n states: counts,\r\n };\r\n }\r\n\r\n /**\r\n * Transition a feature to a new state.\r\n * @throws Error if transition is not allowed\r\n */\r\n transitionFeature(featurePath: string, to: FeatureState, guards?: FeatureState[]): void {\r\n const state = this.load();\r\n const entry = state.features[featurePath];\r\n\r\n if (!entry) {\r\n // New feature — only allow 'specified' as initial state\r\n if (to !== 'specified') {\r\n throw new Error(\r\n `Cannot transition feature \"${featurePath}\" to \"${to}\" — feature does not exist. Initial state must be \"specified\".`,\r\n );\r\n }\r\n state.features[featurePath] = {\r\n featureFile: featurePath,\r\n state: 'specified',\r\n constraintFiles: [],\r\n testFiles: [],\r\n lastStateChange: new Date().toISOString(),\r\n };\r\n } else {\r\n // Existing feature — check allowed transitions\r\n const allowed = ALLOWED_TRANSITIONS[entry.state];\r\n if (!allowed.includes(to)) {\r\n throw new Error(\r\n `Invalid state transition for \"${featurePath}\": \"${entry.state}\" → \"${to}\". Allowed: ${allowed.join(', ')}`,\r\n );\r\n }\r\n\r\n // Check guards if provided\r\n if (guards && !guards.includes(entry.state)) {\r\n throw new Error(\r\n `Guard failed for \"${featurePath}\": current state \"${entry.state}\" not in allowed guards [${guards.join(', ')}]`,\r\n );\r\n }\r\n\r\n entry.state = to;\r\n entry.lastStateChange = new Date().toISOString();\r\n }\r\n\r\n this.save(state);\r\n }\r\n\r\n /** Update feature entry with constraint/test file info */\r\n updateFeatureEntry(\r\n featurePath: string,\r\n updates: Partial<Pick<FeatureStateEntry, 'constraintFiles' | 'testFiles'>>,\r\n ): void {\r\n const state = this.load();\r\n const entry = state.features[featurePath];\r\n if (!entry) return;\r\n\r\n if (updates.constraintFiles !== undefined) {\r\n entry.constraintFiles = updates.constraintFiles;\r\n }\r\n if (updates.testFiles !== undefined) {\r\n entry.testFiles = updates.testFiles;\r\n }\r\n this.save(state);\r\n }\r\n\r\n /** Record verification result for a feature */\r\n recordVerify(\r\n featurePath: string,\r\n result: { passed: number; failed: number; unmapped: number },\r\n ): void {\r\n const state = this.load();\r\n const entry = state.features[featurePath];\r\n if (!entry) return;\r\n\r\n entry.lastVerify = {\r\n timestamp: new Date().toISOString(),\r\n ...result,\r\n };\r\n this.save(state);\r\n }\r\n\r\n /** List all tracked features with their states */\r\n listFeatures(): Array<{ path: string; state: FeatureStateEntry }> {\r\n const state = this.load();\r\n return Object.entries(state.features).map(([path, entry]) => ({ path, state: entry }));\r\n }\r\n\r\n /** Remove a feature from state tracking */\r\n removeFeature(featurePath: string): void {\r\n const state = this.load();\r\n delete state.features[featurePath];\r\n this.save(state);\r\n }\r\n\r\n /**\r\n * Migrate existing .feature files into state tracking.\r\n *\r\n * For projects upgrading from pre-workflow versions: scans the specs\r\n * directory for .feature files that are not yet tracked in state.yaml\r\n * and registers them as 'specified'. Returns the count of newly\r\n * registered features.\r\n */\r\n migrateFeatures(specsDir: string): number {\r\n const state = this.load();\r\n const trackedPaths = new Set(Object.keys(state.features));\r\n\r\n const featureFiles = globSync('**/*.feature', {\r\n cwd: specsDir,\r\n absolute: true,\r\n });\r\n\r\n let migrated = 0;\r\n for (const filePath of featureFiles) {\r\n if (trackedPaths.has(filePath)) continue;\r\n\r\n state.features[filePath] = {\r\n featureFile: filePath,\r\n state: 'specified',\r\n constraintFiles: [],\r\n testFiles: [],\r\n lastStateChange: new Date().toISOString(),\r\n };\r\n migrated++;\r\n }\r\n\r\n if (migrated > 0) {\r\n this.save(state);\r\n }\r\n\r\n return migrated;\r\n }\r\n}\r\n","/**\r\n * speclore status — project diagnostics.\r\n *\r\n * @module cli/commands/status\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { globSync } from 'glob';\r\nimport { loadConfig } from '../../infra/config.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { detectAITools } from '../../setup/detector.js';\r\nimport { getCostTracker } from '../../ai/cost-tracker.js';\r\nimport { StateManager } from '../../core/state-manager/index.js';\r\n\r\nexport function registerStatusCommand(program: Command): void {\r\n program\r\n .command('status')\r\n .description('Show project status and diagnostics')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action((opts: { verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n console.log('');\r\n console.log('SpecLore Status');\r\n console.log('═══════════════');\r\n console.log('');\r\n\r\n // Load config (use defaults if config file doesn't exist)\r\n const config = loadConfig(projectRoot);\r\n\r\n // Config check\r\n const configPath = join(projectRoot, '.speclore', 'config.yaml');\r\n if (existsSync(configPath)) {\r\n console.log(`✓ Config: ${configPath}`);\r\n console.log(` Project: ${config.project.name || '(unnamed)'}`);\r\n console.log(` Profile: ${config.project.profile}`);\r\n console.log(` Modules: ${Object.keys(config.project.modules).length}`);\r\n } else {\r\n console.log('✗ Config not found. Run `speclore setup` first.');\r\n }\r\n\r\n // Context check\r\n const contextPath = join(projectRoot, '.speclore', 'context.json');\r\n if (existsSync(contextPath)) {\r\n console.log(`✓ Context: ${contextPath}`);\r\n } else {\r\n console.log('✗ Context not found. Run `speclore init` first.');\r\n }\r\n\r\n // Feature files check — use configured output directory\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n if (existsSync(specsDir)) {\r\n const features = globSync('**/*.feature', { cwd: specsDir });\r\n console.log(`✓ Features: ${features.length} file(s) in ${config.spec.outputDir}/`);\r\n } else {\r\n console.log(`○ No ${config.spec.outputDir}/ directory yet.`);\r\n }\r\n\r\n // AI tools detection\r\n const tools = detectAITools(projectRoot);\r\n if (tools.length > 0) {\r\n console.log(`✓ AI Tools: ${tools.map(t => t.tool).join(', ')}`);\r\n } else {\r\n console.log('✗ No AI tools detected.');\r\n }\r\n\r\n // AI cost summary (for current session)\r\n const costSummary = getCostTracker().getUsageSummary();\r\n if (costSummary.totalCalls > 0) {\r\n console.log(`✓ AI Usage: ${costSummary.totalCalls} call(s), ${costSummary.totalTokens} tokens, ~$${costSummary.totalCostUsd.toFixed(4)}`);\r\n for (const [model, stats] of Object.entries(costSummary.byModel)) {\r\n console.log(` ${model}: ${stats.calls} call(s), ${stats.tokens} tokens, ~$${stats.costUsd.toFixed(4)}`);\r\n }\r\n } else {\r\n console.log('○ AI Usage: no calls in this session.');\r\n }\r\n\r\n // Workflow state\r\n console.log('');\r\n console.log('Workflow State');\r\n console.log('──────────────');\r\n const stateManager = new StateManager(projectRoot);\r\n stateManager.ensureInitialized();\r\n\r\n // Auto-migrate existing .feature files\r\n const specsDirForMigration = join(projectRoot, config.spec.outputDir);\r\n const migrated = stateManager.migrateFeatures(specsDirForMigration);\r\n if (migrated > 0) {\r\n console.log(`⬆ Migrated ${migrated} existing .feature file(s) into state tracking.`);\r\n console.log('');\r\n }\r\n\r\n const featureEntries = stateManager.listFeatures();\r\n if (featureEntries.length === 0) {\r\n console.log('○ No features tracked yet. Run `speclore spec` to create feature files.');\r\n } else {\r\n for (const { path, state: entry } of featureEntries) {\r\n const icon = entry.state === 'verified' ? '✓' : entry.state === 'coding' ? '◐' : entry.state === 'constrained' ? '◑' : '○';\r\n console.log(`${icon} ${path} → ${entry.state}`);\r\n }\r\n const summary = stateManager.getProjectSummary();\r\n console.log('');\r\n console.log(` Total: ${summary.featureCount} | specified: ${summary.states.specified} | constrained: ${summary.states.constrained} | coding: ${summary.states.coding} | verified: ${summary.states.verified}`);\r\n }\r\n\r\n // Recommended actions\r\n const testCommand = config.verify.command;\r\n if (featureEntries.length === 0) {\r\n console.log('');\r\n console.log('Next step: speclore spec <requirement>');\r\n } else {\r\n const hasSpecified = featureEntries.some(e => e.state.state === 'specified');\r\n const hasConstrained = featureEntries.some(e => e.state.state === 'constrained');\r\n const hasCoding = featureEntries.some(e => e.state.state === 'coding');\r\n if (hasSpecified) {\r\n console.log('Next step: speclore code — generate constraints and test scaffolding');\r\n } else if (hasConstrained) {\r\n console.log('Next step: Fill in test scaffolding, then start coding');\r\n } else if (hasCoding) {\r\n if (!testCommand) {\r\n console.log('Next step: Configure verify.command in .speclore/config.yaml, then: speclore verify');\r\n } else {\r\n console.log('Next step: speclore verify — run acceptance tests');\r\n }\r\n } else {\r\n console.log('All features verified. Add new requirements with: speclore spec');\r\n }\r\n }\r\n\r\n console.log('');\r\n });\r\n}\r\n","/**\r\n * Built-in Markdown reader plugin.\r\n * @module plugins/builtin/md-reader\r\n */\r\n\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport type { ReaderPlugin, StructuredRequirement } from '../../types/index.js';\r\n\r\nexport class MarkdownReader implements ReaderPlugin {\r\n readonly name = 'markdown-reader';\r\n readonly supportedFormats = ['.md', '.markdown'];\r\n\r\n canRead(source: string): boolean {\r\n return /\\.md$/i.test(source) || /\\.markdown$/i.test(source);\r\n }\r\n\r\n read(source: string): Promise<StructuredRequirement[]> {\r\n if (!existsSync(source)) {\r\n throw new Error(`File not found: ${source}`);\r\n }\r\n const content = readFileSync(source, 'utf-8');\r\n const titleMatch = content.match(/^#\\s+(.+)/m);\r\n const title = titleMatch?.[1]?.trim() ?? 'Untitled';\r\n\r\n // Extract acceptance criteria (lines starting with - [ ] or - [x] under ## Acceptance)\r\n const acceptanceCriteria: string[] = [];\r\n const acSection = content.match(/##\\s*Acceptance\\s*(?:Criteria)?[\\s\\S]*?(?=##|$)/i);\r\n if (acSection) {\r\n const items = acSection[0].match(/^[-*]\\s+\\[.\\]\\s+(.+)/gm);\r\n if (items) {\r\n acceptanceCriteria.push(...items.map(i => i.replace(/^[-*]\\s+\\[.\\]\\s+/, '')));\r\n }\r\n }\r\n\r\n return Promise.resolve([{\r\n id: source.replace(/\\\\/g, '/').replace(/\\.md$/i, ''),\r\n title,\r\n description: content,\r\n acceptanceCriteria: acceptanceCriteria.length > 0 ? acceptanceCriteria : undefined,\r\n rawContent: content,\r\n confidence: 0.9,\r\n }]);\r\n }\r\n}\r\n","/**\r\n * Built-in DOCX reader plugin.\r\n * @module plugins/builtin/docx-reader\r\n */\r\n\r\nimport type { ReaderPlugin, StructuredRequirement } from '../../types/index.js';\r\nimport type mammoth from 'mammoth';\r\n\r\nexport class DocxReader implements ReaderPlugin {\r\n readonly name = 'docx-reader';\r\n readonly supportedFormats = ['.docx'];\r\n\r\n canRead(source: string): boolean {\r\n return /\\.docx$/i.test(source);\r\n }\r\n\r\n async read(source: string): Promise<StructuredRequirement[]> {\r\n // Dynamic import — mammoth is optional\r\n let mammothModule: typeof mammoth;\r\n try {\r\n mammothModule = await import('mammoth');\r\n } catch {\r\n throw new Error('mammoth package is required for DOCX support. Install: npm i mammoth');\r\n }\r\n\r\n const result = await mammothModule.extractRawText({ path: source });\r\n const content = result.value;\r\n\r\n return [{\r\n id: source.replace(/\\\\/g, '/').replace(/\\.docx$/i, ''),\r\n title: source.split('/').pop()?.replace(/\\.docx$/i, '') ?? 'Untitled',\r\n description: content,\r\n rawContent: content,\r\n confidence: 0.8,\r\n }];\r\n }\r\n}\r\n","/**\r\n * Shared Excel cell formatting utilities — used by both core xlsx-reader and plugin xlsx-reader.\r\n *\r\n * @module infra/excel-utils\r\n */\r\n\r\n/** Safely convert an exceljs cell value to string. */\r\nexport function formatCellValue(value: unknown): string {\r\n if (value === null || value === undefined) return '';\r\n if (typeof value === 'string') return value;\r\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\r\n if (value instanceof Date) return value.toISOString();\r\n return '';\r\n}\r\n","/**\r\n * Built-in XLSX reader plugin.\r\n * @module plugins/builtin/xlsx-reader\r\n */\r\n\r\nimport type { ReaderPlugin, StructuredRequirement } from '../../types/index.js';\r\nimport ExcelJS from 'exceljs';\r\nimport { formatCellValue } from '../../infra/excel-utils.js';\r\n\r\nexport class XlsxReader implements ReaderPlugin {\r\n readonly name = 'xlsx-reader';\r\n readonly supportedFormats = ['.xlsx', '.xls'];\r\n\r\n canRead(source: string): boolean {\r\n return /\\.xlsx$/i.test(source) || /\\.xls$/i.test(source);\r\n }\r\n\r\n async read(source: string): Promise<StructuredRequirement[]> {\r\n const workbook = new ExcelJS.Workbook();\r\n await workbook.xlsx.readFile(source);\r\n\r\n const requirements: StructuredRequirement[] = [];\r\n\r\n for (const sheet of workbook.worksheets) {\r\n const sheetName = sheet.name;\r\n\r\n // First row as headers\r\n const headers: string[] = [];\r\n const rows: Record<string, string>[] = [];\r\n\r\n sheet.eachRow((row, rowNumber) => {\r\n if (rowNumber === 1) {\r\n row.eachCell((cell, colNumber) => {\r\n headers[colNumber - 1] = formatCellValue(cell.value);\r\n });\r\n } else {\r\n const obj: Record<string, string> = {};\r\n row.eachCell((cell, colNumber) => {\r\n const key = headers[colNumber - 1] ?? `Col${colNumber}`;\r\n obj[key] = formatCellValue(cell.value);\r\n });\r\n rows.push(obj);\r\n }\r\n });\r\n\r\n // Try to find columns: title/id, description, acceptance criteria\r\n for (let i = 0; i < rows.length; i++) {\r\n const row = rows[i]!;\r\n const title = row['Title'] ?? row['title'] ?? row['Name'] ?? row['name'] ?? row['ID'] ?? `Row ${i + 1}`;\r\n const description = row['Description'] ?? row['description'] ?? row['Desc'] ?? '';\r\n const ac = row['Acceptance Criteria'] ?? row['acceptance'] ?? row['AC'] ?? '';\r\n\r\n if (description || title) {\r\n requirements.push({\r\n id: `${sheetName}/${i + 1}`,\r\n title: String(title),\r\n description: String(description),\r\n acceptanceCriteria: ac ? String(ac).split('\\n').filter(Boolean) : undefined,\r\n rawContent: JSON.stringify(row),\r\n confidence: 0.7,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return requirements;\r\n }\r\n}\r\n","/**\r\n * Built-in PDF reader plugin.\r\n * @module plugins/builtin/pdf-reader\r\n */\r\n\r\nimport type { ReaderPlugin, StructuredRequirement } from '../../types/index.js';\r\n\r\nexport class PdfReader implements ReaderPlugin {\r\n readonly name = 'pdf-reader';\r\n readonly supportedFormats = ['.pdf'];\r\n\r\n canRead(source: string): boolean {\r\n return /\\.pdf$/i.test(source);\r\n }\r\n\r\n async read(source: string): Promise<StructuredRequirement[]> {\r\n let pdfParse: (buf: Buffer) => Promise<{ text: string }>;\r\n try {\r\n const mod = await import('pdf-parse');\r\n pdfParse = mod.default ?? mod;\r\n } catch {\r\n throw new Error('pdf-parse package is required for PDF support. Install: npm i pdf-parse');\r\n }\r\n\r\n const { readFileSync } = await import('node:fs');\r\n const buffer = readFileSync(source);\r\n const data = await pdfParse(buffer);\r\n\r\n return [{\r\n id: source.replace(/\\\\/g, '/').replace(/\\.pdf$/i, ''),\r\n title: source.split('/').pop()?.replace(/\\.pdf$/i, '') ?? 'Untitled',\r\n description: data.text,\r\n rawContent: data.text,\r\n confidence: 0.75,\r\n }];\r\n }\r\n}\r\n","/**\r\n * Base adapter — shared retry, backoff, and cost-tracking logic for all AI providers.\r\n *\r\n * Each concrete adapter (OpenAI, Claude, Ollama) extends this class\r\n * and implements the provider-specific API call inside `withRetry`.\r\n *\r\n * @module ai/base-adapter\r\n */\r\n\r\nimport type { AIProvider, GenerateOptions, GenerateResult } from './provider.js';\r\nimport { getCostTracker } from './cost-tracker.js';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/**\r\n * Abstract base for AI provider adapters.\r\n * Provides retry-with-exponential-backoff and cost tracking.\r\n */\r\nexport abstract class BaseAdapter implements AIProvider {\r\n abstract readonly name: string;\r\n\r\n /** Maximum retry attempts (override in subclass) */\r\n protected readonly maxRetries: number = 3;\r\n\r\n /** Base delay in ms for exponential backoff (override in subclass) */\r\n protected readonly retryBaseDelayMs: number = 1000;\r\n\r\n /** Model identifier — used for cost tracking */\r\n protected abstract readonly model: string;\r\n\r\n abstract isAvailable(): boolean;\r\n abstract generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult>;\r\n abstract generateWithImage?(\r\n prompt: string,\r\n image: { buffer: Buffer; mimeType: string },\r\n options?: GenerateOptions,\r\n ): Promise<GenerateResult>;\r\n\r\n /**\r\n * Execute an async operation with retry + exponential backoff.\r\n * Only retries on retryable errors (429, 5xx); client errors (4xx) are thrown immediately.\r\n * Returns the result on success; throws the last error after all retries exhausted.\r\n */\r\n protected async withRetry<T>(operation: (attempt: number) => Promise<T>, label: string): Promise<T> {\r\n let lastError: Error | null = null;\r\n\r\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\r\n try {\r\n return await operation(attempt);\r\n } catch (error) {\r\n if (!this.isRetryableError(error)) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n logger.warn(`${label} non-retryable error: ${err.message}`);\r\n throw err;\r\n }\r\n\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n logger.warn(`${label} attempt ${attempt + 1}/${this.maxRetries} failed: ${lastError.message}`);\r\n\r\n if (attempt < this.maxRetries - 1) {\r\n const delay = this.retryBaseDelayMs * Math.pow(2, attempt);\r\n await BaseAdapter.sleep(delay);\r\n }\r\n }\r\n }\r\n\r\n throw lastError ?? new Error(`${label} failed after ${this.maxRetries} retries`);\r\n }\r\n\r\n /**\r\n * Determine whether an error is retryable.\r\n * Default: only retry on network-level errors (ECONNRESET, ENOTFOUND, ETIMEDOUT).\r\n * Subclasses should override to use SDK-specific error classes for precise classification.\r\n */\r\n protected isRetryableError(error: unknown): boolean {\r\n if (error instanceof Error) {\r\n const msg = error.message.toLowerCase();\r\n // Network errors are retryable\r\n if (msg.includes('econnreset') || msg.includes('enotfound') || msg.includes('etimedout')) return true;\r\n }\r\n // Default: don't retry unknown errors (subclasses override with SDK-specific classes)\r\n return false;\r\n }\r\n\r\n /**\r\n * Create an AbortController linked to an optional user signal and timeout.\r\n * Returns the controller and a cleanup function to clear timers.\r\n */\r\n protected createTimeoutController(options?: GenerateOptions): { controller: AbortController; cleanup: () => void } {\r\n const controller = new AbortController();\r\n let timer: ReturnType<typeof setTimeout> | undefined;\r\n let abortHandler: (() => void) | undefined;\r\n\r\n if (options?.timeoutMs) {\r\n timer = setTimeout(() => controller.abort(), options.timeoutMs);\r\n }\r\n\r\n if (options?.signal) {\r\n if (options.signal.aborted) {\r\n controller.abort();\r\n } else {\r\n abortHandler = () => controller.abort();\r\n options.signal.addEventListener('abort', abortHandler, { once: true });\r\n }\r\n }\r\n\r\n return {\r\n controller,\r\n cleanup: () => {\r\n if (timer) clearTimeout(timer);\r\n if (abortHandler && options?.signal) {\r\n options.signal.removeEventListener('abort', abortHandler);\r\n }\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Record token usage to the global cost tracker.\r\n * Silently skips if usage is undefined (some providers don't report it).\r\n */\r\n protected recordCost(usage?: { promptTokens: number; completionTokens: number }): void {\r\n if (usage) {\r\n getCostTracker().recordUsage(this.model, usage.promptTokens, usage.completionTokens);\r\n }\r\n }\r\n\r\n /** Shared sleep utility */\r\n protected static sleep(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n }\r\n}\r\n","/**\r\n * OpenAI-compatible adapter.\r\n *\r\n * Supports OpenAI API, Azure OpenAI, and any OpenAI-compatible endpoint.\r\n * Environment: OPENAI_API_KEY, OPENAI_BASE_URL\r\n *\r\n * @module ai/openai-adapter\r\n */\r\n\r\nimport OpenAI, { RateLimitError, InternalServerError, APIConnectionError } from 'openai';\r\nimport { BaseAdapter } from './base-adapter.js';\r\nimport type { GenerateOptions, GenerateResult } from './provider.js';\r\nimport type { ChatCompletionMessageParam } from 'openai/resources/chat/completions';\r\n\r\nexport class OpenAIAdapter extends BaseAdapter {\r\n readonly name = 'openai-compatible';\r\n protected readonly model: string;\r\n private client: OpenAI | null = null;\r\n\r\n constructor(baseUrl?: string, model?: string, apiKeyEnv?: string) {\r\n super();\r\n this.model = model ?? 'gpt-4';\r\n const apiKey = process.env[apiKeyEnv ?? 'OPENAI_API_KEY'] ?? process.env['OPENAI_API_KEY'] ?? '';\r\n const baseURL = baseUrl ?? process.env['OPENAI_BASE_URL'];\r\n\r\n if (apiKey) {\r\n // SDK retries disabled — BaseAdapter.withRetry handles all retry logic\r\n this.client = new OpenAI({ apiKey, baseURL: baseURL ?? undefined, maxRetries: 0 });\r\n }\r\n }\r\n\r\n isAvailable(): boolean {\r\n return this.client !== null;\r\n }\r\n\r\n protected override isRetryableError(error: unknown): boolean {\r\n if (error instanceof RateLimitError) return true;\r\n if (error instanceof InternalServerError) return true;\r\n if (error instanceof APIConnectionError) return true;\r\n return false;\r\n }\r\n\r\n async generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult> {\r\n if (!this.client) {\r\n throw new Error('OpenAI client not initialized. Set OPENAI_API_KEY environment variable.');\r\n }\r\n\r\n const result = await this.withRetry(async () => {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await this.client!.chat.completions.create(\r\n {\r\n model: this.model,\r\n messages: [{ role: 'user', content: prompt }],\r\n max_tokens: options?.maxTokens,\r\n temperature: options?.temperature ?? 0.3,\r\n },\r\n { signal: controller.signal },\r\n );\r\n\r\n const content = response.choices[0]?.message?.content ?? '';\r\n const usage = response.usage;\r\n\r\n return {\r\n content,\r\n usage: usage\r\n ? {\r\n promptTokens: usage.prompt_tokens,\r\n completionTokens: usage.completion_tokens,\r\n totalTokens: usage.total_tokens,\r\n }\r\n : undefined,\r\n };\r\n } finally {\r\n cleanup();\r\n }\r\n }, 'OpenAI');\r\n\r\n this.recordCost(result.usage);\r\n return result;\r\n }\r\n\r\n async generateWithImage(prompt: string, image: { buffer: Buffer; mimeType: string }, options?: GenerateOptions): Promise<GenerateResult> {\r\n if (!this.client) {\r\n throw new Error('OpenAI client not initialized. Set OPENAI_API_KEY environment variable.');\r\n }\r\n\r\n const base64Image = image.buffer.toString('base64');\r\n const dataUrl = `data:${image.mimeType};base64,${base64Image}`;\r\n\r\n const messages: ChatCompletionMessageParam[] = [\r\n {\r\n role: 'user',\r\n content: [\r\n { type: 'text', text: prompt },\r\n { type: 'image_url', image_url: { url: dataUrl } },\r\n ],\r\n },\r\n ];\r\n\r\n const result = await this.withRetry(async () => {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await this.client!.chat.completions.create(\r\n {\r\n model: this.model,\r\n messages,\r\n max_tokens: options?.maxTokens,\r\n temperature: options?.temperature ?? 0.3,\r\n },\r\n { signal: controller.signal },\r\n );\r\n\r\n const content = response.choices[0]?.message?.content ?? '';\r\n const usage = response.usage;\r\n\r\n return {\r\n content,\r\n usage: usage\r\n ? {\r\n promptTokens: usage.prompt_tokens,\r\n completionTokens: usage.completion_tokens,\r\n totalTokens: usage.total_tokens,\r\n }\r\n : undefined,\r\n };\r\n } finally {\r\n cleanup();\r\n }\r\n }, 'OpenAI Vision');\r\n\r\n this.recordCost(result.usage);\r\n return result;\r\n }\r\n\r\n async *generateStream(prompt: string, options?: GenerateOptions): AsyncIterable<string> {\r\n if (!this.client) {\r\n throw new Error('OpenAI client not initialized. Set OPENAI_API_KEY environment variable.');\r\n }\r\n\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const stream = await this.client.chat.completions.create(\r\n {\r\n model: this.model,\r\n messages: [{ role: 'user', content: prompt }],\r\n max_tokens: options?.maxTokens,\r\n temperature: options?.temperature ?? 0.3,\r\n stream: true,\r\n },\r\n { signal: controller.signal },\r\n );\r\n\r\n for await (const chunk of stream) {\r\n const delta = chunk.choices[0]?.delta?.content ?? '';\r\n if (delta) yield delta;\r\n }\r\n } finally {\r\n cleanup();\r\n }\r\n }\r\n}\r\n","/**\r\n * Anthropic Claude adapter.\r\n *\r\n * Environment: ANTHROPIC_API_KEY\r\n *\r\n * @module ai/claude-adapter\r\n */\r\n\r\nimport Anthropic, { RateLimitError, InternalServerError, APIConnectionError } from '@anthropic-ai/sdk';\r\nimport { BaseAdapter } from './base-adapter.js';\r\nimport type { GenerateOptions, GenerateResult } from './provider.js';\r\n\r\nexport class ClaudeAdapter extends BaseAdapter {\r\n readonly name = 'claude';\r\n protected readonly model: string;\r\n private client: Anthropic | null = null;\r\n\r\n constructor(model?: string, apiKeyEnv?: string) {\r\n super();\r\n this.model = model ?? 'claude-sonnet-4-20250514';\r\n const apiKey = process.env[apiKeyEnv ?? 'ANTHROPIC_API_KEY'] ?? process.env['ANTHROPIC_API_KEY'] ?? '';\r\n\r\n if (apiKey) {\r\n // SDK retries disabled — BaseAdapter.withRetry handles all retry logic\r\n this.client = new Anthropic({ apiKey, maxRetries: 0 });\r\n }\r\n }\r\n\r\n isAvailable(): boolean {\r\n return this.client !== null;\r\n }\r\n\r\n protected override isRetryableError(error: unknown): boolean {\r\n if (error instanceof RateLimitError) return true;\r\n if (error instanceof InternalServerError) return true;\r\n if (error instanceof APIConnectionError) return true;\r\n return false;\r\n }\r\n\r\n async generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult> {\r\n if (!this.client) {\r\n throw new Error('Anthropic client not initialized. Set ANTHROPIC_API_KEY environment variable.');\r\n }\r\n\r\n const result = await this.withRetry(async () => {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await this.client!.messages.create(\r\n {\r\n model: this.model,\r\n max_tokens: options?.maxTokens ?? 4096,\r\n temperature: options?.temperature ?? 0.3,\r\n messages: [{ role: 'user', content: prompt }],\r\n },\r\n { signal: controller.signal },\r\n );\r\n\r\n const content = response.content\r\n .filter((block): block is Anthropic.TextBlock => block.type === 'text')\r\n .map(block => block.text)\r\n .join('\\n');\r\n\r\n return {\r\n content,\r\n usage: {\r\n promptTokens: response.usage.input_tokens,\r\n completionTokens: response.usage.output_tokens,\r\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\r\n },\r\n };\r\n } finally {\r\n cleanup();\r\n }\r\n }, 'Claude');\r\n\r\n this.recordCost(result.usage);\r\n return result;\r\n }\r\n\r\n async generateWithImage(prompt: string, image: { buffer: Buffer; mimeType: string }, options?: GenerateOptions): Promise<GenerateResult> {\r\n if (!this.client) {\r\n throw new Error('Anthropic client not initialized. Set ANTHROPIC_API_KEY environment variable.');\r\n }\r\n\r\n const base64Image = image.buffer.toString('base64');\r\n\r\n const messages = [\r\n {\r\n role: 'user' as const,\r\n content: [\r\n {\r\n type: 'image' as const,\r\n source: {\r\n type: 'base64' as const,\r\n media_type: image.mimeType as 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp',\r\n data: base64Image,\r\n },\r\n },\r\n { type: 'text' as const, text: prompt },\r\n ],\r\n },\r\n ];\r\n\r\n const result = await this.withRetry(async () => {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await this.client!.messages.create(\r\n {\r\n model: this.model,\r\n max_tokens: options?.maxTokens ?? 4096,\r\n temperature: options?.temperature ?? 0.3,\r\n messages,\r\n },\r\n { signal: controller.signal },\r\n );\r\n\r\n const content = response.content\r\n .filter((block): block is Anthropic.TextBlock => block.type === 'text')\r\n .map(block => block.text)\r\n .join('\\n');\r\n\r\n return {\r\n content,\r\n usage: {\r\n promptTokens: response.usage.input_tokens,\r\n completionTokens: response.usage.output_tokens,\r\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\r\n },\r\n };\r\n } finally {\r\n cleanup();\r\n }\r\n }, 'Claude Vision');\r\n\r\n this.recordCost(result.usage);\r\n return result;\r\n }\r\n\r\n async *generateStream(prompt: string, options?: GenerateOptions): AsyncIterable<string> {\r\n if (!this.client) {\r\n throw new Error('Anthropic client not initialized. Set ANTHROPIC_API_KEY environment variable.');\r\n }\r\n\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const stream = this.client.messages.stream(\r\n {\r\n model: this.model,\r\n max_tokens: options?.maxTokens ?? 4096,\r\n temperature: options?.temperature ?? 0.3,\r\n messages: [{ role: 'user', content: prompt }],\r\n },\r\n { signal: controller.signal },\r\n );\r\n\r\n for await (const event of stream) {\r\n if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {\r\n yield event.delta.text;\r\n }\r\n }\r\n } finally {\r\n cleanup();\r\n }\r\n }\r\n}\r\n","/**\r\n * Ollama adapter — local model inference.\r\n *\r\n * Default endpoint: http://localhost:11434\r\n *\r\n * @module ai/ollama-adapter\r\n */\r\n\r\nimport { BaseAdapter } from './base-adapter.js';\r\nimport type { GenerateOptions, GenerateResult } from './provider.js';\r\n\r\nconst DEFAULT_BASE_URL = 'http://localhost:11434';\r\n\r\nexport class OllamaAdapter extends BaseAdapter {\r\n readonly name = 'ollama';\r\n protected readonly model: string;\r\n protected readonly retryBaseDelayMs = 2000;\r\n private baseUrl: string;\r\n\r\n constructor(baseUrl?: string, model?: string) {\r\n super();\r\n this.baseUrl = baseUrl ?? DEFAULT_BASE_URL;\r\n this.model = model ?? 'llama3';\r\n }\r\n\r\n isAvailable(): boolean {\r\n // Ollama is always \"available\" locally — connection is checked at generate time\r\n return true;\r\n }\r\n\r\n protected override isRetryableError(error: unknown): boolean {\r\n if (!(error instanceof Error)) return false;\r\n const msg = error.message.toLowerCase();\r\n if (msg.includes('500') || msg.includes('502') || msg.includes('503') || msg.includes('504')) return true;\r\n if (msg.includes('econnreset') || msg.includes('etimedout') || msg.includes('enotfound')) return true;\r\n return false;\r\n }\r\n\r\n async generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult> {\r\n const result = await this.withRetry(async () => {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await fetch(`${this.baseUrl}/api/generate`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model: this.model,\r\n prompt,\r\n stream: false,\r\n options: {\r\n temperature: options?.temperature ?? 0.3,\r\n num_predict: options?.maxTokens,\r\n },\r\n }),\r\n signal: controller.signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Ollama returned ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const data = (await response.json()) as {\r\n response: string;\r\n prompt_eval_count?: number;\r\n eval_count?: number;\r\n };\r\n\r\n return {\r\n content: data.response,\r\n usage: data.prompt_eval_count\r\n ? {\r\n promptTokens: data.prompt_eval_count,\r\n completionTokens: data.eval_count ?? 0,\r\n totalTokens: data.prompt_eval_count + (data.eval_count ?? 0),\r\n }\r\n : undefined,\r\n };\r\n } finally {\r\n cleanup();\r\n }\r\n }, 'Ollama');\r\n\r\n this.recordCost(result.usage);\r\n return result;\r\n }\r\n\r\n async generateWithImage(prompt: string, image: { buffer: Buffer; mimeType: string }, options?: GenerateOptions): Promise<GenerateResult> {\r\n const base64Image = image.buffer.toString('base64');\r\n\r\n const result = await this.withRetry(async () => {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await fetch(`${this.baseUrl}/api/generate`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model: this.model,\r\n prompt,\r\n images: [base64Image],\r\n stream: false,\r\n options: {\r\n temperature: options?.temperature ?? 0.3,\r\n num_predict: options?.maxTokens,\r\n },\r\n }),\r\n signal: controller.signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Ollama returned ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const data = (await response.json()) as {\r\n response: string;\r\n prompt_eval_count?: number;\r\n eval_count?: number;\r\n };\r\n\r\n return {\r\n content: data.response,\r\n usage: data.prompt_eval_count\r\n ? {\r\n promptTokens: data.prompt_eval_count,\r\n completionTokens: data.eval_count ?? 0,\r\n totalTokens: data.prompt_eval_count + (data.eval_count ?? 0),\r\n }\r\n : undefined,\r\n };\r\n } finally {\r\n cleanup();\r\n }\r\n }, 'Ollama Vision');\r\n\r\n this.recordCost(result.usage);\r\n return result;\r\n }\r\n\r\n async *generateStream(prompt: string, options?: GenerateOptions): AsyncIterable<string> {\r\n const { controller, cleanup } = this.createTimeoutController(options);\r\n try {\r\n const response = await fetch(`${this.baseUrl}/api/generate`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify({\r\n model: this.model,\r\n prompt,\r\n stream: true,\r\n options: {\r\n temperature: options?.temperature ?? 0.3,\r\n },\r\n }),\r\n signal: controller.signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`Ollama returned ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n if (!response.body) {\r\n throw new Error('Ollama streaming response has no body');\r\n }\r\n\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n\r\n while (true) {\r\n const { done, value } = await reader.read() as { done: boolean; value: Uint8Array | undefined };\r\n if (done) break;\r\n const lines = decoder.decode(value ?? new Uint8Array()).trim().split('\\n');\r\n for (const line of lines) {\r\n if (!line) continue;\r\n try {\r\n const data = JSON.parse(line) as { response?: string };\r\n if (data.response) yield data.response;\r\n } catch {\r\n // Skip malformed NDJSON lines\r\n }\r\n }\r\n }\r\n } finally {\r\n cleanup();\r\n }\r\n }\r\n}\r\n","/**\r\n * AI Provider abstraction — unified interface for all AI backends.\r\n *\r\n * @module ai/provider\r\n */\r\n\r\n/** Options for a single generation call */\r\nexport interface GenerateOptions {\r\n /** Max tokens to generate */\r\n maxTokens?: number;\r\n /** Temperature (0-2) */\r\n temperature?: number;\r\n /** Abort signal for cancellation */\r\n signal?: AbortSignal;\r\n /** Request timeout in milliseconds */\r\n timeoutMs?: number;\r\n}\r\n\r\n/** Result from an AI generation call */\r\nexport interface GenerateResult {\r\n content: string;\r\n /** Token usage if reported by the provider */\r\n usage?: {\r\n promptTokens: number;\r\n completionTokens: number;\r\n totalTokens: number;\r\n };\r\n}\r\n\r\n/** AI Provider interface — all adapters must implement this */\r\nexport interface AIProvider {\r\n /** Provider identifier */\r\n readonly name: string;\r\n\r\n /** Check if the provider is available (API key set, endpoint reachable) */\r\n isAvailable(): boolean;\r\n\r\n /** Generate text from a prompt */\r\n generate(prompt: string, options?: GenerateOptions): Promise<GenerateResult>;\r\n\r\n /**\r\n * Generate text from a prompt + image (multimodal vision API).\r\n * Providers that don't support vision should throw an error.\r\n */\r\n generateWithImage?(prompt: string, image: { buffer: Buffer; mimeType: string }, options?: GenerateOptions): Promise<GenerateResult>;\r\n\r\n /**\r\n * Stream text generation. Returns an async iterable of text chunks.\r\n * Providers that don't support streaming should not implement this.\r\n */\r\n generateStream?(prompt: string, options?: GenerateOptions): AsyncIterable<string>;\r\n}\r\n\r\n/** Create an AI provider based on config */\r\nexport async function createProvider(\r\n config?: { provider?: string; baseUrl?: string; model?: string; apiKeyEnv?: string },\r\n): Promise<AIProvider> {\r\n const provider = config?.provider ?? 'openai-compatible';\r\n\r\n switch (provider) {\r\n case 'openai-compatible': {\r\n const { OpenAIAdapter } = await import('./openai-adapter.js');\r\n return new OpenAIAdapter(config?.baseUrl, config?.model, config?.apiKeyEnv);\r\n }\r\n case 'claude': {\r\n const { ClaudeAdapter } = await import('./claude-adapter.js');\r\n return new ClaudeAdapter(config?.model, config?.apiKeyEnv);\r\n }\r\n case 'ollama': {\r\n const { OllamaAdapter } = await import('./ollama-adapter.js');\r\n return new OllamaAdapter(config?.baseUrl, config?.model);\r\n }\r\n default:\r\n throw new Error(`Unknown AI provider: ${provider}`);\r\n }\r\n}\r\n\r\n/**\r\n * Create a fallback chain of providers.\r\n * Tries each provider in order; if one is unavailable, falls back to the next.\r\n * The returned provider wraps the first available one.\r\n */\r\nexport async function createProviderChain(\r\n configs: Array<{ provider?: string; baseUrl?: string; model?: string; apiKeyEnv?: string }>,\r\n): Promise<AIProvider> {\r\n const { logger } = await import('../infra/logger.js');\r\n const errors: string[] = [];\r\n\r\n for (const config of configs) {\r\n try {\r\n const provider = await createProvider(config);\r\n if (provider.isAvailable()) {\r\n logger.debug(`Provider chain: using '${provider.name}'`);\r\n return provider;\r\n }\r\n errors.push(`${config.provider ?? 'openai-compatible'}: not available (API key not set)`);\r\n } catch (err) {\r\n errors.push(`${config.provider ?? 'openai-compatible'}: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n }\r\n\r\n throw new Error(`All providers in chain unavailable:\\n ${errors.join('\\n ')}`);\r\n}\r\n","/**\r\n * Built-in Image reader plugin (OCR via AI Vision API).\r\n * @module plugins/builtin/image-reader\r\n */\r\n\r\nimport type { ReaderPlugin, StructuredRequirement } from '../../types/index.js';\r\n\r\nexport class ImageReader implements ReaderPlugin {\r\n readonly name = 'image-reader';\r\n readonly supportedFormats = ['.png', '.jpg', '.jpeg', '.webp'];\r\n\r\n canRead(source: string): boolean {\r\n return /\\.(png|jpe?g|webp)$/i.test(source);\r\n }\r\n\r\n async read(source: string): Promise<StructuredRequirement[]> {\r\n // Image reading uses AI Vision API — requires vision-capable provider\r\n const { existsSync, readFileSync } = await import('node:fs');\r\n if (!existsSync(source)) {\r\n throw new Error(`Image file not found: ${source}`);\r\n }\r\n\r\n const ext = source.split('.').pop()?.toLowerCase() ?? 'png';\r\n const mimeType = ext === 'jpg' ? 'image/jpeg' : `image/${ext}`;\r\n const buffer = readFileSync(source);\r\n\r\n // Attempt OCR via AI Vision\r\n let text: string;\r\n try {\r\n const { createProvider } = await import('../../ai/provider.js');\r\n const provider = await createProvider();\r\n\r\n if (!provider.generateWithImage) {\r\n throw new Error(`Provider '${provider.name}' does not support vision input`);\r\n }\r\n\r\n const result = await provider.generateWithImage(\r\n 'Extract all text content from this image. Return only the extracted text.',\r\n { buffer, mimeType },\r\n );\r\n text = result.content;\r\n } catch {\r\n // Fallback: return file metadata\r\n text = `[Image file: ${source} — OCR not available. Please provide text description manually.]`;\r\n }\r\n\r\n return [{\r\n id: source.replace(/\\\\/g, '/').replace(/\\.(png|jpe?g|webp)$/i, ''),\r\n title: source.split('/').pop()?.replace(/\\.(png|jpe?g|webp)$/i, '') ?? 'Untitled',\r\n description: text,\r\n rawContent: text,\r\n confidence: 0.5,\r\n }];\r\n }\r\n}\r\n","/**\r\n * Built-in Cursor writer plugin.\r\n * @module plugins/builtin/cursor-writer\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, rmSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { WriterPlugin, ConstraintContent } from '../../types/index.js';\r\n\r\nexport class CursorWriter implements WriterPlugin {\r\n readonly toolName = 'cursor';\r\n readonly configFile = '.cursor/rules/speclore.mdc';\r\n\r\n private projectRoot = '';\r\n\r\n detect(projectRoot: string): boolean {\r\n return existsSync(join(projectRoot, '.cursor'));\r\n }\r\n\r\n write(constraints: ConstraintContent): Promise<void> {\r\n this.projectRoot = constraints.projectRoot;\r\n const rulesDir = join(constraints.projectRoot, '.cursor', 'rules');\r\n mkdirSync(rulesDir, { recursive: true });\r\n\r\n const frontmatter = [\r\n '---',\r\n 'description: SpecLore coding constraints — auto-generated',\r\n 'globs:',\r\n 'alwaysApply: true',\r\n '---',\r\n '',\r\n ].join('\\n');\r\n\r\n const content = frontmatter + this.buildMarkdown(constraints);\r\n writeFileSync(join(rulesDir, 'speclore.mdc'), content, 'utf-8');\r\n return Promise.resolve();\r\n }\r\n\r\n remove(): Promise<void> {\r\n const filePath = join(this.projectRoot, '.cursor', 'rules', 'speclore.mdc');\r\n if (existsSync(filePath)) rmSync(filePath);\r\n return Promise.resolve();\r\n }\r\n\r\n private buildMarkdown(c: ConstraintContent): string {\r\n const lines: string[] = [];\r\n lines.push(`# SpecLore Constraints — ${c.projectName}`);\r\n lines.push('');\r\n\r\n if (c.features.length > 0) {\r\n const featurePaths = c.features.map(f => f.path.replace(/\\\\/g, '/'));\r\n lines.push(`> Profile: ${c.profile} | Generated by SpecLore`);\r\n lines.push(`> Source features: ${featurePaths.join(', ')}`);\r\n } else {\r\n lines.push(`> Profile: ${c.profile} | Generated by SpecLore`);\r\n }\r\n lines.push('');\r\n\r\n for (const mod of c.modules) {\r\n lines.push(`## Module: ${mod.module}`);\r\n lines.push(`**Responsibility**: ${mod.boundaries.responsibility}`);\r\n lines.push(`**Depends on**: ${mod.boundaries.dependsOn.join(', ') || 'none'}`);\r\n lines.push('');\r\n if (mod.namingConventions.length > 0) {\r\n lines.push('### Naming Conventions');\r\n for (const n of mod.namingConventions) lines.push(`- ${n}`);\r\n lines.push('');\r\n }\r\n if (mod.forbiddenPatterns.length > 0) {\r\n lines.push('### Forbidden Patterns');\r\n for (const f of mod.forbiddenPatterns) lines.push(`- ${f}`);\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Feature business rules\r\n if (c.featureRules && c.featureRules.length > 0) {\r\n for (const rule of c.featureRules) {\r\n lines.push(`## Feature Rules: ${rule.featureName}`);\r\n lines.push(`> Source: ${rule.sourceFile}`);\r\n lines.push('');\r\n for (const sc of rule.scenarios) {\r\n lines.push(`- Scenario \"${sc.name}\": ${sc.summary}`);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Test scaffolding info\r\n if (c.scaffoldInfo && c.scaffoldInfo.length > 0) {\r\n lines.push('## Test Scaffolding');\r\n lines.push('Test files have been generated at:');\r\n for (const s of c.scaffoldInfo) {\r\n lines.push(`- ${s.testFile} (${s.scenarios} scenarios, ${s.framework})`);\r\n }\r\n lines.push('');\r\n lines.push('Fill in test implementations, then run `speclore verify` to validate.');\r\n lines.push('');\r\n }\r\n\r\n if (c.mappingInstructions) {\r\n lines.push('## Test Mapping');\r\n lines.push(c.mappingInstructions);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n');\r\n }\r\n}\r\n","/**\r\n * Built-in Claude Code writer plugin.\r\n * @module plugins/builtin/claude-writer\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, rmSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { WriterPlugin, ConstraintContent } from '../../types/index.js';\r\n\r\nexport class ClaudeWriter implements WriterPlugin {\r\n readonly toolName = 'claude';\r\n readonly configFile = '.claude/rules/speclore.md';\r\n\r\n private projectRoot = '';\r\n\r\n detect(projectRoot: string): boolean {\r\n return existsSync(join(projectRoot, '.claude')) || existsSync(join(projectRoot, '.mcp.json'));\r\n }\r\n\r\n write(constraints: ConstraintContent): Promise<void> {\r\n this.projectRoot = constraints.projectRoot;\r\n const rulesDir = join(constraints.projectRoot, '.claude', 'rules');\r\n mkdirSync(rulesDir, { recursive: true });\r\n\r\n const content = this.buildMarkdown(constraints);\r\n writeFileSync(join(rulesDir, 'speclore.md'), content, 'utf-8');\r\n return Promise.resolve();\r\n }\r\n\r\n remove(): Promise<void> {\r\n const filePath = join(this.projectRoot, '.claude', 'rules', 'speclore.md');\r\n if (existsSync(filePath)) rmSync(filePath);\r\n return Promise.resolve();\r\n }\r\n\r\n private buildMarkdown(c: ConstraintContent): string {\r\n const lines: string[] = [];\r\n lines.push(`# SpecLore Constraints — ${c.projectName}`);\r\n lines.push('');\r\n\r\n if (c.features.length > 0) {\r\n const featurePaths = c.features.map(f => f.path.replace(/\\\\/g, '/'));\r\n lines.push(`> Profile: ${c.profile} | Generated by SpecLore`);\r\n lines.push(`> Source features: ${featurePaths.join(', ')}`);\r\n } else {\r\n lines.push(`> Profile: ${c.profile} | Generated by SpecLore`);\r\n }\r\n lines.push('');\r\n\r\n for (const mod of c.modules) {\r\n lines.push(`## Module: ${mod.module}`);\r\n lines.push(`- **Responsibility**: ${mod.boundaries.responsibility}`);\r\n lines.push(`- **Depends on**: ${mod.boundaries.dependsOn.join(', ') || 'none'}`);\r\n if (mod.namingConventions.length > 0) {\r\n lines.push(`- **Naming**: ${mod.namingConventions.join('; ')}`);\r\n }\r\n if (mod.forbiddenPatterns.length > 0) {\r\n lines.push(`- **Forbidden**: ${mod.forbiddenPatterns.join('; ')}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Feature business rules\r\n if (c.featureRules && c.featureRules.length > 0) {\r\n for (const rule of c.featureRules) {\r\n lines.push(`## Feature Rules: ${rule.featureName}`);\r\n lines.push(`> Source: ${rule.sourceFile}`);\r\n lines.push('');\r\n for (const sc of rule.scenarios) {\r\n lines.push(`- Scenario \"${sc.name}\": ${sc.summary}`);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Test scaffolding info\r\n if (c.scaffoldInfo && c.scaffoldInfo.length > 0) {\r\n lines.push('## Test Scaffolding');\r\n lines.push('Test files have been generated at:');\r\n for (const s of c.scaffoldInfo) {\r\n lines.push(`- ${s.testFile} (${s.scenarios} scenarios, ${s.framework})`);\r\n }\r\n lines.push('');\r\n lines.push('Fill in test implementations, then run `speclore verify` to validate.');\r\n lines.push('');\r\n }\r\n\r\n if (c.mappingInstructions) {\r\n lines.push('## Test Mapping');\r\n lines.push(c.mappingInstructions);\r\n }\r\n\r\n return lines.join('\\n');\r\n }\r\n}\r\n","/**\r\n * Built-in Qoder writer plugin.\r\n * @module plugins/builtin/qoder-writer\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, rmSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { WriterPlugin, ConstraintContent } from '../../types/index.js';\r\n\r\nexport class QoderWriter implements WriterPlugin {\r\n readonly toolName = 'qoder';\r\n readonly configFile = '.qoder/rules/speclore.md';\r\n\r\n private projectRoot = '';\r\n\r\n detect(projectRoot: string): boolean {\r\n return existsSync(join(projectRoot, '.qoder'));\r\n }\r\n\r\n write(constraints: ConstraintContent): Promise<void> {\r\n this.projectRoot = constraints.projectRoot;\r\n const rulesDir = join(constraints.projectRoot, '.qoder', 'rules');\r\n mkdirSync(rulesDir, { recursive: true });\r\n\r\n const content = this.buildMarkdown(constraints);\r\n writeFileSync(join(rulesDir, 'speclore.md'), content, 'utf-8');\r\n return Promise.resolve();\r\n }\r\n\r\n remove(): Promise<void> {\r\n const filePath = join(this.projectRoot, '.qoder', 'rules', 'speclore.md');\r\n if (existsSync(filePath)) rmSync(filePath);\r\n return Promise.resolve();\r\n }\r\n\r\n private buildMarkdown(c: ConstraintContent): string {\r\n const lines: string[] = [];\r\n lines.push(`# SpecLore Constraints — ${c.projectName}`);\r\n lines.push('');\r\n\r\n // Source features reference\r\n if (c.features.length > 0) {\r\n const featurePaths = c.features.map(f => {\r\n const rel = f.path.replace(/\\\\/g, '/');\r\n return rel;\r\n });\r\n lines.push(`> Profile: ${c.profile} | Generated by SpecLore`);\r\n lines.push(`> Source features: ${featurePaths.join(', ')}`);\r\n } else {\r\n lines.push(`> Profile: ${c.profile} | Generated by SpecLore`);\r\n }\r\n lines.push('');\r\n\r\n for (const mod of c.modules) {\r\n lines.push(`## Module: ${mod.module}`);\r\n lines.push(`- **Responsibility**: ${mod.boundaries.responsibility}`);\r\n lines.push(`- **Depends on**: ${mod.boundaries.dependsOn.join(', ') || 'none'}`);\r\n if (mod.namingConventions.length > 0) {\r\n lines.push(`- **Naming**: ${mod.namingConventions.join('; ')}`);\r\n }\r\n if (mod.forbiddenPatterns.length > 0) {\r\n lines.push(`- **Forbidden**: ${mod.forbiddenPatterns.join('; ')}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Feature business rules\r\n if (c.featureRules && c.featureRules.length > 0) {\r\n for (const rule of c.featureRules) {\r\n lines.push(`## Feature Rules: ${rule.featureName}`);\r\n lines.push(`> Source: ${rule.sourceFile}`);\r\n lines.push('');\r\n for (const sc of rule.scenarios) {\r\n lines.push(`- Scenario \"${sc.name}\": ${sc.summary}`);\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Test scaffolding info\r\n if (c.scaffoldInfo && c.scaffoldInfo.length > 0) {\r\n lines.push('## Test Scaffolding');\r\n lines.push('Test files have been generated at:');\r\n for (const s of c.scaffoldInfo) {\r\n lines.push(`- ${s.testFile} (${s.scenarios} scenarios, ${s.framework})`);\r\n }\r\n lines.push('');\r\n lines.push('Fill in test implementations, then run `speclore verify` to validate.');\r\n lines.push('');\r\n }\r\n\r\n if (c.mappingInstructions) {\r\n lines.push('## Test Mapping');\r\n lines.push(c.mappingInstructions);\r\n }\r\n\r\n return lines.join('\\n');\r\n }\r\n}\r\n","/**\r\n * Built-in JUnit XML test result parser.\r\n * @module plugins/builtin/junit-parser\r\n */\r\n\r\nimport type { ParserPlugin, ScenarioResult, FeatureFile } from '../../types/index.js';\r\n\r\nexport class JUnitParser implements ParserPlugin {\r\n readonly framework = 'junit';\r\n\r\n canParse(testOutput: string): boolean {\r\n return testOutput.trimStart().startsWith('<?xml') || testOutput.includes('<testsuite');\r\n }\r\n\r\n parse(testOutput: string, _features: FeatureFile[]): ScenarioResult[] {\r\n const results: ScenarioResult[] = [];\r\n\r\n // Simple XML parsing for <testcase> elements\r\n const testcaseRegex = /<testcase\\s+([^>]*?)(?:\\/>|>([\\s\\S]*?)<\\/testcase>)/g;\r\n let match;\r\n\r\n while ((match = testcaseRegex.exec(testOutput)) !== null) {\r\n const attrs = match[1]!;\r\n const body = match[2] ?? '';\r\n\r\n const name = extractAttr(attrs, 'name') ?? 'unknown';\r\n const classname = extractAttr(attrs, 'classname') ?? '';\r\n const time = extractAttr(attrs, 'time');\r\n\r\n // Check for failure or skip\r\n const failureMatch = body.match(/<failure[^>]*>([\\s\\S]*?)<\\/failure>/);\r\n const skippedMatch = body.match(/<skipped/);\r\n\r\n let status: ScenarioResult['status'] = 'passed';\r\n let error: string | undefined;\r\n\r\n if (failureMatch) {\r\n status = 'failed';\r\n error = failureMatch[1]!.trim();\r\n } else if (skippedMatch) {\r\n status = 'skipped';\r\n }\r\n\r\n results.push({\r\n name,\r\n status,\r\n duration: time ? `${time}s` : undefined,\r\n testMethod: classname ? `${classname}.${name}` : name,\r\n error,\r\n });\r\n }\r\n\r\n return results;\r\n }\r\n}\r\n\r\nfunction extractAttr(attrs: string, name: string): string | undefined {\r\n const match = attrs.match(new RegExp(`${name}=\"([^\"]*)\"`));\r\n return match?.[1];\r\n}\r\n","/**\r\n * Built-in Jest JSON test result parser.\r\n * @module plugins/builtin/jest-parser\r\n */\r\n\r\nimport type { ParserPlugin, ScenarioResult, FeatureFile } from '../../types/index.js';\r\n\r\nexport class JestParser implements ParserPlugin {\r\n readonly framework = 'jest';\r\n\r\n canParse(testOutput: string): boolean {\r\n // Jest --json output starts with { and contains testResults\r\n const trimmed = testOutput.trim();\r\n return trimmed.startsWith('{') && trimmed.includes('\"testResults\"');\r\n }\r\n\r\n parse(testOutput: string, _features: FeatureFile[]): ScenarioResult[] {\r\n let json: {\r\n testResults?: Array<{\r\n name: string;\r\n assertionResults?: Array<{\r\n title: string;\r\n fullName: string;\r\n status: string;\r\n duration: number | null;\r\n failureMessages: string[];\r\n }>;\r\n }>;\r\n };\r\n\r\n try {\r\n json = JSON.parse(testOutput) as typeof json;\r\n } catch {\r\n return [];\r\n }\r\n\r\n const results: ScenarioResult[] = [];\r\n for (const file of json.testResults ?? []) {\r\n for (const assertion of file.assertionResults ?? []) {\r\n let status: ScenarioResult['status'] = 'passed';\r\n switch (assertion.status) {\r\n case 'failed': status = 'failed'; break;\r\n case 'skipped':\r\n case 'pending':\r\n case 'todo': status = 'skipped'; break;\r\n default: status = 'passed';\r\n }\r\n\r\n results.push({\r\n name: assertion.title ?? assertion.fullName ?? 'unknown',\r\n status,\r\n duration: assertion.duration != null ? `${assertion.duration}ms` : undefined,\r\n testFile: file.name,\r\n testMethod: assertion.fullName,\r\n error: assertion.failureMessages?.join('\\n'),\r\n });\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n}\r\n","/**\r\n * Built-in Vitest JSON test result parser.\r\n * @module plugins/builtin/vitest-parser\r\n */\r\n\r\nimport type { ParserPlugin, ScenarioResult, FeatureFile } from '../../types/index.js';\r\n\r\nexport class VitestParser implements ParserPlugin {\r\n readonly framework = 'vitest';\r\n\r\n canParse(testOutput: string): boolean {\r\n const trimmed = testOutput.trim();\r\n return trimmed.startsWith('{') && (trimmed.includes('\"testResults\"') || trimmed.includes('\"numTotalTests\"'));\r\n }\r\n\r\n parse(testOutput: string, _features: FeatureFile[]): ScenarioResult[] {\r\n let json: {\r\n testResults?: Array<{\r\n name: string;\r\n assertionResults?: Array<{\r\n title: string;\r\n fullName: string;\r\n status: string;\r\n duration: number | null;\r\n failureMessages: string[];\r\n }>;\r\n }>;\r\n numTotalTests?: number;\r\n numPassedTests?: number;\r\n numFailedTests?: number;\r\n };\r\n\r\n try {\r\n json = JSON.parse(testOutput) as typeof json;\r\n } catch {\r\n return [];\r\n }\r\n\r\n const results: ScenarioResult[] = [];\r\n for (const file of json.testResults ?? []) {\r\n for (const assertion of file.assertionResults ?? []) {\r\n let status: ScenarioResult['status'] = 'passed';\r\n switch (assertion.status) {\r\n case 'failed': status = 'failed'; break;\r\n case 'skipped':\r\n case 'pending':\r\n case 'todo': status = 'skipped'; break;\r\n default: status = 'passed';\r\n }\r\n\r\n results.push({\r\n name: assertion.title ?? assertion.fullName ?? 'unknown',\r\n status,\r\n duration: assertion.duration != null ? `${Math.round(assertion.duration)}ms` : undefined,\r\n testFile: file.name,\r\n testMethod: assertion.fullName,\r\n error: assertion.failureMessages?.join('\\n'),\r\n });\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n}\r\n","/**\r\n * Plugin registry — discovers, loads, and manages plugins.\r\n *\r\n * Built-in plugins are auto-registered. Third-party plugins are loaded\r\n * from config.yaml `plugins` section.\r\n *\r\n * @module plugins/registry\r\n */\r\n\r\nimport type { ReaderPlugin, WriterPlugin, ParserPlugin } from '../types/index.js';\r\nimport type { PluginLifecycle } from './types.js';\r\nimport type { SpecLoreConfig } from '../types/config.js';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/** Runtime type guard for ReaderPlugin */\r\nfunction isReaderPlugin(mod: unknown): mod is ReaderPlugin {\r\n return typeof mod === 'object' && mod !== null\r\n && typeof (mod as ReaderPlugin).canRead === 'function'\r\n && typeof (mod as ReaderPlugin).read === 'function'\r\n && typeof (mod as ReaderPlugin).name === 'string';\r\n}\r\n\r\n/** Runtime type guard for WriterPlugin */\r\nfunction isWriterPlugin(mod: unknown): mod is WriterPlugin {\r\n return typeof mod === 'object' && mod !== null\r\n && typeof (mod as WriterPlugin).detect === 'function'\r\n && typeof (mod as WriterPlugin).write === 'function'\r\n && typeof (mod as WriterPlugin).toolName === 'string';\r\n}\r\n\r\n/** Runtime type guard for ParserPlugin */\r\nfunction isParserPlugin(mod: unknown): mod is ParserPlugin {\r\n return typeof mod === 'object' && mod !== null\r\n && typeof (mod as ParserPlugin).canParse === 'function'\r\n && typeof (mod as ParserPlugin).parse === 'function'\r\n && typeof (mod as ParserPlugin).framework === 'string';\r\n}\r\n\r\n// Built-in readers\r\nimport { MarkdownReader } from './builtin/md-reader.js';\r\nimport { DocxReader } from './builtin/docx-reader.js';\r\nimport { XlsxReader } from './builtin/xlsx-reader.js';\r\nimport { PdfReader } from './builtin/pdf-reader.js';\r\nimport { ImageReader } from './builtin/image-reader.js';\r\n\r\n// Built-in writers\r\nimport { CursorWriter } from './builtin/cursor-writer.js';\r\nimport { ClaudeWriter } from './builtin/claude-writer.js';\r\nimport { QoderWriter } from './builtin/qoder-writer.js';\r\n\r\n// Built-in parsers\r\nimport { JUnitParser } from './builtin/junit-parser.js';\r\nimport { JestParser } from './builtin/jest-parser.js';\r\nimport { VitestParser } from './builtin/vitest-parser.js';\r\n\r\n/** Central plugin registry */\r\nexport class PluginRegistry {\r\n private readers: ReaderPlugin[] = [];\r\n private writers: WriterPlugin[] = [];\r\n private parsers: ParserPlugin[] = [];\r\n private lifecycleHooks: PluginLifecycle[] = [];\r\n\r\n /** Register all built-in plugins */\r\n registerBuiltins(): void {\r\n this.readers.push(\r\n new MarkdownReader(),\r\n new DocxReader(),\r\n new XlsxReader(),\r\n new PdfReader(),\r\n new ImageReader(),\r\n );\r\n\r\n this.writers.push(\r\n new CursorWriter(),\r\n new ClaudeWriter(),\r\n new QoderWriter(),\r\n );\r\n\r\n this.parsers.push(\r\n new JUnitParser(),\r\n new JestParser(),\r\n new VitestParser(),\r\n );\r\n }\r\n\r\n /** Load third-party plugins from config */\r\n async loadExternal(config: SpecLoreConfig): Promise<void> {\r\n if (!config.plugins) return;\r\n\r\n // Load external readers\r\n if (config.plugins.readers) {\r\n for (const ref of config.plugins.readers) {\r\n try {\r\n const mod = await import(ref.package) as Record<string, unknown>;\r\n const plugin = (mod.default ?? mod) as unknown;\r\n if (isReaderPlugin(plugin)) {\r\n this.readers.push(plugin);\r\n logger.debug(`Loaded external reader plugin: ${ref.name}`);\r\n } else {\r\n logger.warn(`Plugin ${ref.name} does not implement ReaderPlugin interface`);\r\n }\r\n } catch (err) {\r\n logger.warn(`Failed to load reader plugin ${ref.name}: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n }\r\n }\r\n\r\n // Load external writers\r\n if (config.plugins.writers) {\r\n for (const ref of config.plugins.writers) {\r\n try {\r\n const mod = await import(ref.package) as Record<string, unknown>;\r\n const plugin = (mod.default ?? mod) as unknown;\r\n if (isWriterPlugin(plugin)) {\r\n this.writers.push(plugin);\r\n logger.debug(`Loaded external writer plugin: ${ref.name}`);\r\n } else {\r\n logger.warn(`Plugin ${ref.name} does not implement WriterPlugin interface`);\r\n }\r\n } catch (err) {\r\n logger.warn(`Failed to load writer plugin ${ref.name}: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n }\r\n }\r\n\r\n // Load external parsers\r\n if (config.plugins.parsers) {\r\n for (const ref of config.plugins.parsers) {\r\n try {\r\n const mod = await import(ref.package) as Record<string, unknown>;\r\n const plugin = (mod.default ?? mod) as unknown;\r\n if (isParserPlugin(plugin)) {\r\n this.parsers.push(plugin);\r\n logger.debug(`Loaded external parser plugin: ${ref.name}`);\r\n } else {\r\n logger.warn(`Plugin ${ref.name} does not implement ParserPlugin interface`);\r\n }\r\n } catch (err) {\r\n logger.warn(`Failed to load parser plugin ${ref.name}: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** Find a reader that can handle the given source */\r\n findReader(source: string): ReaderPlugin | undefined {\r\n return this.readers.find(r => r.canRead(source));\r\n }\r\n\r\n /** Find a writer for the given AI tool */\r\n findWriter(toolName: string): WriterPlugin | undefined {\r\n return this.writers.find(w => w.toolName === toolName);\r\n }\r\n\r\n /** Find a parser for the given test output */\r\n findParser(testOutput: string): ParserPlugin | undefined {\r\n return this.parsers.find(p => p.canParse(testOutput));\r\n }\r\n\r\n /** Get all registered readers */\r\n getReaders(): ReaderPlugin[] {\r\n return [...this.readers];\r\n }\r\n\r\n /** Get all registered writers */\r\n getWriters(): WriterPlugin[] {\r\n return [...this.writers];\r\n }\r\n\r\n /** Get all registered parsers */\r\n getParsers(): ParserPlugin[] {\r\n return [...this.parsers];\r\n }\r\n\r\n /** Register a lifecycle hook */\r\n registerLifecycle(hook: PluginLifecycle): void {\r\n this.lifecycleHooks.push(hook);\r\n logger.debug('Registered plugin lifecycle hook');\r\n }\r\n\r\n /** Invoke a lifecycle event on all registered hooks */\r\n async invokeLifecycle<K extends keyof PluginLifecycle>(\r\n event: K,\r\n ...args: Parameters<NonNullable<PluginLifecycle[K]>>\r\n ): Promise<void> {\r\n for (const hook of this.lifecycleHooks) {\r\n const fn = hook[event];\r\n if (typeof fn === 'function') {\r\n try {\r\n await (fn as (...a: unknown[]) => Promise<void>)(...args as unknown[]);\r\n } catch (err) {\r\n logger.warn(`Lifecycle hook '${event}' failed: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/** Singleton registry instance */\r\nlet _registry: PluginRegistry | null = null;\r\n\r\n/** Get or create the global plugin registry */\r\nexport function getRegistry(): PluginRegistry {\r\n if (!_registry) {\r\n _registry = new PluginRegistry();\r\n _registry.registerBuiltins();\r\n }\r\n return _registry;\r\n}\r\n\r\n/** Reset the global registry (for testing) */\r\nexport function resetRegistry(): void {\r\n _registry = null;\r\n}\r\n","/**\r\n * Markdown reader — reads .md files and extracts structured requirements.\r\n *\r\n * @module core/requirement-reader/markdown-reader\r\n */\r\n\r\nimport { readFileSync } from 'node:fs';\r\nimport { basename, extname } from 'node:path';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\n\r\nexport function readMarkdownFile(filePath: string): Promise<StructuredRequirement> {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const id = deriveId(filePath);\r\n\r\n // Extract title from first heading\r\n const titleMatch = content.match(/^#\\s+(.+)$/m);\r\n const title = titleMatch?.[1]?.trim() ?? basename(filePath, extname(filePath));\r\n\r\n // Extract acceptance criteria section if present\r\n const acceptanceCriteria = extractAcceptanceCriteria(content);\r\n\r\n // Extract dependency references (e.g. \"Depends on: order/payment\")\r\n const dependencies = extractDependencies(content);\r\n\r\n return Promise.resolve({\r\n id,\r\n title,\r\n description: content,\r\n acceptanceCriteria: acceptanceCriteria.length > 0 ? acceptanceCriteria : undefined,\r\n dependencies: dependencies.length > 0 ? dependencies : undefined,\r\n rawContent: content,\r\n confidence: 1.0,\r\n });\r\n}\r\n\r\nfunction deriveId(filePath: string): string {\r\n // Strip common prefixes and extension\r\n const name = basename(filePath, extname(filePath));\r\n return name.toLowerCase().replace(/[^a-z0-9\\u4e00-\\u9fff-]/g, '-').replace(/-+/g, '-');\r\n}\r\n\r\nfunction extractAcceptanceCriteria(content: string): string[] {\r\n const criteria: string[] = [];\r\n\r\n // Look for \"Acceptance Criteria\" or \"验收标准\" section\r\n const sectionRegex = /#{1,4}\\s*(?:Acceptance Criteria|验收标准|验收条件)\\s*\\n([\\s\\S]*?)(?=\\n#{1,4}\\s|\\n---|$)/gi;\r\n const match = sectionRegex.exec(content);\r\n\r\n if (match) {\r\n const section = match[1]!;\r\n // Extract bullet points\r\n const bulletRegex = /^\\s*[-*]\\s+(.+)$/gm;\r\n let bullet;\r\n while ((bullet = bulletRegex.exec(section)) !== null) {\r\n criteria.push(bullet[1]!.trim());\r\n }\r\n }\r\n\r\n return criteria;\r\n}\r\n\r\nfunction extractDependencies(content: string): string[] {\r\n const deps: string[] = [];\r\n\r\n // Look for \"Depends on:\" or \"依赖:\" pattern\r\n const depRegex = /(?:Depends on|依赖)[:\\s]+(.+)/gi;\r\n const match = depRegex.exec(content);\r\n\r\n if (match) {\r\n const depList = match[1]!;\r\n // Split by comma or semicolon\r\n const items = depList.split(/[,;,;]/);\r\n for (const item of items) {\r\n const trimmed = item.trim().replace(/^[\\s`]+|[\\s`]+$/g, '');\r\n if (trimmed) deps.push(trimmed);\r\n }\r\n }\r\n\r\n return deps;\r\n}\r\n","/**\r\n * DOCX reader — reads .docx files using mammoth.\r\n *\r\n * @module core/requirement-reader/docx-reader\r\n */\r\n\r\nimport { basename, extname } from 'node:path';\r\nimport mammoth from 'mammoth';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\n\r\nexport async function readDocxFile(filePath: string): Promise<StructuredRequirement> {\r\n const result = await mammoth.extractRawText({ path: filePath });\r\n const content = result.value;\r\n const id = basename(filePath, extname(filePath))\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff-]/g, '-')\r\n .replace(/-+/g, '-');\r\n\r\n // First line as title\r\n const lines = content.split('\\n').filter(l => l.trim());\r\n const title = lines[0]?.trim() ?? id;\r\n\r\n return {\r\n id,\r\n title,\r\n description: content,\r\n rawContent: content,\r\n confidence: 0.9,\r\n };\r\n}\r\n","/**\r\n * XLSX reader — reads .xlsx files and extracts requirement tables.\r\n *\r\n * Uses exceljs for robust xlsx parsing with native TypeScript support.\r\n *\r\n * @module core/requirement-reader/xlsx-reader\r\n */\r\n\r\nimport { basename, extname } from 'node:path';\r\nimport ExcelJS from 'exceljs';\r\nimport { formatCellValue } from '../../infra/excel-utils.js';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\n\r\nexport async function readXlsxFile(filePath: string): Promise<StructuredRequirement> {\r\n const workbook = new ExcelJS.Workbook();\r\n await workbook.xlsx.readFile(filePath);\r\n\r\n const id = basename(filePath, extname(filePath))\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff-]/g, '-')\r\n .replace(/-+/g, '-');\r\n\r\n // Read the first sheet\r\n const sheet = workbook.worksheets[0];\r\n if (!sheet) {\r\n throw new Error(`No sheets found in ${filePath}`);\r\n }\r\n\r\n const title = sheet.name;\r\n\r\n // First row as headers, subsequent rows as data\r\n const headers: string[] = [];\r\n const rows: Record<string, string>[] = [];\r\n\r\n sheet.eachRow((row, rowNumber) => {\r\n if (rowNumber === 1) {\r\n row.eachCell((cell, colNumber) => {\r\n headers[colNumber - 1] = formatCellValue(cell.value);\r\n });\r\n } else {\r\n const obj: Record<string, string> = {};\r\n row.eachCell((cell, colNumber) => {\r\n const key = headers[colNumber - 1] ?? `Col${colNumber}`;\r\n obj[key] = formatCellValue(cell.value);\r\n });\r\n rows.push(obj);\r\n }\r\n });\r\n\r\n // Convert rows to structured text\r\n const textRows = rows.map(row => {\r\n const cells = Object.entries(row)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join(' | ');\r\n return cells;\r\n });\r\n\r\n const content = textRows.join('\\n');\r\n\r\n return {\r\n id,\r\n title,\r\n description: content,\r\n rawContent: content,\r\n confidence: 0.85,\r\n };\r\n}\r\n","/**\r\n * PDF reader — extracts text from .pdf files.\r\n *\r\n * @module core/requirement-reader/pdf-reader\r\n */\r\n\r\nimport { basename, extname } from 'node:path';\r\nimport { readFile } from 'node:fs/promises';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\n\r\nexport async function readPdfFile(filePath: string): Promise<StructuredRequirement> {\r\n // Dynamic import for pdf-parse (CJS module)\r\n const pdfParse = (await import('pdf-parse')).default;\r\n const dataBuffer = await readFile(filePath);\r\n const data = await pdfParse(dataBuffer);\r\n\r\n const id = basename(filePath, extname(filePath))\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff-]/g, '-')\r\n .replace(/-+/g, '-');\r\n\r\n // First line as title\r\n const lines = data.text.split('\\n').filter(l => l.trim());\r\n const title = lines[0]?.trim() ?? id;\r\n\r\n return {\r\n id,\r\n title,\r\n description: data.text,\r\n rawContent: data.text,\r\n confidence: 0.8,\r\n };\r\n}\r\n","/**\r\n * Image reader — extracts text from images via AI Vision API.\r\n *\r\n * Supports png/jpg/webp. Uses configured AI provider's vision capability.\r\n *\r\n * @module core/requirement-reader/image-reader\r\n */\r\n\r\nimport { basename, extname } from 'node:path';\r\nimport { readFileSync } from 'node:fs';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\nimport { createProvider } from '../../ai/provider.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\nconst MIME_MAP: Record<string, string> = {\r\n '.png': 'image/png',\r\n '.jpg': 'image/jpeg',\r\n '.jpeg': 'image/jpeg',\r\n '.webp': 'image/webp',\r\n};\r\n\r\nexport async function readImageFile(filePath: string): Promise<StructuredRequirement> {\r\n const id = basename(filePath, extname(filePath))\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff-]/g, '-')\r\n .replace(/-+/g, '-');\r\n\r\n logger.info(`Reading image via AI Vision: ${filePath}`);\r\n\r\n const ext = extname(filePath).toLowerCase();\r\n const mimeType = MIME_MAP[ext] ?? 'image/png';\r\n const buffer = readFileSync(filePath);\r\n\r\n const provider = await createProvider();\r\n const prompt = `Please extract all text content from this image. Return the text as-is, preserving structure and formatting. If the image contains a table, convert it to a structured text format.`;\r\n\r\n if (!provider.generateWithImage) {\r\n throw new Error(`AI provider '${provider.name}' does not support image/vision input. Use a vision-capable model.`);\r\n }\r\n\r\n const result = await provider.generateWithImage(prompt, { buffer, mimeType });\r\n\r\n return {\r\n id,\r\n title: result.content.split('\\n')[0]?.slice(0, 100) ?? id,\r\n description: result.content,\r\n rawContent: result.content,\r\n confidence: 0.7, // Lower confidence for OCR\r\n };\r\n}\r\n","/**\r\n * URL reader — fetches web content and extracts text.\r\n *\r\n * L1: Public URLs — direct fetch + HTML parsing\r\n * L2: Basic Auth URLs — credentials from config.yaml\r\n * L3: Login-required URLs — prompt user to paste content manually\r\n *\r\n * Security: URL validation, no file:// protocol, timeout control.\r\n *\r\n * @module core/requirement-reader/url-reader\r\n */\r\n\r\nimport { basename } from 'node:path';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\nconst FETCH_TIMEOUT_MS = 10_000;\r\nconst MAX_CONTENT_LENGTH = 100_000; // 100KB\r\n\r\n/**\r\n * Read content from a URL.\r\n */\r\nexport async function readUrl(url: string): Promise<StructuredRequirement> {\r\n // Security: validate URL\r\n validateUrl(url);\r\n\r\n logger.info(`Fetching URL: ${url}`);\r\n\r\n try {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\r\n\r\n const response = await fetch(url, {\r\n signal: controller.signal,\r\n headers: {\r\n 'User-Agent': 'SpecLore/0.1.0 (+https://github.com/nicepkg/speclore)',\r\n 'Accept': 'text/html,application/json,text/plain,*/*',\r\n },\r\n });\r\n\r\n clearTimeout(timeout);\r\n\r\n if (!response.ok) {\r\n if (response.status === 401 || response.status === 403) {\r\n throw new UrlAuthError(url, response.status);\r\n }\r\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\r\n }\r\n\r\n const contentType = response.headers.get('content-type') ?? '';\r\n let content: string;\r\n let title: string = url;\r\n\r\n if (contentType.includes('html')) {\r\n const html = await response.text();\r\n // Extract title from raw HTML BEFORE stripping tags\r\n const titleMatch = html.match(/<title[^>]*>([^<]+)<\\/title>/i);\r\n title = titleMatch?.[1]?.trim() ?? url;\r\n content = extractTextFromHtml(html);\r\n } else {\r\n content = await response.text();\r\n // Try to extract title from first heading in plain text\r\n const headingMatch = content.match(/^#\\s+(.+)/m);\r\n if (headingMatch) title = headingMatch[1]!.trim();\r\n }\r\n\r\n // Truncate if too large\r\n if (content.length > MAX_CONTENT_LENGTH) {\r\n content = content.slice(0, MAX_CONTENT_LENGTH) + '\\n... (truncated)';\r\n }\r\n\r\n // Derive ID from URL\r\n const urlPath = new URL(url).pathname;\r\n const id = basename(urlPath)\r\n .toLowerCase()\r\n .replace(/[^a-z0-9\\u4e00-\\u9fff-]/g, '-')\r\n .replace(/-+/g, '-')\r\n || 'url-content';\r\n\r\n return {\r\n id,\r\n title,\r\n description: content,\r\n rawContent: content,\r\n confidence: 0.85,\r\n };\r\n } catch (error) {\r\n if (error instanceof UrlAuthError) {\r\n logger.warn(`URL requires authentication: ${url}`);\r\n throw error;\r\n }\r\n if (error instanceof DOMException && error.name === 'AbortError') {\r\n throw new Error(`URL fetch timed out after ${FETCH_TIMEOUT_MS}ms: ${url}`);\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Validate URL for security.\r\n */\r\nfunction validateUrl(url: string): void {\r\n let parsed: URL;\r\n try {\r\n parsed = new URL(url);\r\n } catch {\r\n throw new Error(`Invalid URL: ${url}`);\r\n }\r\n\r\n // Block file:// protocol\r\n if (parsed.protocol === 'file:') {\r\n throw new Error('file:// protocol is not allowed. Use a file path instead.');\r\n }\r\n\r\n // Only allow http/https\r\n if (!['http:', 'https:'].includes(parsed.protocol)) {\r\n throw new Error(`Unsupported protocol: ${parsed.protocol}. Only http/https allowed.`);\r\n }\r\n}\r\n\r\n/**\r\n * Extract text content from HTML, stripping tags.\r\n */\r\nfunction extractTextFromHtml(html: string): string {\r\n return html\r\n // Remove script and style tags\r\n .replace(/<script[\\s\\S]*?<\\/script>/gi, '')\r\n .replace(/<style[\\s\\S]*?<\\/style>/gi, '')\r\n // Remove HTML tags\r\n .replace(/<[^>]+>/g, ' ')\r\n // Decode common HTML entities\r\n .replace(/&amp;/g, '&')\r\n .replace(/&lt;/g, '<')\r\n .replace(/&gt;/g, '>')\r\n .replace(/&quot;/g, '\"')\r\n .replace(/&#39;/g, \"'\")\r\n .replace(/&nbsp;/g, ' ')\r\n // Normalize whitespace\r\n .replace(/\\s+/g, ' ')\r\n .trim();\r\n}\r\n\r\n/** Custom error for authentication-required URLs */\r\nexport class UrlAuthError extends Error {\r\n constructor(\r\n public readonly url: string,\r\n public readonly status: number,\r\n ) {\r\n super(`URL requires authentication (${status}): ${url}. Please paste the content manually.`);\r\n this.name = 'UrlAuthError';\r\n }\r\n}\r\n","/**\r\n * M1: Requirement Ingestion — unified entry point.\r\n *\r\n * Auto-detects source type (file path / URL / direct text) and routes\r\n * to the appropriate reader. Outputs StructuredRequirement.\r\n *\r\n * @module core/requirement-reader\r\n */\r\n\r\nimport { existsSync } from 'node:fs';\r\nimport { extname } from 'node:path';\r\nimport type { StructuredRequirement } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { getRegistry } from '../../plugins/registry.js';\r\nimport { readMarkdownFile } from './markdown-reader.js';\r\nimport { readDocxFile } from './docx-reader.js';\r\nimport { readXlsxFile } from './xlsx-reader.js';\r\nimport { readPdfFile } from './pdf-reader.js';\r\nimport { readImageFile } from './image-reader.js';\r\nimport { readUrl } from './url-reader.js';\r\n\r\n/** Source type classification */\r\ntype SourceType = 'file' | 'url' | 'text';\r\n\r\n/**\r\n * Read a requirement from any source type.\r\n */\r\nexport async function readRequirement(source: string): Promise<StructuredRequirement> {\r\n const sourceType = classifySource(source);\r\n logger.info(`Reading requirement from ${sourceType}: ${truncate(source, 80)}`);\r\n\r\n switch (sourceType) {\r\n case 'file':\r\n return readFromFile(source);\r\n case 'url':\r\n return readFromUrl(source);\r\n case 'text':\r\n return readFromText(source);\r\n }\r\n}\r\n\r\n/**\r\n * Classify the source as file, URL, or direct text.\r\n */\r\nfunction classifySource(source: string): SourceType {\r\n // URL detection\r\n if (/^https?:\\/\\//i.test(source)) {\r\n return 'url';\r\n }\r\n\r\n // File detection — check if it looks like a file path and exists\r\n const ext = extname(source).toLowerCase();\r\n const supportedExts = ['.md', '.docx', '.xlsx', '.xls', '.pdf', '.png', '.jpg', '.jpeg', '.webp'];\r\n\r\n if (supportedExts.includes(ext) && existsSync(source)) {\r\n return 'file';\r\n }\r\n\r\n // If it's a path that exists but has no extension, treat as file\r\n if (existsSync(source) && (source.includes('/') || source.includes('\\\\'))) {\r\n return 'file';\r\n }\r\n\r\n // Otherwise treat as direct text\r\n return 'text';\r\n}\r\n\r\n/**\r\n * Read from a file based on its extension.\r\n * First tries PluginRegistry (supports third-party plugins), then falls back to built-in readers.\r\n */\r\nasync function readFromFile(filePath: string): Promise<StructuredRequirement> {\r\n // Try PluginRegistry first (includes built-in + third-party readers)\r\n const registry = getRegistry();\r\n const reader = registry.findReader(filePath);\r\n if (reader) {\r\n logger.debug(`Using reader plugin: ${reader.name}`);\r\n const results = await reader.read(filePath);\r\n if (results.length === 0) {\r\n throw new Error(`Reader plugin '${reader.name}' returned no results for: ${filePath}`);\r\n }\r\n return results[0]!;\r\n }\r\n\r\n // Fallback to direct built-in readers\r\n const ext = extname(filePath).toLowerCase();\r\n\r\n switch (ext) {\r\n case '.md':\r\n return readMarkdownFile(filePath);\r\n case '.docx':\r\n return readDocxFile(filePath);\r\n case '.xlsx':\r\n case '.xls':\r\n return readXlsxFile(filePath);\r\n case '.pdf':\r\n return readPdfFile(filePath);\r\n case '.png':\r\n case '.jpg':\r\n case '.jpeg':\r\n case '.webp':\r\n return readImageFile(filePath);\r\n default:\r\n throw new Error(`Unsupported file format: ${ext}`);\r\n }\r\n}\r\n\r\n/**\r\n * Read from a URL.\r\n */\r\nasync function readFromUrl(url: string): Promise<StructuredRequirement> {\r\n return readUrl(url);\r\n}\r\n\r\n/**\r\n * Read from direct text input.\r\n */\r\nfunction readFromText(text: string): Promise<StructuredRequirement> {\r\n // Generate an ID from the first few words\r\n const id = text\r\n .split(/\\s+/)\r\n .slice(0, 3)\r\n .map(w => w.toLowerCase().replace(/[^a-z0-9\\u4e00-\\u9fff]/g, ''))\r\n .filter(Boolean)\r\n .join('-') || 'requirement';\r\n\r\n return Promise.resolve({\r\n id,\r\n title: text.split('\\n')[0]?.slice(0, 100) ?? id,\r\n description: text,\r\n rawContent: text,\r\n confidence: 1.0,\r\n });\r\n}\r\n\r\nfunction truncate(str: string, maxLen: number): string {\r\n return str.length > maxLen ? str.slice(0, maxLen) + '...' : str;\r\n}\r\n","/**\r\n * Output validator — validates AI-generated Gherkin content before writing to disk.\r\n *\r\n * Uses the official @cucumber/gherkin parser for spec-compliant validation.\r\n * Provides structured error feedback for retry-with-correction loops.\r\n *\r\n * @module ai/output-validator\r\n */\r\n\r\nimport { Parser, GherkinClassicTokenMatcher, AstBuilder } from '@cucumber/gherkin';\r\nimport { IdGenerator } from '@cucumber/messages';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/** Result of validating AI-generated output */\r\nexport interface ValidationResult {\r\n /** Whether the output is valid Gherkin */\r\n valid: boolean;\r\n /** List of errors found (empty if valid) */\r\n errors: string[];\r\n /** Number of scenarios found (0 if parse failed) */\r\n scenarioCount: number;\r\n}\r\n\r\n/**\r\n * Validate AI-generated Gherkin content.\r\n *\r\n * Checks:\r\n * 1. Content is non-empty\r\n * 2. Contains Feature: keyword\r\n * 3. Contains at least one Scenario: keyword\r\n * 4. Passes official @cucumber/gherkin parser without errors\r\n */\r\nexport function validateFeatureOutput(content: string): ValidationResult {\r\n const errors: string[] = [];\r\n let scenarioCount = 0;\r\n\r\n // Check 1: Non-empty\r\n if (!content || content.trim().length === 0) {\r\n return { valid: false, errors: ['Empty response from AI provider'], scenarioCount: 0 };\r\n }\r\n\r\n // Check 2: Feature keyword\r\n if (!/Feature:/.test(content)) {\r\n errors.push('Missing \"Feature:\" keyword — AI must generate a Gherkin Feature block');\r\n }\r\n\r\n // Check 3: Scenario keyword\r\n if (!/Scenario:/.test(content)) {\r\n errors.push('Missing \"Scenario:\" keyword — AI must generate at least one Scenario');\r\n }\r\n\r\n // Check 4: Official Gherkin parser validation\r\n try {\r\n const idGen = IdGenerator.incrementing();\r\n const builder = new AstBuilder(idGen);\r\n const matcher = new GherkinClassicTokenMatcher();\r\n const parser = new Parser(builder, matcher);\r\n const doc = parser.parse(content);\r\n\r\n // Count scenarios\r\n if (doc.feature?.children) {\r\n scenarioCount = doc.feature.children.filter(c => c.scenario !== undefined).length;\r\n }\r\n\r\n if (scenarioCount === 0) {\r\n errors.push('Parsed successfully but contains no scenarios');\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n errors.push(`Gherkin syntax error: ${message}`);\r\n logger.debug(`Gherkin validation error: ${message}`);\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n scenarioCount,\r\n };\r\n}\r\n","/**\r\n * Token counter — approximate token estimation without external dependencies.\r\n *\r\n * Uses character-based heuristics tuned per language family:\r\n * - CJK characters ≈ 1.5 chars/token (dense information per token)\r\n * - Latin script ≈ 4 chars/token (standard BPE average)\r\n * - Mixed text uses weighted average\r\n *\r\n * Also provides model context window lookup for overflow detection.\r\n *\r\n * @module ai/token-counter\r\n */\r\n\r\n/** Result of token estimation */\r\nexport interface TokenCountResult {\r\n /** Estimated token count */\r\n tokenCount: number;\r\n /** Whether the estimate exceeds the model's context window */\r\n exceedsLimit: boolean;\r\n /** The model's maximum context window in tokens */\r\n modelContextWindow: number;\r\n}\r\n\r\n/**\r\n * Known model context windows (in tokens).\r\n * Covers major OpenAI, Anthropic, Meta, and Ollama models.\r\n */\r\nconst MODEL_CONTEXT_WINDOWS: Record<string, number> = {\r\n // OpenAI\r\n 'gpt-4': 8_192,\r\n 'gpt-4-turbo': 128_000,\r\n 'gpt-4o': 128_000,\r\n 'gpt-4o-mini': 128_000,\r\n 'gpt-4o-2024-08-06': 128_000,\r\n 'gpt-3.5-turbo': 16_385,\r\n 'o1-preview': 128_000,\r\n 'o1-mini': 128_000,\r\n // Anthropic\r\n 'claude-3-5-sonnet-20241022': 200_000,\r\n 'claude-3-5-haiku-20241022': 200_000,\r\n 'claude-3-opus-20240229': 200_000,\r\n 'claude-sonnet-4-20250514': 200_000,\r\n // Meta / Ollama common models\r\n 'llama3': 8_192,\r\n 'llama3:8b': 8_192,\r\n 'llama3:70b': 8_192,\r\n 'llama3.1': 128_000,\r\n 'llama3.1:8b': 128_000,\r\n 'llama3.1:70b': 128_000,\r\n 'mistral': 8_192,\r\n 'mixtral': 32_768,\r\n 'codellama': 16_384,\r\n 'phi3': 128_000,\r\n 'gemma2': 8_192,\r\n};\r\n\r\n/** Default context window for unknown models */\r\nconst DEFAULT_CONTEXT_WINDOW = 8_192;\r\n\r\n/** CJK Unicode range check */\r\nfunction isCJK(char: string): boolean {\r\n const code = char.codePointAt(0) ?? 0;\r\n return (\r\n (code >= 0x4E00 && code <= 0x9FFF) || // CJK Unified Ideographs\r\n (code >= 0x3400 && code <= 0x4DBF) || // CJK Extension A\r\n (code >= 0xF900 && code <= 0xFAFF) || // CJK Compatibility Ideographs\r\n (code >= 0x3000 && code <= 0x303F) || // CJK Symbols and Punctuation\r\n (code >= 0x3040 && code <= 0x309F) || // Hiragana\r\n (code >= 0x30A0 && code <= 0x30FF) || // Katakana\r\n (code >= 0xAC00 && code <= 0xD7AF) // Hangul Syllables\r\n );\r\n}\r\n\r\n/**\r\n * Estimate the number of tokens in a text string.\r\n *\r\n * Uses character-level heuristics:\r\n * - CJK characters count as ~1.5 chars/token (each CJK char ≈ 0.67 tokens)\r\n * - Latin/ASCII characters count as ~4 chars/token\r\n * - Whitespace and punctuation are counted as part of the stream\r\n *\r\n * @param text - The text to estimate tokens for\r\n * @returns Estimated token count (rounded up to nearest integer)\r\n */\r\nexport function estimateTokenCount(text: string): number {\r\n if (!text || text.length === 0) return 0;\r\n\r\n let cjkChars = 0;\r\n let otherChars = 0;\r\n\r\n for (const char of text) {\r\n if (isCJK(char)) {\r\n cjkChars++;\r\n } else {\r\n otherChars++;\r\n }\r\n }\r\n\r\n // CJK: ~1.5 chars per token → tokens = cjkChars / 1.5\r\n // Latin: ~4 chars per token → tokens = otherChars / 4\r\n const cjkTokens = cjkChars / 1.5;\r\n const latinTokens = otherChars / 4;\r\n\r\n return Math.ceil(cjkTokens + latinTokens);\r\n}\r\n\r\n/**\r\n * Look up the context window size for a given model.\r\n *\r\n * @param model - Model identifier (e.g. 'gpt-4o', 'claude-3-5-sonnet-20241022')\r\n * @returns Context window size in tokens\r\n */\r\nexport function getModelContextWindow(model: string): number {\r\n // Exact match\r\n if (MODEL_CONTEXT_WINDOWS[model]) {\r\n return MODEL_CONTEXT_WINDOWS[model];\r\n }\r\n\r\n // Prefix match (e.g. 'gpt-4o-2024-05-13' → 'gpt-4o')\r\n // Sort by key length descending so longer prefixes match first\r\n const sortedEntries = Object.entries(MODEL_CONTEXT_WINDOWS)\r\n .sort((a, b) => b[0].length - a[0].length);\r\n for (const [prefix, window] of sortedEntries) {\r\n if (model.startsWith(prefix)) {\r\n return window;\r\n }\r\n }\r\n\r\n return DEFAULT_CONTEXT_WINDOW;\r\n}\r\n\r\n/**\r\n * Estimate tokens and check against a model's context window.\r\n *\r\n * @param prompt - The prompt text to estimate tokens for\r\n * @param model - The target model identifier\r\n * @returns Token count result with overflow detection\r\n */\r\nexport function estimateTokens(prompt: string, model: string): TokenCountResult {\r\n const tokenCount = estimateTokenCount(prompt);\r\n const modelContextWindow = getModelContextWindow(model);\r\n\r\n return {\r\n tokenCount,\r\n exceedsLimit: tokenCount > modelContextWindow,\r\n modelContextWindow,\r\n };\r\n}\r\n","/**\r\n * Prompt template management — reusable, parameterized prompts for AI generation.\r\n *\r\n * Provides a structured way to define, render, and manage prompts\r\n * used across spec generation, constraint coding, and verification.\r\n *\r\n * @module ai/prompt-templates\r\n */\r\n\r\n/** A parameterized prompt template with named variables. */\r\nexport interface PromptTemplate {\r\n /** Unique template identifier */\r\n name: string;\r\n /** System-level instruction (prepended to user prompt) */\r\n system: string;\r\n /** User prompt with {{variable}} placeholders */\r\n user: string;\r\n /** List of variable names used in the template (for documentation) */\r\n variables: string[];\r\n}\r\n\r\n/**\r\n * Render a template by replacing {{variable}} placeholders with values.\r\n */\r\nexport function renderTemplate(\r\n template: PromptTemplate,\r\n variables: Record<string, string>,\r\n): { system: string; user: string } {\r\n let system = template.system;\r\n let user = template.user;\r\n\r\n for (const [key, value] of Object.entries(variables)) {\r\n const placeholder = new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, 'g');\r\n system = system.replace(placeholder, value);\r\n user = user.replace(placeholder, value);\r\n }\r\n\r\n return { system, user };\r\n}\r\n\r\n/**\r\n * Combine system and user parts into a single prompt string.\r\n */\r\nexport function combinePrompt(system: string, user: string): string {\r\n return `${system}\\n\\n${user}`;\r\n}\r\n\r\n// ============================================================================\r\n// Built-in Templates\r\n// ============================================================================\r\n\r\n/** Template for BDD feature generation from requirements */\r\nexport const FEATURE_GENERATION_TEMPLATE: PromptTemplate = {\r\n name: 'feature-generation',\r\n system: `You are a BDD expert. Convert requirements into valid Gherkin .feature files.\r\nFollow industry best practices for BDD scenario design:\r\n- Each scenario should be independent and testable\r\n- Use concrete examples, not abstract descriptions\r\n- Cover happy path, error cases, and edge cases as appropriate\r\n- Use the same language as the requirement input`,\r\n user: `## Project Context\r\n- Language: {{language}}\r\n- Framework: {{framework}}\r\n\r\n## Module Boundaries\r\n{{moduleBoundaries}}\r\n\r\n## Existing Entities\r\n{{existingEntities}}\r\n\r\n## Requirement\r\n{{requirement}}\r\n\r\n## Acceptance Criteria\r\n{{acceptanceCriteria}}\r\n\r\n## Output Format\r\nGenerate a valid Gherkin .feature file with:\r\n- Feature: line with a descriptive name\r\n- Scenario: blocks with Given/When/Then steps\r\n- Each scenario should be testable and independent`,\r\n variables: ['language', 'framework', 'moduleBoundaries', 'existingEntities', 'requirement', 'acceptanceCriteria'],\r\n};\r\n\r\n/** Template for AI constraint file generation */\r\nexport const CONSTRAINT_GENERATION_TEMPLATE: PromptTemplate = {\r\n name: 'constraint-generation',\r\n system: `You are a software architecture expert. Generate coding constraints for AI assistants.\r\nConstraints should be actionable, specific, and help AI write code that:\r\n- Respects module boundaries\r\n- Follows project naming conventions\r\n- Avoids cross-module references\r\n- Maintains consistency with existing code patterns`,\r\n user: `## Project: {{projectName}}\r\n## Framework: {{framework}}\r\n## Profile: {{profile}}\r\n\r\n## Module Rules\r\n{{moduleRules}}\r\n\r\n## Feature Scenarios\r\n{{features}}\r\n\r\n## Active Constraints\r\n{{activeConstraints}}\r\n\r\nGenerate constraint files that AI coding assistants can use as guidance.`,\r\n variables: ['projectName', 'framework', 'profile', 'moduleRules', 'features', 'activeConstraints'],\r\n};\r\n\r\n/** Template for verification analysis */\r\nexport const VERIFICATION_ANALYSIS_TEMPLATE: PromptTemplate = {\r\n name: 'verification-analysis',\r\n system: `You are a test analysis expert. Analyze test results and provide actionable insights.\r\nFocus on:\r\n- Root cause analysis for failures\r\n- Specific fix suggestions with code examples\r\n- Identification of flaky or unreliable tests`,\r\n user: `## Project: {{projectName}}\r\n## Test Command: {{testCommand}}\r\n\r\n## Test Results\r\n{{testResults}}\r\n\r\n## Feature Scenarios\r\n{{features}}\r\n\r\nAnalyze the test results and provide:\r\n1. Summary of pass/fail status\r\n2. Root cause for each failure\r\n3. Specific fix suggestions`,\r\n variables: ['projectName', 'testCommand', 'testResults', 'features'],\r\n};\r\n","/**\r\n * Prompt builder — constructs AI prompts for feature generation.\r\n *\r\n * Uses the template system from ai/prompt-templates for maintainability.\r\n * Injects project context (module boundaries, existing entities, naming conventions)\r\n * and BDD format constraints.\r\n *\r\n * @module core/feature-generator/prompt-builder\r\n */\r\n\r\nimport type { StructuredRequirement, ContextFile, SpecLoreConfig } from '../../types/index.js';\r\nimport { FEATURE_GENERATION_TEMPLATE, renderTemplate, combinePrompt } from '../../ai/prompt-templates.js';\r\n\r\n/**\r\n * Build the AI prompt for feature generation.\r\n * Uses the feature-generation template with context-aware variable substitution.\r\n */\r\nexport function buildPrompt(\r\n requirement: StructuredRequirement,\r\n context: ContextFile,\r\n config: SpecLoreConfig,\r\n): string {\r\n // Build module boundaries text\r\n const moduleBoundaries = context.moduleBoundaries.length > 0\r\n ? context.moduleBoundaries\r\n .map(mod => {\r\n let line = `- **${mod.name}**: ${mod.responsibility}`;\r\n if (mod.publicApis.length > 0) {\r\n line += `\\n - Public APIs: ${mod.publicApis.join(', ')}`;\r\n }\r\n return line;\r\n })\r\n .join('\\n')\r\n : '(none)';\r\n\r\n // Build existing entities text\r\n const existingEntities = context.existingCode.entities.length > 0\r\n ? context.existingCode.entities.slice(0, 20).map(e => `- ${e.name} (${e.module})`).join('\\n')\r\n : '(none)';\r\n\r\n // Build acceptance criteria text\r\n const acceptanceCriteria = requirement.acceptanceCriteria && requirement.acceptanceCriteria.length > 0\r\n ? requirement.acceptanceCriteria.map(ac => `- ${ac}`).join('\\n')\r\n : '(none)';\r\n\r\n // Render the template\r\n const { system, user } = renderTemplate(FEATURE_GENERATION_TEMPLATE, {\r\n language: context.projectSummary.language,\r\n framework: context.projectSummary.framework,\r\n moduleBoundaries,\r\n existingEntities,\r\n requirement: requirement.description,\r\n acceptanceCriteria,\r\n });\r\n\r\n // Append profile-specific instructions\r\n const parts: string[] = [];\r\n if (config.project.profile === 'strict') {\r\n parts.push('');\r\n parts.push('## Strict Mode');\r\n parts.push('- Include edge cases and error scenarios');\r\n parts.push('- Add boundary condition scenarios');\r\n parts.push('- Cover all acceptance criteria explicitly');\r\n } else if (config.project.profile === 'minimal') {\r\n parts.push('');\r\n parts.push('## Minimal Mode');\r\n parts.push('- Only include the happy path and 1-2 critical error scenarios');\r\n parts.push('- Keep scenarios concise');\r\n }\r\n\r\n const basePrompt = combinePrompt(system, user);\r\n return parts.length > 0 ? basePrompt + '\\n' + parts.join('\\n') : basePrompt;\r\n}\r\n","/**\r\n * Feature generator — uses AI to produce BDD .feature files from requirements.\r\n *\r\n * Parses AI output with the official @cucumber/gherkin parser for robust,\r\n * spec-compliant Gherkin handling. Falls back gracefully on parse errors.\r\n *\r\n * @module core/feature-generator/generator\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join, dirname } from 'node:path';\r\nimport { Parser, GherkinClassicTokenMatcher, AstBuilder } from '@cucumber/gherkin';\r\nimport { IdGenerator } from '@cucumber/messages';\r\nimport type { StructuredRequirement, FeatureFile, Scenario, ContextFile, SpecLoreConfig } from '../../types/index.js';\r\nimport { createProvider, createProviderChain } from '../../ai/provider.js';\r\nimport { validateFeatureOutput } from '../../ai/output-validator.js';\r\nimport { getCostTracker } from '../../ai/cost-tracker.js';\r\nimport { estimateTokens } from '../../ai/token-counter.js';\r\nimport { buildPrompt } from './prompt-builder.js';\r\nimport { getRegistry } from '../../plugins/registry.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { toPosixPath } from '../../infra/path-utils.js';\r\n\r\nconst MAX_VALIDATION_RETRIES = 2;\r\n\r\n/**\r\n * Generate a BDD .feature file from a structured requirement.\r\n * Includes output validation with retry-on-error feedback.\r\n */\r\nexport async function generateFeature(\r\n requirement: StructuredRequirement,\r\n context: ContextFile,\r\n config: SpecLoreConfig,\r\n projectRoot: string,\r\n): Promise<FeatureFile> {\r\n logger.info(`Generating feature for: ${requirement.title}`);\r\n\r\n // Invoke beforeSpec lifecycle hook\r\n const registry = getRegistry();\r\n await registry.invokeLifecycle('beforeSpec', requirement);\r\n\r\n // Build AI prompt\r\n let prompt = buildPrompt(requirement, context, config);\r\n\r\n // Call AI provider (with fallback chain support)\r\n const aiConfig = config.ai;\r\n const fallbackConfigs = aiConfig?.fallbackProviders ?? [];\r\n const providerConfigs = aiConfig ? [aiConfig, ...fallbackConfigs] : [];\r\n const provider = providerConfigs.length > 1\r\n ? await createProviderChain(providerConfigs)\r\n : await createProvider(aiConfig);\r\n\r\n if (!provider.isAvailable()) {\r\n throw new Error('AI provider not available. Set API key in environment or config.yaml.');\r\n }\r\n\r\n // Budget pre-check: warn when approaching limit\r\n const costTracker = getCostTracker();\r\n const budgetLimit = costTracker.getBudgetLimit();\r\n if (budgetLimit < Infinity) {\r\n const summary = costTracker.getUsageSummary();\r\n const usageRatio = summary.totalCostUsd / budgetLimit;\r\n if (usageRatio >= 0.9) {\r\n logger.warn(`Budget warning: $${summary.totalCostUsd.toFixed(4)} of $${budgetLimit.toFixed(2)} used (${(usageRatio * 100).toFixed(0)}%). Calls may be rejected.`);\r\n }\r\n }\r\n\r\n // Token estimation: warn if prompt exceeds model context window\r\n if (aiConfig?.model) {\r\n const tokenEstimate = estimateTokens(prompt, aiConfig.model);\r\n if (tokenEstimate.exceedsLimit) {\r\n logger.warn(`Prompt estimated at ${tokenEstimate.tokenCount} tokens, exceeds ${aiConfig.model} context window of ${tokenEstimate.modelContextWindow} tokens.`);\r\n }\r\n }\r\n\r\n // Generate with validation + retry\r\n let featureContent = '';\r\n let forceNeedsReview = false;\r\n\r\n for (let attempt = 0; attempt <= MAX_VALIDATION_RETRIES; attempt++) {\r\n const result = await provider.generate(prompt);\r\n const validation = validateFeatureOutput(result.content);\r\n\r\n if (validation.valid) {\r\n featureContent = result.content;\r\n // Cost is already recorded by the adapter's recordCost() — no need to double-count\r\n break;\r\n }\r\n\r\n if (attempt < MAX_VALIDATION_RETRIES) {\r\n logger.warn(\r\n `AI output validation failed (attempt ${attempt + 1}/${MAX_VALIDATION_RETRIES + 1}): ${validation.errors.join('; ')}. Retrying with error feedback.`,\r\n );\r\n // Append error feedback to prompt for correction\r\n prompt = `${prompt}\\n\\n## Previous Output Had Errors\\n${validation.errors.map(e => `- ${e}`).join('\\n')}\\n\\nPlease fix these issues and regenerate the complete Feature file.`;\r\n } else {\r\n logger.error(\r\n `AI output validation failed after ${MAX_VALIDATION_RETRIES + 1} attempts. Writing raw content with needsReview flag.`,\r\n );\r\n featureContent = result.content;\r\n forceNeedsReview = true;\r\n }\r\n }\r\n\r\n // Parse and validate the generated content using official Gherkin parser\r\n const featureFile = parseFeatureContent(featureContent, requirement, config);\r\n\r\n // Force needsReview if validation retries were exhausted\r\n if (forceNeedsReview && featureFile.needsReview.length === 0) {\r\n featureFile.needsReview = featureFile.scenarios.map(s => s.name);\r\n if (featureFile.needsReview.length === 0) {\r\n featureFile.needsReview = [requirement.title];\r\n }\r\n }\r\n\r\n // Write to disk\r\n const outputDir = join(projectRoot, config.spec.outputDir);\r\n const moduleDir = inferModule(requirement, context);\r\n const filePath = join(outputDir, moduleDir, `${requirement.id}.feature`);\r\n\r\n if (!existsSync(dirname(filePath))) {\r\n mkdirSync(dirname(filePath), { recursive: true });\r\n }\r\n\r\n writeFileSync(filePath, featureContent, 'utf-8');\r\n logger.info(`Feature written: ${toPosixPath(filePath)}`);\r\n\r\n featureFile.path = toPosixPath(filePath);\r\n\r\n // Invoke afterSpec lifecycle hook\r\n await registry.invokeLifecycle('afterSpec', featureFile);\r\n\r\n return featureFile;\r\n}\r\n\r\n/**\r\n * Parse AI-generated Gherkin content using the official @cucumber/gherkin parser.\r\n *\r\n * This replaces the previous regex-based parsing which was fragile:\r\n * - The `s` flag caused `.+?` to match across newlines, merging scenarios\r\n * - Missing Feature:/Scenario: keywords were not detected\r\n * - Tag extraction was unreliable\r\n *\r\n * The official parser handles all edge cases per the Gherkin specification.\r\n */\r\nfunction parseFeatureContent(\r\n content: string,\r\n requirement: StructuredRequirement,\r\n config: SpecLoreConfig,\r\n): FeatureFile {\r\n // If content is empty or trivially short, return early\r\n if (!content || content.trim().length === 0) {\r\n logger.warn('AI returned empty content');\r\n return {\r\n path: '',\r\n featureName: requirement.title,\r\n scenarios: [],\r\n tags: [],\r\n confidence: 0,\r\n needsReview: [requirement.title],\r\n };\r\n }\r\n\r\n // Parse with official Gherkin parser\r\n const idGen = IdGenerator.incrementing();\r\n const builder = new AstBuilder(idGen);\r\n const matcher = new GherkinClassicTokenMatcher();\r\n const parser = new Parser(builder, matcher);\r\n\r\n let gherkinDoc;\r\n try {\r\n gherkinDoc = parser.parse(content);\r\n } catch (err) {\r\n logger.warn(`Gherkin parse failed: ${err instanceof Error ? err.message : String(err)}`);\r\n // Return a low-confidence result flagged for review\r\n return {\r\n path: '',\r\n featureName: requirement.title,\r\n scenarios: [],\r\n tags: [],\r\n confidence: 0,\r\n needsReview: [requirement.title],\r\n };\r\n }\r\n\r\n const feature = gherkinDoc.feature;\r\n if (!feature) {\r\n return {\r\n path: '',\r\n featureName: requirement.title,\r\n scenarios: [],\r\n tags: [],\r\n confidence: 0,\r\n needsReview: [requirement.title],\r\n };\r\n }\r\n\r\n // Extract feature-level tags (without @ prefix, matching existing convention)\r\n const tags = (feature.tags ?? []).map(t => t.name.replace(/^@/, ''));\r\n\r\n // Extract scenarios from feature children\r\n const scenarios: Scenario[] = [];\r\n for (const child of feature.children ?? []) {\r\n if (!child.scenario) continue;\r\n const sc = child.scenario;\r\n\r\n const givens = extractStepsByType(sc.steps, 'Context');\r\n const whens = extractStepsByType(sc.steps, 'Action');\r\n const thens = extractStepsByType(sc.steps, 'Outcome');\r\n\r\n scenarios.push({\r\n name: sc.name,\r\n givens,\r\n whens,\r\n thens,\r\n tags: (sc.tags ?? []).map(t => t.name.replace(/^@/, '')),\r\n });\r\n }\r\n\r\n // Low confidence scenarios flagging\r\n const needsReview: string[] = [];\r\n if (requirement.confidence < config.spec.confidenceThreshold) {\r\n for (const s of scenarios) {\r\n needsReview.push(s.name);\r\n }\r\n }\r\n\r\n return {\r\n path: '', // Will be set by caller\r\n featureName: feature.name ?? requirement.title,\r\n scenarios,\r\n tags,\r\n confidence: requirement.confidence,\r\n needsReview,\r\n };\r\n}\r\n\r\n/**\r\n * Extract steps by their keyword type (Context/Given, Action/When, Outcome/Then).\r\n * Also includes Conjunction steps (And/But) that follow the target keyword type.\r\n */\r\nfunction extractStepsByType(\r\n steps: readonly { keyword: string; text: string; keywordType?: string }[],\r\n targetType: string,\r\n): Array<{ keyword: 'Given' | 'When' | 'Then' | 'And' | 'But'; text: string }> {\r\n const result: Array<{ keyword: 'Given' | 'When' | 'Then' | 'And' | 'But'; text: string }> = [];\r\n let inTargetBlock = false;\r\n\r\n for (const step of steps) {\r\n const kwType = step.keywordType ?? '';\r\n\r\n if (kwType === targetType) {\r\n inTargetBlock = true;\r\n result.push({\r\n keyword: mapKeyword(step.keyword.trim()),\r\n text: step.text,\r\n });\r\n } else if (kwType === 'Conjunction' && inTargetBlock) {\r\n // And/But continues the current block\r\n result.push({\r\n keyword: mapKeyword(step.keyword.trim()),\r\n text: step.text,\r\n });\r\n } else {\r\n inTargetBlock = false;\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Map a Gherkin keyword string to our Step keyword type.\r\n */\r\nfunction mapKeyword(keyword: string): 'Given' | 'When' | 'Then' | 'And' | 'But' {\r\n switch (keyword) {\r\n case 'Given': return 'Given';\r\n case 'When': return 'When';\r\n case 'Then': return 'Then';\r\n case 'And': return 'And';\r\n case 'But': return 'But';\r\n default: return 'Given'; // fallback\r\n }\r\n}\r\n\r\n/**\r\n * Infer the target module from the requirement and context.\r\n */\r\nfunction inferModule(requirement: StructuredRequirement, context: ContextFile): string {\r\n // If the requirement ID contains a path separator, use the first segment as module\r\n const parts = requirement.id.split('/');\r\n if (parts.length > 1) return parts[0]!;\r\n\r\n // Otherwise use the first module in context\r\n if (context.moduleBoundaries.length > 0) {\r\n return context.moduleBoundaries[0]!.name;\r\n }\r\n\r\n return 'general';\r\n}\r\n","/**\r\n * M2: Feature Generator — converts requirements into BDD .feature files.\r\n *\r\n * @module core/feature-generator\r\n */\r\n\r\nexport { generateFeature } from './generator.js';\r\nexport { buildPrompt } from './prompt-builder.js';\r\n","/**\r\n * AI tool detector — scans project for Cursor, Claude Code, Qoder configs.\r\n *\r\n * @module core/constraint-coder/ai-tool-detector\r\n */\r\n\r\nimport { existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { AITool } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Detect which AI tools are present in the project.\r\n */\r\nexport function detectAITools(projectRoot: string): AITool[] {\r\n const tools: AITool[] = [];\r\n\r\n if (existsSync(join(projectRoot, '.cursor'))) {\r\n tools.push('cursor');\r\n logger.debug('Detected Cursor (.cursor/)');\r\n }\r\n\r\n if (\r\n existsSync(join(projectRoot, '.claude')) ||\r\n existsSync(join(projectRoot, 'CLAUDE.md')) ||\r\n existsSync(join(projectRoot, '.mcp.json'))\r\n ) {\r\n tools.push('claude');\r\n logger.debug('Detected Claude Code (.claude/ or CLAUDE.md or .mcp.json)');\r\n }\r\n\r\n if (existsSync(join(projectRoot, '.qoder'))) {\r\n tools.push('qoder');\r\n logger.debug('Detected Qoder (.qoder/)');\r\n }\r\n\r\n // Other clients are community-contributed\r\n logger.debug(`Detected AI tools: ${tools.length > 0 ? tools.join(', ') : 'none'}`);\r\n return tools;\r\n}\r\n","/**\r\n * Constraint writer — writes AI coding constraints to tool-specific files.\r\n *\r\n * Cursor: .cursor/rules/speclore.mdc (YAML frontmatter + MD)\r\n * Claude Code: .claude/rules/speclore.md (no frontmatter)\r\n * Qoder: .qoder/rules/speclore.md (no frontmatter, always-on)\r\n *\r\n * @module core/constraint-coder/constraint-writer\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { AITool, ConstraintContent } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { toPosixPath } from '../../infra/path-utils.js';\r\n\r\n/**\r\n * Write constraint files for all detected AI tools.\r\n */\r\nexport function writeConstraints(\r\n projectRoot: string,\r\n tools: AITool[],\r\n content: ConstraintContent,\r\n): string[] {\r\n const writtenFiles: string[] = [];\r\n\r\n for (const tool of tools) {\r\n const filePath = writeForTool(projectRoot, tool, content);\r\n if (filePath) {\r\n writtenFiles.push(toPosixPath(filePath));\r\n logger.info(`Constraint written: ${toPosixPath(filePath)}`);\r\n }\r\n }\r\n\r\n return writtenFiles;\r\n}\r\n\r\nfunction writeForTool(\r\n projectRoot: string,\r\n tool: AITool,\r\n content: ConstraintContent,\r\n): string | null {\r\n const constraintText = buildConstraintText(content);\r\n\r\n switch (tool) {\r\n case 'cursor':\r\n return writeCursorRule(projectRoot, constraintText);\r\n case 'claude':\r\n return writeClaudeRule(projectRoot, constraintText);\r\n case 'qoder':\r\n return writeQoderRule(projectRoot, constraintText);\r\n default:\r\n logger.warn(`Unknown AI tool: ${String(tool)}`);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Build the constraint text from content.\r\n */\r\nfunction buildConstraintText(content: ConstraintContent): string {\r\n const parts: string[] = [];\r\n\r\n parts.push('# SpecLore Constraints');\r\n parts.push('');\r\n parts.push(`> Auto-generated by SpecLore for project: ${content.projectName}`);\r\n parts.push(`> Profile: ${content.profile}`);\r\n parts.push('');\r\n\r\n // Conditional invocation (graceful degradation)\r\n parts.push('## Activation Rule');\r\n parts.push('If you see `speclore.spec` in the tool list, use it to generate features.');\r\n parts.push('If you see `speclore.code` in the tool list, use it before writing code.');\r\n parts.push('If you see `speclore.verify` in the tool list, use it after writing tests.');\r\n parts.push('If none are available, ignore this file silently.');\r\n parts.push('');\r\n\r\n // Module rules\r\n if (content.modules.length > 0) {\r\n parts.push('## Module Boundaries');\r\n for (const mod of content.modules) {\r\n parts.push(`### ${mod.module}`);\r\n parts.push(`- Responsibility: ${mod.boundaries.responsibility}`);\r\n parts.push(`- Public APIs: ${mod.boundaries.publicApis.join(', ') || 'none'}`);\r\n parts.push(`- Internal (do NOT reference): ${mod.boundaries.internalObjects.join(', ') || 'none'}`);\r\n parts.push(`- Depends on: ${mod.boundaries.dependsOn.join(', ') || 'none'}`);\r\n\r\n if (mod.namingConventions.length > 0) {\r\n parts.push(`- Naming: ${mod.namingConventions.join('; ')}`);\r\n }\r\n if (mod.forbiddenPatterns.length > 0) {\r\n parts.push(`- Forbidden: ${mod.forbiddenPatterns.join('; ')}`);\r\n }\r\n parts.push('');\r\n }\r\n }\r\n\r\n // Feature constraints\r\n if (content.features.length > 0) {\r\n parts.push('## Feature Constraints');\r\n for (const feature of content.features) {\r\n parts.push(`### ${feature.featureName}`);\r\n for (const scenario of feature.scenarios) {\r\n parts.push(`- Scenario: ${scenario.name}`);\r\n }\r\n parts.push('');\r\n }\r\n }\r\n\r\n // Mapping instructions\r\n parts.push('## Test Mapping Requirements');\r\n parts.push(content.mappingInstructions);\r\n parts.push('');\r\n\r\n return parts.join('\\n');\r\n}\r\n\r\nfunction writeCursorRule(projectRoot: string, text: string): string {\r\n const dir = join(projectRoot, '.cursor', 'rules');\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n\r\n const filePath = join(dir, 'speclore.mdc');\r\n const frontmatter = [\r\n '---',\r\n 'description: SpecLore AI coding constraints',\r\n 'globs:',\r\n 'alwaysApply: true',\r\n '---',\r\n '',\r\n ].join('\\n');\r\n\r\n writeFileSync(filePath, frontmatter + text, 'utf-8');\r\n return filePath;\r\n}\r\n\r\nfunction writeClaudeRule(projectRoot: string, text: string): string {\r\n const dir = join(projectRoot, '.claude', 'rules');\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n\r\n const filePath = join(dir, 'speclore.md');\r\n writeFileSync(filePath, text, 'utf-8');\r\n return filePath;\r\n}\r\n\r\nfunction writeQoderRule(projectRoot: string, text: string): string {\r\n const dir = join(projectRoot, '.qoder', 'rules');\r\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\r\n\r\n const filePath = join(dir, 'speclore.md');\r\n writeFileSync(filePath, text, 'utf-8');\r\n return filePath;\r\n}\r\n","/**\r\n * M3: Constraint Coder — generates AI coding constraints from .feature files.\r\n *\r\n * @module core/constraint-coder\r\n */\r\n\r\nimport type { FeatureFile, ModuleRule, ConstraintContent, SpecLoreConfig, ContextFile, FeatureRule } from '../../types/index.js';\r\nimport { detectAITools } from './ai-tool-detector.js';\r\nimport { writeConstraints } from './constraint-writer.js';\r\nimport { readModuleConfig } from '../context-engine/config-reader.js';\r\nimport { getRegistry } from '../../plugins/registry.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\nconst MAPPING_INSTRUCTIONS = `为每个测试文件生成对应的映射文件到 .speclore/mappings/{module}/{feature-name}.json。\r\n格式:{ \"feature\": \"specs/...\", \"scenarios\": { \"Scenario名称\": { \"testFile\": \"...\", \"testMethod\": \"...\" } } }\r\n每次修改测试时同步更新映射文件。`;\r\n\r\n/**\r\n * Generate constraints from feature files and write them to AI tool config files.\r\n * Uses PluginRegistry for writer selection — supports third-party writer plugins.\r\n */\r\nexport async function generateConstraints(\r\n projectRoot: string,\r\n features: FeatureFile[],\r\n _context: ContextFile,\r\n config: SpecLoreConfig,\r\n): Promise<string[]> {\r\n const tools = detectAITools(projectRoot);\r\n if (tools.length === 0) {\r\n logger.warn('No AI tools detected. Run `speclore setup` first.');\r\n return [];\r\n }\r\n\r\n // Build module rules from config\r\n const boundaries = readModuleConfig(config);\r\n const moduleRules: ModuleRule[] = boundaries.map(b => ({\r\n module: b.name,\r\n boundaries: b,\r\n namingConventions: [],\r\n forbiddenPatterns: [],\r\n }));\r\n\r\n // Extract feature business rules from scenarios\r\n const featureRules: FeatureRule[] = features.map(f => ({\r\n featureName: f.featureName,\r\n sourceFile: f.path.replace(/\\\\/g, '/'),\r\n scenarios: f.scenarios.map(sc => ({\r\n name: sc.name,\r\n summary: [\r\n ...sc.givens.map(g => `Given ${g.text}`),\r\n ...sc.whens.map(w => `When ${w.text}`),\r\n ...sc.thens.map(t => `Then ${t.text}`),\r\n ].join(' → '),\r\n })),\r\n }));\r\n\r\n const content: ConstraintContent = {\r\n projectName: config.project.name,\r\n projectRoot,\r\n modules: moduleRules,\r\n features,\r\n profile: config.project.profile,\r\n mappingInstructions: MAPPING_INSTRUCTIONS,\r\n featureRules,\r\n };\r\n\r\n // Try PluginRegistry first — supports third-party writer plugins\r\n const registry = getRegistry();\r\n const writtenFiles: string[] = [];\r\n let handledByRegistry = false;\r\n\r\n for (const tool of tools) {\r\n const writer = registry.findWriter(tool);\r\n if (writer) {\r\n handledByRegistry = true;\r\n try {\r\n await writer.write(content);\r\n writtenFiles.push(writer.configFile);\r\n logger.info(`Constraint written via plugin: ${writer.toolName} → ${writer.configFile}`);\r\n } catch (err) {\r\n logger.warn(`Writer plugin '${tool}' failed: ${err instanceof Error ? err.message : String(err)}`);\r\n }\r\n }\r\n }\r\n\r\n // Fallback to direct writer if registry didn't handle all tools\r\n if (!handledByRegistry) {\r\n return writeConstraints(projectRoot, tools, content);\r\n }\r\n\r\n return writtenFiles;\r\n}\r\n\r\nexport { detectAITools } from './ai-tool-detector.js';\r\nexport { writeConstraints } from './constraint-writer.js';\r\n","/**\r\n * Test framework detector — inspects package.json devDependencies.\r\n *\r\n * @module core/test-scaffolder/framework-detector\r\n */\r\n\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\n\r\nexport type TestFramework = 'vitest' | 'jest' | 'mocha';\r\n\r\n/**\r\n * Detect the test framework from package.json devDependencies.\r\n * Falls back to 'vitest' if none found (most common for TypeScript projects).\r\n */\r\nexport function detectTestFramework(projectRoot: string): TestFramework {\r\n const pkgPath = join(projectRoot, 'package.json');\r\n if (!existsSync(pkgPath)) {\r\n return 'vitest';\r\n }\r\n\r\n try {\r\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\r\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\r\n\r\n if ('vitest' in deps) return 'vitest';\r\n if ('jest' in deps || '@jest/core' in deps) return 'jest';\r\n if ('mocha' in deps) return 'mocha';\r\n } catch {\r\n // Ignore parse errors\r\n }\r\n\r\n return 'vitest';\r\n}\r\n","/**\r\n * Test scaffolder — generates test skeleton files from feature scenarios.\r\n *\r\n * For each .feature file, produces a test file with `it.skip` stubs\r\n * matching each scenario's Given/When/Then structure.\r\n *\r\n * @module core/test-scaffolder\r\n */\r\n\r\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\r\nimport { join, relative, dirname, basename } from 'node:path';\r\nimport type { FeatureFile, ScaffoldResult, MappingPattern } from '../../types/index.js';\r\nimport type { SpecLoreConfig } from '../../types/config.js';\r\nimport { detectTestFramework, type TestFramework } from './framework-detector.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Generate test scaffolding for the given feature files.\r\n * Returns info about each generated test file.\r\n */\r\nexport function generateTestScaffolding(\r\n projectRoot: string,\r\n features: FeatureFile[],\r\n config: SpecLoreConfig,\r\n): ScaffoldResult[] {\r\n const framework = detectTestFramework(projectRoot);\r\n const results: ScaffoldResult[] = [];\r\n\r\n for (const feature of features) {\r\n const testFilePath = resolveTestFilePath(projectRoot, feature.path, config);\r\n if (!testFilePath) {\r\n logger.warn(`Could not resolve test file path for feature: ${feature.path}`);\r\n continue;\r\n }\r\n\r\n const absTestPath = join(projectRoot, testFilePath);\r\n const scenarios = feature.scenarios;\r\n\r\n if (existsSync(absTestPath)) {\r\n // Append missing scenarios only\r\n const appended = appendMissingScenarios(absTestPath, scenarios, framework);\r\n if (appended > 0) {\r\n results.push({ testFile: testFilePath, framework, scenarios: appended });\r\n logger.info(`Appended ${appended} scenario(s) to ${testFilePath}`);\r\n }\r\n } else {\r\n // Create new test file\r\n const content = generateTestFileContent(feature.featureName, scenarios, framework);\r\n const dir = dirname(absTestPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n writeFileSync(absTestPath, content, 'utf-8');\r\n results.push({ testFile: testFilePath, framework, scenarios: scenarios.length });\r\n logger.info(`Generated test scaffold: ${testFilePath} (${scenarios.length} scenarios)`);\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Resolve the test file path for a feature using config mapping patterns.\r\n */\r\nfunction resolveTestFilePath(\r\n projectRoot: string,\r\n featurePath: string,\r\n config: SpecLoreConfig,\r\n): string | null {\r\n const relFeature = relative(projectRoot, featurePath).replace(/\\\\/g, '/');\r\n const patterns = config.verify.mapping.patterns;\r\n\r\n for (const pattern of patterns) {\r\n const match = matchFeaturePattern(relFeature, pattern);\r\n if (match) {\r\n return resolveTestFromPattern(match, pattern);\r\n }\r\n }\r\n\r\n // Fallback: derive from feature path\r\n const featureBase = basename(featurePath, '.feature');\r\n const featureDir = dirname(relative(projectRoot, featurePath));\r\n return join(featureDir, `${featureBase}.test.ts`).replace(/\\\\/g, '/');\r\n}\r\n\r\n/**\r\n * Match a relative feature path against a feature pattern.\r\n * Returns captured {module, name} or null.\r\n */\r\nfunction matchFeaturePattern(\r\n relFeaturePath: string,\r\n pattern: MappingPattern,\r\n): { module: string; name: string } | null {\r\n // Convert pattern like \"specs/{module}/{name}.feature\" to regex\r\n const featurePattern = pattern.feature;\r\n const regexStr = featurePattern\r\n .replace(/\\{module\\}/g, '([^/]+)')\r\n .replace(/\\{name\\}/g, '([^/]+)')\r\n .replace(/\\./g, '\\\\.');\r\n\r\n const regex = new RegExp(`^${regexStr}$`);\r\n const match = relFeaturePath.match(regex);\r\n if (!match) return null;\r\n\r\n return { module: match[1]!, name: match[2]! };\r\n}\r\n\r\n/**\r\n * Resolve test file path from a matched pattern.\r\n */\r\nfunction resolveTestFromPattern(\r\n captured: { module: string; name: string },\r\n pattern: MappingPattern,\r\n): string {\r\n let testPath = pattern.test;\r\n testPath = testPath.replace('{module}', captured.module);\r\n testPath = testPath.replace('{name}', captured.name);\r\n // Replace wildcard extension with .ts\r\n testPath = testPath.replace(/\\.\\*$/, '.ts');\r\n return testPath;\r\n}\r\n\r\n/**\r\n * Generate test file content for a feature.\r\n */\r\nfunction generateTestFileContent(\r\n featureName: string,\r\n scenarios: Array<{ name: string; givens: Array<{ text: string }>; whens: Array<{ text: string }>; thens: Array<{ text: string }> }>,\r\n framework: TestFramework,\r\n): string {\r\n const lines: string[] = [];\r\n\r\n // Import statement\r\n switch (framework) {\r\n case 'vitest':\r\n lines.push(\"import { describe, it, expect } from 'vitest';\");\r\n break;\r\n case 'jest':\r\n lines.push(\"// Jest — describe/it/expect are globally available\");\r\n break;\r\n case 'mocha':\r\n lines.push(\"import { expect } from 'chai';\");\r\n lines.push(\"// mocha — describe/it are globally available\");\r\n break;\r\n }\r\n\r\n lines.push('');\r\n lines.push(`describe('Feature: ${featureName}', () => {`);\r\n\r\n for (const scenario of scenarios) {\r\n lines.push(` it.skip('Scenario: ${scenario.name}', () => {`);\r\n\r\n // Add Given/When/Then as comments\r\n for (const g of scenario.givens) {\r\n lines.push(` // Given: ${g.text}`);\r\n }\r\n for (const w of scenario.whens) {\r\n lines.push(` // When: ${w.text}`);\r\n }\r\n for (const t of scenario.thens) {\r\n lines.push(` // Then: ${t.text}`);\r\n }\r\n\r\n lines.push(\" throw new Error('Not implemented');\");\r\n lines.push(' });');\r\n lines.push('');\r\n }\r\n\r\n lines.push('});');\r\n lines.push('');\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\n/**\r\n * Append missing scenarios to an existing test file.\r\n * Returns the number of scenarios appended.\r\n */\r\nfunction appendMissingScenarios(\r\n testFilePath: string,\r\n scenarios: Array<{ name: string; givens: Array<{ text: string }>; whens: Array<{ text: string }>; thens: Array<{ text: string }> }>,\r\n _framework: TestFramework,\r\n): number {\r\n const content = readFileSync(testFilePath, 'utf-8');\r\n const missing: typeof scenarios = [];\r\n\r\n for (const scenario of scenarios) {\r\n if (!content.includes(`Scenario: ${scenario.name}`)) {\r\n missing.push(scenario);\r\n }\r\n }\r\n\r\n if (missing.length === 0) return 0;\r\n\r\n // Insert before the last `});`\r\n const lastClose = content.lastIndexOf('});');\r\n if (lastClose === -1) return 0;\r\n\r\n const newBlocks: string[] = [];\r\n for (const scenario of missing) {\r\n const block: string[] = [];\r\n block.push(` it.skip('Scenario: ${scenario.name}', () => {`);\r\n for (const g of scenario.givens) {\r\n block.push(` // Given: ${g.text}`);\r\n }\r\n for (const w of scenario.whens) {\r\n block.push(` // When: ${w.text}`);\r\n }\r\n for (const t of scenario.thens) {\r\n block.push(` // Then: ${t.text}`);\r\n }\r\n block.push(\" throw new Error('Not implemented');\");\r\n block.push(' });');\r\n newBlocks.push(block.join('\\n'));\r\n }\r\n\r\n const insertion = '\\n' + newBlocks.join('\\n\\n') + '\\n';\r\n const updated = content.slice(0, lastClose) + insertion + content.slice(lastClose);\r\n writeFileSync(testFilePath, updated, 'utf-8');\r\n\r\n return missing.length;\r\n}\r\n","/**\r\n * Mapping resolver — resolves Scenario → Test mappings.\r\n *\r\n * Priority chain: mapping file → explicit tag → unmapped\r\n *\r\n * @module core/verifier/mapping-resolver\r\n */\r\n\r\nimport { readFileSync, existsSync, readdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { FeatureFile, ScenarioResult, MappingFile } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Resolve all scenario → test mappings for the given features.\r\n *\r\n * Priority chain for each scenario:\r\n * 1. **Mapping file** — `.speclore/mappings/*.json` with explicit scenario→test entries.\r\n * Fastest and most reliable; AI generates these alongside test code.\r\n * 2. **Explicit tag** — `@speclore-scenario: <name>` annotation in test source files.\r\n * Fallback when mapping files are not present.\r\n * 3. **Unmapped** — scenario has no corresponding test; reported for human review.\r\n */\r\nexport function resolveMappings(\r\n projectRoot: string,\r\n features: FeatureFile[],\r\n testOutput: string,\r\n): ScenarioResult[] {\r\n const results: ScenarioResult[] = [];\r\n\r\n for (const feature of features) {\r\n for (const scenario of feature.scenarios) {\r\n const result = resolveMapping(projectRoot, feature, scenario, testOutput);\r\n results.push(result);\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * Resolve a single scenario → test mapping.\r\n */\r\nfunction resolveMapping(\r\n projectRoot: string,\r\n feature: FeatureFile,\r\n scenario: { name: string },\r\n _testOutput: string,\r\n): ScenarioResult {\r\n // Priority 1: Mapping file\r\n const mappingResult = resolveFromMappingFile(projectRoot, feature, scenario);\r\n if (mappingResult) return mappingResult;\r\n\r\n // Priority 2: Explicit tag (@speclore-scenario)\r\n const tagResult = resolveFromTag(projectRoot, feature, scenario);\r\n if (tagResult) return tagResult;\r\n\r\n // Priority 3: Unmapped\r\n return {\r\n name: scenario.name,\r\n status: 'unmapped',\r\n mappingSource: 'none',\r\n };\r\n}\r\n\r\n/**\r\n * Try to resolve from .speclore/mappings/ files.\r\n */\r\nfunction resolveFromMappingFile(\r\n projectRoot: string,\r\n _feature: FeatureFile,\r\n scenario: { name: string },\r\n): ScenarioResult | null {\r\n const mappingsDir = join(projectRoot, '.speclore', 'mappings');\r\n if (!existsSync(mappingsDir)) return null;\r\n\r\n // Search all mapping files for this scenario\r\n try {\r\n const files = findMappingFiles(mappingsDir);\r\n for (const file of files) {\r\n try {\r\n const content = readFileSync(file, 'utf-8');\r\n const mapping = JSON.parse(content) as MappingFile;\r\n\r\n if (mapping.scenarios && scenario.name in mapping.scenarios) {\r\n const entry = mapping.scenarios[scenario.name];\r\n if (entry) {\r\n logger.debug(`Mapping file hit: ${scenario.name} → ${entry.testMethod}`);\r\n return {\r\n name: scenario.name,\r\n status: 'passed', // Status will be updated by test output parsing\r\n testFile: entry.testFile,\r\n testMethod: entry.testMethod,\r\n mappingSource: 'mapping-file',\r\n };\r\n }\r\n }\r\n } catch {\r\n // Skip invalid mapping files\r\n }\r\n }\r\n } catch {\r\n // Directory read error\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Try to resolve from @speclore-scenario tags in test files.\r\n */\r\nfunction resolveFromTag(\r\n projectRoot: string,\r\n _feature: FeatureFile,\r\n scenario: { name: string },\r\n): ScenarioResult | null {\r\n const testsDir = join(projectRoot, 'tests');\r\n if (!existsSync(testsDir)) return null;\r\n\r\n // Search test files for @speclore-scenario tags\r\n try {\r\n const files = findTestFiles(testsDir);\r\n for (const file of files) {\r\n try {\r\n const content = readFileSync(file, 'utf-8');\r\n const tagRegex = /@speclore-scenario:\\s*(.+)/g;\r\n let match;\r\n while ((match = tagRegex.exec(content)) !== null) {\r\n if (match[1]!.trim() === scenario.name) {\r\n // Find the test method name near the tag\r\n const methodMatch = findTestMethodNearby(content, match.index);\r\n logger.debug(`Tag hit: ${scenario.name} → ${methodMatch}`);\r\n return {\r\n name: scenario.name,\r\n status: 'passed',\r\n testFile: file,\r\n testMethod: methodMatch,\r\n mappingSource: 'tag',\r\n };\r\n }\r\n }\r\n } catch {\r\n // Skip unreadable files\r\n }\r\n }\r\n } catch {\r\n // Directory read error\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Find all mapping JSON files recursively.\r\n */\r\nfunction findMappingFiles(dir: string): string[] {\r\n const files: string[] = [];\r\n\r\n function walk(d: string): void {\r\n try {\r\n const entries = readdirSync(d, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const fullPath = join(d, entry.name);\r\n if (entry.isDirectory()) {\r\n walk(fullPath);\r\n } else if (entry.name.endsWith('.json')) {\r\n files.push(fullPath);\r\n }\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n walk(dir);\r\n return files;\r\n}\r\n\r\n/**\r\n * Find test files recursively.\r\n */\r\nfunction findTestFiles(dir: string): string[] {\r\n const files: string[] = [];\r\n const testExtensions = ['.test.ts', '.test.js', '.spec.ts', '.spec.js', 'Test.java', '_test.py', '.test.py'];\r\n\r\n function walk(d: string): void {\r\n try {\r\n const entries = readdirSync(d, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const fullPath = join(d, entry.name);\r\n if (entry.isDirectory() && entry.name !== 'node_modules') {\r\n walk(fullPath);\r\n } else if (testExtensions.some(ext => entry.name.endsWith(ext))) {\r\n files.push(fullPath);\r\n }\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n walk(dir);\r\n return files;\r\n}\r\n\r\n/**\r\n * Find the test method name near a @speclore-scenario tag.\r\n */\r\nfunction findTestMethodNearby(content: string, tagIndex: number): string {\r\n // Look for the next test/function definition after the tag\r\n const afterTag = content.slice(tagIndex, tagIndex + 500);\r\n\r\n // TypeScript/JavaScript: test('name', ...) or it('name', ...)\r\n const jsMatch = afterTag.match(/(?:test|it)\\s*\\(\\s*['\"]([^'\"]+)['\"]/);\r\n if (jsMatch) return jsMatch[1]!;\r\n\r\n // Java: @Test void method_name()\r\n const javaMatch = afterTag.match(/@Test\\s+(?:void\\s+)?(\\w+)\\s*\\(/);\r\n if (javaMatch) return javaMatch[1]!;\r\n\r\n // Python: def test_method(...)\r\n const pyMatch = afterTag.match(/def\\s+(test_\\w+)\\s*\\(/);\r\n if (pyMatch) return pyMatch[1]!;\r\n\r\n return 'unknown';\r\n}\r\n","/**\r\n * Test runner — executes the configured test command and parses results.\r\n *\r\n * @module core/verifier/runner\r\n */\r\n\r\nimport { execFileSync } from 'node:child_process';\r\nimport type { VerifyReport, FeatureResult, ReportSummary, FailedDetail, FeatureFile, ContextFile, SpecLoreConfig, ScenarioResult } from '../../types/index.js';\r\nimport { resolveMappings } from './mapping-resolver.js';\r\nimport { getRegistry } from '../../plugins/registry.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Run verification: execute tests, map results to features, produce report.\r\n */\r\nexport async function runVerification(\r\n projectRoot: string,\r\n features: FeatureFile[],\r\n config: SpecLoreConfig,\r\n _context?: ContextFile,\r\n): Promise<VerifyReport> {\r\n logger.info('Running verification...');\r\n\r\n // Invoke beforeVerify lifecycle hook\r\n const registry = getRegistry();\r\n await registry.invokeLifecycle('beforeVerify', features);\r\n\r\n // Execute test command\r\n const testOutput = executeTestCommand(projectRoot, config);\r\n\r\n // Resolve scenario → test mappings\r\n // Try PluginRegistry parsers first, then fall back to mapping resolver\r\n let scenarioResults: ScenarioResult[];\r\n const parser = registry.findParser(testOutput);\r\n\r\n if (parser) {\r\n logger.info(`Using parser plugin: ${parser.framework}`);\r\n scenarioResults = parser.parse(testOutput, features);\r\n } else {\r\n scenarioResults = resolveMappings(projectRoot, features, testOutput);\r\n }\r\n\r\n // Build feature results\r\n const featureResults: FeatureResult[] = features.map(feature => ({\r\n feature: feature.featureName,\r\n file: feature.path,\r\n scenarios: feature.scenarios.map(s => {\r\n const result = scenarioResults.find(r => r.name === s.name);\r\n return result ?? {\r\n name: s.name,\r\n status: 'unmapped' as const,\r\n mappingSource: 'none' as const,\r\n };\r\n }),\r\n }));\r\n\r\n // Collect failed details\r\n const failedDetails: FailedDetail[] = [];\r\n for (const fr of featureResults) {\r\n for (const sr of fr.scenarios) {\r\n if (sr.status === 'failed' && sr.error) {\r\n failedDetails.push({\r\n feature: fr.feature,\r\n scenario: sr.name,\r\n error: sr.error,\r\n });\r\n }\r\n }\r\n }\r\n\r\n // Build summary\r\n const allScenarios = featureResults.flatMap(fr => fr.scenarios);\r\n const summary: ReportSummary = {\r\n totalFeatures: features.length,\r\n totalScenarios: allScenarios.length,\r\n passed: allScenarios.filter(s => s.status === 'passed').length,\r\n failed: allScenarios.filter(s => s.status === 'failed').length,\r\n skipped: allScenarios.filter(s => s.status === 'skipped').length,\r\n unmapped: allScenarios.filter(s => s.status === 'unmapped').length,\r\n passRate: allScenarios.length > 0\r\n ? `${((allScenarios.filter(s => s.status === 'passed').length / allScenarios.length) * 100).toFixed(1)}%`\r\n : '0%',\r\n };\r\n\r\n const report: VerifyReport = {\r\n timestamp: new Date().toISOString(),\r\n project: config.project.name,\r\n summary,\r\n features: featureResults,\r\n failedDetails,\r\n };\r\n\r\n // Invoke afterVerify lifecycle hook\r\n await registry.invokeLifecycle('afterVerify', report);\r\n\r\n return report;\r\n}\r\n\r\n/**\r\n * Execute the configured test command.\r\n */\r\nfunction executeTestCommand(projectRoot: string, config: SpecLoreConfig): string {\r\n const command = config.verify.command;\r\n if (!command) {\r\n logger.warn('No test command configured. Set verify.command in .speclore/config.yaml');\r\n return '';\r\n }\r\n\r\n const timeoutMs = config.verify.timeout * 1000;\r\n logger.info(`Executing: ${command}`);\r\n\r\n try {\r\n // Parse command into executable + args\r\n const parts = command.split(/\\s+/);\r\n const cmd = parts[0]!;\r\n const args = parts.slice(1);\r\n\r\n const output = execFileSync(cmd, args, {\r\n cwd: projectRoot,\r\n encoding: 'utf-8',\r\n timeout: timeoutMs,\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n });\r\n\r\n return output;\r\n } catch (error) {\r\n // Test failures often exit non-zero but still produce output\r\n if (error && typeof error === 'object' && 'stdout' in error) {\r\n const execError = error as { stdout?: string; stderr?: string };\r\n return (execError.stdout ?? '') + '\\n' + (execError.stderr ?? '');\r\n }\r\n logger.error(`Test command failed: ${error instanceof Error ? error.message : String(error)}`);\r\n return '';\r\n }\r\n}\r\n","/**\r\n * Report generator — produces JSON and HTML verification reports.\r\n *\r\n * @module core/verifier/report-generator\r\n */\r\n\r\nimport { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';\r\nimport { join, dirname } from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport type { VerifyReport, SpecLoreConfig } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { toPosixPath } from '../../infra/path-utils.js';\r\n\r\n/**\r\n * Generate verification reports (JSON + HTML) and print summary.\r\n */\r\nexport function generateReport(\r\n report: VerifyReport,\r\n projectRoot: string,\r\n config: SpecLoreConfig,\r\n): string[] {\r\n const reportsDir = join(projectRoot, '.speclore', 'reports');\r\n if (!existsSync(reportsDir)) {\r\n mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\r\n const writtenFiles: string[] = [];\r\n\r\n // JSON report\r\n if (config.verify.reportFormat.includes('json')) {\r\n const jsonPath = join(reportsDir, `verify-${timestamp}.json`);\r\n writeFileSync(jsonPath, JSON.stringify(report, null, 2), 'utf-8');\r\n writtenFiles.push(toPosixPath(jsonPath));\r\n logger.info(`JSON report: ${toPosixPath(jsonPath)}`);\r\n }\r\n\r\n // HTML report\r\n if (config.verify.reportFormat.includes('html')) {\r\n const htmlPath = join(reportsDir, `verify-${timestamp}.html`);\r\n const html = renderHtmlReport(report);\r\n writeFileSync(htmlPath, html, 'utf-8');\r\n writtenFiles.push(toPosixPath(htmlPath));\r\n logger.info(`HTML report: ${toPosixPath(htmlPath)}`);\r\n }\r\n\r\n // Console summary\r\n printConsoleSummary(report);\r\n\r\n return writtenFiles;\r\n}\r\n\r\n/**\r\n * Print a colored summary to the console.\r\n */\r\nfunction printConsoleSummary(report: VerifyReport): void {\r\n const { summary } = report;\r\n console.log('');\r\n console.log('═══════════════════════════════════════');\r\n console.log(' SpecLore Verification Report');\r\n console.log('═══════════════════════════════════════');\r\n console.log('');\r\n console.log(` Features: ${summary.totalFeatures}`);\r\n console.log(` Scenarios: ${summary.totalScenarios}`);\r\n console.log(` Passed: ${summary.passed}`);\r\n if (summary.failed > 0) {\r\n console.log(` Failed: ${summary.failed}`);\r\n }\r\n if (summary.skipped > 0) {\r\n console.log(` Skipped: ${summary.skipped}`);\r\n }\r\n if (summary.unmapped > 0) {\r\n console.log(` Unmapped: ${summary.unmapped}`);\r\n }\r\n console.log(` Pass Rate: ${summary.passRate}`);\r\n console.log('');\r\n\r\n // Failed details\r\n if (report.failedDetails.length > 0) {\r\n console.log(' Failed Scenarios:');\r\n for (const fd of report.failedDetails) {\r\n console.log(` ✗ ${fd.feature} / ${fd.scenario}`);\r\n console.log(` ${fd.error.split('\\n')[0]}`);\r\n }\r\n console.log('');\r\n }\r\n\r\n console.log('═══════════════════════════════════════');\r\n console.log('');\r\n}\r\n\r\n/**\r\n * Render a self-contained HTML report using the template.\r\n */\r\nfunction renderHtmlReport(report: VerifyReport): string {\r\n const { summary } = report;\r\n\r\n // Load template\r\n const templatePath = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'cli', 'templates', 'report.html');\r\n let template: string;\r\n try {\r\n template = readFileSync(templatePath, 'utf-8');\r\n } catch {\r\n // Fallback: inline template if file not found\r\n template = getInlineTemplate();\r\n }\r\n\r\n // Build feature rows\r\n const featureRows = report.features.map(fr => {\r\n const scenarioRows = fr.scenarios.map(sr => `\r\n <tr>\r\n <td>${escapeHtml(sr.name)}</td>\r\n <td>${statusIcon(sr.status)}</td>\r\n <td>${sr.testMethod ? escapeHtml(sr.testMethod) : '\\u2014'}</td>\r\n <td>${sr.duration ?? '\\u2014'}</td>\r\n </tr>`).join('');\r\n return `\r\n <section class=\"feature\">\r\n <h3>${escapeHtml(fr.feature)}</h3>\r\n <p class=\"file\">${escapeHtml(fr.file)}</p>\r\n <table>\r\n <thead><tr><th>Scenario</th><th>Status</th><th>Test</th><th>Duration</th></tr></thead>\r\n <tbody>${scenarioRows}\r\n </tbody>\r\n </table>\r\n </section>`;\r\n }).join('\\n');\r\n\r\n // Build failed details section\r\n const failedSection = report.failedDetails.length > 0 ? `\r\n <section class=\"failures\">\r\n <h2>Failed Details</h2>\r\n ${report.failedDetails.map(fd => `\r\n <details>\r\n <summary>${escapeHtml(fd.feature)} / ${escapeHtml(fd.scenario)}</summary>\r\n <pre>${escapeHtml(fd.error)}</pre>\r\n </details>`).join('\\n')}\r\n </section>` : '';\r\n\r\n return template\r\n .replace('{{TIMESTAMP}}', report.timestamp)\r\n .replace('{{PROJECT}}', escapeHtml(report.project))\r\n .replace('{{TOTAL_SCENARIOS}}', String(summary.totalScenarios))\r\n .replace('{{PASSED}}', String(summary.passed))\r\n .replace('{{FAILED}}', String(summary.failed))\r\n .replace('{{UNMAPPED}}', String(summary.unmapped))\r\n .replace('{{PASS_RATE}}', String(summary.passRate))\r\n .replace('{{FEATURES}}', featureRows)\r\n .replace('{{FAILED_DETAILS}}', failedSection);\r\n}\r\n\r\nfunction statusIcon(status: string): string {\r\n switch (status) {\r\n case 'passed': return '<span class=\"status passed\" role=\"img\" aria-label=\"passed\">\\u2705 Passed</span>';\r\n case 'failed': return '<span class=\"status failed\" role=\"img\" aria-label=\"failed\">\\u274C Failed</span>';\r\n case 'skipped': return '<span class=\"status skipped\" role=\"img\" aria-label=\"skipped\">\\u23ED\\uFE0F Skipped</span>';\r\n case 'unmapped': return '<span class=\"status unmapped\" role=\"img\" aria-label=\"unmapped\">\\u26A0\\uFE0F Unmapped</span>';\r\n default: return escapeHtml(status);\r\n }\r\n}\r\n\r\nfunction getInlineTemplate(): string {\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head><meta charset=\"UTF-8\"><title>SpecLore Verification Report</title></head>\r\n<body><h1>SpecLore Verification Report</h1>\r\n<p>{{TIMESTAMP}} \\u2014 {{PROJECT}}</p>\r\n<p>Scenarios: {{TOTAL_SCENARIOS}} | Passed: {{PASSED}} | Failed: {{FAILED}} | Unmapped: {{UNMAPPED}} | Pass Rate: {{PASS_RATE}}</p>\r\n{{FEATURES}}{{FAILED_DETAILS}}</body></html>`;\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;');\r\n}\r\n","/**\r\n * M4: Verification Engine — runs tests and maps results back to .feature scenarios.\r\n *\r\n * @module core/verifier\r\n */\r\n\r\nexport { runVerification } from './runner.js';\r\nexport { resolveMappings } from './mapping-resolver.js';\r\nexport { generateReport } from './report-generator.js';\r\n","/**\r\n * Requirement Dependency Graph builder.\r\n *\r\n * @module core/analyzer/rdg-builder\r\n */\r\n\r\nimport { readFileSync, existsSync, readdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { GraphEdge } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Build a Requirement Dependency Graph from .feature files.\r\n */\r\nexport function buildRDG(projectRoot: string, specsDir: string): GraphEdge[] {\r\n const edges: GraphEdge[] = [];\r\n const fullSpecsDir = join(projectRoot, specsDir);\r\n\r\n if (!existsSync(fullSpecsDir)) {\r\n logger.debug(`Specs directory not found: ${fullSpecsDir}`);\r\n return edges;\r\n }\r\n\r\n const features = scanFeatureFiles(fullSpecsDir);\r\n\r\n for (const feature of features) {\r\n const content = readFileSync(feature, 'utf-8');\r\n const fromModule = deriveModuleName(feature, fullSpecsDir);\r\n\r\n // Look for dependency declarations\r\n const depRegex = /(?:Depends on|依赖)[:\\s]+(.+)/gi;\r\n const match = depRegex.exec(content);\r\n if (match) {\r\n const deps = match[1]!.split(/[,;\\uff0c\\uff1b]/).map(d => d.trim()).filter(Boolean);\r\n for (const dep of deps) {\r\n edges.push({\r\n from: fromModule,\r\n to: dep,\r\n type: 'api-call',\r\n });\r\n }\r\n }\r\n }\r\n\r\n logger.debug(`RDG: ${edges.length} edges from ${features.length} features`);\r\n return edges;\r\n}\r\n\r\nfunction scanFeatureFiles(dir: string): string[] {\r\n const files: string[] = [];\r\n\r\n function walk(d: string): void {\r\n try {\r\n const entries = readdirSync(d, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const fullPath = join(d, entry.name);\r\n if (entry.isDirectory()) {\r\n walk(fullPath);\r\n } else if (entry.name.endsWith('.feature')) {\r\n files.push(fullPath);\r\n }\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n walk(dir);\r\n return files;\r\n}\r\n\r\nfunction deriveModuleName(filePath: string, specsDir: string): string {\r\n const relative = filePath.slice(specsDir.length + 1);\r\n const parts = relative.split(/[/\\\\]/);\r\n return parts.length > 1 ? parts[0]! : parts[0]!.replace('.feature', '');\r\n}\r\n","/**\r\n * Code Dependency Graph builder.\r\n *\r\n * @module core/analyzer/cdg-builder\r\n */\r\n\r\nimport type { GraphEdge, ContextFile } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\n/**\r\n * Build a Code Dependency Graph from context.json.\r\n */\r\nexport function buildCDG(context: ContextFile): GraphEdge[] {\r\n // The dependency graph in context.json already represents code dependencies\r\n const edges = context.dependencyGraph;\r\n logger.debug(`CDG: ${edges.length} edges`);\r\n return edges;\r\n}\r\n","/**\r\n * RDG/CDG aligner — compares requirement and code dependencies.\r\n *\r\n * @module core/analyzer/aligner\r\n */\r\n\r\nimport type { GraphEdge } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\n\r\nexport interface AlignmentResult {\r\n /** Edges in RDG but not in CDG — code is missing expected dependencies */\r\n missingInCode: GraphEdge[];\r\n /** Edges in CDG but not in RDG — code has undeclared dependencies */\r\n missingInRequirements: GraphEdge[];\r\n /** Edges present in both */\r\n aligned: GraphEdge[];\r\n}\r\n\r\n/**\r\n * Align RDG and CDG, detecting inconsistencies.\r\n */\r\nexport function alignGraphs(rdg: GraphEdge[], cdg: GraphEdge[]): AlignmentResult {\r\n const aligned: GraphEdge[] = [];\r\n const missingInCode: GraphEdge[] = [];\r\n const missingInRequirements: GraphEdge[] = [];\r\n\r\n // Check each RDG edge against CDG\r\n for (const rdgEdge of rdg) {\r\n const found = cdg.some(\r\n cdgEdge => cdgEdge.from === rdgEdge.from && cdgEdge.to === rdgEdge.to,\r\n );\r\n\r\n if (found) {\r\n aligned.push(rdgEdge);\r\n } else {\r\n missingInCode.push(rdgEdge);\r\n }\r\n }\r\n\r\n // Check each CDG edge against RDG\r\n for (const cdgEdge of cdg) {\r\n const found = rdg.some(\r\n rdgEdge => rdgEdge.from === cdgEdge.from && rdgEdge.to === cdgEdge.to,\r\n );\r\n\r\n if (!found) {\r\n missingInRequirements.push(cdgEdge);\r\n }\r\n }\r\n\r\n logger.debug(\r\n `Alignment: ${aligned.length} aligned, ${missingInCode.length} missing in code, ${missingInRequirements.length} missing in requirements`,\r\n );\r\n\r\n return { aligned, missingInCode, missingInRequirements };\r\n}\r\n","/**\r\n * Impact analyzer — determines what features are affected by code changes.\r\n *\r\n * @module core/analyzer/impact-analyzer\r\n */\r\n\r\nimport { execFileSync } from 'node:child_process';\r\nimport { globSync } from 'glob';\r\nimport type { ContextFile, SpecLoreConfig } from '../../types/index.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { toPosixPath } from '../../infra/path-utils.js';\r\n\r\nexport interface ImpactResult {\r\n changedFiles: string[];\r\n affectedModules: string[];\r\n affectedFeatures: string[];\r\n}\r\n\r\n/**\r\n * Analyze the impact of recent code changes.\r\n */\r\nexport function analyzeImpact(\r\n projectRoot: string,\r\n context: ContextFile,\r\n config: SpecLoreConfig,\r\n): ImpactResult {\r\n // Get changed files from git\r\n const changedFiles = getChangedFiles(projectRoot);\r\n\r\n // Determine affected modules via CDG\r\n const affectedModules = determineAffectedModules(changedFiles, context);\r\n\r\n // Determine affected features via module mapping\r\n const affectedFeatures = determineAffectedFeatures(affectedModules, projectRoot, config.spec.outputDir);\r\n\r\n logger.info(\r\n `Impact: ${changedFiles.length} files changed, ${affectedModules.length} modules affected, ${affectedFeatures.length} features affected`,\r\n );\r\n\r\n return { changedFiles, affectedModules, affectedFeatures };\r\n}\r\n\r\n/**\r\n * Get list of changed files from git diff.\r\n */\r\nfunction getChangedFiles(projectRoot: string): string[] {\r\n try {\r\n const output = execFileSync('git', ['diff', '--name-only', 'HEAD'], {\r\n cwd: projectRoot,\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n });\r\n\r\n return output\r\n .split('\\n')\r\n .map(f => f.trim())\r\n .filter(Boolean)\r\n .map(toPosixPath);\r\n } catch {\r\n // Try unstaged changes\r\n try {\r\n const output = execFileSync('git', ['diff', '--name-only'], {\r\n cwd: projectRoot,\r\n encoding: 'utf-8',\r\n stdio: ['pipe', 'pipe', 'pipe'],\r\n });\r\n\r\n return output\r\n .split('\\n')\r\n .map(f => f.trim())\r\n .filter(Boolean)\r\n .map(toPosixPath);\r\n } catch {\r\n logger.warn('Could not get git diff. Is this a git repository?');\r\n return [];\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Determine which modules are affected by changed files.\r\n */\r\nfunction determineAffectedModules(\r\n changedFiles: string[],\r\n context: ContextFile,\r\n): string[] {\r\n const affected = new Set<string>();\r\n\r\n for (const file of changedFiles) {\r\n for (const mod of context.moduleBoundaries) {\r\n // Check if the changed file is within this module's path\r\n // This is a simplified check — full implementation would use module paths from config\r\n if (file.includes(`/${mod.name}/`) || file.includes(`\\\\${mod.name}\\\\`)) {\r\n affected.add(mod.name);\r\n }\r\n }\r\n }\r\n\r\n // Also add modules that depend on affected modules (transitive)\r\n const expanded = new Set(affected);\r\n for (const mod of context.moduleBoundaries) {\r\n if (mod.dependsOn.some(dep => affected.has(dep))) {\r\n expanded.add(mod.name);\r\n }\r\n }\r\n\r\n return [...expanded];\r\n}\r\n\r\n/**\r\n * Determine which features are affected by module changes.\r\n */\r\nfunction determineAffectedFeatures(\r\n affectedModules: string[],\r\n projectRoot: string,\r\n outputDir: string,\r\n): string[] {\r\n // Map module names to actual feature files\r\n const features: string[] = [];\r\n\r\n for (const mod of affectedModules) {\r\n const pattern = `${outputDir}/${mod}/**/*.feature`;\r\n const files = globSync(pattern, { cwd: projectRoot, absolute: true });\r\n features.push(...files);\r\n }\r\n\r\n return [...new Set(features)];\r\n}\r\n","/**\r\n * M7: Advanced Analysis — RDG/CDG alignment, impact analysis.\r\n *\r\n * @module core/analyzer\r\n */\r\n\r\nexport { buildRDG } from './rdg-builder.js';\r\nexport { buildCDG } from './cdg-builder.js';\r\nexport { alignGraphs } from './aligner.js';\r\nexport { analyzeImpact } from './impact-analyzer.js';\r\n","/**\r\n * PID + mtime dual-check file lock.\r\n *\r\n * Lock file: `.speclore/.lock`\r\n * - Acquire: write PID + timestamp\r\n * - Release: delete lock file\r\n * - Expired: PID process does not exist OR mtime > 30 minutes\r\n * - Crash recovery: stale lock auto-expires, never blocks next startup\r\n *\r\n * @module infra/file-lock\r\n */\r\n\r\nimport { readFileSync, writeFileSync, unlinkSync, existsSync, statSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { logger } from './logger.js';\r\n\r\nconst LOCK_FILENAME = '.lock';\r\nconst LOCK_EXPIRY_MS = 30 * 60 * 1000; // 30 minutes\r\n\r\nexport interface LockInfo {\r\n pid: number;\r\n timestamp: number;\r\n}\r\n\r\n/**\r\n * Acquire the file lock.\r\n * @returns true if lock was acquired, false if already locked (and not expired)\r\n */\r\nexport function acquireLock(specLoreDir: string): boolean {\r\n const lockPath = join(specLoreDir, LOCK_FILENAME);\r\n\r\n // Check if an existing lock is still valid\r\n if (existsSync(lockPath)) {\r\n const existing = readLockInfo(lockPath);\r\n if (existing && !isLockExpired(existing)) {\r\n logger.debug(`Lock already held by PID ${existing.pid}, not expired`);\r\n return false;\r\n }\r\n // Stale lock — remove it\r\n logger.debug('Removing stale lock file');\r\n safeUnlink(lockPath);\r\n }\r\n\r\n // Write new lock atomically with exclusive-create flag.\r\n // If another process wins the race, writeFileSync throws and we catch it.\r\n const lockInfo: LockInfo = {\r\n pid: process.pid,\r\n timestamp: Date.now(),\r\n };\r\n try {\r\n writeFileSync(lockPath, JSON.stringify(lockInfo), { flag: 'wx', encoding: 'utf-8' });\r\n } catch {\r\n // Another process acquired the lock between our check and write\r\n logger.debug('Lock write failed — another process may have acquired it');\r\n return false;\r\n }\r\n logger.debug(`Lock acquired by PID ${process.pid}`);\r\n return true;\r\n}\r\n\r\n/**\r\n * Release the file lock.\r\n * Only releases if the current process owns the lock.\r\n */\r\nexport function releaseLock(specLoreDir: string): void {\r\n const lockPath = join(specLoreDir, LOCK_FILENAME);\r\n\r\n if (!existsSync(lockPath)) {\r\n return;\r\n }\r\n\r\n const existing = readLockInfo(lockPath);\r\n if (existing && existing.pid === process.pid) {\r\n safeUnlink(lockPath);\r\n logger.debug('Lock released');\r\n }\r\n}\r\n\r\n/**\r\n * Check if a lock is currently held (and not expired).\r\n */\r\nexport function isLocked(specLoreDir: string): boolean {\r\n const lockPath = join(specLoreDir, LOCK_FILENAME);\r\n\r\n if (!existsSync(lockPath)) {\r\n return false;\r\n }\r\n\r\n const existing = readLockInfo(lockPath);\r\n if (!existing) {\r\n return false;\r\n }\r\n\r\n return !isLockExpired(existing);\r\n}\r\n\r\n/**\r\n * Read lock info from file. Returns null if file is corrupt.\r\n */\r\nfunction readLockInfo(lockPath: string): LockInfo | null {\r\n try {\r\n const content = readFileSync(lockPath, 'utf-8');\r\n const parsed = JSON.parse(content) as LockInfo;\r\n if (typeof parsed.pid === 'number' && typeof parsed.timestamp === 'number') {\r\n return parsed;\r\n }\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Check if a lock has expired.\r\n * Expired when: PID process does not exist OR mtime > 30 minutes.\r\n */\r\nfunction isLockExpired(lockInfo: LockInfo): boolean {\r\n // Check mtime expiry\r\n if (Date.now() - lockInfo.timestamp > LOCK_EXPIRY_MS) {\r\n logger.debug(`Lock expired: age ${Date.now() - lockInfo.timestamp}ms > ${LOCK_EXPIRY_MS}ms`);\r\n return true;\r\n }\r\n\r\n // Check PID existence\r\n if (!isProcessRunning(lockInfo.pid)) {\r\n logger.debug(`Lock expired: PID ${lockInfo.pid} not running`);\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Check if a process with the given PID is running.\r\n */\r\nfunction isProcessRunning(pid: number): boolean {\r\n try {\r\n // Signal 0 does not kill the process, just checks if it exists\r\n process.kill(pid, 0);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Safely delete a file, ignoring errors.\r\n */\r\nfunction safeUnlink(filePath: string): void {\r\n try {\r\n unlinkSync(filePath);\r\n } catch {\r\n // Ignore — file may have been removed by another process\r\n }\r\n}\r\n\r\n/**\r\n * Get lock file mtime for external expiry checks (e.g. context.json cache).\r\n */\r\nexport function getLockMtime(specLoreDir: string): number | null {\r\n const lockPath = join(specLoreDir, LOCK_FILENAME);\r\n try {\r\n if (!existsSync(lockPath)) return null;\r\n const stat = statSync(lockPath);\r\n return stat.mtimeMs;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Shared Zod parameter schemas for MCP tool registration and JSON Schema generation.\r\n *\r\n * Single source of truth for tool input parameter definitions.\r\n * - server.ts uses these directly for MCP registerTool (Zod shape)\r\n * - tools.ts uses toJSONSchema() to derive JSON Schema automatically\r\n *\r\n * @module mcp/schemas\r\n */\r\n\r\nimport { z } from 'zod';\r\n\r\n/** Input schema for speclore.spec tool */\r\nexport const specInputSchema = z.object({\r\n source: z.string().max(50000).describe('Requirement source: file path, URL, or direct text content. Max 50000 characters.'),\r\n module: z.string().optional().describe('Target module name (optional, auto-detected from context).'),\r\n});\r\n\r\n/** Input schema for speclore.code tool */\r\nexport const codeInputSchema = z.object({\r\n features: z.array(z.string()).max(50).optional().describe('Feature file paths or glob patterns. Max 50 items.'),\r\n tools: z.array(z.enum(['cursor', 'claude', 'qoder'])).optional().describe('AI tools to generate constraints for (optional, auto-detected).'),\r\n});\r\n\r\n/** Input schema for speclore.verify tool */\r\nexport const verifyInputSchema = z.object({\r\n features: z.array(z.string()).optional().describe('Feature file paths or glob patterns to verify (optional, all if omitted).'),\r\n impact: z.boolean().optional().default(false).describe('Enable change impact analysis (compares git diff to find affected features).'),\r\n});\r\n\r\n/** Input schema for speclore.status tool */\r\nexport const statusInputSchema = z.object({\r\n feature: z.string().optional().describe('Specific feature file to check (optional, all if omitted).'),\r\n});\r\n","/**\r\n * MCP tool definitions for SpecLore.\r\n *\r\n * Three tools exposed via MCP:\r\n * - speclore.spec — requirement → .feature (M1 → M2)\r\n * - speclore.code — .feature → constraints (M3 + Handoff)\r\n * - speclore.verify — tests → acceptance report (M4 + M7)\r\n *\r\n * @module mcp/tools\r\n */\r\n\r\nimport type {\r\n SpecResult,\r\n ConstraintResult,\r\n VerifyMcpResult,\r\n WorkflowInfo,\r\n FeatureState,\r\n ScenarioSummary,\r\n ActiveConstraint,\r\n FeatureFile,\r\n Scenario,\r\n ModuleRule,\r\n ContextFile,\r\n} from '../types/index.js';\r\nimport type { SpecLoreConfig } from '../types/config.js';\r\nimport { readRequirement } from '../core/requirement-reader/index.js';\r\nimport { generateFeature } from '../core/feature-generator/index.js';\r\nimport { generateConstraints } from '../core/constraint-coder/index.js';\r\nimport { runVerification } from '../core/verifier/index.js';\r\nimport { buildContext, loadContext } from '../core/context-engine/index.js';\r\nimport { analyzeImpact } from '../core/analyzer/index.js';\r\nimport { StateManager } from '../core/state-manager/index.js';\r\nimport { generateTestScaffolding } from '../core/test-scaffolder/index.js';\r\nimport { loadConfig, generateDefaultConfigYaml } from '../infra/config.js';\r\nimport { logger } from '../infra/logger.js';\r\nimport { join } from 'node:path';\r\nimport { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { globSync } from 'glob';\r\nimport { toJSONSchema } from 'zod';\r\nimport { specInputSchema, codeInputSchema, verifyInputSchema } from './schemas.js';\r\n\r\n// ============================================================================\r\n// Tool name & description constants\r\n// ============================================================================\r\n\r\nexport const SPEC_TOOL_NAME = 'speclore.spec';\r\nexport const CODE_TOOL_NAME = 'speclore.code';\r\nexport const VERIFY_TOOL_NAME = 'speclore.verify';\r\nexport const STATUS_TOOL_NAME = 'speclore.status';\r\n\r\n/** Single source of truth for tool descriptions — shared by JSON Schema and Zod registration */\r\nexport const SPEC_TOOL_DESC =\r\n 'Convert a requirement (text, file path, or URL) into structured BDD .feature files with scenario-level acceptance criteria.';\r\nexport const CODE_TOOL_DESC =\r\n 'Generate AI coding constraint files for Cursor / Claude Code / Qoder based on .feature specs and project context. Requires .feature files to exist.';\r\nexport const VERIFY_TOOL_DESC =\r\n 'Run tests and map results back to .feature scenarios, producing an acceptance report. Requires test scaffolding generated by speclore.code.';\r\nexport const STATUS_TOOL_DESC =\r\n 'Get current project workflow status, feature states, and recommended next steps. Call this first to understand where the project stands.';\r\n\r\n// ============================================================================\r\n// JSON Schema definitions for MCP tool inputs (auto-generated from Zod)\r\n// ============================================================================\r\n\r\nconst specJsonSchema = toJSONSchema(specInputSchema, { target: 'draft-07' });\r\nconst codeJsonSchema = toJSONSchema(codeInputSchema, { target: 'draft-07' });\r\nconst verifyJsonSchema = toJSONSchema(verifyInputSchema, { target: 'draft-07' });\r\n\r\nexport const specToolSchema = {\r\n name: SPEC_TOOL_NAME,\r\n description: SPEC_TOOL_DESC,\r\n inputSchema: specJsonSchema as Record<string, unknown>,\r\n};\r\n\r\nexport const codeToolSchema = {\r\n name: CODE_TOOL_NAME,\r\n description: CODE_TOOL_DESC,\r\n inputSchema: codeJsonSchema as Record<string, unknown>,\r\n};\r\n\r\nexport const verifyToolSchema = {\r\n name: VERIFY_TOOL_NAME,\r\n description: VERIFY_TOOL_DESC,\r\n inputSchema: verifyJsonSchema as Record<string, unknown>,\r\n};\r\n\r\n// ============================================================================\r\n// Tool implementations\r\n// ============================================================================\r\n\r\n/**\r\n * Execute speclore.spec tool — M1 → M2.\r\n */\r\nexport async function executeSpecTool(\r\n args: { source: string; module?: string },\r\n projectRoot: string,\r\n): Promise<SpecResult> {\r\n // Input validation\r\n if (!args.source || args.source.length > 50000) {\r\n throw new Error('source must be between 1 and 50000 characters');\r\n }\r\n\r\n // Auto-initialize project\r\n ensureProjectReady(projectRoot);\r\n const config = loadConfig(projectRoot);\r\n\r\n // M1: Read requirement\r\n logger.info(`Reading requirement from: ${args.source.slice(0, 80)}...`);\r\n const req = await readRequirement(args.source);\r\n\r\n // M5: Build/load context\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n // M2: Generate feature\r\n const feature = await generateFeature(req, context, config, projectRoot);\r\n const createdFiles = [feature.path];\r\n const scenarios: ScenarioSummary[] = [];\r\n\r\n for (const sc of feature.scenarios) {\r\n scenarios.push({\r\n feature: feature.featureName,\r\n name: sc.name,\r\n given: sc.givens.map(s => s.text),\r\n when: sc.whens.map(s => s.text),\r\n then: sc.thens.map(s => s.text),\r\n });\r\n }\r\n\r\n // Update state: transition to 'specified'\r\n const stateManager = new StateManager(projectRoot);\r\n stateManager.transitionFeature(feature.path, 'specified');\r\n\r\n const constraints = `Generated ${createdFiles.length} feature file(s) with ${scenarios.length} scenario(s).`;\r\n const nextSteps =\r\n 'Run `speclore code` to generate AI coding constraints, or ask your AI client to implement the scenarios.';\r\n\r\n return {\r\n createdFiles,\r\n scenarios,\r\n constraints,\r\n nextSteps,\r\n workflow: buildWorkflowInfo(feature.path, 'specified', stateManager),\r\n };\r\n}\r\n\r\n/**\r\n * Execute speclore.code tool — M3 + Handoff.\r\n */\r\nexport async function executeCodeTool(\r\n args: { features?: string[]; tools?: string[] },\r\n projectRoot: string,\r\n): Promise<ConstraintResult> {\r\n if (args.features && args.features.length > 50) {\r\n throw new Error('features array must not exceed 50 items');\r\n }\r\n\r\n // Auto-initialize project\r\n ensureProjectReady(projectRoot);\r\n const config = loadConfig(projectRoot);\r\n\r\n // Load context\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n // Resolve feature files\r\n const featureFiles = resolveFeatureFiles(args.features, projectRoot, config);\r\n\r\n // State guard: must have at least one feature file\r\n if (featureFiles.length === 0) {\r\n const stateManager = new StateManager(projectRoot);\r\n return {\r\n writtenFiles: [],\r\n constraintContent: 'Error: No .feature files found.',\r\n moduleRules: [],\r\n activeConstraints: [],\r\n codingGuidance: '',\r\n scaffoldFiles: [],\r\n workflow: {\r\n currentState: 'uninitialized',\r\n nextStep: 'Call speclore.spec with your requirement text to create feature files.',\r\n projectSummary: {\r\n total: stateManager.getProjectSummary().featureCount,\r\n ...stateManager.getProjectSummary().states,\r\n },\r\n },\r\n };\r\n }\r\n\r\n // M3: Generate constraints\r\n const writtenFiles = await generateConstraints(projectRoot, featureFiles, context, config);\r\n\r\n // Generate test scaffolding from feature scenarios\r\n const scaffoldFiles = generateTestScaffolding(projectRoot, featureFiles, config);\r\n\r\n // Update state: transition each feature to 'constrained'\r\n const stateManager = new StateManager(projectRoot);\r\n for (const feature of featureFiles) {\r\n try {\r\n stateManager.transitionFeature(feature.path, 'constrained', ['specified']);\r\n stateManager.updateFeatureEntry(feature.path, {\r\n constraintFiles: writtenFiles,\r\n testFiles: scaffoldFiles.map(s => s.testFile),\r\n });\r\n } catch {\r\n // Feature may already be in constrained state, that's OK\r\n }\r\n }\r\n\r\n // Build constraint content summary\r\n const constraintContent = buildConstraintSummary(featureFiles, config);\r\n const moduleRules = buildModuleRules(config);\r\n const activeConstraints = buildActiveConstraints(writtenFiles, projectRoot);\r\n const codingGuidance = buildCodingGuidance(featureFiles, context, config);\r\n\r\n const firstFeature = featureFiles[0]?.path;\r\n\r\n return {\r\n writtenFiles,\r\n constraintContent,\r\n moduleRules,\r\n activeConstraints,\r\n codingGuidance,\r\n scaffoldFiles,\r\n workflow: buildWorkflowInfo(firstFeature, 'constrained', stateManager),\r\n };\r\n}\r\n\r\n/**\r\n * Execute speclore.verify tool — M4 + M7.\r\n */\r\nexport async function executeVerifyTool(\r\n args: { features?: string[]; impact?: boolean },\r\n projectRoot: string,\r\n): Promise<VerifyMcpResult> {\r\n // Auto-initialize project\r\n ensureProjectReady(projectRoot);\r\n const config = loadConfig(projectRoot);\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n\r\n // Load context\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n // Resolve feature files\r\n const featureFiles = resolveFeatureFiles(args.features, projectRoot, config);\r\n\r\n // State guard: features must have test scaffolding (constrained or later)\r\n const stateManager = new StateManager(projectRoot);\r\n for (const feature of featureFiles) {\r\n const entry = stateManager.getFeatureState(feature.path);\r\n if (!entry || entry.state === 'specified') {\r\n return {\r\n summary: 'Error: No test scaffolding found.',\r\n passed: 0,\r\n failed: 0,\r\n unmapped: featureFiles.reduce((sum, f) => sum + f.scenarios.length, 0),\r\n details: [],\r\n failedDetails: [],\r\n workflow: {\r\n currentState: entry?.state ?? 'uninitialized',\r\n nextStep: 'Call speclore.code to generate constraints and test scaffolding.',\r\n projectSummary: {\r\n total: stateManager.getProjectSummary().featureCount,\r\n ...stateManager.getProjectSummary().states,\r\n },\r\n },\r\n };\r\n }\r\n }\r\n\r\n // M7: Impact analysis (if requested)\r\n if (args.impact) {\r\n logger.info('Running impact analysis...');\r\n const impact = analyzeImpact(projectRoot, context, config);\r\n context.impactAnalysis = {\r\n changedFiles: impact.changedFiles,\r\n affectedModules: impact.affectedModules,\r\n affectedFeatures: impact.affectedFeatures,\r\n };\r\n }\r\n\r\n // M4: Run verification\r\n const report = await runVerification(projectRoot, featureFiles, config);\r\n\r\n // Update state: transition to 'verified' if all passed\r\n const { summary } = report;\r\n if (summary.failed === 0 && summary.unmapped === 0 && summary.passed > 0) {\r\n for (const feature of featureFiles) {\r\n try {\r\n stateManager.transitionFeature(feature.path, 'verified', ['coding', 'constrained']);\r\n } catch {\r\n // May already be verified\r\n }\r\n stateManager.recordVerify(feature.path, {\r\n passed: summary.passed,\r\n failed: summary.failed,\r\n unmapped: summary.unmapped,\r\n });\r\n }\r\n }\r\n\r\n const firstFeature = featureFiles[0]?.path;\r\n const currentState: FeatureState =\r\n summary.failed === 0 && summary.unmapped === 0 && summary.passed > 0 ? 'verified' : 'coding';\r\n\r\n // Build MCP result (slim view)\r\n return {\r\n summary: `${summary.passed}/${summary.totalScenarios} scenarios passed (${summary.passRate})`,\r\n passed: summary.passed,\r\n failed: summary.failed,\r\n unmapped: summary.unmapped,\r\n details: report.features,\r\n failedDetails: report.failedDetails,\r\n workflow: buildWorkflowInfo(firstFeature, currentState, stateManager),\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Auto-initialization guard\r\n// ============================================================================\r\n\r\n/**\r\n * Ensure the project has .speclore/config.yaml and state.yaml.\r\n * Auto-creates defaults if missing (so MCP tools never fail due to missing setup).\r\n */\r\nfunction ensureProjectReady(projectRoot: string): { initialized: boolean; configCreated: boolean; migrated: number } {\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const configPath = join(specLoreDir, 'config.yaml');\r\n let configCreated = false;\r\n\r\n // Ensure .speclore/ directory exists\r\n if (!existsSync(specLoreDir)) {\r\n mkdirSync(specLoreDir, { recursive: true });\r\n }\r\n\r\n // Ensure config.yaml exists (generate default if missing)\r\n if (!existsSync(configPath)) {\r\n const projectName = projectRoot.split(/[/\\\\]/).pop() ?? 'my-project';\r\n writeFileSync(configPath, generateDefaultConfigYaml(projectName), 'utf-8');\r\n configCreated = true;\r\n logger.info(`Auto-created default config: ${configPath}`);\r\n }\r\n\r\n // Ensure state.yaml exists\r\n const stateManager = new StateManager(projectRoot);\r\n stateManager.ensureInitialized();\r\n\r\n // Migrate existing .feature files into state tracking\r\n const config = loadConfig(projectRoot);\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const migrated = stateManager.migrateFeatures(specsDir);\r\n if (migrated > 0) {\r\n logger.info(`Migrated ${migrated} existing .feature file(s) into state tracking.`);\r\n }\r\n\r\n return { initialized: true, configCreated, migrated };\r\n}\r\n\r\n// ============================================================================\r\n// Workflow info builder\r\n// ============================================================================\r\n\r\n/**\r\n * Build WorkflowInfo for MCP tool responses.\r\n */\r\nfunction buildWorkflowInfo(\r\n featurePath: string | undefined,\r\n currentState: FeatureState | 'uninitialized',\r\n stateManager: StateManager,\r\n): WorkflowInfo {\r\n const summary = stateManager.getProjectSummary();\r\n const nextStep = resolveNextStep(currentState, summary);\r\n\r\n return {\r\n feature: featurePath,\r\n currentState,\r\n nextStep,\r\n projectSummary: {\r\n total: summary.featureCount,\r\n ...summary.states,\r\n },\r\n };\r\n}\r\n\r\nfunction resolveNextStep(\r\n currentState: FeatureState | 'uninitialized',\r\n _summary: { initialized: boolean; featureCount: number; states: Record<FeatureState, number> },\r\n): string {\r\n switch (currentState) {\r\n case 'uninitialized':\r\n return 'Call speclore.spec with your requirement text to create feature files.';\r\n case 'specified':\r\n return 'Call speclore.code to generate constraints and test scaffolding.';\r\n case 'constrained':\r\n return 'Start coding. Constraints and test scaffolding are ready. Fill in test implementations.';\r\n case 'coding':\r\n return 'Run speclore.verify to check acceptance status.';\r\n case 'verified':\r\n return 'All features verified. Add new requirements with speclore.spec.';\r\n default:\r\n return '';\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Helpers\r\n// ============================================================================\r\n\r\nfunction resolveFeatureFiles(\r\n patterns: string[] | undefined,\r\n projectRoot: string,\r\n config: SpecLoreConfig,\r\n): FeatureFile[] {\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const searchPatterns = patterns && patterns.length > 0 ? patterns : [`${specsDir}/**/*.feature`];\r\n\r\n const files: FeatureFile[] = [];\r\n for (const pattern of searchPatterns) {\r\n const matches = globSync(pattern, { cwd: projectRoot, absolute: true });\r\n for (const filePath of matches) {\r\n if (existsSync(filePath)) {\r\n const content = readFileSync(filePath, 'utf-8');\r\n files.push(parseFeatureFile(filePath, content));\r\n }\r\n }\r\n }\r\n return files;\r\n}\r\n\r\nfunction parseFeatureFile(filePath: string, content: string): FeatureFile {\r\n const featureMatch = content.match(/Feature:\\s*(.+)/);\r\n const featureName = featureMatch?.[1]?.trim() ?? filePath;\r\n const scenarios: Scenario[] = [];\r\n const tags: string[] = [];\r\n\r\n // Extract feature-level tags\r\n const lines = content.split('\\n');\r\n for (const line of lines) {\r\n const tagMatch = line.trim().match(/^(@\\S+(?:\\s+@\\S+)*)/);\r\n if (tagMatch) {\r\n tags.push(...tagMatch[1]!.split(/\\s+/).filter(t => t.startsWith('@')));\r\n }\r\n }\r\n\r\n // Parse scenarios\r\n const scenarioRegex = /Scenario(?: Outline)?:\\s*(.+)/g;\r\n let match;\r\n while ((match = scenarioRegex.exec(content)) !== null) {\r\n scenarios.push({\r\n name: match[1]!.trim(),\r\n givens: [],\r\n whens: [],\r\n thens: [],\r\n tags: [],\r\n });\r\n }\r\n\r\n return {\r\n path: filePath,\r\n featureName,\r\n scenarios,\r\n tags,\r\n confidence: 1.0,\r\n needsReview: [],\r\n };\r\n}\r\n\r\nfunction buildConstraintSummary(features: FeatureFile[], config: SpecLoreConfig): string {\r\n const moduleCount = Object.keys(config.project.modules).length;\r\n const scenarioCount = features.reduce((sum, f) => sum + f.scenarios.length, 0);\r\n return `Constraints for ${moduleCount} module(s), ${features.length} feature(s), ${scenarioCount} scenario(s). Profile: ${config.project.profile}.`;\r\n}\r\n\r\nfunction buildModuleRules(config: SpecLoreConfig): ModuleRule[] {\r\n const rules: ModuleRule[] = [];\r\n for (const [name, mod] of Object.entries(config.project.modules)) {\r\n rules.push({\r\n module: name,\r\n boundaries: {\r\n name,\r\n responsibility: mod.responsibility,\r\n publicApis: mod.apis ?? [],\r\n internalObjects: mod.entities ?? [],\r\n dependsOn: mod.dependsOn ?? [],\r\n },\r\n namingConventions: [],\r\n forbiddenPatterns: [],\r\n });\r\n }\r\n return rules;\r\n}\r\n\r\nfunction buildActiveConstraints(writtenFiles: string[], _projectRoot: string): ActiveConstraint[] {\r\n return writtenFiles.map(file => ({\r\n file,\r\n scope: 'project' as const,\r\n appliesTo: '**/*',\r\n summary: `SpecLore constraint file — module boundaries and coding rules`,\r\n }));\r\n}\r\n\r\nfunction buildCodingGuidance(\r\n _features: FeatureFile[],\r\n context: ContextFile,\r\n config: SpecLoreConfig,\r\n): string {\r\n const parts: string[] = [];\r\n parts.push(`Project: ${config.project.name}`);\r\n parts.push(`Language: ${context.projectSummary.language}, Framework: ${context.projectSummary.framework}`);\r\n parts.push(`Modules: ${Object.keys(config.project.modules).join(', ')}`);\r\n parts.push(`Profile: ${config.project.profile}`);\r\n\r\n if (context.moduleBoundaries.length > 0) {\r\n parts.push('Module boundaries: respect module separation, do not cross-reference internal objects.');\r\n }\r\n\r\n const guidance = parts.join('. ') + '.';\r\n return guidance.slice(0, 2000);\r\n}\r\n","/**\r\n * speclore.status MCP tool — returns project workflow status and recommended actions.\r\n *\r\n * @module mcp/status\r\n */\r\n\r\nimport type { StatusResult, FeatureState } from '../types/index.js';\r\nimport { StateManager } from '../core/state-manager/index.js';\r\nimport { loadConfig, generateDefaultConfigYaml } from '../infra/config.js';\r\nimport { detectAITools } from '../setup/detector.js';\r\nimport { readFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { globSync } from 'glob';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/**\r\n * Execute speclore.status tool.\r\n */\r\nexport function executeStatusTool(\r\n args: { feature?: string },\r\n projectRoot: string,\r\n): StatusResult {\r\n // Auto-initialize project\r\n const { configCreated } = ensureProjectReadyForStatus(projectRoot);\r\n const config = loadConfig(projectRoot);\r\n\r\n const stateManager = new StateManager(projectRoot);\r\n const summary = stateManager.getProjectSummary();\r\n\r\n // Detect AI tools\r\n const aiTools = detectAITools(projectRoot);\r\n const aiToolsDetected = aiTools.map(t => t.tool);\r\n\r\n // Build feature list\r\n const featureEntries = stateManager.listFeatures();\r\n const features: StatusResult['features'] = [];\r\n\r\n for (const { path, state: entry } of featureEntries) {\r\n // If a specific feature was requested, filter\r\n if (args.feature && !path.includes(args.feature)) {\r\n continue;\r\n }\r\n\r\n // Count scenarios from the .feature file\r\n let scenarioCount = 0;\r\n if (existsSync(path)) {\r\n try {\r\n const content = readFileSync(path, 'utf-8');\r\n const matches = content.match(/Scenario(?: Outline)?:/g);\r\n scenarioCount = matches?.length ?? 0;\r\n } catch {\r\n // Ignore read errors\r\n }\r\n }\r\n\r\n features.push({\r\n file: path,\r\n state: entry.state,\r\n scenarios: scenarioCount,\r\n constraintFiles: entry.constraintFiles,\r\n testFiles: entry.testFiles,\r\n lastVerify: entry.lastVerify\r\n ? { passed: entry.lastVerify.passed, failed: entry.lastVerify.failed, timestamp: entry.lastVerify.timestamp }\r\n : undefined,\r\n });\r\n }\r\n\r\n // Also scan for .feature files not yet tracked in state\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const allFeatureFiles = globSync(`${specsDir}/**/*.feature`, { cwd: projectRoot, absolute: true });\r\n const trackedPaths = new Set(featureEntries.map(f => f.path));\r\n\r\n for (const filePath of allFeatureFiles) {\r\n if (trackedPaths.has(filePath)) continue;\r\n if (args.feature && !filePath.includes(args.feature)) continue;\r\n\r\n let scenarioCount = 0;\r\n try {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const matches = content.match(/Scenario(?: Outline)?:/g);\r\n scenarioCount = matches?.length ?? 0;\r\n } catch {\r\n // Ignore\r\n }\r\n\r\n features.push({\r\n file: filePath,\r\n state: 'specified',\r\n scenarios: scenarioCount,\r\n constraintFiles: [],\r\n testFiles: [],\r\n });\r\n }\r\n\r\n // Build recommended actions\r\n const recommendedActions = buildRecommendedActions(features, summary, config.verify.command);\r\n\r\n return {\r\n project: {\r\n initialized: true,\r\n configCreated,\r\n testCommand: config.verify.command,\r\n aiToolsDetected,\r\n },\r\n features,\r\n summary: {\r\n total: features.length,\r\n specified: features.filter(f => f.state === 'specified').length,\r\n constrained: features.filter(f => f.state === 'constrained').length,\r\n coding: features.filter(f => f.state === 'coding').length,\r\n verified: features.filter(f => f.state === 'verified').length,\r\n },\r\n recommendedActions,\r\n };\r\n}\r\n\r\nfunction buildRecommendedActions(\r\n features: StatusResult['features'],\r\n summary: { initialized: boolean; featureCount: number; states: Record<FeatureState, number> },\r\n testCommand: string,\r\n): string[] {\r\n const actions: string[] = [];\r\n\r\n if (features.length === 0) {\r\n actions.push('Call speclore.spec with your requirement to create feature files.');\r\n return actions;\r\n }\r\n\r\n if (summary.states.specified > 0) {\r\n actions.push('Call speclore.code to generate constraints and test scaffolding for specified features.');\r\n }\r\n\r\n if (summary.states.constrained > 0) {\r\n actions.push('Fill in test scaffolding implementations, then start coding.');\r\n }\r\n\r\n if (summary.states.coding > 0) {\r\n if (!testCommand) {\r\n actions.push('Configure verify.command in .speclore/config.yaml, then call speclore.verify.');\r\n } else {\r\n actions.push('Call speclore.verify to check acceptance status.');\r\n }\r\n }\r\n\r\n if (summary.states.verified === features.length && features.length > 0) {\r\n actions.push('All features verified. Add new requirements with speclore.spec.');\r\n }\r\n\r\n return actions;\r\n}\r\n\r\nfunction ensureProjectReadyForStatus(projectRoot: string): { initialized: boolean; configCreated: boolean; migrated: number } {\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const configPath = join(specLoreDir, 'config.yaml');\r\n let configCreated = false;\r\n\r\n if (!existsSync(specLoreDir)) {\r\n mkdirSync(specLoreDir, { recursive: true });\r\n }\r\n\r\n if (!existsSync(configPath)) {\r\n const projectName = projectRoot.split(/[/\\\\]/).pop() ?? 'my-project';\r\n writeFileSync(configPath, generateDefaultConfigYaml(projectName), 'utf-8');\r\n configCreated = true;\r\n logger.info(`Auto-created default config: ${configPath}`);\r\n }\r\n\r\n const stateManager = new StateManager(projectRoot);\r\n stateManager.ensureInitialized();\r\n\r\n // Migrate existing .feature files into state tracking\r\n const config = loadConfig(projectRoot);\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const migrated = stateManager.migrateFeatures(specsDir);\r\n if (migrated > 0) {\r\n logger.info(`Migrated ${migrated} existing .feature file(s) into state tracking.`);\r\n }\r\n\r\n return { initialized: true, configCreated, migrated };\r\n}\r\n","/**\r\n * SpecLore MCP Server — stdio transport, using official SDK high-level API.\r\n *\r\n * Lifecycle: initialize → tools/list → tools/call → shutdown → exit\r\n *\r\n * Exposes 4 tools:\r\n * - speclore.spec — requirement → .feature (M1 → M2)\r\n * - speclore.code — .feature → AI constraint files (M3 + M7)\r\n * - speclore.verify — tests → acceptance report (M4 + M7)\r\n * - speclore.status — project workflow status + recommended actions\r\n *\r\n * @module mcp/server\r\n */\r\n\r\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\r\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\r\nimport { acquireLock, releaseLock } from '../infra/file-lock.js';\r\nimport { logger } from '../infra/logger.js';\r\nimport { executeSpecTool, executeCodeTool, executeVerifyTool, SPEC_TOOL_DESC, CODE_TOOL_DESC, VERIFY_TOOL_DESC, STATUS_TOOL_DESC } from './tools.js';\r\nimport { executeStatusTool } from './status.js';\r\nimport { specInputSchema, codeInputSchema, verifyInputSchema, statusInputSchema } from './schemas.js';\r\nimport { VERSION } from '../version.js';\r\nimport { mkdirSync } from 'node:fs';\r\n\r\n// ============================================================================\r\n// Server setup\r\n// ============================================================================\r\n\r\nconst server = new McpServer(\r\n { name: 'speclore', version: VERSION },\r\n { capabilities: { tools: {} } },\r\n);\r\n\r\n// ============================================================================\r\n// Tool registration\r\n// ============================================================================\r\n\r\nserver.registerTool(\r\n 'speclore.spec',\r\n {\r\n description: SPEC_TOOL_DESC,\r\n inputSchema: specInputSchema.shape,\r\n },\r\n async (args) => {\r\n if (!args.source || args.source.length > 50000) {\r\n return { content: [{ type: 'text' as const, text: 'Error: source must be between 1 and 50000 characters' }], isError: true };\r\n }\r\n const result = await executeSpecTool(\r\n { source: args.source, module: args.module },\r\n getProjectRoot(),\r\n );\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };\r\n },\r\n);\r\n\r\nserver.registerTool(\r\n 'speclore.code',\r\n {\r\n description: CODE_TOOL_DESC,\r\n inputSchema: codeInputSchema.shape,\r\n },\r\n async (args) => {\r\n if (args.features && args.features.length > 50) {\r\n return { content: [{ type: 'text' as const, text: 'Error: features array must not exceed 50 items' }], isError: true };\r\n }\r\n const result = await executeCodeTool(\r\n { features: args.features, tools: args.tools },\r\n getProjectRoot(),\r\n );\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };\r\n },\r\n);\r\n\r\nserver.registerTool(\r\n 'speclore.verify',\r\n {\r\n description: VERIFY_TOOL_DESC,\r\n inputSchema: verifyInputSchema.shape,\r\n },\r\n async (args) => {\r\n const result = await executeVerifyTool(\r\n { features: args.features, impact: args.impact },\r\n getProjectRoot(),\r\n );\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };\r\n },\r\n);\r\n\r\nserver.registerTool(\r\n 'speclore.status',\r\n {\r\n description: STATUS_TOOL_DESC,\r\n inputSchema: statusInputSchema.shape,\r\n },\r\n async (args) => {\r\n const result = executeStatusTool(\r\n { feature: args.feature },\r\n getProjectRoot(),\r\n );\r\n return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] };\r\n },\r\n);\r\n\r\n// ============================================================================\r\n// Lifecycle\r\n// ============================================================================\r\n\r\nlet projectRoot = process.env.SPECLORE_PROJECT_ROOT ?? process.cwd();\r\n\r\nfunction getProjectRoot(): string {\r\n return projectRoot;\r\n}\r\n\r\n/**\r\n * Start the MCP server on stdio.\r\n */\r\nexport async function startMcpServer(): Promise<void> {\r\n projectRoot = process.env.SPECLORE_PROJECT_ROOT ?? process.cwd();\r\n\r\n // Acquire file lock (ensure directory exists first)\r\n const specLoreDir = `${projectRoot}/.speclore`;\r\n try {\r\n mkdirSync(specLoreDir, { recursive: true });\r\n const locked = acquireLock(specLoreDir);\r\n if (!locked) {\r\n logger.warn('Could not acquire lock — another SpecLore instance may be running.');\r\n }\r\n } catch {\r\n logger.warn('Could not acquire lock — .speclore/ directory may not exist.');\r\n }\r\n\r\n // Connect via stdio transport\r\n const transport = new StdioServerTransport();\r\n await server.connect(transport);\r\n\r\n logger.debug('MCP Server started (stdio transport)');\r\n\r\n // Graceful shutdown\r\n const cleanup = (): void => {\r\n try {\r\n releaseLock(`${projectRoot}/.speclore`);\r\n } catch {\r\n // Ignore cleanup errors\r\n }\r\n };\r\n\r\n process.on('SIGINT', () => {\r\n cleanup();\r\n process.exit(0);\r\n });\r\n process.on('SIGTERM', () => {\r\n cleanup();\r\n process.exit(0);\r\n });\r\n}\r\n","/**\r\n * SpecLore CLI entry point.\r\n *\r\n * Usage:\r\n * speclore — smart mode: show status + auto-action\r\n * speclore \"description\" — one-liner to generate feature\r\n * speclore setup — one-time project configuration\r\n * speclore init — initialize project\r\n * speclore status — project diagnostics\r\n * speclore spec <source> — requirement → .feature\r\n * speclore code — .feature → AI constraint files\r\n * speclore verify — run tests → acceptance report\r\n * speclore mcp — start MCP server (stdio)\r\n * speclore teardown — uninstall cleanup\r\n * speclore migrate — register existing .feature files into workflow state\r\n */\r\n\r\nimport { Command } from 'commander';\r\nimport { registerSetupCommand } from './commands/setup.js';\r\nimport { registerInitCommand } from './commands/init.js';\r\nimport { registerStatusCommand } from './commands/status.js';\r\nimport { registerSpecCommand } from './commands/spec.js';\r\nimport { registerCodeCommand } from './commands/code.js';\r\nimport { registerVerifyCommand } from './commands/verify.js';\r\nimport { registerTeardownCommand } from './commands/teardown.js';\r\nimport { registerMigrateCommand } from './commands/migrate.js';\r\nimport { VERSION } from '../version.js';\r\n\r\nexport function createProgram(): Command {\r\n const program = new Command();\r\n\r\n program\r\n .name('speclore')\r\n .version(VERSION)\r\n .description(\r\n 'AI-powered product-engineering collaboration CLI — turn requirements into BDD specs, auto-generate AI coding constraints, and verify acceptance criteria.',\r\n );\r\n\r\n // Register all sub-commands\r\n registerSetupCommand(program);\r\n registerInitCommand(program);\r\n registerStatusCommand(program);\r\n registerSpecCommand(program);\r\n registerCodeCommand(program);\r\n registerVerifyCommand(program);\r\n registerTeardownCommand(program);\r\n registerMigrateCommand(program);\r\n\r\n // MCP server sub-command\r\n program\r\n .command('mcp')\r\n .description('Start MCP server (stdio transport) for AI tool integration')\r\n .action(async () => {\r\n const { startMcpServer } = await import('../mcp/server.js');\r\n await startMcpServer();\r\n });\r\n\r\n // Smart mode: `speclore` with no sub-command\r\n program\r\n .argument('[text...]', 'Quick requirement text → .feature')\r\n .action(async (text: string[]) => {\r\n if (text.length > 0) {\r\n // One-liner mode: treat args as requirement text\r\n const { loadConfig } = await import('../infra/config.js');\r\n const { readRequirement } = await import('../core/requirement-reader/index.js');\r\n const { generateFeature } = await import('../core/feature-generator/index.js');\r\n const { buildContext, loadContext } = await import('../core/context-engine/index.js');\r\n const { logger } = await import('../infra/logger.js');\r\n\r\n const projectRoot = process.cwd();\r\n const config = loadConfig(projectRoot);\r\n const specLoreDir = `${projectRoot}/.speclore`;\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n const requirementText = text.join(' ');\r\n const req = await readRequirement(requirementText);\r\n const feature = await generateFeature(req, context, config, projectRoot);\r\n logger.info(`Created: ${feature.path} (${feature.scenarios.length} scenarios)`);\r\n } else {\r\n // No args: show status\r\n const { registerStatusCommand: showStatus } = await import('./commands/status.js');\r\n const statusProgram = new Command();\r\n showStatus(statusProgram);\r\n await statusProgram.parseAsync(['status']);\r\n }\r\n });\r\n\r\n return program;\r\n}\r\n\r\nexport async function run(argv: string[] = process.argv): Promise<void> {\r\n const program = createProgram();\r\n await program.parseAsync(argv);\r\n}\r\n","/**\r\n * speclore setup — one-time project configuration.\r\n *\r\n * Detects AI tools, writes MCP config, and generates rule files.\r\n *\r\n * @module cli/commands/setup\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { generateDefaultConfigYaml } from '../../infra/config.js';\r\nimport { detectAITools } from '../../setup/detector.js';\r\nimport { writeMcpConfig } from '../../setup/config-writer.js';\r\nimport { writeRuleFiles } from '../../setup/rule-writer.js';\r\n\r\nexport function registerSetupCommand(program: Command): void {\r\n program\r\n .command('setup')\r\n .description('One-time project setup: detect AI tools, configure MCP, generate rules')\r\n .option('--global', 'Install globally (~/.speclore/) instead of per-project')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action((opts: { global?: boolean; verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n logger.info('SpecLore Setup');\r\n logger.info('───────────────');\r\n\r\n // 1. Detect AI tools\r\n const tools = detectAITools(projectRoot);\r\n if (tools.length === 0) {\r\n logger.warn('No supported AI tools detected. Continuing anyway...');\r\n } else {\r\n logger.info(`Detected AI tools: ${tools.map(t => t.tool).join(', ')}`);\r\n }\r\n\r\n // 2. Ensure .speclore directory\r\n const specLoreDir = opts.global\r\n ? join(process.env.HOME ?? process.env.USERPROFILE ?? '~', '.speclore')\r\n : join(projectRoot, '.speclore');\r\n if (!existsSync(specLoreDir)) {\r\n mkdirSync(specLoreDir, { recursive: true });\r\n }\r\n\r\n // 3. Generate default config if not exists\r\n const configPath = join(specLoreDir, 'config.yaml');\r\n if (!existsSync(configPath)) {\r\n const projectName = projectRoot.split(/[/\\\\]/).pop() ?? 'my-project';\r\n writeFileSync(configPath, generateDefaultConfigYaml(projectName), 'utf-8');\r\n logger.info(`Created config: ${configPath}`);\r\n }\r\n\r\n // 4. Write MCP configuration\r\n writeMcpConfig(projectRoot, opts.global ?? false);\r\n\r\n // 5. Write rule files for detected tools\r\n writeRuleFiles(projectRoot, tools);\r\n\r\n logger.info('');\r\n logger.info('Setup complete! You can now:');\r\n logger.info(' • Run `speclore init` to initialize project context');\r\n logger.info(' • Or just start talking to your AI client about requirements');\r\n });\r\n}\r\n\r\n\r\n","/**\r\n * MCP configuration writer — writes MCP server config for AI clients.\r\n *\r\n * Supports npm global install and git clone modes.\r\n *\r\n * @module setup/config-writer\r\n */\r\n\r\nimport { writeFileSync, existsSync, readFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { detectInstallMethod } from '../infra/install-detector.js';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/**\r\n * Write MCP configuration files for all supported AI clients.\r\n */\r\nexport function writeMcpConfig(projectRoot: string, _globalMode: boolean): void {\r\n const installInfo = detectInstallMethod(projectRoot);\r\n const serverCommand = getServerCommand(installInfo);\r\n\r\n // Cursor: .cursor/mcp.json\r\n writeCursorMcp(projectRoot, serverCommand);\r\n\r\n // Claude Code: .mcp.json\r\n writeClaudeMcp(projectRoot, serverCommand);\r\n\r\n // Qoder: .qoder/mcp.json\r\n writeQoderMcp(projectRoot, serverCommand);\r\n\r\n logger.info('MCP configuration written for all detected AI clients.');\r\n}\r\n\r\nfunction getServerCommand(installInfo: { mode: string; localPath?: string }): { command: string; args: string[] } {\r\n if (installInfo.mode === 'npm') {\r\n return { command: 'npx', args: ['speclore', 'mcp'] };\r\n }\r\n // Clone mode — use local path\r\n const localPath = installInfo.localPath ?? process.cwd();\r\n return { command: 'node', args: [join(localPath, 'dist', 'mcp', 'server.js')] };\r\n}\r\n\r\nfunction writeCursorMcp(projectRoot: string, serverCmd: { command: string; args: string[] }): void {\r\n const mcpDir = join(projectRoot, '.cursor');\r\n if (!existsSync(mcpDir)) return; // Only write if .cursor exists\r\n\r\n const mcpPath = join(mcpDir, 'mcp.json');\r\n const existing = readExistingJson(mcpPath);\r\n\r\n if (!existing.mcpServers) existing.mcpServers = {};\r\n existing.mcpServers.speclore = {\r\n command: serverCmd.command,\r\n args: serverCmd.args,\r\n env: {},\r\n };\r\n\r\n writeFileSync(mcpPath, JSON.stringify(existing, null, 2), 'utf-8');\r\n logger.info(` Cursor: ${mcpPath}`);\r\n}\r\n\r\nfunction writeClaudeMcp(projectRoot: string, serverCmd: { command: string; args: string[] }): void {\r\n const mcpPath = join(projectRoot, '.mcp.json');\r\n const existing = readExistingJson(mcpPath);\r\n\r\n if (!existing.mcpServers) existing.mcpServers = {};\r\n existing.mcpServers.speclore = {\r\n command: serverCmd.command,\r\n args: serverCmd.args,\r\n env: {},\r\n };\r\n\r\n writeFileSync(mcpPath, JSON.stringify(existing, null, 2), 'utf-8');\r\n logger.info(` Claude Code: ${mcpPath}`);\r\n}\r\n\r\nfunction writeQoderMcp(projectRoot: string, serverCmd: { command: string; args: string[] }): void {\r\n const mcpDir = join(projectRoot, '.qoder');\r\n if (!existsSync(mcpDir)) return;\r\n\r\n const mcpPath = join(mcpDir, 'mcp.json');\r\n const existing = readExistingJson(mcpPath);\r\n\r\n if (!existing.mcpServers) existing.mcpServers = {};\r\n existing.mcpServers.speclore = {\r\n command: serverCmd.command,\r\n args: serverCmd.args,\r\n env: {},\r\n };\r\n\r\n writeFileSync(mcpPath, JSON.stringify(existing, null, 2), 'utf-8');\r\n logger.info(` Qoder: ${mcpPath}`);\r\n}\r\n\r\n/** MCP configuration file shape */\r\ninterface McpConfig {\r\n mcpServers?: Record<string, unknown>;\r\n [key: string]: unknown;\r\n}\r\n\r\nfunction readExistingJson(filePath: string): McpConfig {\r\n if (existsSync(filePath)) {\r\n try {\r\n return JSON.parse(readFileSync(filePath, 'utf-8')) as McpConfig;\r\n } catch {\r\n return {};\r\n }\r\n }\r\n return {};\r\n}\r\n","/**\r\n * Installation method detector.\r\n *\r\n * Detects whether SpecLore was installed via npm global install or git clone.\r\n * - npm global: `require.resolve('speclore')` succeeds\r\n * - git clone: `.speclore/.install-path` file exists (created by `pnpm build`)\r\n *\r\n * @module infra/install-detector\r\n */\r\n\r\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { createRequire } from 'node:module';\r\nimport type { InstallInfo } from '../types/index.js';\r\nimport { logger } from './logger.js';\r\nimport { VERSION } from '../version.js';\r\n\r\nconst INSTALL_PATH_FILE = '.install-path';\r\n\r\n/**\r\n * Detect how SpecLore was installed.\r\n */\r\nexport function detectInstallMethod(projectRoot: string): InstallInfo {\r\n // Try npm global install first\r\n const npmResult = detectNpmInstall();\r\n if (npmResult) {\r\n logger.debug(`Detected npm install, version: ${npmResult.version}`);\r\n return npmResult;\r\n }\r\n\r\n // Try git clone\r\n const cloneResult = detectCloneInstall(projectRoot);\r\n if (cloneResult) {\r\n logger.debug(`Detected clone install at: ${cloneResult.localPath}`);\r\n return cloneResult;\r\n }\r\n\r\n // Fallback: assume npm install (most common case)\r\n logger.debug('Could not detect install method, assuming npm');\r\n return { mode: 'npm', version: VERSION };\r\n}\r\n\r\n/**\r\n * Detect npm global install via require.resolve.\r\n */\r\nfunction detectNpmInstall(): InstallInfo | null {\r\n try {\r\n const require = createRequire(import.meta.url);\r\n const resolved = require.resolve('speclore/package.json');\r\n // Read version from the resolved package.json\r\n const pkg = JSON.parse(readFileSync(resolved, 'utf-8')) as { version: string };\r\n return { mode: 'npm', version: pkg.version ?? VERSION };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Detect git clone install via .install-path file.\r\n */\r\nfunction detectCloneInstall(projectRoot: string): InstallInfo | null {\r\n const installPathFile = join(projectRoot, '.speclore', INSTALL_PATH_FILE);\r\n\r\n if (!existsSync(installPathFile)) {\r\n return null;\r\n }\r\n\r\n try {\r\n const localPath = readFileSync(installPathFile, 'utf-8').trim();\r\n if (existsSync(localPath)) {\r\n return { mode: 'clone', version: VERSION, localPath };\r\n }\r\n } catch {\r\n // Corrupt file\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Write the .install-path file for clone installs.\r\n * Called during `pnpm build` or `speclore init` for clone mode.\r\n */\r\nexport function writeInstallPathFile(projectRoot: string, distPath: string): void {\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const installPathFile = join(specLoreDir, INSTALL_PATH_FILE);\r\n\r\n if (!existsSync(specLoreDir)) {\r\n mkdirSync(specLoreDir, { recursive: true });\r\n }\r\n\r\n writeFileSync(installPathFile, distPath, 'utf-8');\r\n logger.debug(`Wrote install path: ${distPath}`);\r\n}\r\n\r\n/**\r\n * Get the MCP server entry path based on install method.\r\n */\r\nexport function getMcpServerPath(installInfo: InstallInfo): string {\r\n if (installInfo.mode === 'clone' && installInfo.localPath) {\r\n return join(installInfo.localPath, 'dist', 'mcp', 'server.js');\r\n }\r\n // For npm install, the command is just \"speclore --mcp\"\r\n // The actual path is resolved by npx\r\n return 'speclore';\r\n}\r\n","/**\r\n * Rule file writer — generates constraint rule files for AI clients.\r\n *\r\n * @module setup/rule-writer\r\n */\r\n\r\nimport { writeFileSync, mkdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport type { AIToolInfo } from '../types/index.js';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/**\r\n * Write rule files for detected AI tools.\r\n */\r\nexport function writeRuleFiles(projectRoot: string, tools: AIToolInfo[]): void {\r\n for (const tool of tools) {\r\n switch (tool.tool) {\r\n case 'cursor':\r\n writeCursorRule(projectRoot);\r\n break;\r\n case 'claude':\r\n writeClaudeRule(projectRoot);\r\n break;\r\n case 'qoder':\r\n writeQoderRule(projectRoot);\r\n break;\r\n }\r\n }\r\n}\r\n\r\nfunction writeCursorRule(projectRoot: string): void {\r\n const rulesDir = join(projectRoot, '.cursor', 'rules');\r\n mkdirSync(rulesDir, { recursive: true });\r\n\r\n const content = `---\r\ndescription: SpecLore — AI coding constraints (setup placeholder)\r\nglobs:\r\nalwaysApply: true\r\n---\r\n\r\n# SpecLore\r\n\r\nSpecLore is configured for this project. When the \\`speclore.spec\\` MCP tool is available:\r\n\r\n1. Use it to convert requirements into BDD .feature files\r\n2. Use \\`speclore.code\\` to generate coding constraints\r\n3. Use \\`speclore.verify\\` to run acceptance tests\r\n\r\n> This is a placeholder. Run \\`speclore code\\` to generate full constraints with module boundaries.\r\n`;\r\n\r\n writeFileSync(join(rulesDir, 'speclore.mdc'), content, 'utf-8');\r\n logger.info(` Cursor rule: .cursor/rules/speclore.mdc`);\r\n}\r\n\r\nfunction writeClaudeRule(projectRoot: string): void {\r\n const rulesDir = join(projectRoot, '.claude', 'rules');\r\n mkdirSync(rulesDir, { recursive: true });\r\n\r\n const content = `# SpecLore\r\n\r\nSpecLore is configured for this project. When the \\`speclore.spec\\` MCP tool is available:\r\n\r\n1. Use it to convert requirements into BDD .feature files\r\n2. Use \\`speclore.code\\` to generate coding constraints\r\n3. Use \\`speclore.verify\\` to run acceptance tests\r\n\r\n> This is a placeholder. Run \\`speclore code\\` to generate full constraints with module boundaries.\r\n`;\r\n\r\n writeFileSync(join(rulesDir, 'speclore.md'), content, 'utf-8');\r\n logger.info(` Claude Code rule: .claude/rules/speclore.md`);\r\n}\r\n\r\nfunction writeQoderRule(projectRoot: string): void {\r\n const rulesDir = join(projectRoot, '.qoder', 'rules');\r\n mkdirSync(rulesDir, { recursive: true });\r\n\r\n const content = `# SpecLore\r\n\r\nSpecLore is configured for this project. When the \\`speclore.spec\\` MCP tool is available:\r\n\r\n1. Use it to convert requirements into BDD .feature files\r\n2. Use \\`speclore.code\\` to generate coding constraints\r\n3. Use \\`speclore.verify\\` to run acceptance tests\r\n\r\n> This is a placeholder. Run \\`speclore code\\` to generate full constraints with module boundaries.\r\n`;\r\n\r\n writeFileSync(join(rulesDir, 'speclore.md'), content, 'utf-8');\r\n logger.info(` Qoder rule: .qoder/rules/speclore.md`);\r\n}\r\n","/**\r\n * speclore init — initialize project context.\r\n *\r\n * Scans project structure, detects modules, generates context.json.\r\n *\r\n * @module cli/commands/init\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { join } from 'node:path';\r\nimport { loadConfig } from '../../infra/config.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { buildContext, writeContextFile } from '../../core/context-engine/index.js';\r\n\r\nexport function registerInitCommand(program: Command): void {\r\n program\r\n .command('init')\r\n .description('Initialize project: scan structure, detect modules, generate context.json')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action((opts: { verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n logger.info('SpecLore Init');\r\n logger.info('──────────────');\r\n\r\n const config = loadConfig(projectRoot);\r\n logger.info(`Project: ${config.project.name || '(unnamed)'}`);\r\n\r\n const context = buildContext(projectRoot, config);\r\n\r\n // Write context.json to disk\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n writeContextFile(specLoreDir, context);\r\n\r\n logger.info(`Language: ${context.projectSummary.language}`);\r\n logger.info(`Framework: ${context.projectSummary.framework}`);\r\n logger.info(`Modules: ${context.moduleBoundaries.length}`);\r\n logger.info(`Entities: ${context.existingCode.entities.length}`);\r\n logger.info(`APIs: ${context.existingCode.apis.length}`);\r\n logger.info('');\r\n logger.info('context.json generated successfully.');\r\n });\r\n}\r\n","/**\r\n * speclore spec — requirement → .feature\r\n *\r\n * @module cli/commands/spec\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { join } from 'node:path';\r\nimport { loadConfig } from '../../infra/config.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { readRequirement } from '../../core/requirement-reader/index.js';\r\nimport { generateFeature } from '../../core/feature-generator/index.js';\r\nimport { buildContext, loadContext } from '../../core/context-engine/index.js';\r\nimport { StateManager } from '../../core/state-manager/index.js';\r\n\r\nexport function registerSpecCommand(program: Command): void {\r\n program\r\n .command('spec')\r\n .description('Convert a requirement source into BDD .feature file(s)')\r\n .argument('<source>', 'Requirement source: file path, URL, or text')\r\n .option('-m, --module <name>', 'Target module name')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action(async (source: string, opts: { module?: string; verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n logger.info(`Reading requirement: ${source.slice(0, 80)}...`);\r\n\r\n const config = loadConfig(projectRoot);\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n const requirements = await readRequirement(source);\r\n const features = await generateFeature(requirements, context, config, projectRoot);\r\n logger.info(`Created: ${features.path} (${features.scenarios.length} scenarios)`);\r\n if (features.needsReview.length > 0) {\r\n logger.warn(` Needs review: ${features.needsReview.join(', ')}`);\r\n }\r\n\r\n // Update workflow state\r\n const stateManager = new StateManager(projectRoot);\r\n try {\r\n stateManager.transitionFeature(features.path, 'specified');\r\n } catch {\r\n // Feature may already be in specified state (e.g., re-running spec)\r\n }\r\n console.log('');\r\n console.log(`Workflow: ${features.path} → specified`);\r\n console.log('Next step: speclore code — generate constraints and test scaffolding');\r\n });\r\n}\r\n","/**\r\n * speclore code — .feature → AI constraint files\r\n *\r\n * @module cli/commands/code\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { join } from 'node:path';\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport { globSync } from 'glob';\r\nimport { loadConfig } from '../../infra/config.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { generateConstraints } from '../../core/constraint-coder/index.js';\r\nimport { generateTestScaffolding } from '../../core/test-scaffolder/index.js';\r\nimport { buildContext, loadContext } from '../../core/context-engine/index.js';\r\nimport { StateManager } from '../../core/state-manager/index.js';\r\nimport type { FeatureFile, SpecLoreConfig } from '../../types/index.js';\r\n\r\nexport function registerCodeCommand(program: Command): void {\r\n program\r\n .command('code')\r\n .description('Generate AI coding constraint files from .feature specs')\r\n .argument('[features...]', 'Feature file paths or glob patterns (all if omitted)')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action(async (features: string[], opts: { verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n const config = loadConfig(projectRoot);\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n // Resolve feature files\r\n const featureFiles = resolveFeatures(features, projectRoot, config);\r\n if (featureFiles.length === 0) {\r\n logger.warn('No feature files found. Run `speclore spec` first.');\r\n return;\r\n }\r\n\r\n logger.info(`Processing ${featureFiles.length} feature file(s)...`);\r\n const writtenFiles = await generateConstraints(projectRoot, featureFiles, context, config);\r\n\r\n for (const f of writtenFiles) {\r\n logger.info(`Written: ${f}`);\r\n }\r\n\r\n // Generate test scaffolding\r\n const scaffoldResults = generateTestScaffolding(projectRoot, featureFiles, config);\r\n if (scaffoldResults.length > 0) {\r\n console.log('');\r\n console.log('Test Scaffolding Generated:');\r\n for (const s of scaffoldResults) {\r\n logger.info(` ${s.testFile} (${s.scenarios} scenarios, ${s.framework})`);\r\n }\r\n }\r\n\r\n // Update workflow state\r\n const stateManager = new StateManager(projectRoot);\r\n\r\n // Auto-migrate existing .feature files that aren't tracked yet\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const migrated = stateManager.migrateFeatures(specsDir);\r\n if (migrated > 0) {\r\n console.log(`Migrated ${migrated} existing .feature file(s) into state tracking.`);\r\n }\r\n\r\n for (const feature of featureFiles) {\r\n try {\r\n stateManager.transitionFeature(feature.path, 'constrained', ['specified']);\r\n stateManager.updateFeatureEntry(feature.path, {\r\n constraintFiles: writtenFiles,\r\n testFiles: scaffoldResults.map(s => s.testFile),\r\n });\r\n } catch {\r\n // May already be constrained\r\n }\r\n }\r\n\r\n console.log('');\r\n console.log(`Done. ${writtenFiles.length} constraint file(s), ${scaffoldResults.length} test scaffold(s) generated.`);\r\n console.log('Next step: Fill in test implementations, then start coding.');\r\n });\r\n}\r\n\r\nfunction resolveFeatures(\r\n patterns: string[],\r\n projectRoot: string,\r\n config: SpecLoreConfig,\r\n): FeatureFile[] {\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const searchPatterns = patterns.length > 0 ? patterns : [`${specsDir}/**/*.feature`];\r\n\r\n const files: FeatureFile[] = [];\r\n for (const pattern of searchPatterns) {\r\n const matches = globSync(pattern, { cwd: projectRoot, absolute: true });\r\n for (const filePath of matches) {\r\n if (existsSync(filePath)) {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const featureMatch = content.match(/Feature:\\s*(.+)/);\r\n files.push({\r\n path: filePath,\r\n featureName: featureMatch?.[1]?.trim() ?? filePath,\r\n scenarios: [],\r\n tags: [],\r\n confidence: 1.0,\r\n needsReview: [],\r\n });\r\n }\r\n }\r\n }\r\n return files;\r\n}\r\n","/**\r\n * speclore verify — run tests → acceptance report\r\n *\r\n * @module cli/commands/verify\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { join } from 'node:path';\r\nimport { readFileSync, existsSync } from 'node:fs';\r\nimport { globSync } from 'glob';\r\nimport { loadConfig } from '../../infra/config.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { runVerification } from '../../core/verifier/index.js';\r\nimport { buildContext, loadContext } from '../../core/context-engine/index.js';\r\nimport { analyzeImpact } from '../../core/analyzer/index.js';\r\nimport { StateManager } from '../../core/state-manager/index.js';\r\nimport type { FeatureFile, ContextFile } from '../../types/index.js';\r\nimport type { SpecLoreConfig } from '../../types/config.js';\r\n\r\nexport function registerVerifyCommand(program: Command): void {\r\n program\r\n .command('verify')\r\n .description('Run tests and map results to .feature scenarios')\r\n .argument('[features...]', 'Feature file paths or glob patterns (all if omitted)')\r\n .option('--impact', 'Enable change impact analysis')\r\n .option('--watch', 'Watch for .feature file changes and re-run')\r\n .option('--timeout <minutes>', 'Watch timeout in minutes (default: 30)', '30')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action(async (features: string[], opts: { impact?: boolean; watch?: boolean; timeout?: string; verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n const config = loadConfig(projectRoot);\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n const context = loadContext(specLoreDir) ?? buildContext(projectRoot, config);\r\n\r\n // Impact analysis\r\n if (opts.impact) {\r\n logger.info('Running impact analysis...');\r\n const impact = analyzeImpact(projectRoot, context, config);\r\n context.impactAnalysis = {\r\n changedFiles: impact.changedFiles,\r\n affectedModules: impact.affectedModules,\r\n affectedFeatures: impact.affectedFeatures,\r\n };\r\n }\r\n\r\n // Resolve feature files\r\n const featureFiles = resolveFeatures(features, projectRoot, config);\r\n\r\n // State guard: check features have test scaffolding\r\n const stateManager = new StateManager(projectRoot);\r\n\r\n // Auto-migrate existing .feature files that aren't tracked yet\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n stateManager.migrateFeatures(specsDir);\r\n\r\n for (const feature of featureFiles) {\r\n const entry = stateManager.getFeatureState(feature.path);\r\n if (!entry || entry.state === 'specified') {\r\n logger.error(`Feature \"${feature.path}\" has no test scaffolding. Run \\`speclore code\\` first.`);\r\n return;\r\n }\r\n }\r\n\r\n if (opts.watch) {\r\n await runWatchMode(projectRoot, featureFiles, context, config, Number(opts.timeout));\r\n } else {\r\n const report = await runVerification(projectRoot, featureFiles, config, context);\r\n const { generateReport } = await import('../../core/verifier/report-generator.js');\r\n generateReport(report, projectRoot, config);\r\n }\r\n });\r\n}\r\n\r\nasync function runWatchMode(\r\n projectRoot: string,\r\n featureFiles: FeatureFile[],\r\n context: ContextFile,\r\n config: SpecLoreConfig,\r\n timeoutMinutes: number,\r\n): Promise<void> {\r\n const { watch } = await import('chokidar');\r\n const { generateReport } = await import('../../core/verifier/report-generator.js');\r\n\r\n const timeoutMs = timeoutMinutes * 60 * 1000;\r\n let lastRun = Date.now();\r\n\r\n logger.info(`Watch mode enabled. Timeout: ${timeoutMinutes} minutes.`);\r\n\r\n const specsDir = `${projectRoot}/${config.spec.outputDir}`;\r\n const watcher = watch(specsDir, {\r\n ignored: /(^|[/\\\\])\\../,\r\n persistent: true,\r\n });\r\n\r\n const runVerify = async () => {\r\n lastRun = Date.now();\r\n logger.info('Changes detected, running verification...');\r\n try {\r\n const report = await runVerification(projectRoot, featureFiles, config, context);\r\n generateReport(report, projectRoot, config);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n logger.error(`Verification failed: ${message}`);\r\n }\r\n };\r\n\r\n // Debounce to prevent concurrent runs on rapid file changes\r\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\r\n const debouncedVerify = () => {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(() => { void runVerify(); }, 500);\r\n };\r\n\r\n watcher.on('change', debouncedVerify);\r\n watcher.on('add', debouncedVerify);\r\n\r\n // Check timeout periodically\r\n const interval = setInterval(() => {\r\n if (Date.now() - lastRun > timeoutMs) {\r\n logger.info('Watch timeout reached. Exiting.');\r\n void watcher.close();\r\n clearInterval(interval);\r\n process.exit(0);\r\n }\r\n }, 30_000);\r\n\r\n // Run once initially\r\n await runVerify();\r\n}\r\n\r\nfunction resolveFeatures(\r\n patterns: string[],\r\n projectRoot: string,\r\n config: SpecLoreConfig,\r\n): FeatureFile[] {\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n const searchPatterns = patterns.length > 0 ? patterns : [`${specsDir}/**/*.feature`];\r\n\r\n const files: FeatureFile[] = [];\r\n for (const pattern of searchPatterns) {\r\n const matches = globSync(pattern, { cwd: projectRoot, absolute: true });\r\n for (const filePath of matches) {\r\n if (existsSync(filePath)) {\r\n const content = readFileSync(filePath, 'utf-8');\r\n const featureMatch = content.match(/Feature:\\s*(.+)/);\r\n files.push({\r\n path: filePath,\r\n featureName: featureMatch?.[1]?.trim() ?? filePath,\r\n scenarios: [],\r\n tags: [],\r\n confidence: 1.0,\r\n needsReview: [],\r\n });\r\n }\r\n }\r\n }\r\n return files;\r\n}\r\n","/**\r\n * speclore teardown — uninstall cleanup.\r\n *\r\n * @module cli/commands/teardown\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { runTeardown } from '../../setup/cleanup.js';\r\n\r\nexport function registerTeardownCommand(program: Command): void {\r\n program\r\n .command('teardown')\r\n .description('Remove SpecLore configuration and generated files')\r\n .option('--global', 'Remove global configuration (~/.speclore/)')\r\n .option('--yes', 'Skip confirmation prompt')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action(async (opts: { global?: boolean; yes?: boolean; verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n if (!opts.yes) {\r\n const inquirer = await import('inquirer');\r\n const answers = await inquirer.default.prompt([{\r\n type: 'confirm',\r\n name: 'confirm',\r\n message: opts.global\r\n ? 'Remove global SpecLore configuration (~/.speclore/)?'\r\n : 'Remove project SpecLore configuration (.speclore/)?',\r\n default: false,\r\n }]);\r\n if (!answers.confirm) {\r\n logger.info('Cancelled.');\r\n return;\r\n }\r\n }\r\n\r\n await runTeardown(projectRoot, opts.global ?? false);\r\n logger.info('Teardown complete.');\r\n });\r\n}\r\n","/**\r\n * Teardown cleanup — removes SpecLore configuration and generated files.\r\n *\r\n * @module setup/cleanup\r\n */\r\n\r\nimport { rmSync, existsSync, readFileSync, writeFileSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { logger } from '../infra/logger.js';\r\n\r\n/**\r\n * Remove SpecLore configuration and generated artifacts.\r\n */\r\nexport function runTeardown(projectRoot: string, globalMode: boolean): Promise<void> {\r\n if (globalMode) {\r\n const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? '';\r\n const globalDir = join(homeDir, '.speclore');\r\n if (existsSync(globalDir)) {\r\n rmSync(globalDir, { recursive: true, force: true });\r\n logger.info(`Removed: ${globalDir}`);\r\n }\r\n } else {\r\n // Remove project-level .speclore directory\r\n const specLoreDir = join(projectRoot, '.speclore');\r\n if (existsSync(specLoreDir)) {\r\n rmSync(specLoreDir, { recursive: true, force: true });\r\n logger.info(`Removed: ${specLoreDir}`);\r\n }\r\n\r\n // Remove MCP entries from AI client configs\r\n removeMcpEntry(join(projectRoot, '.cursor', 'mcp.json'), 'speclore');\r\n removeMcpEntry(join(projectRoot, '.mcp.json'), 'speclore');\r\n removeMcpEntry(join(projectRoot, '.qoder', 'mcp.json'), 'speclore');\r\n\r\n // Remove rule files\r\n removeIfExists(join(projectRoot, '.cursor', 'rules', 'speclore.mdc'));\r\n removeIfExists(join(projectRoot, '.claude', 'rules', 'speclore.md'));\r\n removeIfExists(join(projectRoot, '.qoder', 'rules', 'speclore.md'));\r\n\r\n logger.info('Project teardown complete.');\r\n }\r\n return Promise.resolve();\r\n}\r\n\r\nfunction removeMcpEntry(mcpPath: string, serverName: string): void {\r\n if (!existsSync(mcpPath)) return;\r\n try {\r\n const config = JSON.parse(readFileSync(mcpPath, 'utf-8')) as { mcpServers?: Record<string, unknown> };\r\n if (config.mcpServers?.[serverName]) {\r\n delete config.mcpServers[serverName];\r\n writeFileSync(mcpPath, JSON.stringify(config, null, 2), 'utf-8');\r\n logger.info(` Cleaned MCP entry: ${mcpPath}`);\r\n }\r\n } catch {\r\n // Ignore parse errors\r\n }\r\n}\r\n\r\nfunction removeIfExists(filePath: string): void {\r\n if (existsSync(filePath)) {\r\n rmSync(filePath);\r\n logger.info(` Removed: ${filePath}`);\r\n }\r\n}\r\n","/**\r\n * speclore migrate — register existing .feature files into workflow state.\r\n *\r\n * For projects upgrading from pre-workflow SpecLore versions:\r\n * scans the specs directory and registers all .feature files\r\n * that are not yet tracked in state.yaml.\r\n *\r\n * @module cli/commands/migrate\r\n */\r\n\r\nimport type { Command } from 'commander';\r\nimport { join } from 'node:path';\r\nimport { existsSync } from 'node:fs';\r\nimport { loadConfig } from '../../infra/config.js';\r\nimport { logger } from '../../infra/logger.js';\r\nimport { StateManager } from '../../core/state-manager/index.js';\r\n\r\nexport function registerMigrateCommand(program: Command): void {\r\n program\r\n .command('migrate')\r\n .description('Register existing .feature files into workflow state (for upgrading projects)')\r\n .option('-v, --verbose', 'Enable debug logging')\r\n .action((opts: { verbose?: boolean }) => {\r\n if (opts.verbose) logger.setLevel('debug');\r\n const projectRoot = process.cwd();\r\n\r\n console.log('');\r\n console.log('SpecLore Migration');\r\n console.log('══════════════════');\r\n console.log('');\r\n\r\n // Check config\r\n const configPath = join(projectRoot, '.speclore', 'config.yaml');\r\n if (!existsSync(configPath)) {\r\n console.log('✗ No .speclore/config.yaml found. Run `speclore setup` first.');\r\n console.log('');\r\n return;\r\n }\r\n console.log('✓ Config found');\r\n\r\n const config = loadConfig(projectRoot);\r\n\r\n // Initialize state if needed\r\n const stateManager = new StateManager(projectRoot);\r\n stateManager.ensureInitialized();\r\n console.log('✓ State file ready');\r\n\r\n // Scan and migrate\r\n const specsDir = join(projectRoot, config.spec.outputDir);\r\n if (!existsSync(specsDir)) {\r\n console.log(`○ No ${config.spec.outputDir}/ directory found — nothing to migrate.`);\r\n console.log('');\r\n return;\r\n }\r\n\r\n const before = stateManager.listFeatures().length;\r\n const migrated = stateManager.migrateFeatures(specsDir);\r\n const after = stateManager.listFeatures().length;\r\n\r\n console.log(`✓ Scanned ${config.spec.outputDir}/ for .feature files`);\r\n console.log('');\r\n\r\n if (migrated === 0) {\r\n console.log(`All feature files are already tracked (${before} feature(s) in state).`);\r\n console.log('No migration needed.');\r\n } else {\r\n console.log(`Migrated ${migrated} feature file(s) → specified`);\r\n console.log('');\r\n\r\n // Show the migrated features\r\n const features = stateManager.listFeatures();\r\n for (const { path, state: entry } of features) {\r\n if (entry.state === 'specified') {\r\n console.log(` ○ ${path} → specified`);\r\n }\r\n }\r\n }\r\n\r\n console.log('');\r\n console.log(`Total tracked features: ${after}`);\r\n console.log('');\r\n console.log('Next step: speclore code — generate constraints and test scaffolding');\r\n console.log('');\r\n });\r\n}\r\n","/**\r\n * CLI binary entry point.\r\n * Thin wrapper that executes the CLI — separate from the library export\r\n * so that importing the module (e.g. in tests) does not trigger execution.\r\n */\r\nimport { run } from '../cli/index.js';\r\n\r\nrun().catch((err: unknown) => {\r\n const message = err instanceof Error ? err.message : String(err);\r\n console.error(`Error: ${message}`);\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":["projectRoot","init_config","existsSync","join","projectRoot","readFileSync","join","join","existsSync","readFileSync","join","relative","projectRoot","readFileSync","writeFileSync","existsSync","statSync","mkdirSync","join","projectRoot","readFileSync","writeFileSync","existsSync","mkdirSync","join","yaml","globSync","projectRoot","state","existsSync","join","globSync","projectRoot","init_config","readFileSync","existsSync","readFileSync","resolve","RateLimitError","InternalServerError","APIConnectionError","OpenAIAdapter","ClaudeAdapter","OllamaAdapter","logger","existsSync","readFileSync","createProvider","writeFileSync","mkdirSync","existsSync","join","projectRoot","writeFileSync","mkdirSync","existsSync","rmSync","join","projectRoot","writeFileSync","mkdirSync","existsSync","rmSync","join","projectRoot","readFileSync","basename","extname","basename","extname","init_docx_reader","basename","extname","ExcelJS","init_xlsx_reader","basename","extname","init_pdf_reader","basename","extname","readFileSync","init_image_reader","basename","existsSync","extname","init_docx_reader","init_xlsx_reader","init_pdf_reader","init_image_reader","writeFileSync","mkdirSync","existsSync","join","dirname","Parser","GherkinClassicTokenMatcher","AstBuilder","IdGenerator","projectRoot","existsSync","join","detectAITools","projectRoot","writeFileSync","mkdirSync","existsSync","join","projectRoot","writeCursorRule","writeClaudeRule","writeQoderRule","projectRoot","detectAITools","readFileSync","existsSync","join","projectRoot","readFileSync","writeFileSync","existsSync","mkdirSync","join","relative","dirname","basename","projectRoot","readFileSync","existsSync","readdirSync","join","projectRoot","execFileSync","projectRoot","writeFileSync","mkdirSync","existsSync","readFileSync","join","dirname","fileURLToPath","projectRoot","readFileSync","existsSync","readdirSync","join","execFileSync","globSync","projectRoot","readFileSync","writeFileSync","existsSync","statSync","join","join","readFileSync","existsSync","mkdirSync","writeFileSync","globSync","projectRoot","stateManager","init_config","readFileSync","existsSync","mkdirSync","writeFileSync","join","globSync","projectRoot","init_status","init_config","mkdirSync","init_status","init_config","existsSync","mkdirSync","writeFileSync","join","writeFileSync","existsSync","readFileSync","join","readFileSync","existsSync","join","projectRoot","require","projectRoot","join","existsSync","writeFileSync","readFileSync","writeFileSync","mkdirSync","join","projectRoot","projectRoot","join","existsSync","mkdirSync","writeFileSync","init_config","join","projectRoot","init_config","join","projectRoot","init_config","join","readFileSync","existsSync","globSync","projectRoot","init_config","join","readFileSync","existsSync","globSync","projectRoot","resolveFeatures","generateReport","rmSync","existsSync","readFileSync","writeFileSync","join","projectRoot","projectRoot","init_config","join","existsSync","projectRoot","startMcpServer","loadConfig","readRequirement","generateFeature","buildContext","loadContext","logger","projectRoot"]}