@kjerneverk/riotplan-format 1.0.0-dev.0

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,"file":"index.js","sources":["../src/config.ts","../src/storage/sqlite-provider.ts","../src/storage/directory-provider.ts","../src/storage/utils.ts","../src/storage/factory.ts","../src/migration/validator.ts","../src/migration/migrator.ts","../src/renderer/markdown.ts","../src/index.ts"],"sourcesContent":["/**\n * Configuration types for RiotPlan format selection\n * \n * These types define the configuration options for storage format selection\n * and format-specific settings.\n */\n\nimport type { StorageFormat } from './types.js';\n\n/**\n * Configuration options for SQLite storage\n */\nexport interface SqliteConfig {\n /** Enable WAL mode for better concurrency (default: true) */\n walMode?: boolean;\n \n /** SQLite pragma settings */\n pragmas?: Record<string, string | number | boolean>;\n \n /** File extension for SQLite plan files (default: '.plan') */\n extension?: string;\n}\n\n/**\n * Configuration options for directory storage\n */\nexport interface DirectoryConfig {\n /** Create plan subdirectory by default (default: true) */\n usePlanSubdir?: boolean;\n \n /** Default directory permissions (default: '0755') */\n permissions?: string;\n}\n\n/**\n * Format-related configuration for RiotPlan\n */\nexport interface FormatConfig {\n /** Default plan storage format (default: 'directory') */\n defaultFormat?: StorageFormat;\n \n /** SQLite-specific options */\n sqlite?: SqliteConfig;\n \n /** Directory-specific options */\n directory?: DirectoryConfig;\n}\n\n/**\n * Default SQLite configuration\n */\nexport const DEFAULT_SQLITE_CONFIG: Required<SqliteConfig> = {\n walMode: true,\n pragmas: {\n 'journal_mode': 'WAL',\n 'synchronous': 'NORMAL',\n 'foreign_keys': true,\n 'temp_store': 'memory',\n },\n extension: '.plan',\n};\n\n/**\n * Default directory configuration\n */\nexport const DEFAULT_DIRECTORY_CONFIG: Required<DirectoryConfig> = {\n usePlanSubdir: true,\n permissions: '0755',\n};\n\n/**\n * Resolved format configuration with all fields required\n */\nexport interface ResolvedFormatConfig {\n defaultFormat: StorageFormat;\n sqlite: Required<SqliteConfig>;\n directory: Required<DirectoryConfig>;\n}\n\n/**\n * Default format configuration\n */\nexport const DEFAULT_FORMAT_CONFIG: ResolvedFormatConfig = {\n defaultFormat: 'directory',\n sqlite: DEFAULT_SQLITE_CONFIG,\n directory: DEFAULT_DIRECTORY_CONFIG,\n};\n\n/**\n * Merge user config with defaults\n */\nexport function mergeFormatConfig(userConfig?: Partial<FormatConfig>): ResolvedFormatConfig {\n if (!userConfig) {\n return DEFAULT_FORMAT_CONFIG;\n }\n\n return {\n defaultFormat: userConfig.defaultFormat ?? DEFAULT_FORMAT_CONFIG.defaultFormat,\n sqlite: {\n ...DEFAULT_SQLITE_CONFIG,\n ...userConfig.sqlite,\n pragmas: {\n ...DEFAULT_SQLITE_CONFIG.pragmas,\n ...userConfig.sqlite?.pragmas,\n },\n },\n directory: {\n ...DEFAULT_DIRECTORY_CONFIG,\n ...userConfig.directory,\n },\n };\n}\n","/**\n * SQLite Storage Provider\n * \n * Implements the StorageProvider interface using SQLite (better-sqlite3)\n * for storing plans in a single .plan file.\n */\n\nimport Database from 'better-sqlite3';\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport type {\n PlanMetadata,\n PlanStep,\n PlanFile,\n TimelineEvent,\n EvidenceRecord,\n FeedbackRecord,\n Checkpoint,\n CheckpointSnapshot,\n StorageResult,\n} from '../types.js';\nimport type { StorageProvider, SearchResult } from './provider.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * SQLite-based storage provider for .plan files\n */\nexport class SqliteStorageProvider implements StorageProvider {\n readonly format = 'sqlite' as const;\n readonly path: string;\n private db: Database.Database;\n private planId: number | null = null;\n\n constructor(planPath: string) {\n this.path = planPath;\n this.db = new Database(planPath);\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n }\n\n /**\n * Initialize the database with schema\n */\n private initializeSchema(): void {\n const schemaPath = join(__dirname, 'schema.sql');\n const schema = readFileSync(schemaPath, 'utf-8');\n this.db.exec(schema);\n }\n\n /**\n * Get the plan ID, loading it if necessary\n */\n private getPlanId(): number {\n if (this.planId !== null) {\n return this.planId;\n }\n \n const row = this.db.prepare('SELECT id FROM plans LIMIT 1').get() as { id: number } | undefined;\n if (!row) {\n throw new Error('No plan found in database');\n }\n this.planId = row.id;\n return this.planId;\n }\n\n // ==================== Core Operations ====================\n\n async exists(): Promise<boolean> {\n try {\n const row = this.db.prepare('SELECT COUNT(*) as count FROM plans').get() as { count: number };\n return row.count > 0;\n } catch {\n return false;\n }\n }\n\n async initialize(metadata: PlanMetadata): Promise<StorageResult<void>> {\n try {\n this.initializeSchema();\n \n const stmt = this.db.prepare(`\n INSERT INTO plans (code, name, description, stage, created_at, updated_at, schema_version)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n \n const result = stmt.run(\n metadata.id,\n metadata.name,\n metadata.description || null,\n metadata.stage,\n metadata.createdAt,\n metadata.updatedAt,\n metadata.schemaVersion\n );\n \n this.planId = result.lastInsertRowid as number;\n \n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to initialize plan' \n };\n }\n }\n\n async close(): Promise<void> {\n this.db.close();\n }\n\n // ==================== Metadata Operations ====================\n\n async getMetadata(): Promise<StorageResult<PlanMetadata>> {\n try {\n const row = this.db.prepare(`\n SELECT code, name, description, stage, created_at, updated_at, schema_version\n FROM plans WHERE id = ?\n `).get(this.getPlanId()) as {\n code: string;\n name: string;\n description: string | null;\n stage: string;\n created_at: string;\n updated_at: string;\n schema_version: number;\n } | undefined;\n\n if (!row) {\n return { success: false, error: 'Plan not found' };\n }\n\n return {\n success: true,\n data: {\n id: row.code,\n name: row.name,\n description: row.description || undefined,\n stage: row.stage as PlanMetadata['stage'],\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n schemaVersion: row.schema_version,\n }\n };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get metadata' \n };\n }\n }\n\n async updateMetadata(metadata: Partial<PlanMetadata>): Promise<StorageResult<void>> {\n try {\n const updates: string[] = [];\n const values: unknown[] = [];\n\n if (metadata.name !== undefined) {\n updates.push('name = ?');\n values.push(metadata.name);\n }\n if (metadata.description !== undefined) {\n updates.push('description = ?');\n values.push(metadata.description);\n }\n if (metadata.stage !== undefined) {\n updates.push('stage = ?');\n values.push(metadata.stage);\n }\n\n updates.push('updated_at = ?');\n values.push(new Date().toISOString());\n values.push(this.getPlanId());\n\n this.db.prepare(`UPDATE plans SET ${updates.join(', ')} WHERE id = ?`).run(...values);\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to update metadata' \n };\n }\n }\n\n // ==================== Step Operations ====================\n\n async getSteps(): Promise<StorageResult<PlanStep[]>> {\n try {\n const rows = this.db.prepare(`\n SELECT number, code, title, description, status, started_at, completed_at, content\n FROM plan_steps WHERE plan_id = ? ORDER BY number\n `).all(this.getPlanId()) as Array<{\n number: number;\n code: string;\n title: string;\n description: string | null;\n status: string;\n started_at: string | null;\n completed_at: string | null;\n content: string;\n }>;\n\n const steps: PlanStep[] = rows.map(row => ({\n number: row.number,\n code: row.code,\n title: row.title,\n description: row.description || undefined,\n status: row.status as PlanStep['status'],\n startedAt: row.started_at || undefined,\n completedAt: row.completed_at || undefined,\n content: row.content,\n }));\n\n return { success: true, data: steps };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get steps' \n };\n }\n }\n\n async getStep(number: number): Promise<StorageResult<PlanStep | null>> {\n try {\n const row = this.db.prepare(`\n SELECT number, code, title, description, status, started_at, completed_at, content\n FROM plan_steps WHERE plan_id = ? AND number = ?\n `).get(this.getPlanId(), number) as {\n number: number;\n code: string;\n title: string;\n description: string | null;\n status: string;\n started_at: string | null;\n completed_at: string | null;\n content: string;\n } | undefined;\n\n if (!row) {\n return { success: true, data: null };\n }\n\n return {\n success: true,\n data: {\n number: row.number,\n code: row.code,\n title: row.title,\n description: row.description || undefined,\n status: row.status as PlanStep['status'],\n startedAt: row.started_at || undefined,\n completedAt: row.completed_at || undefined,\n content: row.content,\n }\n };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get step' \n };\n }\n }\n\n async addStep(step: PlanStep): Promise<StorageResult<void>> {\n try {\n this.db.prepare(`\n INSERT INTO plan_steps (plan_id, number, code, title, description, status, started_at, completed_at, content)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n this.getPlanId(),\n step.number,\n step.code,\n step.title,\n step.description || null,\n step.status,\n step.startedAt || null,\n step.completedAt || null,\n step.content\n );\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to add step' \n };\n }\n }\n\n async updateStep(number: number, updates: Partial<PlanStep>): Promise<StorageResult<void>> {\n try {\n const fields: string[] = [];\n const values: unknown[] = [];\n\n if (updates.code !== undefined) {\n fields.push('code = ?');\n values.push(updates.code);\n }\n if (updates.title !== undefined) {\n fields.push('title = ?');\n values.push(updates.title);\n }\n if (updates.description !== undefined) {\n fields.push('description = ?');\n values.push(updates.description);\n }\n if (updates.status !== undefined) {\n fields.push('status = ?');\n values.push(updates.status);\n }\n if (updates.startedAt !== undefined) {\n fields.push('started_at = ?');\n values.push(updates.startedAt);\n }\n if (updates.completedAt !== undefined) {\n fields.push('completed_at = ?');\n values.push(updates.completedAt);\n }\n if (updates.content !== undefined) {\n fields.push('content = ?');\n values.push(updates.content);\n }\n\n if (fields.length === 0) {\n return { success: true };\n }\n\n values.push(this.getPlanId(), number);\n this.db.prepare(`UPDATE plan_steps SET ${fields.join(', ')} WHERE plan_id = ? AND number = ?`).run(...values);\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to update step' \n };\n }\n }\n\n async deleteStep(number: number): Promise<StorageResult<void>> {\n try {\n this.db.prepare('DELETE FROM plan_steps WHERE plan_id = ? AND number = ?').run(this.getPlanId(), number);\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to delete step' \n };\n }\n }\n\n // ==================== File Operations ====================\n\n async getFiles(): Promise<StorageResult<PlanFile[]>> {\n try {\n const rows = this.db.prepare(`\n SELECT file_type, filename, content, created_at, updated_at\n FROM plan_files WHERE plan_id = ?\n `).all(this.getPlanId()) as Array<{\n file_type: string;\n filename: string;\n content: string;\n created_at: string;\n updated_at: string;\n }>;\n\n const files: PlanFile[] = rows.map(row => ({\n type: row.file_type as PlanFile['type'],\n filename: row.filename,\n content: row.content,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }));\n\n return { success: true, data: files };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get files' \n };\n }\n }\n\n async getFile(type: string, filename: string): Promise<StorageResult<PlanFile | null>> {\n try {\n const row = this.db.prepare(`\n SELECT file_type, filename, content, created_at, updated_at\n FROM plan_files WHERE plan_id = ? AND file_type = ? AND filename = ?\n `).get(this.getPlanId(), type, filename) as {\n file_type: string;\n filename: string;\n content: string;\n created_at: string;\n updated_at: string;\n } | undefined;\n\n if (!row) {\n return { success: true, data: null };\n }\n\n return {\n success: true,\n data: {\n type: row.file_type as PlanFile['type'],\n filename: row.filename,\n content: row.content,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n }\n };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get file' \n };\n }\n }\n\n async saveFile(file: PlanFile): Promise<StorageResult<void>> {\n try {\n this.db.prepare(`\n INSERT INTO plan_files (plan_id, file_type, filename, content, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(plan_id, file_type, filename) DO UPDATE SET\n content = excluded.content,\n updated_at = excluded.updated_at\n `).run(\n this.getPlanId(),\n file.type,\n file.filename,\n file.content,\n file.createdAt,\n file.updatedAt\n );\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to save file' \n };\n }\n }\n\n async deleteFile(type: string, filename: string): Promise<StorageResult<void>> {\n try {\n this.db.prepare('DELETE FROM plan_files WHERE plan_id = ? AND file_type = ? AND filename = ?')\n .run(this.getPlanId(), type, filename);\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to delete file' \n };\n }\n }\n\n // ==================== Timeline Operations ====================\n\n async getTimelineEvents(options?: {\n since?: string;\n type?: string;\n limit?: number;\n }): Promise<StorageResult<TimelineEvent[]>> {\n try {\n let sql = 'SELECT id, timestamp, event_type, data FROM timeline_events WHERE plan_id = ?';\n const params: unknown[] = [this.getPlanId()];\n\n if (options?.since) {\n sql += ' AND timestamp >= ?';\n params.push(options.since);\n }\n if (options?.type) {\n sql += ' AND event_type = ?';\n params.push(options.type);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n if (options?.limit) {\n sql += ' LIMIT ?';\n params.push(options.limit);\n }\n\n const rows = this.db.prepare(sql).all(...params) as Array<{\n id: string;\n timestamp: string;\n event_type: string;\n data: string;\n }>;\n\n const events: TimelineEvent[] = rows.map(row => ({\n id: row.id,\n timestamp: row.timestamp,\n type: row.event_type as TimelineEvent['type'],\n data: JSON.parse(row.data),\n }));\n\n return { success: true, data: events };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get timeline events' \n };\n }\n }\n\n async addTimelineEvent(event: TimelineEvent): Promise<StorageResult<void>> {\n try {\n this.db.prepare(`\n INSERT INTO timeline_events (id, plan_id, timestamp, event_type, data)\n VALUES (?, ?, ?, ?, ?)\n `).run(\n event.id || randomUUID(),\n this.getPlanId(),\n event.timestamp,\n event.type,\n JSON.stringify(event.data)\n );\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to add timeline event' \n };\n }\n }\n\n // ==================== Evidence Operations ====================\n\n async getEvidence(): Promise<StorageResult<EvidenceRecord[]>> {\n try {\n const rows = this.db.prepare(`\n SELECT id, description, source, source_url, gathering_method, content, file_path, \n relevance_score, original_query, summary, created_at\n FROM evidence_records WHERE plan_id = ?\n `).all(this.getPlanId()) as Array<{\n id: string;\n description: string;\n source: string | null;\n source_url: string | null;\n gathering_method: string | null;\n content: string | null;\n file_path: string | null;\n relevance_score: number | null;\n original_query: string | null;\n summary: string | null;\n created_at: string;\n }>;\n\n const evidence: EvidenceRecord[] = rows.map(row => ({\n id: row.id,\n description: row.description,\n source: row.source || undefined,\n sourceUrl: row.source_url || undefined,\n gatheringMethod: row.gathering_method as EvidenceRecord['gatheringMethod'],\n content: row.content || undefined,\n filePath: row.file_path || undefined,\n relevanceScore: row.relevance_score ?? undefined,\n originalQuery: row.original_query || undefined,\n summary: row.summary || undefined,\n createdAt: row.created_at,\n }));\n\n return { success: true, data: evidence };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get evidence' \n };\n }\n }\n\n async addEvidence(evidence: EvidenceRecord): Promise<StorageResult<void>> {\n try {\n this.db.prepare(`\n INSERT INTO evidence_records (id, plan_id, description, source, source_url, gathering_method, \n content, file_path, relevance_score, original_query, summary, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n evidence.id || randomUUID(),\n this.getPlanId(),\n evidence.description,\n evidence.source || null,\n evidence.sourceUrl || null,\n evidence.gatheringMethod || null,\n evidence.content || null,\n evidence.filePath || null,\n evidence.relevanceScore ?? null,\n evidence.originalQuery || null,\n evidence.summary || null,\n evidence.createdAt\n );\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to add evidence' \n };\n }\n }\n\n // ==================== Feedback Operations ====================\n\n async getFeedback(): Promise<StorageResult<FeedbackRecord[]>> {\n try {\n const rows = this.db.prepare(`\n SELECT id, title, platform, content, participants, created_at\n FROM feedback_records WHERE plan_id = ?\n `).all(this.getPlanId()) as Array<{\n id: string;\n title: string | null;\n platform: string | null;\n content: string;\n participants: string | null;\n created_at: string;\n }>;\n\n const feedback: FeedbackRecord[] = rows.map(row => ({\n id: row.id,\n title: row.title || undefined,\n platform: row.platform || undefined,\n content: row.content,\n participants: row.participants ? JSON.parse(row.participants) : undefined,\n createdAt: row.created_at,\n }));\n\n return { success: true, data: feedback };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get feedback' \n };\n }\n }\n\n async addFeedback(feedback: FeedbackRecord): Promise<StorageResult<void>> {\n try {\n this.db.prepare(`\n INSERT INTO feedback_records (id, plan_id, title, platform, content, participants, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `).run(\n feedback.id || randomUUID(),\n this.getPlanId(),\n feedback.title || null,\n feedback.platform || null,\n feedback.content,\n feedback.participants ? JSON.stringify(feedback.participants) : null,\n feedback.createdAt\n );\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to add feedback' \n };\n }\n }\n\n // ==================== Checkpoint Operations ====================\n\n async getCheckpoints(): Promise<StorageResult<Checkpoint[]>> {\n try {\n const rows = this.db.prepare(`\n SELECT name, message, created_at, snapshot\n FROM checkpoints WHERE plan_id = ? ORDER BY created_at DESC\n `).all(this.getPlanId()) as Array<{\n name: string;\n message: string;\n created_at: string;\n snapshot: string;\n }>;\n\n const checkpoints: Checkpoint[] = rows.map(row => ({\n name: row.name,\n message: row.message,\n createdAt: row.created_at,\n snapshot: JSON.parse(row.snapshot),\n }));\n\n return { success: true, data: checkpoints };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get checkpoints' \n };\n }\n }\n\n async getCheckpoint(name: string): Promise<StorageResult<Checkpoint | null>> {\n try {\n const row = this.db.prepare(`\n SELECT name, message, created_at, snapshot\n FROM checkpoints WHERE plan_id = ? AND name = ?\n `).get(this.getPlanId(), name) as {\n name: string;\n message: string;\n created_at: string;\n snapshot: string;\n } | undefined;\n\n if (!row) {\n return { success: true, data: null };\n }\n\n return {\n success: true,\n data: {\n name: row.name,\n message: row.message,\n createdAt: row.created_at,\n snapshot: JSON.parse(row.snapshot),\n }\n };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to get checkpoint' \n };\n }\n }\n\n async createCheckpoint(checkpoint: Checkpoint): Promise<StorageResult<void>> {\n try {\n this.db.prepare(`\n INSERT INTO checkpoints (plan_id, name, message, created_at, snapshot)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(plan_id, name) DO UPDATE SET\n message = excluded.message,\n created_at = excluded.created_at,\n snapshot = excluded.snapshot\n `).run(\n this.getPlanId(),\n checkpoint.name,\n checkpoint.message,\n checkpoint.createdAt,\n JSON.stringify(checkpoint.snapshot)\n );\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to create checkpoint' \n };\n }\n }\n\n async restoreCheckpoint(name: string): Promise<StorageResult<void>> {\n try {\n const checkpointResult = await this.getCheckpoint(name);\n if (!checkpointResult.success || !checkpointResult.data) {\n return { success: false, error: `Checkpoint not found: ${name}` };\n }\n\n const snapshot = checkpointResult.data.snapshot;\n const planId = this.getPlanId();\n\n // Use a transaction for atomic restore\n const restore = this.db.transaction(() => {\n // Restore metadata\n this.db.prepare(`\n UPDATE plans SET name = ?, description = ?, stage = ?, updated_at = ?\n WHERE id = ?\n `).run(\n snapshot.metadata.name,\n snapshot.metadata.description || null,\n snapshot.metadata.stage,\n new Date().toISOString(),\n planId\n );\n\n // Restore step statuses\n for (const step of snapshot.steps) {\n this.db.prepare(`\n UPDATE plan_steps SET status = ?, started_at = ?, completed_at = ?\n WHERE plan_id = ? AND number = ?\n `).run(\n step.status,\n step.startedAt || null,\n step.completedAt || null,\n planId,\n step.number\n );\n }\n\n // Restore files\n for (const file of snapshot.files) {\n this.db.prepare(`\n INSERT INTO plan_files (plan_id, file_type, filename, content, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(plan_id, file_type, filename) DO UPDATE SET\n content = excluded.content,\n updated_at = excluded.updated_at\n `).run(\n planId,\n file.type,\n file.filename,\n file.content,\n new Date().toISOString(),\n new Date().toISOString()\n );\n }\n });\n\n restore();\n\n return { success: true };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to restore checkpoint' \n };\n }\n }\n\n // ==================== Search Operations ====================\n\n async search(query: string): Promise<StorageResult<SearchResult[]>> {\n try {\n const results: SearchResult[] = [];\n const planId = this.getPlanId();\n const searchPattern = `%${query}%`;\n\n // Search steps\n const stepRows = this.db.prepare(`\n SELECT number, title, content FROM plan_steps\n WHERE plan_id = ? AND (title LIKE ? OR content LIKE ?)\n `).all(planId, searchPattern, searchPattern) as Array<{\n number: number;\n title: string;\n content: string;\n }>;\n\n for (const row of stepRows) {\n results.push({\n type: 'step',\n id: String(row.number),\n snippet: this.extractSnippet(row.content, query),\n score: this.calculateScore(row.content, query),\n });\n }\n\n // Search files\n const fileRows = this.db.prepare(`\n SELECT file_type, filename, content FROM plan_files\n WHERE plan_id = ? AND content LIKE ?\n `).all(planId, searchPattern) as Array<{\n file_type: string;\n filename: string;\n content: string;\n }>;\n\n for (const row of fileRows) {\n results.push({\n type: 'file',\n id: row.filename,\n snippet: this.extractSnippet(row.content, query),\n score: this.calculateScore(row.content, query),\n });\n }\n\n // Search evidence\n const evidenceRows = this.db.prepare(`\n SELECT id, description, content FROM evidence_records\n WHERE plan_id = ? AND (description LIKE ? OR content LIKE ?)\n `).all(planId, searchPattern, searchPattern) as Array<{\n id: string;\n description: string;\n content: string | null;\n }>;\n\n for (const row of evidenceRows) {\n results.push({\n type: 'evidence',\n id: row.id,\n snippet: this.extractSnippet(row.content || row.description, query),\n score: this.calculateScore(row.content || row.description, query),\n });\n }\n\n // Sort by score descending\n results.sort((a, b) => b.score - a.score);\n\n return { success: true, data: results };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : 'Failed to search' \n };\n }\n }\n\n private extractSnippet(content: string, query: string): string {\n const lowerContent = content.toLowerCase();\n const lowerQuery = query.toLowerCase();\n const index = lowerContent.indexOf(lowerQuery);\n \n if (index === -1) {\n return content.slice(0, 100) + '...';\n }\n\n const start = Math.max(0, index - 50);\n const end = Math.min(content.length, index + query.length + 50);\n let snippet = content.slice(start, end);\n \n if (start > 0) snippet = '...' + snippet;\n if (end < content.length) snippet = snippet + '...';\n \n return snippet;\n }\n\n private calculateScore(content: string, query: string): number {\n const lowerContent = content.toLowerCase();\n const lowerQuery = query.toLowerCase();\n \n // Count occurrences\n let count = 0;\n let pos = 0;\n while ((pos = lowerContent.indexOf(lowerQuery, pos)) !== -1) {\n count++;\n pos += lowerQuery.length;\n }\n\n // Normalize score (0-1)\n return Math.min(1, count / 10);\n }\n\n // ==================== Utility Methods ====================\n\n /**\n * Create a snapshot of the current plan state for checkpoints\n */\n async createSnapshot(): Promise<CheckpointSnapshot> {\n const metadataResult = await this.getMetadata();\n const stepsResult = await this.getSteps();\n const filesResult = await this.getFiles();\n\n if (!metadataResult.success || !metadataResult.data) {\n throw new Error('Failed to get metadata for snapshot');\n }\n\n return {\n metadata: metadataResult.data,\n steps: (stepsResult.data || []).map(s => ({\n number: s.number,\n status: s.status,\n startedAt: s.startedAt,\n completedAt: s.completedAt,\n })),\n files: (filesResult.data || []).map(f => ({\n type: f.type,\n filename: f.filename,\n content: f.content,\n })),\n };\n }\n}\n\n/**\n * Create a new SQLite storage provider\n */\nexport function createSqliteProvider(planPath: string): SqliteStorageProvider {\n return new SqliteStorageProvider(planPath);\n}\n","/**\n * Directory Storage Provider\n * \n * Provides storage operations for directory-based plan format.\n * This is a skeleton implementation - the full implementation will be\n * in the main riotplan package since it needs access to the existing\n * plan loading logic.\n */\n\nimport type { StorageProvider, SearchResult } from './provider.js';\nimport type { StorageResult } from '../types.js';\nimport type {\n PlanMetadata,\n PlanStep,\n PlanFile,\n TimelineEvent,\n EvidenceRecord,\n FeedbackRecord,\n Checkpoint,\n CheckpointSnapshot,\n StorageFormat,\n} from '../types.js';\n\n/**\n * Directory-based storage provider\n * \n * This provider stores plans as a directory structure with markdown files.\n * The directory structure follows the RiotPlan convention:\n * \n * ```\n * my-plan/\n * ├── SUMMARY.md\n * ├── STATUS.md\n * ├── IDEA.md (optional)\n * ├── SHAPING.md (optional)\n * ├── EXECUTION_PLAN.md (optional)\n * ├── plan/\n * │ ├── 01-step-one.md\n * │ ├── 02-step-two.md\n * │ └── ...\n * ├── evidence/\n * │ └── *.md\n * ├── feedback/\n * │ └── *.md\n * ├── reflections/\n * │ └── *.md\n * └── .history/\n * ├── timeline.json\n * └── checkpoints/\n * └── *.json\n * ```\n * \n * @remarks\n * This is a base implementation that throws \"not implemented\" errors.\n * The main riotplan package should extend this class and implement\n * the methods using its existing file loading logic.\n */\nexport class DirectoryStorageProvider implements StorageProvider {\n readonly format: StorageFormat = 'directory';\n readonly path: string;\n\n constructor(planPath: string) {\n this.path = planPath;\n }\n\n async exists(): Promise<boolean> {\n throw new Error('DirectoryStorageProvider.exists() not implemented - use main riotplan package');\n }\n\n async initialize(_metadata: PlanMetadata): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.initialize() not implemented - use main riotplan package');\n }\n\n async close(): Promise<void> {\n // No-op for directory provider\n }\n\n // Metadata operations\n async getMetadata(): Promise<StorageResult<PlanMetadata>> {\n throw new Error('DirectoryStorageProvider.getMetadata() not implemented - use main riotplan package');\n }\n\n async updateMetadata(_updates: Partial<PlanMetadata>): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.updateMetadata() not implemented - use main riotplan package');\n }\n\n // Step operations\n async getSteps(): Promise<StorageResult<PlanStep[]>> {\n throw new Error('DirectoryStorageProvider.getSteps() not implemented - use main riotplan package');\n }\n\n async getStep(_number: number): Promise<StorageResult<PlanStep | null>> {\n throw new Error('DirectoryStorageProvider.getStep() not implemented - use main riotplan package');\n }\n\n async addStep(_step: PlanStep): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.addStep() not implemented - use main riotplan package');\n }\n\n async updateStep(_number: number, _updates: Partial<PlanStep>): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.updateStep() not implemented - use main riotplan package');\n }\n\n async deleteStep(_number: number): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.deleteStep() not implemented - use main riotplan package');\n }\n\n // File operations\n async getFiles(): Promise<StorageResult<PlanFile[]>> {\n throw new Error('DirectoryStorageProvider.getFiles() not implemented - use main riotplan package');\n }\n\n async getFile(_type: string, _filename: string): Promise<StorageResult<PlanFile | null>> {\n throw new Error('DirectoryStorageProvider.getFile() not implemented - use main riotplan package');\n }\n\n async saveFile(_file: PlanFile): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.saveFile() not implemented - use main riotplan package');\n }\n\n async deleteFile(_type: string, _filename: string): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.deleteFile() not implemented - use main riotplan package');\n }\n\n // Timeline operations\n async getTimelineEvents(): Promise<StorageResult<TimelineEvent[]>> {\n throw new Error('DirectoryStorageProvider.getTimelineEvents() not implemented - use main riotplan package');\n }\n\n async addTimelineEvent(_event: TimelineEvent): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.addTimelineEvent() not implemented - use main riotplan package');\n }\n\n // Evidence operations\n async getEvidence(): Promise<StorageResult<EvidenceRecord[]>> {\n throw new Error('DirectoryStorageProvider.getEvidence() not implemented - use main riotplan package');\n }\n\n async addEvidence(_evidence: EvidenceRecord): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.addEvidence() not implemented - use main riotplan package');\n }\n\n // Feedback operations\n async getFeedback(): Promise<StorageResult<FeedbackRecord[]>> {\n throw new Error('DirectoryStorageProvider.getFeedback() not implemented - use main riotplan package');\n }\n\n async addFeedback(_feedback: FeedbackRecord): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.addFeedback() not implemented - use main riotplan package');\n }\n\n // Checkpoint operations\n async getCheckpoints(): Promise<StorageResult<Checkpoint[]>> {\n throw new Error('DirectoryStorageProvider.getCheckpoints() not implemented - use main riotplan package');\n }\n\n async getCheckpoint(_name: string): Promise<StorageResult<Checkpoint | null>> {\n throw new Error('DirectoryStorageProvider.getCheckpoint() not implemented - use main riotplan package');\n }\n\n async createCheckpoint(_checkpoint: Checkpoint): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.createCheckpoint() not implemented - use main riotplan package');\n }\n\n async restoreCheckpoint(_name: string): Promise<StorageResult<void>> {\n throw new Error('DirectoryStorageProvider.restoreCheckpoint() not implemented - use main riotplan package');\n }\n\n // Search operations\n async search(_query: string): Promise<StorageResult<SearchResult[]>> {\n throw new Error('DirectoryStorageProvider.search() not implemented - use main riotplan package');\n }\n\n // Snapshot operations\n async createSnapshot(): Promise<CheckpointSnapshot> {\n throw new Error('DirectoryStorageProvider.createSnapshot() not implemented - use main riotplan package');\n }\n}\n\n/**\n * Create a directory storage provider\n * \n * @param planPath - Path to the plan directory\n * @returns A directory storage provider instance\n * \n * @remarks\n * This creates a base provider that throws \"not implemented\" errors.\n * Use the implementation from the main riotplan package for actual functionality.\n */\nexport function createDirectoryProvider(planPath: string): DirectoryStorageProvider {\n return new DirectoryStorageProvider(planPath);\n}\n","/**\n * Storage utility functions\n * \n * Provides utilities for format detection, path handling, and storage operations.\n */\n\nimport { existsSync, statSync, readFileSync } from 'node:fs';\nimport { join, extname } from 'node:path';\nimport type { StorageFormat } from '../types.js';\nimport type { FormatConfig } from '../config.js';\nimport { DEFAULT_FORMAT_CONFIG } from '../config.js';\n\n/**\n * SQLite file header magic bytes\n * SQLite databases start with \"SQLite format 3\\0\"\n */\nconst SQLITE_HEADER = Buffer.from('SQLite format 3\\0');\n\n/**\n * Known plan file markers for directory format\n */\nconst DIRECTORY_PLAN_MARKERS = [\n 'SUMMARY.md',\n 'STATUS.md',\n 'IDEA.md',\n 'EXECUTION_PLAN.md',\n];\n\n/**\n * Detect the format of a plan at the given path\n * \n * @param planPath - Path to check\n * @returns The detected format or 'unknown' if not a valid plan\n */\nexport function detectPlanFormat(planPath: string): StorageFormat | 'unknown' {\n if (!existsSync(planPath)) {\n return 'unknown';\n }\n\n const stats = statSync(planPath);\n\n if (stats.isDirectory()) {\n // Check if directory contains plan files\n for (const marker of DIRECTORY_PLAN_MARKERS) {\n if (existsSync(join(planPath, marker))) {\n return 'directory';\n }\n }\n // Also check for plan/ subdirectory with step files\n const planDir = join(planPath, 'plan');\n if (existsSync(planDir) && statSync(planDir).isDirectory()) {\n return 'directory';\n }\n return 'unknown';\n }\n\n if (stats.isFile()) {\n // Check for SQLite header\n if (hasSqliteHeader(planPath)) {\n return 'sqlite';\n }\n // Check file extension\n if (planPath.endsWith('.plan')) {\n // File has .plan extension but isn't SQLite - might be empty or corrupted\n return 'unknown';\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Check if a file has a valid SQLite header\n * \n * @param filePath - Path to the file\n * @returns True if the file starts with SQLite magic bytes\n */\nexport function hasSqliteHeader(filePath: string): boolean {\n try {\n const fd = readFileSync(filePath, { flag: 'r' });\n if (fd.length < SQLITE_HEADER.length) {\n return false;\n }\n return fd.subarray(0, SQLITE_HEADER.length).equals(SQLITE_HEADER);\n } catch {\n return false;\n }\n}\n\n/**\n * Check if a path looks like it should be a SQLite plan file\n * \n * @param planPath - Path to check\n * @param config - Optional format configuration\n * @returns True if the path has a SQLite plan extension\n */\nexport function isSqlitePath(planPath: string, config?: FormatConfig): boolean {\n const extension: string = config?.sqlite?.extension ?? DEFAULT_FORMAT_CONFIG.sqlite.extension;\n return planPath.endsWith(extension);\n}\n\n/**\n * Check if a path looks like it should be a directory plan\n * \n * @param planPath - Path to check\n * @returns True if the path exists and is a directory, or doesn't have a file extension\n */\nexport function isDirectoryPath(planPath: string): boolean {\n if (existsSync(planPath)) {\n return statSync(planPath).isDirectory();\n }\n // If path doesn't exist, check if it has a file extension\n const ext = extname(planPath);\n return ext === '' || ext === '.';\n}\n\n/**\n * Get the appropriate file extension for a format\n * \n * @param format - The storage format\n * @param config - Optional format configuration\n * @returns The file extension (empty string for directory format)\n */\nexport function getFormatExtension(format: StorageFormat, config?: FormatConfig): string {\n if (format === 'sqlite') {\n const extension: string = config?.sqlite?.extension ?? DEFAULT_FORMAT_CONFIG.sqlite.extension;\n return extension;\n }\n return ''; // directories don't have extensions\n}\n\n/**\n * Ensure a path has the correct extension for the format\n * \n * @param planPath - The plan path\n * @param format - The storage format\n * @param config - Optional format configuration\n * @returns The path with the correct extension\n */\nexport function ensureFormatExtension(\n planPath: string,\n format: StorageFormat,\n config?: FormatConfig\n): string {\n if (format === 'sqlite') {\n const extension = getFormatExtension(format, config);\n if (!planPath.endsWith(extension)) {\n return `${planPath}${extension}`;\n }\n }\n return planPath;\n}\n\n/**\n * Infer the format from a path based on extension and existence\n * \n * @param planPath - The plan path\n * @param config - Optional format configuration\n * @returns The inferred format\n */\nexport function inferFormatFromPath(planPath: string, config?: FormatConfig): StorageFormat {\n // First check if it exists and detect actual format\n if (existsSync(planPath)) {\n const detected = detectPlanFormat(planPath);\n if (detected !== 'unknown') {\n return detected;\n }\n }\n\n // Infer from path characteristics\n if (isSqlitePath(planPath, config)) {\n return 'sqlite';\n }\n\n if (isDirectoryPath(planPath)) {\n return 'directory';\n }\n\n // Default to config preference\n return config?.defaultFormat ?? DEFAULT_FORMAT_CONFIG.defaultFormat;\n}\n\n/**\n * Validate that a plan path is valid for the given format\n * \n * @param planPath - The plan path\n * @param format - The expected format\n * @param config - Optional format configuration\n * @returns An error message if invalid, or null if valid\n */\nexport function validatePlanPath(\n planPath: string,\n format: StorageFormat,\n config?: FormatConfig\n): string | null {\n if (!planPath || planPath.trim() === '') {\n return 'Plan path cannot be empty';\n }\n\n if (format === 'sqlite') {\n const extension = getFormatExtension(format, config);\n if (!planPath.endsWith(extension)) {\n return `SQLite plan path must end with ${extension}`;\n }\n }\n\n if (format === 'directory') {\n const ext = extname(planPath);\n if (ext && ext !== '.') {\n return `Directory plan path should not have a file extension (got ${ext})`;\n }\n }\n\n return null;\n}\n\n/**\n * Get plan name from path\n * \n * @param planPath - The plan path\n * @param format - The storage format\n * @param config - Optional format configuration\n * @returns The plan name extracted from the path\n */\nexport function getPlanNameFromPath(\n planPath: string,\n format: StorageFormat,\n config?: FormatConfig\n): string {\n // Remove extension if present\n let name = planPath;\n \n if (format === 'sqlite') {\n const extension = getFormatExtension(format, config);\n if (name.endsWith(extension)) {\n name = name.slice(0, -extension.length);\n }\n }\n\n // Get the last path component\n const parts = name.split(/[/\\\\]/);\n return parts[parts.length - 1] || name;\n}\n","/**\n * Storage Provider Factory\n * \n * Creates storage providers based on path and configuration.\n */\n\nimport type { StorageProvider, StorageProviderFactory } from './provider.js';\nimport { SqliteStorageProvider } from './sqlite-provider.js';\nimport type { FormatConfig, ResolvedFormatConfig } from '../config.js';\nimport { mergeFormatConfig } from '../config.js';\nimport {\n detectPlanFormat,\n isSqlitePath,\n isDirectoryPath,\n ensureFormatExtension,\n inferFormatFromPath,\n} from './utils.js';\nimport type { StorageFormat } from '../types.js';\n\n/**\n * Options for creating a storage provider\n */\nexport interface CreateProviderOptions {\n /** Force a specific format instead of auto-detecting */\n format?: StorageFormat;\n /** Create the plan if it doesn't exist */\n create?: boolean;\n}\n\n/**\n * Default storage provider factory implementation\n * \n * Creates appropriate storage providers based on path characteristics\n * and configuration preferences.\n */\nexport class DefaultStorageProviderFactory implements StorageProviderFactory {\n private config: ResolvedFormatConfig;\n\n constructor(config?: Partial<FormatConfig>) {\n this.config = mergeFormatConfig(config);\n }\n\n /**\n * Create a storage provider for the given path\n * \n * @param planPath - Path to the plan\n * @param options - Optional creation options\n * @returns A storage provider instance\n */\n createProvider(planPath: string, options?: CreateProviderOptions): StorageProvider {\n const format = this.determineFormat(planPath, options?.format);\n \n if (format === 'sqlite') {\n const finalPath = ensureFormatExtension(planPath, 'sqlite', this.config);\n return new SqliteStorageProvider(finalPath);\n }\n \n // For directory format, we would return a DirectoryStorageProvider\n // This will be implemented when integrating with the main riotplan package\n throw new Error(\n 'Directory storage provider is not yet implemented in riotplan-format. ' +\n 'Use the main riotplan package for directory-based plans.'\n );\n }\n\n /**\n * Check if this factory supports the given path\n * \n * @param planPath - Path to check\n * @returns True if a provider can be created for this path\n */\n supportsPath(planPath: string): boolean {\n const format = detectPlanFormat(planPath);\n if (format !== 'unknown') {\n return true;\n }\n \n // Check if path looks like it could be a plan\n return isSqlitePath(planPath, this.config) || isDirectoryPath(planPath);\n }\n\n /**\n * Determine the format to use for a path\n * \n * @param planPath - The plan path\n * @param forcedFormat - Optional format override\n * @returns The format to use\n */\n private determineFormat(planPath: string, forcedFormat?: StorageFormat): StorageFormat {\n // If format is explicitly specified, use it\n if (forcedFormat) {\n return forcedFormat;\n }\n\n // Try to detect from existing plan\n const detected = detectPlanFormat(planPath);\n if (detected !== 'unknown') {\n return detected;\n }\n\n // Infer from path characteristics\n return inferFormatFromPath(planPath, this.config);\n }\n\n /**\n * Get the default format from configuration\n */\n get defaultFormat(): StorageFormat {\n return this.config.defaultFormat;\n }\n\n /**\n * Get the SQLite configuration\n */\n get sqliteConfig() {\n return this.config.sqlite;\n }\n\n /**\n * Get the directory configuration\n */\n get directoryConfig() {\n return this.config.directory;\n }\n}\n\n/**\n * Create a storage provider factory with the given configuration\n * \n * @param config - Optional format configuration\n * @returns A storage provider factory\n */\nexport function createStorageFactory(config?: Partial<FormatConfig>): DefaultStorageProviderFactory {\n return new DefaultStorageProviderFactory(config);\n}\n\n/**\n * Create a storage provider for the given path using default configuration\n * \n * This is a convenience function for simple use cases.\n * \n * @param planPath - Path to the plan\n * @param options - Optional creation options\n * @returns A storage provider instance\n */\nexport function createProvider(\n planPath: string,\n options?: CreateProviderOptions & { config?: Partial<FormatConfig> }\n): StorageProvider {\n const factory = createStorageFactory(options?.config);\n return factory.createProvider(planPath, options);\n}\n","/**\n * Migration Validator\n * \n * Validates that migration preserved all data correctly.\n */\n\nimport type { StorageProvider } from '../storage/provider.js';\nimport type { ValidationResult, ValidationError } from './types.js';\n\n/**\n * Validates migration fidelity between source and target\n */\nexport class MigrationValidator {\n /**\n * Validate that target contains all data from source\n */\n async validate(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<ValidationResult> {\n const errors: ValidationError[] = [];\n const warnings: string[] = [];\n const stats = {\n stepsCompared: 0,\n filesCompared: 0,\n timelineEventsCompared: 0,\n evidenceCompared: 0,\n feedbackCompared: 0,\n };\n\n // Validate metadata\n await this.validateMetadata(source, target, errors);\n\n // Validate steps\n const stepsResult = await this.validateSteps(source, target, errors);\n stats.stepsCompared = stepsResult;\n\n // Validate files\n const filesResult = await this.validateFiles(source, target, errors);\n stats.filesCompared = filesResult;\n\n // Validate timeline events\n const timelineResult = await this.validateTimeline(source, target, errors, warnings);\n stats.timelineEventsCompared = timelineResult;\n\n // Validate evidence\n const evidenceResult = await this.validateEvidence(source, target, errors);\n stats.evidenceCompared = evidenceResult;\n\n // Validate feedback\n const feedbackResult = await this.validateFeedback(source, target, errors);\n stats.feedbackCompared = feedbackResult;\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n stats,\n };\n }\n\n private async validateMetadata(\n source: StorageProvider,\n target: StorageProvider,\n errors: ValidationError[]\n ): Promise<void> {\n const sourceResult = await source.getMetadata();\n const targetResult = await target.getMetadata();\n\n if (!sourceResult.success || !sourceResult.data) {\n errors.push({\n type: 'metadata_difference',\n path: 'metadata',\n expected: 'valid metadata',\n actual: 'failed to read source metadata',\n message: 'Could not read source metadata',\n });\n return;\n }\n\n if (!targetResult.success || !targetResult.data) {\n errors.push({\n type: 'metadata_difference',\n path: 'metadata',\n expected: 'valid metadata',\n actual: 'failed to read target metadata',\n message: 'Could not read target metadata',\n });\n return;\n }\n\n const sourceData = sourceResult.data;\n const targetData = targetResult.data;\n\n if (sourceData.id !== targetData.id) {\n errors.push({\n type: 'metadata_difference',\n path: 'metadata.id',\n expected: sourceData.id,\n actual: targetData.id,\n message: `Plan ID mismatch: expected \"${sourceData.id}\", got \"${targetData.id}\"`,\n });\n }\n\n if (sourceData.name !== targetData.name) {\n errors.push({\n type: 'metadata_difference',\n path: 'metadata.name',\n expected: sourceData.name,\n actual: targetData.name,\n message: `Plan name mismatch: expected \"${sourceData.name}\", got \"${targetData.name}\"`,\n });\n }\n\n if (sourceData.stage !== targetData.stage) {\n errors.push({\n type: 'metadata_difference',\n path: 'metadata.stage',\n expected: sourceData.stage,\n actual: targetData.stage,\n message: `Plan stage mismatch: expected \"${sourceData.stage}\", got \"${targetData.stage}\"`,\n });\n }\n }\n\n private async validateSteps(\n source: StorageProvider,\n target: StorageProvider,\n errors: ValidationError[]\n ): Promise<number> {\n const sourceResult = await source.getSteps();\n const targetResult = await target.getSteps();\n\n if (!sourceResult.success || !sourceResult.data) {\n return 0;\n }\n\n const sourceSteps = sourceResult.data;\n const targetSteps = targetResult.data || [];\n\n for (const sourceStep of sourceSteps) {\n const targetStep = targetSteps.find(s => s.number === sourceStep.number);\n\n if (!targetStep) {\n errors.push({\n type: 'missing_step',\n path: `steps[${sourceStep.number}]`,\n expected: sourceStep,\n actual: null,\n message: `Step ${sourceStep.number} is missing in target`,\n });\n continue;\n }\n\n if (sourceStep.title !== targetStep.title) {\n errors.push({\n type: 'content_mismatch',\n path: `steps[${sourceStep.number}].title`,\n expected: sourceStep.title,\n actual: targetStep.title,\n message: `Step ${sourceStep.number} title mismatch`,\n });\n }\n\n if (sourceStep.status !== targetStep.status) {\n errors.push({\n type: 'content_mismatch',\n path: `steps[${sourceStep.number}].status`,\n expected: sourceStep.status,\n actual: targetStep.status,\n message: `Step ${sourceStep.number} status mismatch`,\n });\n }\n\n // Compare content (normalize whitespace for comparison)\n const sourceContent = sourceStep.content.trim();\n const targetContent = targetStep.content.trim();\n if (sourceContent !== targetContent) {\n errors.push({\n type: 'content_mismatch',\n path: `steps[${sourceStep.number}].content`,\n expected: `${sourceContent.length} chars`,\n actual: `${targetContent.length} chars`,\n message: `Step ${sourceStep.number} content mismatch`,\n });\n }\n }\n\n // Check for extra steps in target\n for (const targetStep of targetSteps) {\n const sourceStep = sourceSteps.find(s => s.number === targetStep.number);\n if (!sourceStep) {\n errors.push({\n type: 'content_mismatch',\n path: `steps[${targetStep.number}]`,\n expected: null,\n actual: targetStep,\n message: `Unexpected step ${targetStep.number} in target`,\n });\n }\n }\n\n return sourceSteps.length;\n }\n\n private async validateFiles(\n source: StorageProvider,\n target: StorageProvider,\n errors: ValidationError[]\n ): Promise<number> {\n const sourceResult = await source.getFiles();\n const targetResult = await target.getFiles();\n\n if (!sourceResult.success || !sourceResult.data) {\n return 0;\n }\n\n const sourceFiles = sourceResult.data;\n const targetFiles = targetResult.data || [];\n\n for (const sourceFile of sourceFiles) {\n const targetFile = targetFiles.find(\n f => f.type === sourceFile.type && f.filename === sourceFile.filename\n );\n\n if (!targetFile) {\n errors.push({\n type: 'missing_file',\n path: `files[${sourceFile.type}/${sourceFile.filename}]`,\n expected: sourceFile,\n actual: null,\n message: `File ${sourceFile.filename} (${sourceFile.type}) is missing in target`,\n });\n continue;\n }\n\n // Compare content\n const sourceContent = sourceFile.content.trim();\n const targetContent = targetFile.content.trim();\n if (sourceContent !== targetContent) {\n errors.push({\n type: 'content_mismatch',\n path: `files[${sourceFile.type}/${sourceFile.filename}].content`,\n expected: `${sourceContent.length} chars`,\n actual: `${targetContent.length} chars`,\n message: `File ${sourceFile.filename} content mismatch`,\n });\n }\n }\n\n return sourceFiles.length;\n }\n\n private async validateTimeline(\n source: StorageProvider,\n target: StorageProvider,\n errors: ValidationError[],\n warnings: string[]\n ): Promise<number> {\n const sourceResult = await source.getTimelineEvents();\n const targetResult = await target.getTimelineEvents();\n\n if (!sourceResult.success || !sourceResult.data) {\n return 0;\n }\n\n const sourceEvents = sourceResult.data;\n const targetEvents = targetResult.data || [];\n\n // Timeline events may have different IDs after migration, so compare by type and timestamp\n for (const sourceEvent of sourceEvents) {\n const targetEvent = targetEvents.find(\n e => e.type === sourceEvent.type && e.timestamp === sourceEvent.timestamp\n );\n\n if (!targetEvent) {\n // Timeline events might be regenerated, so this is a warning not an error\n warnings.push(\n `Timeline event ${sourceEvent.type} at ${sourceEvent.timestamp} not found in target`\n );\n }\n }\n\n return sourceEvents.length;\n }\n\n private async validateEvidence(\n source: StorageProvider,\n target: StorageProvider,\n errors: ValidationError[]\n ): Promise<number> {\n const sourceResult = await source.getEvidence();\n const targetResult = await target.getEvidence();\n\n if (!sourceResult.success || !sourceResult.data) {\n return 0;\n }\n\n const sourceEvidence = sourceResult.data;\n const targetEvidence = targetResult.data || [];\n\n for (const sourceItem of sourceEvidence) {\n const targetItem = targetEvidence.find(e => e.description === sourceItem.description);\n\n if (!targetItem) {\n errors.push({\n type: 'missing_file',\n path: `evidence[${sourceItem.id}]`,\n expected: sourceItem,\n actual: null,\n message: `Evidence \"${sourceItem.description}\" is missing in target`,\n });\n }\n }\n\n return sourceEvidence.length;\n }\n\n private async validateFeedback(\n source: StorageProvider,\n target: StorageProvider,\n errors: ValidationError[]\n ): Promise<number> {\n const sourceResult = await source.getFeedback();\n const targetResult = await target.getFeedback();\n\n if (!sourceResult.success || !sourceResult.data) {\n return 0;\n }\n\n const sourceFeedback = sourceResult.data;\n const targetFeedback = targetResult.data || [];\n\n for (const sourceItem of sourceFeedback) {\n const targetItem = targetFeedback.find(f => f.content === sourceItem.content);\n\n if (!targetItem) {\n errors.push({\n type: 'missing_file',\n path: `feedback[${sourceItem.id}]`,\n expected: sourceItem,\n actual: null,\n message: `Feedback \"${sourceItem.title || sourceItem.id}\" is missing in target`,\n });\n }\n }\n\n return sourceFeedback.length;\n }\n}\n\n/**\n * Create a migration validator\n */\nexport function createValidator(): MigrationValidator {\n return new MigrationValidator();\n}\n","/**\n * Plan Migrator\n * \n * Handles bidirectional conversion between directory and SQLite formats.\n */\n\nimport { existsSync, unlinkSync, rmSync } from 'node:fs';\nimport type { StorageProvider } from '../storage/provider.js';\nimport type { StorageFormat } from '../types.js';\nimport { ensureFormatExtension } from '../storage/utils.js';\nimport { MigrationValidator } from './validator.js';\nimport type {\n MigrationOptions,\n MigrationResult,\n MigrationStats,\n MigrationProgress,\n} from './types.js';\n\n/**\n * Migrates plans between directory and SQLite formats\n */\nexport class PlanMigrator {\n private validator: MigrationValidator;\n\n constructor() {\n this.validator = new MigrationValidator();\n }\n\n /**\n * Migrate a plan from source to target format\n * \n * @param sourcePath - Path to source plan\n * @param targetPath - Path for target plan\n * @param sourceProvider - Provider for reading source\n * @param targetProvider - Provider for writing target\n * @param options - Migration options\n */\n async migrate(\n sourcePath: string,\n targetPath: string,\n sourceProvider: StorageProvider,\n targetProvider: StorageProvider,\n options: MigrationOptions = {}\n ): Promise<MigrationResult> {\n const startTime = Date.now();\n const warnings: string[] = [];\n const stats: MigrationStats = {\n stepsConverted: 0,\n filesConverted: 0,\n timelineEventsConverted: 0,\n evidenceConverted: 0,\n feedbackConverted: 0,\n checkpointsConverted: 0,\n };\n\n try {\n // Detect formats\n const sourceFormat = sourceProvider.format;\n const targetFormat = targetProvider.format;\n\n // Check if target exists\n const targetExists = await targetProvider.exists();\n if (targetExists && !options.force) {\n return {\n success: false,\n sourceFormat,\n targetFormat,\n sourcePath,\n targetPath,\n error: `Target already exists: ${targetPath}. Use force option to overwrite.`,\n warnings,\n stats,\n duration: Date.now() - startTime,\n };\n }\n\n // Report progress: reading\n this.reportProgress(options.onProgress, {\n phase: 'reading',\n percentage: 0,\n });\n\n // Read metadata from source\n const metadataResult = await sourceProvider.getMetadata();\n if (!metadataResult.success || !metadataResult.data) {\n return {\n success: false,\n sourceFormat,\n targetFormat,\n sourcePath,\n targetPath,\n error: `Failed to read source metadata: ${metadataResult.error}`,\n warnings,\n stats,\n duration: Date.now() - startTime,\n };\n }\n\n // Initialize target with metadata\n this.reportProgress(options.onProgress, {\n phase: 'writing',\n percentage: 10,\n currentItem: 'metadata',\n });\n\n const initResult = await targetProvider.initialize(metadataResult.data);\n if (!initResult.success) {\n return {\n success: false,\n sourceFormat,\n targetFormat,\n sourcePath,\n targetPath,\n error: `Failed to initialize target: ${initResult.error}`,\n warnings,\n stats,\n duration: Date.now() - startTime,\n };\n }\n\n // Migrate steps\n this.reportProgress(options.onProgress, {\n phase: 'converting',\n percentage: 20,\n currentItem: 'steps',\n });\n stats.stepsConverted = await this.migrateSteps(sourceProvider, targetProvider);\n\n // Migrate files\n this.reportProgress(options.onProgress, {\n phase: 'converting',\n percentage: 40,\n currentItem: 'files',\n });\n stats.filesConverted = await this.migrateFiles(sourceProvider, targetProvider);\n\n // Migrate timeline events\n this.reportProgress(options.onProgress, {\n phase: 'converting',\n percentage: 60,\n currentItem: 'timeline',\n });\n stats.timelineEventsConverted = await this.migrateTimeline(sourceProvider, targetProvider);\n\n // Migrate evidence\n this.reportProgress(options.onProgress, {\n phase: 'converting',\n percentage: 70,\n currentItem: 'evidence',\n });\n stats.evidenceConverted = await this.migrateEvidence(sourceProvider, targetProvider);\n\n // Migrate feedback\n this.reportProgress(options.onProgress, {\n phase: 'converting',\n percentage: 80,\n currentItem: 'feedback',\n });\n stats.feedbackConverted = await this.migrateFeedback(sourceProvider, targetProvider);\n\n // Migrate checkpoints\n this.reportProgress(options.onProgress, {\n phase: 'converting',\n percentage: 90,\n currentItem: 'checkpoints',\n });\n stats.checkpointsConverted = await this.migrateCheckpoints(sourceProvider, targetProvider);\n\n // Validate if requested\n if (options.validate) {\n this.reportProgress(options.onProgress, {\n phase: 'validating',\n percentage: 95,\n });\n\n const validationResult = await this.validator.validate(sourceProvider, targetProvider);\n if (!validationResult.valid) {\n const errorMessages = validationResult.errors.map(e => e.message).join('; ');\n return {\n success: false,\n sourceFormat,\n targetFormat,\n sourcePath,\n targetPath,\n error: `Validation failed: ${errorMessages}`,\n warnings: [...warnings, ...validationResult.warnings],\n stats,\n duration: Date.now() - startTime,\n };\n }\n warnings.push(...validationResult.warnings);\n }\n\n // Delete source if not keeping\n if (!options.keepSource) {\n await this.deleteSource(sourcePath, sourceFormat);\n }\n\n this.reportProgress(options.onProgress, {\n phase: 'writing',\n percentage: 100,\n });\n\n return {\n success: true,\n sourceFormat,\n targetFormat,\n sourcePath,\n targetPath,\n warnings,\n stats,\n duration: Date.now() - startTime,\n };\n } catch (error) {\n return {\n success: false,\n sourceFormat: sourceProvider.format,\n targetFormat: targetProvider.format,\n sourcePath,\n targetPath,\n error: error instanceof Error ? error.message : 'Unknown error during migration',\n warnings,\n stats,\n duration: Date.now() - startTime,\n };\n }\n }\n\n private async migrateSteps(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<number> {\n const result = await source.getSteps();\n if (!result.success || !result.data) {\n return 0;\n }\n\n for (const step of result.data) {\n await target.addStep(step);\n }\n\n return result.data.length;\n }\n\n private async migrateFiles(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<number> {\n const result = await source.getFiles();\n if (!result.success || !result.data) {\n return 0;\n }\n\n for (const file of result.data) {\n await target.saveFile(file);\n }\n\n return result.data.length;\n }\n\n private async migrateTimeline(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<number> {\n const result = await source.getTimelineEvents();\n if (!result.success || !result.data) {\n return 0;\n }\n\n for (const event of result.data) {\n await target.addTimelineEvent(event);\n }\n\n return result.data.length;\n }\n\n private async migrateEvidence(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<number> {\n const result = await source.getEvidence();\n if (!result.success || !result.data) {\n return 0;\n }\n\n for (const evidence of result.data) {\n await target.addEvidence(evidence);\n }\n\n return result.data.length;\n }\n\n private async migrateFeedback(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<number> {\n const result = await source.getFeedback();\n if (!result.success || !result.data) {\n return 0;\n }\n\n for (const feedback of result.data) {\n await target.addFeedback(feedback);\n }\n\n return result.data.length;\n }\n\n private async migrateCheckpoints(\n source: StorageProvider,\n target: StorageProvider\n ): Promise<number> {\n const result = await source.getCheckpoints();\n if (!result.success || !result.data) {\n return 0;\n }\n\n for (const checkpoint of result.data) {\n await target.createCheckpoint(checkpoint);\n }\n\n return result.data.length;\n }\n\n private async deleteSource(sourcePath: string, format: StorageFormat): Promise<void> {\n if (!existsSync(sourcePath)) {\n return;\n }\n\n if (format === 'sqlite') {\n // Delete SQLite file and any WAL/SHM files\n unlinkSync(sourcePath);\n const walPath = sourcePath + '-wal';\n const shmPath = sourcePath + '-shm';\n if (existsSync(walPath)) unlinkSync(walPath);\n if (existsSync(shmPath)) unlinkSync(shmPath);\n } else {\n // Delete directory recursively\n rmSync(sourcePath, { recursive: true, force: true });\n }\n }\n\n private reportProgress(\n callback: ((progress: MigrationProgress) => void) | undefined,\n progress: MigrationProgress\n ): void {\n if (callback) {\n callback(progress);\n }\n }\n}\n\n/**\n * Create a plan migrator\n */\nexport function createMigrator(): PlanMigrator {\n return new PlanMigrator();\n}\n\n/**\n * Generate a target path based on source path and target format\n */\nexport function generateTargetPath(\n sourcePath: string,\n sourceFormat: StorageFormat,\n targetFormat: StorageFormat\n): string {\n if (targetFormat === 'sqlite') {\n // Remove trailing slash and add .plan extension\n const basePath = sourcePath.replace(/\\/$/, '');\n return ensureFormatExtension(basePath, 'sqlite');\n } else {\n // Remove .plan extension and add _migrated suffix\n const basePath = sourcePath.replace(/\\.plan$/, '');\n return basePath + '_migrated';\n }\n}\n\n/**\n * Infer target format from source format (opposite format)\n */\nexport function inferTargetFormat(sourceFormat: StorageFormat): StorageFormat {\n return sourceFormat === 'sqlite' ? 'directory' : 'sqlite';\n}\n","/**\n * Markdown Renderer\n * \n * Renders plan data to markdown format for export.\n */\n\nimport type { StorageProvider } from '../storage/provider.js';\nimport type { PlanMetadata, PlanStep, EvidenceRecord, FeedbackRecord } from '../types.js';\n\n/**\n * Options for markdown rendering\n */\nexport interface MarkdownRenderOptions {\n /** Include timeline events in output */\n includeTimeline?: boolean;\n \n /** Include evidence records */\n includeEvidence?: boolean;\n \n /** Include feedback records */\n includeFeedback?: boolean;\n \n /** Include source format metadata */\n includeSourceInfo?: boolean;\n}\n\n/**\n * Rendered plan as markdown files\n */\nexport interface RenderedPlan {\n /** Main files (SUMMARY.md, STATUS.md, etc.) */\n files: Map<string, string>;\n \n /** Step files (plan/01-step.md, etc.) */\n steps: Map<string, string>;\n \n /** Evidence files (evidence/*.md) */\n evidence: Map<string, string>;\n \n /** Feedback files (feedback/*.md) */\n feedback: Map<string, string>;\n}\n\n/**\n * Render a plan to markdown format\n */\nexport async function renderPlanToMarkdown(\n provider: StorageProvider,\n options: MarkdownRenderOptions = {}\n): Promise<RenderedPlan> {\n const result: RenderedPlan = {\n files: new Map(),\n steps: new Map(),\n evidence: new Map(),\n feedback: new Map(),\n };\n\n // Get metadata\n const metadataResult = await provider.getMetadata();\n if (metadataResult.success && metadataResult.data) {\n result.files.set('SUMMARY.md', renderSummary(metadataResult.data, options));\n result.files.set('STATUS.md', await renderStatus(provider, metadataResult.data));\n }\n\n // Get and render existing files\n const filesResult = await provider.getFiles();\n if (filesResult.success && filesResult.data) {\n for (const file of filesResult.data) {\n result.files.set(file.filename, file.content);\n }\n }\n\n // Get and render steps\n const stepsResult = await provider.getSteps();\n if (stepsResult.success && stepsResult.data) {\n for (const step of stepsResult.data) {\n const filename = formatStepFilename(step);\n result.steps.set(filename, step.content);\n }\n }\n\n // Get and render evidence\n if (options.includeEvidence !== false) {\n const evidenceResult = await provider.getEvidence();\n if (evidenceResult.success && evidenceResult.data) {\n for (const evidence of evidenceResult.data) {\n const filename = `${evidence.id}.md`;\n result.evidence.set(filename, renderEvidence(evidence));\n }\n }\n }\n\n // Get and render feedback\n if (options.includeFeedback !== false) {\n const feedbackResult = await provider.getFeedback();\n if (feedbackResult.success && feedbackResult.data) {\n for (const feedback of feedbackResult.data) {\n const filename = `${feedback.id}.md`;\n result.feedback.set(filename, renderFeedback(feedback));\n }\n }\n }\n\n return result;\n}\n\n/**\n * Render plan summary\n */\nfunction renderSummary(metadata: PlanMetadata, options: MarkdownRenderOptions): string {\n const lines: string[] = [\n `# ${metadata.name}`,\n '',\n '## Overview',\n '',\n metadata.description || '_No description provided._',\n '',\n '## Metadata',\n '',\n `- **ID**: ${metadata.id}`,\n `- **Stage**: ${metadata.stage}`,\n `- **Created**: ${metadata.createdAt}`,\n `- **Updated**: ${metadata.updatedAt}`,\n ];\n\n if (options.includeSourceInfo) {\n lines.push(`- **Schema Version**: ${metadata.schemaVersion}`);\n }\n\n lines.push('', '---', '', `*Generated: ${new Date().toISOString()}*`);\n\n return lines.join('\\n');\n}\n\n/**\n * Render plan status\n */\nasync function renderStatus(provider: StorageProvider, metadata: PlanMetadata): Promise<string> {\n const stepsResult = await provider.getSteps();\n const steps = stepsResult.data || [];\n\n const completed = steps.filter(s => s.status === 'completed').length;\n const inProgress = steps.filter(s => s.status === 'in_progress').length;\n const pending = steps.filter(s => s.status === 'pending').length;\n const total = steps.length;\n const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;\n\n const statusEmoji = getStatusEmoji(metadata.stage, inProgress > 0);\n\n const lines: string[] = [\n `# ${metadata.name} Status`,\n '',\n '## Current State',\n '',\n '| Field | Value |',\n '|-------|-------|',\n `| **Status** | ${statusEmoji} ${metadata.stage.toUpperCase()} |`,\n `| **Progress** | ${percentage}% (${completed}/${total} steps) |`,\n `| **In Progress** | ${inProgress} |`,\n `| **Pending** | ${pending} |`,\n `| **Last Updated** | ${metadata.updatedAt.split('T')[0]} |`,\n '',\n '## Step Progress',\n '',\n '| Step | Name | Status | Started | Completed |',\n '|------|------|--------|---------|-----------|',\n ];\n\n for (const step of steps) {\n const statusIcon = getStepStatusIcon(step.status);\n lines.push(\n `| ${String(step.number).padStart(2, '0')} | ${step.title} | ${statusIcon} | ${step.startedAt?.split('T')[0] || '-'} | ${step.completedAt?.split('T')[0] || '-'} |`\n );\n }\n\n lines.push('', '---', '', `*Last updated: ${new Date().toISOString().split('T')[0]}*`);\n\n return lines.join('\\n');\n}\n\n/**\n * Format step filename\n */\nfunction formatStepFilename(step: PlanStep): string {\n const num = String(step.number).padStart(2, '0');\n const code = step.code || step.title.toLowerCase().replace(/[^a-z0-9]+/g, '-');\n return `${num}-${code}.md`;\n}\n\n/**\n * Render evidence record to markdown\n */\nfunction renderEvidence(evidence: EvidenceRecord): string {\n const lines: string[] = [\n '---',\n `id: ${evidence.id}`,\n `date: ${evidence.createdAt}`,\n ];\n\n if (evidence.source) {\n lines.push(`source: ${evidence.source}`);\n }\n if (evidence.sourceUrl) {\n lines.push(`url: ${evidence.sourceUrl}`);\n }\n if (evidence.gatheringMethod) {\n lines.push(`gathering_method: ${evidence.gatheringMethod}`);\n }\n\n lines.push('---', '', `# ${evidence.description}`, '');\n\n if (evidence.content) {\n lines.push(evidence.content);\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Render feedback record to markdown\n */\nfunction renderFeedback(feedback: FeedbackRecord): string {\n const lines: string[] = [\n '---',\n `id: ${feedback.id}`,\n `date: ${feedback.createdAt}`,\n ];\n\n if (feedback.title) {\n lines.push(`title: ${feedback.title}`);\n }\n if (feedback.platform) {\n lines.push(`platform: ${feedback.platform}`);\n }\n if (feedback.participants && feedback.participants.length > 0) {\n lines.push(`participants: [${feedback.participants.join(', ')}]`);\n }\n\n lines.push('---', '');\n\n if (feedback.title) {\n lines.push(`# ${feedback.title}`, '');\n }\n\n lines.push(feedback.content);\n\n return lines.join('\\n');\n}\n\n/**\n * Get status emoji based on stage\n */\nfunction getStatusEmoji(stage: string, hasInProgress: boolean): string {\n if (stage === 'completed') return '✅';\n if (stage === 'cancelled') return '❌';\n if (hasInProgress) return '🔄';\n if (stage === 'executing') return '🔄';\n if (stage === 'built') return '📋';\n if (stage === 'shaping') return '🔧';\n return '⬜';\n}\n\n/**\n * Get step status icon\n */\nfunction getStepStatusIcon(status: string): string {\n switch (status) {\n case 'completed': return '✅';\n case 'in_progress': return '🔄';\n case 'skipped': return '⏭️';\n default: return '⬜';\n }\n}\n","/**\n * @kjerneverk/riotplan-format\n * \n * SQLite-based storage format for RiotPlan with dual format support.\n * \n * This package provides a storage abstraction layer that supports both\n * directory-based and SQLite .plan formats for RiotPlan plans.\n * \n * @packageDocumentation\n */\n\n// Export all types\nexport * from './types.js';\n\n// Export configuration types and utilities\nexport * from './config.js';\n\n// Export storage provider interface and types\nexport * from './storage/index.js';\n\n// Export migration utilities\nexport * from './migration/index.js';\n\n// Export renderer utilities\nexport * from './renderer/index.js';\n\n/**\n * Package version\n */\nexport const VERSION = '1.0.0-dev.0';\n\n/**\n * Current SQLite schema version\n */\nexport const SCHEMA_VERSION = 1;\n\n/**\n * File extension for SQLite plan files\n */\nexport const PLAN_FILE_EXTENSION = '.plan';\n"],"names":["__filename","__dirname"],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ -- RiotPlan SQLite Schema v1
2
+ -- This schema captures all the structure from the directory-based plan format
3
+
4
+ -- Schema version tracking for migrations
5
+ CREATE TABLE IF NOT EXISTS schema_version (
6
+ version INTEGER PRIMARY KEY,
7
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
8
+ );
9
+
10
+ -- Core plan metadata
11
+ CREATE TABLE IF NOT EXISTS plans (
12
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
13
+ code TEXT NOT NULL UNIQUE,
14
+ name TEXT NOT NULL,
15
+ description TEXT,
16
+ stage TEXT NOT NULL DEFAULT 'idea',
17
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
18
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
19
+ schema_version INTEGER NOT NULL DEFAULT 1
20
+ );
21
+
22
+ -- Plan steps (corresponds to PlanStep interface)
23
+ CREATE TABLE IF NOT EXISTS plan_steps (
24
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
25
+ plan_id INTEGER NOT NULL,
26
+ number INTEGER NOT NULL,
27
+ code TEXT NOT NULL,
28
+ title TEXT NOT NULL,
29
+ description TEXT,
30
+ status TEXT NOT NULL DEFAULT 'pending',
31
+ started_at TEXT,
32
+ completed_at TEXT,
33
+ content TEXT NOT NULL,
34
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE,
35
+ UNIQUE(plan_id, number)
36
+ );
37
+
38
+ -- Plan files (IDEA.md, SHAPING.md, STATUS.md, etc.)
39
+ CREATE TABLE IF NOT EXISTS plan_files (
40
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
41
+ plan_id INTEGER NOT NULL,
42
+ file_type TEXT NOT NULL,
43
+ filename TEXT NOT NULL,
44
+ content TEXT NOT NULL,
45
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
46
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
47
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE,
48
+ UNIQUE(plan_id, file_type, filename)
49
+ );
50
+
51
+ -- Timeline events (corresponds to TimelineEvent interface)
52
+ CREATE TABLE IF NOT EXISTS timeline_events (
53
+ id TEXT PRIMARY KEY,
54
+ plan_id INTEGER NOT NULL,
55
+ timestamp TEXT NOT NULL,
56
+ event_type TEXT NOT NULL,
57
+ data TEXT NOT NULL, -- JSON blob
58
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE
59
+ );
60
+
61
+ -- Evidence records
62
+ CREATE TABLE IF NOT EXISTS evidence_records (
63
+ id TEXT PRIMARY KEY,
64
+ plan_id INTEGER NOT NULL,
65
+ description TEXT NOT NULL,
66
+ source TEXT,
67
+ source_url TEXT,
68
+ gathering_method TEXT,
69
+ content TEXT,
70
+ file_path TEXT,
71
+ relevance_score REAL,
72
+ original_query TEXT,
73
+ summary TEXT,
74
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
75
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE
76
+ );
77
+
78
+ -- Feedback records
79
+ CREATE TABLE IF NOT EXISTS feedback_records (
80
+ id TEXT PRIMARY KEY,
81
+ plan_id INTEGER NOT NULL,
82
+ title TEXT,
83
+ platform TEXT,
84
+ content TEXT NOT NULL,
85
+ participants TEXT, -- JSON array
86
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
87
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE
88
+ );
89
+
90
+ -- Checkpoints for saving plan state
91
+ CREATE TABLE IF NOT EXISTS checkpoints (
92
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
93
+ plan_id INTEGER NOT NULL,
94
+ name TEXT NOT NULL,
95
+ message TEXT NOT NULL,
96
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
97
+ snapshot TEXT NOT NULL, -- JSON blob of plan state
98
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE,
99
+ UNIQUE(plan_id, name)
100
+ );
101
+
102
+ -- Step reflections
103
+ CREATE TABLE IF NOT EXISTS step_reflections (
104
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
105
+ plan_id INTEGER NOT NULL,
106
+ step_number INTEGER NOT NULL,
107
+ reflection TEXT NOT NULL,
108
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
109
+ FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE,
110
+ UNIQUE(plan_id, step_number)
111
+ );
112
+
113
+ -- Indexes for performance
114
+ CREATE INDEX IF NOT EXISTS idx_steps_plan_number ON plan_steps(plan_id, number);
115
+ CREATE INDEX IF NOT EXISTS idx_files_plan_type ON plan_files(plan_id, file_type);
116
+ CREATE INDEX IF NOT EXISTS idx_timeline_plan_time ON timeline_events(plan_id, timestamp);
117
+ CREATE INDEX IF NOT EXISTS idx_timeline_type ON timeline_events(event_type);
118
+ CREATE INDEX IF NOT EXISTS idx_evidence_plan ON evidence_records(plan_id);
119
+ CREATE INDEX IF NOT EXISTS idx_feedback_plan ON feedback_records(plan_id);
120
+ CREATE INDEX IF NOT EXISTS idx_checkpoints_plan ON checkpoints(plan_id);
121
+
122
+ -- Insert initial schema version
123
+ INSERT OR IGNORE INTO schema_version (version) VALUES (1);
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@kjerneverk/riotplan-format",
3
+ "version": "1.0.0-dev.0",
4
+ "description": "SQLite-based storage format for RiotPlan with dual format support",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "engines": {
15
+ "node": ">=24.0.0"
16
+ },
17
+ "scripts": {
18
+ "clean": "rm -rf dist",
19
+ "build": "vite build",
20
+ "test": "vitest run --coverage",
21
+ "test:coverage": "vitest run --coverage",
22
+ "lint": "eslint src",
23
+ "precommit": "npm run build && npm run lint && npm run test",
24
+ "prepublishOnly": "npm run clean && npm run build"
25
+ },
26
+ "keywords": [
27
+ "riotplan",
28
+ "sqlite",
29
+ "storage",
30
+ "format",
31
+ "plan"
32
+ ],
33
+ "author": "Tim O'Brien <tobrien@discursive.com>",
34
+ "license": "Apache-2.0",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/kjerneverk/riotplan-format"
38
+ },
39
+ "dependencies": {
40
+ "better-sqlite3": "^11.8.1"
41
+ },
42
+ "devDependencies": {
43
+ "@eslint/eslintrc": "^3.3.1",
44
+ "@eslint/js": "^9.28.0",
45
+ "@types/better-sqlite3": "^7.6.12",
46
+ "@types/node": "^24.10.9",
47
+ "@typescript-eslint/eslint-plugin": "^8.34.0",
48
+ "@typescript-eslint/parser": "^8.34.0",
49
+ "@vitest/coverage-v8": "^4.0.17",
50
+ "eslint": "^9.28.0",
51
+ "eslint-plugin-import": "^2.31.0",
52
+ "globals": "^17.0.0",
53
+ "typescript": "^5.8.3",
54
+ "vite": "^7.0.4",
55
+ "vite-plugin-dts": "^4.5.4",
56
+ "vitest": "^4.0.17"
57
+ }
58
+ }