/** * OpenSpec Compatibility Layer * * Ensures perfect compatibility with OpenSpec's tooling and conventions. * Handles config.yaml integration, validation, and context injection. */ import type { ProjectSurveyResult } from './spec-pipeline.js'; /** * Top-level `config.yaml` keys OpenSpec (the host) owns when OpenLore runs as an * OpenSpec plugin. Their presence marks the config as host-managed, in which case * OpenLore writes ONLY its `openlore` key (the one it declares via * `ownsConfigKeys`) and leaves every other key byte-for-byte unchanged — it never * introduces or overwrites a host-owned key. When none of these are present the * config is treated as standalone OpenLore's own, and OpenLore may create * `schema`/`context` as before (it is then the legitimate creator). */ export declare const HOST_OWNED_CONFIG_KEYS: readonly ["version", "profile", "delivery", "workflows", "featureFlags", "plugins"]; /** * Replace (or append) a single top-level YAML block by name in `raw`, touching no * other bytes. The block spans the `:` line at column 0 through the LAST * following indented (non-blank) line — blank lines *within* the body are kept as * part of the block, while trailing blank lines that merely separate it from the * next top-level key are preserved as host content. Replacement stops at the next * column-0 non-blank line (a new top-level key or a column-0 comment) or EOF. When * the key is absent the block is appended. This is a literal text edit — not a YAML * re-serialization — so host content (other keys, comments, CRLF, folded scalars) * is preserved byte-for-byte. * * @param blockText the serialized `: …` YAML (LF-separated) * @param eol the file's detected line ending (`\n` or `\r\n`) */ export declare function spliceTopLevelBlock(raw: string, key: string, blockText: string, eol: string): string; /** * Validation result for specs and config */ export interface ValidationResult { valid: boolean; errors: string[]; warnings: string[]; } /** * OpenSpec config.yaml structure */ export interface OpenSpecConfig { schema?: string; context?: string; rules?: { proposal?: string[]; specs?: string[]; design?: string[]; tasks?: string[]; }; 'openlore'?: OpenLoreMetadata; } /** * openlore metadata added to config.yaml */ export interface OpenLoreMetadata { version: string; generatedAt: string; domains: string[]; confidence: number; adrCount?: number; } /** * Detected project context for injection */ export interface DetectedContext { techStack: string; architecture: string; domains: string[]; patterns: string[]; } /** * Options for context update */ export interface ContextUpdateOptions { preserveUserContext: boolean; appendDetectedInfo: boolean; version: string; } /** * OpenSpec validator for specs and configuration */ export declare class OpenSpecValidator { /** * Validate the complete spec structure */ validateSpecStructure(content: string): ValidationResult; /** * Validate requirement format follows RFC 2119 */ validateRequirementFormat(requirement: string): ValidationResult; /** * Validate scenario format (Given/When/Then) */ validateScenarioFormat(scenario: string): ValidationResult; /** * Validate config.yaml structure */ validateConfigYaml(config: unknown): ValidationResult; /** * Check heading hierarchy is valid (no skipped levels) */ private checkHeadingHierarchy; /** * Check for malformed markdown links */ private checkMarkdownLinks; } /** * OpenSpec config.yaml manager */ export declare class OpenSpecConfigManager { private configPath; private openspecRoot; constructor(projectRoot: string); /** * Check if OpenSpec is initialized */ isInitialized(): Promise; /** * Check if config.yaml exists */ hasConfig(): Promise; /** * Read existing config.yaml */ readConfig(): Promise; /** * Write config.yaml, preserving user content */ writeConfig(config: OpenSpecConfig): Promise; /** * Update config with openlore metadata while preserving user/host content. * * Write discipline (config-key ownership): OpenLore owns exactly the `openlore` * key. When a config.yaml already exists, the update is performed surgically * through the YAML Document API so every other key — and every comment — is * preserved verbatim. If the existing config is host-managed (it carries any * {@link HOST_OWNED_CONFIG_KEYS}, i.e. OpenSpec created it), OpenLore touches * ONLY its `openlore` key and never introduces or overwrites a host-owned key * (context auto-injection is skipped — the host owns `context`). When no config * exists, OpenLore is the legitimate creator and may seed `schema`/`context`. */ updateWithOpenLoreMetadata(metadata: OpenLoreMetadata, detectedContext?: DetectedContext, options?: ContextUpdateOptions): Promise; /** * Build context string combining user and detected info */ private buildContext; /** * Get existing user context from config */ getUserContext(): Promise; /** * Get existing domains from specs directory */ getExistingDomains(): Promise; } /** * Build detected context from analysis results */ export declare function buildDetectedContext(survey: ProjectSurveyResult): DetectedContext; /** * Normalize domain name to OpenSpec conventions */ export declare function normalizeDomainName(name: string): string; /** * Check if domain name follows conventions */ export declare function isValidDomainName(name: string): boolean; /** * Match suggested domains against existing domains */ export declare function matchExistingDomains(suggestedDomains: string[], existingDomains: string[]): Map; /** * Validate a complete spec file */ export declare function validateFullSpec(content: string): ValidationResult; /** * Validate all specs in a directory */ export declare function validateSpecsDirectory(specsDir: string): Promise<{ valid: boolean; results: Map; }>; /** * Create a new OpenSpec compatibility helper */ export declare function createOpenSpecCompat(projectRoot: string): { validator: OpenSpecValidator; configManager: OpenSpecConfigManager; }; //# sourceMappingURL=openspec-compat.d.ts.map