import { promises as fs } from 'fs';
import path from 'path';
import { Storage } from './storage.js';
import { DEFAULT_CONFIG } from '../types/config.js';
/**
* StorageManager provides auto-initialization capabilities for Storage instances.
* This avoids circular dependencies and maintains clean architecture by keeping
* the Storage class as a pure data layer component.
*/
export class StorageManager {
/**
* Creates and initializes a Storage instance, automatically setting up
* the required directory structure if it doesn't exist.
*/
static async createInitializedStorage(rootDir?: string): Promise<Storage> {
const storage = new Storage(rootDir);
try {
await storage.initialize();
return storage;
} catch (error) {
// Check if the error is due to missing initialization
if (error instanceof Error && error.message.includes('not initialized')) {
console.error('SpecLinter not initialized. Auto-initializing with default configuration...');
await this.autoInitialize(rootDir || process.cwd());
// Create a fresh Storage instance after auto-initialization
// This ensures the Storage instance sees the newly created directories
const freshStorage = new Storage(rootDir);
await freshStorage.initialize();
console.error('✅ SpecLinter auto-initialized successfully!');
return freshStorage;
}
// Re-throw other errors
throw error;
}
}
/**
* Performs minimal auto-initialization required for Storage to function.
* Only creates the essential directory structure and configuration.
*/
private static async autoInitialize(rootDir: string): Promise<void> {
const speclinterDir = path.join(rootDir, '.speclinter');
try {
// Create essential directory structure
const directories = [
'.speclinter',
'.speclinter/context',
'speclinter-tasks'
];
for (const dir of directories) {
const dirPath = path.join(rootDir, dir);
await fs.mkdir(dirPath, { recursive: true });
}
// Create default config if it doesn't exist
const configPath = path.join(speclinterDir, 'config.json');
try {
await fs.access(configPath);
// Config already exists, don't overwrite
} catch {
// Config doesn't exist, create it
await fs.writeFile(
configPath,
JSON.stringify(DEFAULT_CONFIG, null, 2)
);
}
// Create context directory (files will be AI-generated on first analysis)
await fs.mkdir(path.join(speclinterDir, 'context'), { recursive: true });
// Create .gitignore for speclinter if it doesn't exist
const gitignorePath = path.join(speclinterDir, '.gitignore');
try {
await fs.access(gitignorePath);
// .gitignore already exists, don't overwrite
} catch {
// .gitignore doesn't exist, create it
await fs.writeFile(gitignorePath, '*.db\n*.db-journal\n');
}
} catch (error) {
throw new Error(
`Failed to auto-initialize SpecLinter: ${error instanceof Error ? error.message : 'Unknown error'}`
);
}
}
// Template creation removed in Option A implementation
// Context files are now generated by AI analysis instead of generic templates
}