@thanh01.pmt/curriculum-kit 1.4.45 → 1.4.46

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storage/fileSystemCurriculumAdapter.ts","../../src/storage/supabaseCurriculumAdapter.ts","../../src/storage/factory.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport type { \n ICurriculumStorage, \n SotDocument, \n LessonArtifactSummary, \n ProjectStatusReport,\n PipelineState,\n ArtifactLifecycleInfo\n} from './types';\n\nexport function computeContentHash(content: string): string {\n return 'sha256:' + crypto.createHash('sha256').update(content.trim(), 'utf-8').digest('hex');\n}\n\nexport const STANDARD_SOT_FILES = [\n 'LEARNER_PROFILE.md',\n 'PROJECT_BRIEF.md',\n 'REFERENCE_PACK.md',\n 'PROJECT_GRAPH.json',\n 'HYBRID_GRAPH.json',\n 'SECTION_LANGUAGE_CONTRACT.md',\n 'CURRICULUM_FRAMEWORK.md',\n 'CONTENT_STYLE_GUIDE.md',\n 'ART_DIRECTION.md',\n 'ALIGNMENT_MATRIX.md',\n];\n\nexport interface FileSystemStorageOptions {\n baseDir?: string;\n}\n\n/**\n * Atomic single-file write (5-Whys RC-race, 2026-09-13): write to a unique\n * temp file in the SAME directory, then `rename` over the target. On POSIX a\n * rename within a filesystem is atomic — a concurrent reader sees either the\n * old or the new complete file, never a torn write, and two racing writers\n * each land a complete file (last rename wins) instead of interleaved halves.\n * Previously a direct writeFileSync let the double-run race truncate/clobber\n * companion files (deck.json / .html disappeared while the .md survived).\n */\nexport function atomicWriteFileSync(targetPath: string, content: string): void {\n const dir = path.dirname(targetPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const tmpPath = path.join(dir, `.${path.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString('hex')}.tmp`);\n try {\n fs.writeFileSync(tmpPath, content, 'utf-8');\n fs.renameSync(tmpPath, targetPath);\n } catch (err) {\n // Best-effort temp cleanup; never mask the original error.\n try { if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath); } catch {}\n throw err;\n }\n}\n\nexport class FileSystemCurriculumAdapter implements ICurriculumStorage {\n private baseDir: string;\n\n constructor(options: FileSystemStorageOptions = {}) {\n this.baseDir = options.baseDir || path.resolve(process.cwd(), 'output', 'projects');\n }\n\n private getProjectDir(projectId: string): string {\n const raw = (projectId || '').replace('proj_', '');\n const directPath = path.join(this.baseDir, raw);\n if (fs.existsSync(directPath)) return directPath;\n const fullIdPath = path.join(this.baseDir, projectId);\n if (fs.existsSync(fullIdPath)) return fullIdPath;\n return directPath;\n }\n\n /** Ensures the resolved path stays within the project directory (prevents path traversal). */\n private assertInsideProject(projectDir: string, targetPath: string): void {\n const resolvedProject = path.resolve(projectDir);\n const resolvedTarget = path.resolve(targetPath);\n if (!resolvedTarget.startsWith(resolvedProject + path.sep) && resolvedTarget !== resolvedProject) {\n throw new Error(`[FileSystemCurriculumAdapter] Path traversal blocked: ${targetPath} is outside project directory ${projectDir}`);\n }\n }\n\n async projectExists(projectId: string): Promise<boolean> {\n return fs.existsSync(this.getProjectDir(projectId));\n }\n\n async readSotDocument(projectId: string, filename: string): Promise<string | null> {\n const projectDir = this.getProjectDir(projectId);\n const possiblePaths = [\n path.join(projectDir, '_sot', filename),\n path.join(projectDir, filename),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p) && fs.statSync(p).isFile()) {\n return fs.readFileSync(p, 'utf-8');\n }\n }\n return null;\n }\n\n async listSotDocuments(projectId: string): Promise<SotDocument[]> {\n const projectDir = this.getProjectDir(projectId);\n const sotDir = path.join(projectDir, '_sot');\n\n const discoveredFiles = new Set<string>(STANDARD_SOT_FILES);\n if (fs.existsSync(sotDir)) {\n try {\n const diskFiles = fs.readdirSync(sotDir);\n for (const f of diskFiles) {\n if (f.startsWith('.') || f.endsWith('.review.json')) continue;\n const fullPath = path.join(sotDir, f);\n if (fs.statSync(fullPath).isFile()) {\n discoveredFiles.add(f);\n }\n }\n } catch {}\n }\n\n return Array.from(discoveredFiles).map(filename => {\n const p = fs.existsSync(path.join(sotDir, filename))\n ? path.join(sotDir, filename)\n : (fs.existsSync(path.join(projectDir, filename)) ? path.join(projectDir, filename) : null);\n\n if (p && fs.existsSync(p)) {\n const stats = fs.statSync(p);\n return {\n name: filename.replace(/\\.(md|json)$/i, '').replace(/_/g, ' '),\n filename,\n exists: true,\n sizeBytes: stats.size\n };\n }\n\n return {\n name: filename.replace(/\\.(md|json)$/i, '').replace(/_/g, ' '),\n filename,\n exists: false,\n sizeBytes: 0\n };\n });\n }\n\n async readArtifact(projectId: string, relPathOrIdentifier: string): Promise<string | null> {\n const projectDir = this.getProjectDir(projectId);\n\n // Block path traversal attempts\n const directCandidate = path.join(projectDir, relPathOrIdentifier);\n this.assertInsideProject(projectDir, directCandidate);\n\n // 1. Direct file path lookup\n const possiblePaths = [\n directCandidate,\n path.join(projectDir, '_sot', relPathOrIdentifier),\n path.join(projectDir, 'lessons', relPathOrIdentifier),\n path.join(projectDir, '_sot', path.basename(relPathOrIdentifier)),\n path.join(projectDir, 'lessons', path.basename(relPathOrIdentifier)),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p) && fs.statSync(p).isFile()) {\n return fs.readFileSync(p, 'utf-8');\n }\n }\n\n // If relPathOrIdentifier was an explicit filename with extension, don't guess\n if (relPathOrIdentifier.includes('.md') || relPathOrIdentifier.includes('/')) {\n return null;\n }\n\n // 2. Intelligent Identifier Resolution for query strings (e.g. \"U01_M01_L01 — Giáo án 5E\")\n const lessonMatch = relPathOrIdentifier.match(/U\\d+_M\\d+_L\\d+/i);\n if (lessonMatch) {\n const lessonId = lessonMatch[0].toUpperCase();\n const lessonDir = path.join(projectDir, 'lessons', lessonId);\n\n if (fs.existsSync(lessonDir) && fs.statSync(lessonDir).isDirectory()) {\n const lower = relPathOrIdentifier.toLowerCase();\n let artifactPrefix = 'LESSON';\n if (lower.includes('act') || lower.includes('lab') || lower.includes('thực hành')) {\n artifactPrefix = 'ACT';\n } else if (lower.includes('quiz') || lower.includes('trắc nghiệm') || lower.includes('đánh giá')) {\n artifactPrefix = 'QUIZ';\n } else if (lower.includes('slide') || lower.includes('bài giảng') || lower.includes('trình chiếu')) {\n artifactPrefix = 'SLIDE';\n } else if (lower.includes('guide') || lower.includes('hướng dẫn')) {\n artifactPrefix = 'GUIDE';\n } else if (lower.includes('wks') || lower.includes('worksheet') || lower.includes('phiếu bài tập')) {\n artifactPrefix = 'WKS';\n } else if (lower.includes('handout') || lower.includes('tài liệu')) {\n artifactPrefix = 'HANDOUT';\n } else if (lower.includes('code')) {\n artifactPrefix = 'CODE';\n } else if (lower.includes('ext') || lower.includes('extension')) {\n artifactPrefix = 'EXT';\n }\n\n const candidateFile = path.join(lessonDir, `${artifactPrefix}_${lessonId}.md`);\n if (fs.existsSync(candidateFile)) {\n return fs.readFileSync(candidateFile, 'utf-8');\n }\n }\n }\n\n return null;\n }\n\n async saveArtifact(projectId: string, relPath: string, content: string): Promise<void> {\n const projectDir = this.getProjectDir(projectId);\n const targetPath = path.join(projectDir, relPath);\n this.assertInsideProject(projectDir, targetPath);\n const targetDir = path.dirname(targetPath);\n\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n }\n\n // Version history (P2): ghi đè file đã tồn tại → chép bản cũ vào .history/ trước (giữ tối đa 10 bản gần nhất)\n if (fs.existsSync(targetPath)) {\n try {\n const oldContent = fs.readFileSync(targetPath, 'utf-8');\n if (oldContent !== content) {\n const historyDir = path.join(projectDir, '.history', relPath);\n fs.mkdirSync(historyDir, { recursive: true });\n atomicWriteFileSync(path.join(historyDir, `${Date.now()}.md`), oldContent);\n const versions = fs.readdirSync(historyDir).filter((f) => f.endsWith('.md')).sort();\n while (versions.length > 10) {\n fs.unlinkSync(path.join(historyDir, versions.shift() as string));\n }\n }\n } catch (histErr: any) {\n // History failure KHÔNG chặn ghi chính — nhưng không âm thầm: log rõ\n console.warn('[FileSystemCurriculumAdapter] version history snapshot failed:', histErr?.message || histErr);\n }\n }\n\n atomicWriteFileSync(targetPath, content);\n\n // Also auto-sync to lessons/ directory if this is a lesson artifact (e.g. _content/U01/SLIDE_U01_M01_L01.md)\n const filename = path.basename(relPath);\n const match = filename.match(/(LESSON|ACT|QUIZ|SLIDE|GUIDE|HANDOUT|WKS|EXT)_(U\\d+_M\\d+_L\\d+)\\.md/i);\n if (match) {\n const lessonId = match[2].toUpperCase();\n atomicWriteFileSync(path.join(projectDir, 'lessons', lessonId, filename), content);\n\n // Also sync to legacy _content/U01_M01_L01/ folder if it exists\n const legacyContentDir = path.join(projectDir, '_content', lessonId);\n if (fs.existsSync(legacyContentDir)) {\n atomicWriteFileSync(path.join(legacyContentDir, filename), content);\n }\n }\n }\n\n async listLessons(projectId: string): Promise<LessonArtifactSummary[]> {\n const lessonsDir = path.join(this.getProjectDir(projectId), 'lessons');\n if (!fs.existsSync(lessonsDir)) return [];\n\n const lessonFolders = fs.readdirSync(lessonsDir).filter(f => !f.startsWith('.'));\n return lessonFolders.map(folder => {\n const lDir = path.join(lessonsDir, folder);\n const isDir = fs.statSync(lDir).isDirectory();\n if (!isDir) {\n return {\n lessonId: folder,\n artifactsCount: 0,\n isComplete: false,\n artifacts: []\n };\n }\n\n const artifacts = fs.readdirSync(lDir).filter(f => !f.startsWith('.'));\n return {\n lessonId: folder,\n artifactsCount: artifacts.length,\n isComplete: artifacts.length >= 4,\n artifacts\n };\n });\n }\n\n async getProjectStatus(projectId: string): Promise<ProjectStatusReport> {\n const sotList = await this.listSotDocuments(projectId);\n const lessons = await this.listLessons(projectId);\n\n const completedCount = lessons.filter(l => l.isComplete).length;\n const totalLessons = lessons.length || 4;\n const progressPercent = Math.round((completedCount / totalLessons) * 100);\n\n const sotTable = sotList.map(doc => `| \\`${doc.filename}\\` | ${doc.exists ? '✅ Sẵn sàng' : '❌ Chưa có'} |`).join('\\n');\n const lessonTable = lessons.length > 0 \n ? lessons.map(l => `| **${l.lessonId}** | ${l.artifactsCount}/4 Artifacts | ${l.isComplete ? '✅ Hoàn tất' : '⏳ Đang tạo sinh'} | ${l.artifacts.join(', ') || '-'} |`).join('\\n')\n : '| Chưa có bài học nào trên đĩa cứng | 0/4 | ⏳ Chờ chạy | - |';\n\n const rawMarkdownReport = `## 📊 BÁO CÁO TRẠNG THÁI DỰ ÁN: \\`${projectId.toUpperCase()}\\`\n\n### 1. Nền tảng Tài liệu (SOT Readiness)\n| Tài liệu SOT | Trạng thái |\n|---|:---:|\n${sotTable}\n\n### 2. Danh mục Bài học & Học liệu (Lessons & Artifacts Matrix)\n| Mã bài học | Số lượng Artifact | Trạng thái | Danh sách Artifact đã tạo |\n|---|:---:|:---:|---|\n${lessonTable}\n\n**Tiến độ tổng thể:** ${completedCount}/${totalLessons} bài học (${progressPercent}%)\n\n### 3. Đề xuất Hành động Tiếp theo:\n- Sử dụng lệnh \\`/create-lesson <id>\\` để tạo sinh các bài học tiếp theo trong pipeline.\n- Sử dụng lệnh \\`/audit-quality\\` để chạy kiểm thử tiêu chuẩn Bloom và Alignment Matrix.`;\n\n return {\n projectId,\n sotReadiness: sotList,\n lessons,\n completedCount,\n totalLessons,\n progressPercent,\n rawMarkdownReport\n };\n }\n\n async getPipelineState(projectId: string): Promise<PipelineState> {\n const projectDir = this.getProjectDir(projectId);\n const stateFile = path.join(projectDir, '_pipeline', 'state.json');\n\n if (fs.existsSync(stateFile)) {\n try {\n const raw = fs.readFileSync(stateFile, 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && parsed.tasks) {\n return parsed as PipelineState;\n }\n } catch (err) {\n console.warn(`[FileSystemCurriculumAdapter] Error reading pipeline state for ${projectId}:`, err);\n }\n }\n\n // Default empty pipeline state\n return {\n projectId,\n updatedAt: new Date().toISOString(),\n tasks: {}\n };\n }\n\n async savePipelineState(projectId: string, state: PipelineState): Promise<void> {\n const projectDir = this.getProjectDir(projectId);\n const pipelineDir = path.join(projectDir, '_pipeline');\n\n if (!fs.existsSync(pipelineDir)) {\n fs.mkdirSync(pipelineDir, { recursive: true });\n }\n\n const stateFile = path.join(pipelineDir, 'state.json');\n state.updatedAt = new Date().toISOString();\n atomicWriteFileSync(stateFile, JSON.stringify(state, null, 2));\n }\n\n async updateArtifactState(\n projectId: string,\n taskId: string,\n artifactType: string,\n update: Partial<ArtifactLifecycleInfo>\n ): Promise<PipelineState> {\n const current = await this.getPipelineState(projectId);\n if (!current.tasks[taskId]) {\n current.tasks[taskId] = {};\n }\n\n const existingInfo = current.tasks[taskId][artifactType] || {\n state: 'pending',\n };\n\n current.tasks[taskId][artifactType] = {\n ...existingInfo,\n ...update,\n };\n\n await this.savePipelineState(projectId, current);\n return current;\n }\n\n /** Disk adapter: purge = rm the file (best-effort, mirrors cloud deleteArtifact). */\n async deleteArtifact(projectId: string, relPath: string): Promise<void> {\n try {\n const projectDir = this.getProjectDir(projectId);\n const targetPath = path.join(projectDir, relPath);\n this.assertInsideProject(projectDir, targetPath);\n if (fs.existsSync(targetPath)) fs.rmSync(targetPath, { force: true });\n } catch { /* best-effort */ }\n }\n}\n","import { createClient, type SupabaseClient } from '@supabase/supabase-js';\nimport type { MilestoneCurriculumBundle } from '../pipeline';\nimport type { \n ICurriculumStorage, \n SotDocument, \n LessonArtifactSummary, \n ProjectStatusReport \n} from './types';\nimport { STANDARD_SOT_FILES } from './fileSystemCurriculumAdapter';\n\nexport interface SupabaseStorageConfig {\n supabaseUrl?: string;\n supabaseServiceRoleKey?: string;\n bucketName?: string;\n client?: SupabaseClient;\n}\n\n/**\n * Supabase Curriculum Adapter — Syncs Markdown artifacts to Storage & Database\n * Implements ICurriculumStorage for multi-tenant Cloud deployment (Vercel, Netlify, Cloudflare, etc.).\n */\nexport class SupabaseCurriculumAdapter implements ICurriculumStorage {\n private client: SupabaseClient;\n private bucketName: string;\n\n constructor(config: SupabaseStorageConfig = {}) {\n this.bucketName = config.bucketName || process.env.SUPABASE_STORAGE_BUCKET || 'course-materials';\n\n if (config.client) {\n this.client = config.client;\n } else {\n const url = config.supabaseUrl || process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.SUPABASE_URL || '';\n const key =\n config.supabaseServiceRoleKey ||\n process.env.SUPABASE_SERVICE_ROLE_KEY ||\n process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ||\n '';\n\n if (!url || !key) {\n throw new Error('Supabase URL or Key is missing in SupabaseCurriculumAdapter');\n }\n\n this.client = createClient(url, key);\n }\n }\n\n async projectExists(projectId: string): Promise<boolean> {\n try {\n const { data, error } = await this.client.storage\n .from(this.bucketName)\n .list(projectId, { limit: 5 });\n return !error && !!data && data.length > 0;\n } catch {\n return false;\n }\n }\n\n async readSotDocument(projectId: string, filename: string): Promise<string | null> {\n const paths = [\n `${projectId}/_sot/${filename}`,\n `${projectId}/${filename}`,\n `${projectId}/_designer/${filename}`,\n `${projectId}/_analyst/${filename}`\n ];\n for (const p of paths) {\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n return await data.text();\n }\n } catch {}\n }\n return null;\n }\n\n async listSotDocuments(projectId: string): Promise<SotDocument[]> {\n const discoveredFiles = new Set<string>(STANDARD_SOT_FILES);\n try {\n const { data, error } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/_sot`);\n if (!error && data) {\n for (const item of data) {\n if (item.name && !item.name.startsWith('.') && !item.name.endsWith('.review.json')) {\n discoveredFiles.add(item.name);\n }\n }\n }\n } catch {}\n\n const results: SotDocument[] = [];\n for (const filename of discoveredFiles) {\n const content = await this.readSotDocument(projectId, filename);\n results.push({\n name: filename.replace(/\\.(md|json)$/i, '').replace(/_/g, ' '),\n filename,\n exists: !!content,\n content: content || undefined,\n sizeBytes: content ? content.length : 0\n });\n }\n return results;\n }\n\n async readArtifact(projectId: string, relPathOrIdentifier: string): Promise<string | null> {\n const cleanPath = relPathOrIdentifier.replace(/^\\//, '');\n\n // 1. Direct path lookup attempts\n const possiblePaths = [\n `${projectId}/${cleanPath}`,\n `${projectId}/_sot/${cleanPath}`,\n `${projectId}/_content/${cleanPath}`,\n `${projectId}/lessons/${cleanPath}`,\n `${projectId}/_sot/${cleanPath.split('/').pop()}`,\n `${projectId}/lessons/${cleanPath.split('/').pop()}`,\n ];\n\n for (const p of possiblePaths) {\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n return await data.text();\n }\n } catch {}\n }\n\n // If relPathOrIdentifier was an explicit filename with extension or path, don't guess\n if (relPathOrIdentifier.includes('.md') || relPathOrIdentifier.includes('.json') || relPathOrIdentifier.includes('/')) {\n return null;\n }\n\n // 2. Intelligent Identifier Resolution (e.g. \"U01_M01_L01 — Giáo án 5E\" or \"U01_M01_L01\")\n const lessonMatch = relPathOrIdentifier.match(/U\\d+_M\\d+_L\\d+/i);\n if (lessonMatch) {\n const lessonId = lessonMatch[0].toUpperCase();\n const unitCode = lessonId.split('_')[0] || 'U01';\n const lower = relPathOrIdentifier.toLowerCase();\n\n let artifactPrefix: string | null = null;\n if (lower.includes('act') || lower.includes('lab') || lower.includes('thực hành')) {\n artifactPrefix = 'ACT';\n } else if (lower.includes('quiz') || lower.includes('trắc nghiệm') || lower.includes('đánh giá')) {\n artifactPrefix = 'QUIZ';\n } else if (lower.includes('slide') || lower.includes('bài giảng') || lower.includes('trình chiếu')) {\n artifactPrefix = 'SLIDE';\n } else if (lower.includes('guide') || lower.includes('hướng dẫn')) {\n artifactPrefix = 'GUIDE';\n } else if (lower.includes('wks') || lower.includes('worksheet') || lower.includes('phiếu bài tập')) {\n artifactPrefix = 'WKS';\n } else if (lower.includes('handout') || lower.includes('tài liệu')) {\n artifactPrefix = 'HANDOUT';\n } else if (lower.includes('code')) {\n artifactPrefix = 'CODE';\n } else if (lower.includes('ext') || lower.includes('extension') || lower.includes('mở rộng')) {\n artifactPrefix = 'EXT';\n } else if (lower.includes('exp') || lower.includes('exposition') || lower.includes('tự học') || lower.includes('kiến thức nền')) {\n artifactPrefix = 'EXPOSITION';\n } else if (lower.includes('rubric')) {\n artifactPrefix = 'RUBRIC';\n } else if (lower.includes('bom')) {\n artifactPrefix = 'BOM';\n } else if (lower.includes('lesson') || lower.includes('giáo án') || lower.includes('5e')) {\n artifactPrefix = 'LESSON';\n }\n\n if (!artifactPrefix) {\n return null;\n }\n\n const candidatePaths = artifactPrefix === 'EXPOSITION'\n ? [\n `${projectId}/_sot/expositions/${lessonId}.md`,\n `${projectId}/_content/${unitCode}/EXPOSITION_${lessonId}.md`,\n `${projectId}/lessons/${lessonId}/EXPOSITION_${lessonId}.md`,\n ]\n : [\n `${projectId}/_content/${unitCode}/${artifactPrefix}_${lessonId}.md`,\n `${projectId}/lessons/${lessonId}/${artifactPrefix}_${lessonId}.md`,\n `${projectId}/${artifactPrefix}_${lessonId}.md`,\n ];\n\n for (const p of candidatePaths) {\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n return await data.text();\n }\n } catch {}\n }\n }\n\n return null;\n }\n\n async saveArtifact(projectId: string, relPath: string, content: string): Promise<void> {\n const fullPath = `${projectId}/${relPath.replace(/^\\//, '')}`;\n const { error } = await this.client.storage\n .from(this.bucketName)\n .upload(fullPath, Buffer.from(content, 'utf-8'), {\n contentType: 'text/markdown',\n upsert: true,\n });\n\n if (error) {\n throw new Error(`Failed to upload artifact to Supabase Storage: ${error.message}`);\n }\n\n // Optional DB Upsert for fast indexed searching if artifacts table exists\n try {\n await this.client.from('curriculum_artifacts').upsert({\n project_id: projectId,\n rel_path: relPath,\n content: content,\n updated_at: new Date().toISOString(),\n }, { onConflict: 'project_id,rel_path' });\n } catch {\n // Ignore if table not yet migrated\n }\n }\n\n /**\n * Split-brain root-cause fix (2026-09-14): purge must reach the cloud copy\n * too. Removes the storage object AND the indexed `curriculum_artifacts`\n * row (the row is what `readArtifact`-style indexed readers resolve first).\n * Best-effort / no-throw per the interface contract.\n */\n async deleteArtifact(projectId: string, relPath: string): Promise<void> {\n const fullPath = `${projectId}/${relPath.replace(/^\\//, '')}`;\n try {\n await this.client.storage.from(this.bucketName).remove([fullPath]);\n } catch { /* object may not exist — fine */ }\n try {\n await this.client\n .from('curriculum_artifacts')\n .delete()\n .match({ project_id: projectId, rel_path: relPath });\n } catch { /* table may not exist — fine */ }\n }\n\n async listLessons(projectId: string): Promise<LessonArtifactSummary[]> {\n const summaries: LessonArtifactSummary[] = [];\n const processedLessons = new Set<string>();\n\n try {\n // 1. Scan _content/ folders (e.g. _content/U01/, _content/U02/)\n const { data: unitDirs } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/_content`);\n\n if (unitDirs) {\n for (const u of unitDirs) {\n const { data: files } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/_content/${u.name}`);\n\n if (files) {\n const lessonMap: Record<string, string[]> = {};\n files.forEach(f => {\n const m = f.name.match(/U\\d+_M\\d+_L\\d+/i);\n if (m) {\n const lid = m[0].toUpperCase();\n lessonMap[lid] = lessonMap[lid] || [];\n lessonMap[lid].push(f.name);\n }\n });\n\n for (const [lid, arts] of Object.entries(lessonMap)) {\n if (!processedLessons.has(lid)) {\n processedLessons.add(lid);\n summaries.push({\n lessonId: lid,\n artifactsCount: arts.length,\n isComplete: arts.length >= 4,\n artifacts: arts,\n });\n }\n }\n }\n }\n }\n\n // 2. Scan lessons/ folders (legacy / alternate structure)\n const { data: lessonDirs } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/lessons`);\n\n if (lessonDirs) {\n for (const dir of lessonDirs) {\n if (!processedLessons.has(dir.name)) {\n const { data: files } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/lessons/${dir.name}`);\n \n const artifacts = (files || []).map(f => f.name).filter(n => !n.startsWith('.'));\n processedLessons.add(dir.name);\n summaries.push({\n lessonId: dir.name,\n artifactsCount: artifacts.length,\n isComplete: artifacts.length >= 4,\n artifacts\n });\n }\n }\n }\n } catch {\n // Fallback\n }\n\n return summaries;\n }\n\n async getProjectStatus(projectId: string): Promise<ProjectStatusReport> {\n const sotList = await this.listSotDocuments(projectId);\n const lessons = await this.listLessons(projectId);\n\n const completedCount = lessons.filter(l => l.isComplete).length;\n const totalLessons = lessons.length || 4;\n const progressPercent = Math.round((completedCount / totalLessons) * 100);\n\n const sotTable = sotList.map(doc => `| \\`${doc.filename}\\` | ${doc.exists ? '✅ Sẵn sàng' : '❌ Chưa có'} |`).join('\\n');\n const lessonTable = lessons.length > 0 \n ? lessons.map(l => `| **${l.lessonId}** | ${l.artifactsCount}/4 Artifacts | ${l.isComplete ? '✅ Hoàn tất' : '⏳ Đang tạo sinh'} | ${l.artifacts.join(', ') || '-'} |`).join('\\n')\n : '| Chưa có bài học nào trên cloud storage | 0/4 | ⏳ Chờ chạy | - |';\n\n const rawMarkdownReport = `## 📊 BÁO CÁO TRẠNG THÁI DỰ ÁN (CLOUD): \\`${projectId.toUpperCase()}\\`\n\n### 1. Nền tảng Tài liệu (SOT Readiness)\n| Tài liệu SOT | Trạng thái |\n|---|:---:|\n${sotTable}\n\n### 2. Danh mục Bài học & Học liệu (Lessons & Artifacts Matrix)\n| Mã bài học | Số lượng Artifact | Trạng thái | Danh sách Artifact đã tạo |\n|---|:---:|:---:|---|\n${lessonTable}\n\n**Tiến độ tổng thể:** ${completedCount}/${totalLessons} bài học (${progressPercent}%)`;\n\n return {\n projectId,\n sotReadiness: sotList,\n lessons,\n completedCount,\n totalLessons,\n progressPercent,\n rawMarkdownReport\n };\n }\n\n /**\n * Uploads a complete milestone bundle (Markdown files) to Supabase Storage\n */\n async uploadMilestoneBundle(\n projectSlug: string,\n bundle: MilestoneCurriculumBundle\n ): Promise<{ lessonUrl?: string; activityUrl?: string; handoutUrl?: string }> {\n const basePath = `${projectSlug}/${bundle.milestoneId}`;\n\n const uploads = [\n {\n path: `${basePath}/LESSON.md`,\n content: bundle.lessonMarkdown,\n type: 'text/markdown',\n },\n {\n path: `${basePath}/ACT.md`,\n content: bundle.activityMarkdown,\n type: 'text/markdown',\n },\n {\n path: `${basePath}/HANDOUT.md`,\n content: bundle.handoutMarkdown,\n type: 'text/markdown',\n },\n ];\n\n const results: Record<string, string> = {};\n\n for (const item of uploads) {\n const { data, error } = await this.client.storage\n .from(this.bucketName)\n .upload(item.path, Buffer.from(item.content, 'utf-8'), {\n contentType: item.type,\n upsert: true,\n });\n\n if (!error && data) {\n const { data: publicUrlData } = this.client.storage.from(this.bucketName).getPublicUrl(item.path);\n results[item.path] = publicUrlData.publicUrl;\n }\n }\n\n return {\n lessonUrl: results[`${basePath}/LESSON.md`],\n activityUrl: results[`${basePath}/ACT.md`],\n handoutUrl: results[`${basePath}/HANDOUT.md`],\n };\n }\n\n async getPipelineState(projectId: string): Promise<import('./types').PipelineState> {\n const p = `${projectId}/_pipeline/state.json`;\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n const text = await data.text();\n return JSON.parse(text);\n }\n } catch {}\n\n return {\n projectId,\n updatedAt: new Date().toISOString(),\n tasks: {}\n };\n }\n\n async savePipelineState(projectId: string, state: import('./types').PipelineState): Promise<void> {\n const p = `${projectId}/_pipeline/state.json`;\n state.updatedAt = new Date().toISOString();\n await this.client.storage.from(this.bucketName).upload(p, Buffer.from(JSON.stringify(state, null, 2), 'utf-8'), {\n contentType: 'application/json',\n upsert: true,\n });\n }\n\n async updateArtifactState(\n projectId: string,\n taskId: string,\n artifactType: string,\n update: Partial<import('./types').ArtifactLifecycleInfo>\n ): Promise<import('./types').PipelineState> {\n const current = await this.getPipelineState(projectId);\n if (!current.tasks[taskId]) {\n current.tasks[taskId] = {};\n }\n current.tasks[taskId][artifactType] = {\n ...(current.tasks[taskId][artifactType] || { state: 'pending' }),\n ...update,\n };\n await this.savePipelineState(projectId, current);\n return current;\n }\n}\n","import type { ICurriculumStorage } from './types';\nimport { FileSystemCurriculumAdapter, FileSystemStorageOptions } from './fileSystemCurriculumAdapter';\nimport { SupabaseCurriculumAdapter, SupabaseStorageConfig } from './supabaseCurriculumAdapter';\n\nexport interface StorageFactoryOptions {\n provider?: 'filesystem' | 'supabase' | 'auto';\n fileSystemOptions?: FileSystemStorageOptions;\n supabaseConfig?: SupabaseStorageConfig;\n}\n\n/**\n * Creates and returns the appropriate ICurriculumStorage instance based on environment or explicit config.\n */\nexport function createCurriculumStorage(options: StorageFactoryOptions = {}): ICurriculumStorage {\n const provider = options.provider || process.env.CURRICULUM_STORAGE_PROVIDER || 'auto';\n\n if (provider === 'supabase') {\n return new SupabaseCurriculumAdapter(options.supabaseConfig);\n }\n\n if (provider === 'auto') {\n const hasSupabase = Boolean(\n (process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL) &&\n (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) &&\n process.env.STORAGE_USE_SUPABASE === 'true'\n );\n\n if (hasSupabase) {\n try {\n return new SupabaseCurriculumAdapter(options.supabaseConfig);\n } catch (e) {\n console.warn('⚠️ Falling back to FileSystemCurriculumAdapter due to Supabase initialization error:', e);\n }\n }\n }\n\n return new FileSystemCurriculumAdapter(options.fileSystemOptions);\n}\n"]}
1
+ {"version":3,"sources":["../../src/storage/fileSystemCurriculumAdapter.ts","../../src/storage/supabaseCurriculumAdapter.ts","../../src/storage/factory.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport type { \n ICurriculumStorage, \n SotDocument, \n LessonArtifactSummary, \n ProjectStatusReport,\n PipelineState,\n ArtifactLifecycleInfo\n} from './types';\n\nexport function computeContentHash(content: string): string {\n return 'sha256:' + crypto.createHash('sha256').update(content.trim(), 'utf-8').digest('hex');\n}\n\nexport const STANDARD_SOT_FILES = [\n 'LEARNER_PROFILE.md',\n 'PROJECT_BRIEF.md',\n 'REFERENCE_PACK.md',\n 'PROJECT_GRAPH.json',\n 'HYBRID_GRAPH.json',\n 'CURRICULUM_FRAMEWORK.md',\n 'CONTENT_STYLE_GUIDE.md',\n 'ART_DIRECTION.md',\n 'ALIGNMENT_MATRIX.md',\n];\n\nexport interface FileSystemStorageOptions {\n baseDir?: string;\n}\n\n/**\n * Atomic single-file write (5-Whys RC-race, 2026-09-13): write to a unique\n * temp file in the SAME directory, then `rename` over the target. On POSIX a\n * rename within a filesystem is atomic — a concurrent reader sees either the\n * old or the new complete file, never a torn write, and two racing writers\n * each land a complete file (last rename wins) instead of interleaved halves.\n * Previously a direct writeFileSync let the double-run race truncate/clobber\n * companion files (deck.json / .html disappeared while the .md survived).\n */\nexport function atomicWriteFileSync(targetPath: string, content: string): void {\n const dir = path.dirname(targetPath);\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n const tmpPath = path.join(dir, `.${path.basename(targetPath)}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString('hex')}.tmp`);\n try {\n fs.writeFileSync(tmpPath, content, 'utf-8');\n fs.renameSync(tmpPath, targetPath);\n } catch (err) {\n // Best-effort temp cleanup; never mask the original error.\n try { if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath); } catch {}\n throw err;\n }\n}\n\nexport class FileSystemCurriculumAdapter implements ICurriculumStorage {\n private baseDir: string;\n\n constructor(options: FileSystemStorageOptions = {}) {\n this.baseDir = options.baseDir || path.resolve(process.cwd(), 'output', 'projects');\n }\n\n private getProjectDir(projectId: string): string {\n const raw = (projectId || '').replace('proj_', '');\n const directPath = path.join(this.baseDir, raw);\n if (fs.existsSync(directPath)) return directPath;\n const fullIdPath = path.join(this.baseDir, projectId);\n if (fs.existsSync(fullIdPath)) return fullIdPath;\n return directPath;\n }\n\n /** Ensures the resolved path stays within the project directory (prevents path traversal). */\n private assertInsideProject(projectDir: string, targetPath: string): void {\n const resolvedProject = path.resolve(projectDir);\n const resolvedTarget = path.resolve(targetPath);\n if (!resolvedTarget.startsWith(resolvedProject + path.sep) && resolvedTarget !== resolvedProject) {\n throw new Error(`[FileSystemCurriculumAdapter] Path traversal blocked: ${targetPath} is outside project directory ${projectDir}`);\n }\n }\n\n async projectExists(projectId: string): Promise<boolean> {\n return fs.existsSync(this.getProjectDir(projectId));\n }\n\n async readSotDocument(projectId: string, filename: string): Promise<string | null> {\n const projectDir = this.getProjectDir(projectId);\n const possiblePaths = [\n path.join(projectDir, '_sot', filename),\n path.join(projectDir, filename),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p) && fs.statSync(p).isFile()) {\n return fs.readFileSync(p, 'utf-8');\n }\n }\n return null;\n }\n\n async listSotDocuments(projectId: string): Promise<SotDocument[]> {\n const projectDir = this.getProjectDir(projectId);\n const sotDir = path.join(projectDir, '_sot');\n\n const discoveredFiles = new Set<string>(STANDARD_SOT_FILES);\n if (fs.existsSync(sotDir)) {\n try {\n const diskFiles = fs.readdirSync(sotDir);\n for (const f of diskFiles) {\n if (f.startsWith('.') || f.endsWith('.review.json')) continue;\n const fullPath = path.join(sotDir, f);\n if (fs.statSync(fullPath).isFile()) {\n discoveredFiles.add(f);\n }\n }\n } catch {}\n }\n\n return Array.from(discoveredFiles).map(filename => {\n const p = fs.existsSync(path.join(sotDir, filename))\n ? path.join(sotDir, filename)\n : (fs.existsSync(path.join(projectDir, filename)) ? path.join(projectDir, filename) : null);\n\n if (p && fs.existsSync(p)) {\n const stats = fs.statSync(p);\n return {\n name: filename.replace(/\\.(md|json)$/i, '').replace(/_/g, ' '),\n filename,\n exists: true,\n sizeBytes: stats.size\n };\n }\n\n return {\n name: filename.replace(/\\.(md|json)$/i, '').replace(/_/g, ' '),\n filename,\n exists: false,\n sizeBytes: 0\n };\n });\n }\n\n async readArtifact(projectId: string, relPathOrIdentifier: string): Promise<string | null> {\n const projectDir = this.getProjectDir(projectId);\n\n // Block path traversal attempts\n const directCandidate = path.join(projectDir, relPathOrIdentifier);\n this.assertInsideProject(projectDir, directCandidate);\n\n // 1. Direct file path lookup\n const possiblePaths = [\n directCandidate,\n path.join(projectDir, '_sot', relPathOrIdentifier),\n path.join(projectDir, 'lessons', relPathOrIdentifier),\n path.join(projectDir, '_sot', path.basename(relPathOrIdentifier)),\n path.join(projectDir, 'lessons', path.basename(relPathOrIdentifier)),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p) && fs.statSync(p).isFile()) {\n return fs.readFileSync(p, 'utf-8');\n }\n }\n\n // If relPathOrIdentifier was an explicit filename with extension, don't guess\n if (relPathOrIdentifier.includes('.md') || relPathOrIdentifier.includes('/')) {\n return null;\n }\n\n // 2. Intelligent Identifier Resolution for query strings (e.g. \"U01_M01_L01 — Giáo án 5E\")\n const lessonMatch = relPathOrIdentifier.match(/U\\d+_M\\d+_L\\d+/i);\n if (lessonMatch) {\n const lessonId = lessonMatch[0].toUpperCase();\n const lessonDir = path.join(projectDir, 'lessons', lessonId);\n\n if (fs.existsSync(lessonDir) && fs.statSync(lessonDir).isDirectory()) {\n const lower = relPathOrIdentifier.toLowerCase();\n let artifactPrefix = 'LESSON';\n if (lower.includes('act') || lower.includes('lab') || lower.includes('thực hành')) {\n artifactPrefix = 'ACT';\n } else if (lower.includes('quiz') || lower.includes('trắc nghiệm') || lower.includes('đánh giá')) {\n artifactPrefix = 'QUIZ';\n } else if (lower.includes('slide') || lower.includes('bài giảng') || lower.includes('trình chiếu')) {\n artifactPrefix = 'SLIDE';\n } else if (lower.includes('guide') || lower.includes('hướng dẫn')) {\n artifactPrefix = 'GUIDE';\n } else if (lower.includes('wks') || lower.includes('worksheet') || lower.includes('phiếu bài tập')) {\n artifactPrefix = 'WKS';\n } else if (lower.includes('handout') || lower.includes('tài liệu')) {\n artifactPrefix = 'HANDOUT';\n } else if (lower.includes('code')) {\n artifactPrefix = 'CODE';\n } else if (lower.includes('ext') || lower.includes('extension')) {\n artifactPrefix = 'EXT';\n }\n\n const candidateFile = path.join(lessonDir, `${artifactPrefix}_${lessonId}.md`);\n if (fs.existsSync(candidateFile)) {\n return fs.readFileSync(candidateFile, 'utf-8');\n }\n }\n }\n\n return null;\n }\n\n async saveArtifact(projectId: string, relPath: string, content: string): Promise<void> {\n const projectDir = this.getProjectDir(projectId);\n const targetPath = path.join(projectDir, relPath);\n this.assertInsideProject(projectDir, targetPath);\n const targetDir = path.dirname(targetPath);\n\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n }\n\n // Version history (P2): ghi đè file đã tồn tại → chép bản cũ vào .history/ trước (giữ tối đa 10 bản gần nhất)\n if (fs.existsSync(targetPath)) {\n try {\n const oldContent = fs.readFileSync(targetPath, 'utf-8');\n if (oldContent !== content) {\n const historyDir = path.join(projectDir, '.history', relPath);\n fs.mkdirSync(historyDir, { recursive: true });\n atomicWriteFileSync(path.join(historyDir, `${Date.now()}.md`), oldContent);\n const versions = fs.readdirSync(historyDir).filter((f) => f.endsWith('.md')).sort();\n while (versions.length > 10) {\n fs.unlinkSync(path.join(historyDir, versions.shift() as string));\n }\n }\n } catch (histErr: any) {\n // History failure KHÔNG chặn ghi chính — nhưng không âm thầm: log rõ\n console.warn('[FileSystemCurriculumAdapter] version history snapshot failed:', histErr?.message || histErr);\n }\n }\n\n atomicWriteFileSync(targetPath, content);\n\n // Also auto-sync to lessons/ directory if this is a lesson artifact (e.g. _content/U01/SLIDE_U01_M01_L01.md)\n const filename = path.basename(relPath);\n const match = filename.match(/(LESSON|ACT|QUIZ|SLIDE|GUIDE|HANDOUT|WKS|EXT)_(U\\d+_M\\d+_L\\d+)\\.md/i);\n if (match) {\n const lessonId = match[2].toUpperCase();\n atomicWriteFileSync(path.join(projectDir, 'lessons', lessonId, filename), content);\n\n // Also sync to legacy _content/U01_M01_L01/ folder if it exists\n const legacyContentDir = path.join(projectDir, '_content', lessonId);\n if (fs.existsSync(legacyContentDir)) {\n atomicWriteFileSync(path.join(legacyContentDir, filename), content);\n }\n }\n }\n\n async listLessons(projectId: string): Promise<LessonArtifactSummary[]> {\n const lessonsDir = path.join(this.getProjectDir(projectId), 'lessons');\n if (!fs.existsSync(lessonsDir)) return [];\n\n const lessonFolders = fs.readdirSync(lessonsDir).filter(f => !f.startsWith('.'));\n return lessonFolders.map(folder => {\n const lDir = path.join(lessonsDir, folder);\n const isDir = fs.statSync(lDir).isDirectory();\n if (!isDir) {\n return {\n lessonId: folder,\n artifactsCount: 0,\n isComplete: false,\n artifacts: []\n };\n }\n\n const artifacts = fs.readdirSync(lDir).filter(f => !f.startsWith('.'));\n return {\n lessonId: folder,\n artifactsCount: artifacts.length,\n isComplete: artifacts.length >= 4,\n artifacts\n };\n });\n }\n\n async getProjectStatus(projectId: string): Promise<ProjectStatusReport> {\n const sotList = await this.listSotDocuments(projectId);\n const lessons = await this.listLessons(projectId);\n\n const completedCount = lessons.filter(l => l.isComplete).length;\n const totalLessons = lessons.length || 4;\n const progressPercent = Math.round((completedCount / totalLessons) * 100);\n\n const sotTable = sotList.map(doc => `| \\`${doc.filename}\\` | ${doc.exists ? '✅ Sẵn sàng' : '❌ Chưa có'} |`).join('\\n');\n const lessonTable = lessons.length > 0 \n ? lessons.map(l => `| **${l.lessonId}** | ${l.artifactsCount}/4 Artifacts | ${l.isComplete ? '✅ Hoàn tất' : '⏳ Đang tạo sinh'} | ${l.artifacts.join(', ') || '-'} |`).join('\\n')\n : '| Chưa có bài học nào trên đĩa cứng | 0/4 | ⏳ Chờ chạy | - |';\n\n const rawMarkdownReport = `## 📊 BÁO CÁO TRẠNG THÁI DỰ ÁN: \\`${projectId.toUpperCase()}\\`\n\n### 1. Nền tảng Tài liệu (SOT Readiness)\n| Tài liệu SOT | Trạng thái |\n|---|:---:|\n${sotTable}\n\n### 2. Danh mục Bài học & Học liệu (Lessons & Artifacts Matrix)\n| Mã bài học | Số lượng Artifact | Trạng thái | Danh sách Artifact đã tạo |\n|---|:---:|:---:|---|\n${lessonTable}\n\n**Tiến độ tổng thể:** ${completedCount}/${totalLessons} bài học (${progressPercent}%)\n\n### 3. Đề xuất Hành động Tiếp theo:\n- Sử dụng lệnh \\`/create-lesson <id>\\` để tạo sinh các bài học tiếp theo trong pipeline.\n- Sử dụng lệnh \\`/audit-quality\\` để chạy kiểm thử tiêu chuẩn Bloom và Alignment Matrix.`;\n\n return {\n projectId,\n sotReadiness: sotList,\n lessons,\n completedCount,\n totalLessons,\n progressPercent,\n rawMarkdownReport\n };\n }\n\n async getPipelineState(projectId: string): Promise<PipelineState> {\n const projectDir = this.getProjectDir(projectId);\n const stateFile = path.join(projectDir, '_pipeline', 'state.json');\n\n if (fs.existsSync(stateFile)) {\n try {\n const raw = fs.readFileSync(stateFile, 'utf-8');\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === 'object' && parsed.tasks) {\n return parsed as PipelineState;\n }\n } catch (err) {\n console.warn(`[FileSystemCurriculumAdapter] Error reading pipeline state for ${projectId}:`, err);\n }\n }\n\n // Default empty pipeline state\n return {\n projectId,\n updatedAt: new Date().toISOString(),\n tasks: {}\n };\n }\n\n async savePipelineState(projectId: string, state: PipelineState): Promise<void> {\n const projectDir = this.getProjectDir(projectId);\n const pipelineDir = path.join(projectDir, '_pipeline');\n\n if (!fs.existsSync(pipelineDir)) {\n fs.mkdirSync(pipelineDir, { recursive: true });\n }\n\n const stateFile = path.join(pipelineDir, 'state.json');\n state.updatedAt = new Date().toISOString();\n atomicWriteFileSync(stateFile, JSON.stringify(state, null, 2));\n }\n\n async updateArtifactState(\n projectId: string,\n taskId: string,\n artifactType: string,\n update: Partial<ArtifactLifecycleInfo>\n ): Promise<PipelineState> {\n const current = await this.getPipelineState(projectId);\n if (!current.tasks[taskId]) {\n current.tasks[taskId] = {};\n }\n\n const existingInfo = current.tasks[taskId][artifactType] || {\n state: 'pending',\n };\n\n current.tasks[taskId][artifactType] = {\n ...existingInfo,\n ...update,\n };\n\n await this.savePipelineState(projectId, current);\n return current;\n }\n\n /** Disk adapter: purge = rm the file (best-effort, mirrors cloud deleteArtifact). */\n async deleteArtifact(projectId: string, relPath: string): Promise<void> {\n try {\n const projectDir = this.getProjectDir(projectId);\n const targetPath = path.join(projectDir, relPath);\n this.assertInsideProject(projectDir, targetPath);\n if (fs.existsSync(targetPath)) fs.rmSync(targetPath, { force: true });\n } catch { /* best-effort */ }\n }\n}\n","import { createClient, type SupabaseClient } from '@supabase/supabase-js';\nimport type { MilestoneCurriculumBundle } from '../pipeline';\nimport type { \n ICurriculumStorage, \n SotDocument, \n LessonArtifactSummary, \n ProjectStatusReport \n} from './types';\nimport { STANDARD_SOT_FILES } from './fileSystemCurriculumAdapter';\n\nexport interface SupabaseStorageConfig {\n supabaseUrl?: string;\n supabaseServiceRoleKey?: string;\n bucketName?: string;\n client?: SupabaseClient;\n}\n\n/**\n * Supabase Curriculum Adapter — Syncs Markdown artifacts to Storage & Database\n * Implements ICurriculumStorage for multi-tenant Cloud deployment (Vercel, Netlify, Cloudflare, etc.).\n */\nexport class SupabaseCurriculumAdapter implements ICurriculumStorage {\n private client: SupabaseClient;\n private bucketName: string;\n\n constructor(config: SupabaseStorageConfig = {}) {\n this.bucketName = config.bucketName || process.env.SUPABASE_STORAGE_BUCKET || 'course-materials';\n\n if (config.client) {\n this.client = config.client;\n } else {\n const url = config.supabaseUrl || process.env.NEXT_PUBLIC_SUPABASE_URL || process.env.SUPABASE_URL || '';\n const key =\n config.supabaseServiceRoleKey ||\n process.env.SUPABASE_SERVICE_ROLE_KEY ||\n process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY ||\n '';\n\n if (!url || !key) {\n throw new Error('Supabase URL or Key is missing in SupabaseCurriculumAdapter');\n }\n\n this.client = createClient(url, key);\n }\n }\n\n async projectExists(projectId: string): Promise<boolean> {\n try {\n const { data, error } = await this.client.storage\n .from(this.bucketName)\n .list(projectId, { limit: 5 });\n return !error && !!data && data.length > 0;\n } catch {\n return false;\n }\n }\n\n async readSotDocument(projectId: string, filename: string): Promise<string | null> {\n const paths = [\n `${projectId}/_sot/${filename}`,\n `${projectId}/${filename}`,\n `${projectId}/_designer/${filename}`,\n `${projectId}/_analyst/${filename}`\n ];\n for (const p of paths) {\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n return await data.text();\n }\n } catch {}\n }\n return null;\n }\n\n async listSotDocuments(projectId: string): Promise<SotDocument[]> {\n const discoveredFiles = new Set<string>(STANDARD_SOT_FILES);\n try {\n const { data, error } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/_sot`);\n if (!error && data) {\n for (const item of data) {\n if (item.name && !item.name.startsWith('.') && !item.name.endsWith('.review.json')) {\n discoveredFiles.add(item.name);\n }\n }\n }\n } catch {}\n\n const results: SotDocument[] = [];\n for (const filename of discoveredFiles) {\n const content = await this.readSotDocument(projectId, filename);\n results.push({\n name: filename.replace(/\\.(md|json)$/i, '').replace(/_/g, ' '),\n filename,\n exists: !!content,\n content: content || undefined,\n sizeBytes: content ? content.length : 0\n });\n }\n return results;\n }\n\n async readArtifact(projectId: string, relPathOrIdentifier: string): Promise<string | null> {\n const cleanPath = relPathOrIdentifier.replace(/^\\//, '');\n\n // 1. Direct path lookup attempts\n const possiblePaths = [\n `${projectId}/${cleanPath}`,\n `${projectId}/_sot/${cleanPath}`,\n `${projectId}/_content/${cleanPath}`,\n `${projectId}/lessons/${cleanPath}`,\n `${projectId}/_sot/${cleanPath.split('/').pop()}`,\n `${projectId}/lessons/${cleanPath.split('/').pop()}`,\n ];\n\n for (const p of possiblePaths) {\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n return await data.text();\n }\n } catch {}\n }\n\n // If relPathOrIdentifier was an explicit filename with extension or path, don't guess\n if (relPathOrIdentifier.includes('.md') || relPathOrIdentifier.includes('.json') || relPathOrIdentifier.includes('/')) {\n return null;\n }\n\n // 2. Intelligent Identifier Resolution (e.g. \"U01_M01_L01 — Giáo án 5E\" or \"U01_M01_L01\")\n const lessonMatch = relPathOrIdentifier.match(/U\\d+_M\\d+_L\\d+/i);\n if (lessonMatch) {\n const lessonId = lessonMatch[0].toUpperCase();\n const unitCode = lessonId.split('_')[0] || 'U01';\n const lower = relPathOrIdentifier.toLowerCase();\n\n let artifactPrefix: string | null = null;\n if (lower.includes('act') || lower.includes('lab') || lower.includes('thực hành')) {\n artifactPrefix = 'ACT';\n } else if (lower.includes('quiz') || lower.includes('trắc nghiệm') || lower.includes('đánh giá')) {\n artifactPrefix = 'QUIZ';\n } else if (lower.includes('slide') || lower.includes('bài giảng') || lower.includes('trình chiếu')) {\n artifactPrefix = 'SLIDE';\n } else if (lower.includes('guide') || lower.includes('hướng dẫn')) {\n artifactPrefix = 'GUIDE';\n } else if (lower.includes('wks') || lower.includes('worksheet') || lower.includes('phiếu bài tập')) {\n artifactPrefix = 'WKS';\n } else if (lower.includes('handout') || lower.includes('tài liệu')) {\n artifactPrefix = 'HANDOUT';\n } else if (lower.includes('code')) {\n artifactPrefix = 'CODE';\n } else if (lower.includes('ext') || lower.includes('extension') || lower.includes('mở rộng')) {\n artifactPrefix = 'EXT';\n } else if (lower.includes('exp') || lower.includes('exposition') || lower.includes('tự học') || lower.includes('kiến thức nền')) {\n artifactPrefix = 'EXPOSITION';\n } else if (lower.includes('rubric')) {\n artifactPrefix = 'RUBRIC';\n } else if (lower.includes('bom')) {\n artifactPrefix = 'BOM';\n } else if (lower.includes('lesson') || lower.includes('giáo án') || lower.includes('5e')) {\n artifactPrefix = 'LESSON';\n }\n\n if (!artifactPrefix) {\n return null;\n }\n\n const candidatePaths = artifactPrefix === 'EXPOSITION'\n ? [\n `${projectId}/_sot/expositions/${lessonId}.md`,\n `${projectId}/_content/${unitCode}/EXPOSITION_${lessonId}.md`,\n `${projectId}/lessons/${lessonId}/EXPOSITION_${lessonId}.md`,\n ]\n : [\n `${projectId}/_content/${unitCode}/${artifactPrefix}_${lessonId}.md`,\n `${projectId}/lessons/${lessonId}/${artifactPrefix}_${lessonId}.md`,\n `${projectId}/${artifactPrefix}_${lessonId}.md`,\n ];\n\n for (const p of candidatePaths) {\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n return await data.text();\n }\n } catch {}\n }\n }\n\n return null;\n }\n\n async saveArtifact(projectId: string, relPath: string, content: string): Promise<void> {\n const fullPath = `${projectId}/${relPath.replace(/^\\//, '')}`;\n const { error } = await this.client.storage\n .from(this.bucketName)\n .upload(fullPath, Buffer.from(content, 'utf-8'), {\n contentType: 'text/markdown',\n upsert: true,\n });\n\n if (error) {\n throw new Error(`Failed to upload artifact to Supabase Storage: ${error.message}`);\n }\n\n // Optional DB Upsert for fast indexed searching if artifacts table exists\n try {\n await this.client.from('curriculum_artifacts').upsert({\n project_id: projectId,\n rel_path: relPath,\n content: content,\n updated_at: new Date().toISOString(),\n }, { onConflict: 'project_id,rel_path' });\n } catch {\n // Ignore if table not yet migrated\n }\n }\n\n /**\n * Split-brain root-cause fix (2026-09-14): purge must reach the cloud copy\n * too. Removes the storage object AND the indexed `curriculum_artifacts`\n * row (the row is what `readArtifact`-style indexed readers resolve first).\n * Best-effort / no-throw per the interface contract.\n */\n async deleteArtifact(projectId: string, relPath: string): Promise<void> {\n const fullPath = `${projectId}/${relPath.replace(/^\\//, '')}`;\n try {\n await this.client.storage.from(this.bucketName).remove([fullPath]);\n } catch { /* object may not exist — fine */ }\n try {\n await this.client\n .from('curriculum_artifacts')\n .delete()\n .match({ project_id: projectId, rel_path: relPath });\n } catch { /* table may not exist — fine */ }\n }\n\n async listLessons(projectId: string): Promise<LessonArtifactSummary[]> {\n const summaries: LessonArtifactSummary[] = [];\n const processedLessons = new Set<string>();\n\n try {\n // 1. Scan _content/ folders (e.g. _content/U01/, _content/U02/)\n const { data: unitDirs } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/_content`);\n\n if (unitDirs) {\n for (const u of unitDirs) {\n const { data: files } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/_content/${u.name}`);\n\n if (files) {\n const lessonMap: Record<string, string[]> = {};\n files.forEach(f => {\n const m = f.name.match(/U\\d+_M\\d+_L\\d+/i);\n if (m) {\n const lid = m[0].toUpperCase();\n lessonMap[lid] = lessonMap[lid] || [];\n lessonMap[lid].push(f.name);\n }\n });\n\n for (const [lid, arts] of Object.entries(lessonMap)) {\n if (!processedLessons.has(lid)) {\n processedLessons.add(lid);\n summaries.push({\n lessonId: lid,\n artifactsCount: arts.length,\n isComplete: arts.length >= 4,\n artifacts: arts,\n });\n }\n }\n }\n }\n }\n\n // 2. Scan lessons/ folders (legacy / alternate structure)\n const { data: lessonDirs } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/lessons`);\n\n if (lessonDirs) {\n for (const dir of lessonDirs) {\n if (!processedLessons.has(dir.name)) {\n const { data: files } = await this.client.storage\n .from(this.bucketName)\n .list(`${projectId}/lessons/${dir.name}`);\n \n const artifacts = (files || []).map(f => f.name).filter(n => !n.startsWith('.'));\n processedLessons.add(dir.name);\n summaries.push({\n lessonId: dir.name,\n artifactsCount: artifacts.length,\n isComplete: artifacts.length >= 4,\n artifacts\n });\n }\n }\n }\n } catch {\n // Fallback\n }\n\n return summaries;\n }\n\n async getProjectStatus(projectId: string): Promise<ProjectStatusReport> {\n const sotList = await this.listSotDocuments(projectId);\n const lessons = await this.listLessons(projectId);\n\n const completedCount = lessons.filter(l => l.isComplete).length;\n const totalLessons = lessons.length || 4;\n const progressPercent = Math.round((completedCount / totalLessons) * 100);\n\n const sotTable = sotList.map(doc => `| \\`${doc.filename}\\` | ${doc.exists ? '✅ Sẵn sàng' : '❌ Chưa có'} |`).join('\\n');\n const lessonTable = lessons.length > 0 \n ? lessons.map(l => `| **${l.lessonId}** | ${l.artifactsCount}/4 Artifacts | ${l.isComplete ? '✅ Hoàn tất' : '⏳ Đang tạo sinh'} | ${l.artifacts.join(', ') || '-'} |`).join('\\n')\n : '| Chưa có bài học nào trên cloud storage | 0/4 | ⏳ Chờ chạy | - |';\n\n const rawMarkdownReport = `## 📊 BÁO CÁO TRẠNG THÁI DỰ ÁN (CLOUD): \\`${projectId.toUpperCase()}\\`\n\n### 1. Nền tảng Tài liệu (SOT Readiness)\n| Tài liệu SOT | Trạng thái |\n|---|:---:|\n${sotTable}\n\n### 2. Danh mục Bài học & Học liệu (Lessons & Artifacts Matrix)\n| Mã bài học | Số lượng Artifact | Trạng thái | Danh sách Artifact đã tạo |\n|---|:---:|:---:|---|\n${lessonTable}\n\n**Tiến độ tổng thể:** ${completedCount}/${totalLessons} bài học (${progressPercent}%)`;\n\n return {\n projectId,\n sotReadiness: sotList,\n lessons,\n completedCount,\n totalLessons,\n progressPercent,\n rawMarkdownReport\n };\n }\n\n /**\n * Uploads a complete milestone bundle (Markdown files) to Supabase Storage\n */\n async uploadMilestoneBundle(\n projectSlug: string,\n bundle: MilestoneCurriculumBundle\n ): Promise<{ lessonUrl?: string; activityUrl?: string; handoutUrl?: string }> {\n const basePath = `${projectSlug}/${bundle.milestoneId}`;\n\n const uploads = [\n {\n path: `${basePath}/LESSON.md`,\n content: bundle.lessonMarkdown,\n type: 'text/markdown',\n },\n {\n path: `${basePath}/ACT.md`,\n content: bundle.activityMarkdown,\n type: 'text/markdown',\n },\n {\n path: `${basePath}/HANDOUT.md`,\n content: bundle.handoutMarkdown,\n type: 'text/markdown',\n },\n ];\n\n const results: Record<string, string> = {};\n\n for (const item of uploads) {\n const { data, error } = await this.client.storage\n .from(this.bucketName)\n .upload(item.path, Buffer.from(item.content, 'utf-8'), {\n contentType: item.type,\n upsert: true,\n });\n\n if (!error && data) {\n const { data: publicUrlData } = this.client.storage.from(this.bucketName).getPublicUrl(item.path);\n results[item.path] = publicUrlData.publicUrl;\n }\n }\n\n return {\n lessonUrl: results[`${basePath}/LESSON.md`],\n activityUrl: results[`${basePath}/ACT.md`],\n handoutUrl: results[`${basePath}/HANDOUT.md`],\n };\n }\n\n async getPipelineState(projectId: string): Promise<import('./types').PipelineState> {\n const p = `${projectId}/_pipeline/state.json`;\n try {\n const { data, error } = await this.client.storage.from(this.bucketName).download(p);\n if (!error && data) {\n const text = await data.text();\n return JSON.parse(text);\n }\n } catch {}\n\n return {\n projectId,\n updatedAt: new Date().toISOString(),\n tasks: {}\n };\n }\n\n async savePipelineState(projectId: string, state: import('./types').PipelineState): Promise<void> {\n const p = `${projectId}/_pipeline/state.json`;\n state.updatedAt = new Date().toISOString();\n await this.client.storage.from(this.bucketName).upload(p, Buffer.from(JSON.stringify(state, null, 2), 'utf-8'), {\n contentType: 'application/json',\n upsert: true,\n });\n }\n\n async updateArtifactState(\n projectId: string,\n taskId: string,\n artifactType: string,\n update: Partial<import('./types').ArtifactLifecycleInfo>\n ): Promise<import('./types').PipelineState> {\n const current = await this.getPipelineState(projectId);\n if (!current.tasks[taskId]) {\n current.tasks[taskId] = {};\n }\n current.tasks[taskId][artifactType] = {\n ...(current.tasks[taskId][artifactType] || { state: 'pending' }),\n ...update,\n };\n await this.savePipelineState(projectId, current);\n return current;\n }\n}\n","import type { ICurriculumStorage } from './types';\nimport { FileSystemCurriculumAdapter, FileSystemStorageOptions } from './fileSystemCurriculumAdapter';\nimport { SupabaseCurriculumAdapter, SupabaseStorageConfig } from './supabaseCurriculumAdapter';\n\nexport interface StorageFactoryOptions {\n provider?: 'filesystem' | 'supabase' | 'auto';\n fileSystemOptions?: FileSystemStorageOptions;\n supabaseConfig?: SupabaseStorageConfig;\n}\n\n/**\n * Creates and returns the appropriate ICurriculumStorage instance based on environment or explicit config.\n */\nexport function createCurriculumStorage(options: StorageFactoryOptions = {}): ICurriculumStorage {\n const provider = options.provider || process.env.CURRICULUM_STORAGE_PROVIDER || 'auto';\n\n if (provider === 'supabase') {\n return new SupabaseCurriculumAdapter(options.supabaseConfig);\n }\n\n if (provider === 'auto') {\n const hasSupabase = Boolean(\n (process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL) &&\n (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) &&\n process.env.STORAGE_USE_SUPABASE === 'true'\n );\n\n if (hasSupabase) {\n try {\n return new SupabaseCurriculumAdapter(options.supabaseConfig);\n } catch (e) {\n console.warn('⚠️ Falling back to FileSystemCurriculumAdapter due to Supabase initialization error:', e);\n }\n }\n }\n\n return new FileSystemCurriculumAdapter(options.fileSystemOptions);\n}\n"]}
@@ -18645,17 +18645,6 @@ function buildLanguageDirective(targetLanguage) {
18645
18645
  ${exampleLine}` : ""}
18646
18646
  - CJK / NON-LATIN SCRIPT BAN (ABSOLUTE): NEVER output characters from Chinese (\u6C49\u5B57), Japanese (\u304B\u306A/\u6F22\u5B57), or Korean (\uD55C\uAE00) scripts ANYWHERE in the document \u2014 not even a single glyph spliced inside a ${name} sentence. Observed past violations that are STRICTLY forbidden: \u6392\u67E5, \u5305\u542B, \u5BFC\u81F4, \u662F\u591A\u5C11, \u6280\u672F, \u771F\u673A, \u4F11\u606F, \u7EB8\u8D28. To express such meaning write it fully in ${name} or keep the ENGLISH technical term (e.g. write "t\u1EF1 ki\u1EC3m tra l\u1ED7i" / "self-debugging", "bao g\u1ED3m" / "includes"). A mechanical scanner rejects any document containing even one CJK character.`;
18647
18647
  }
18648
- function matchesArtifactType(candidate, target) {
18649
- const c = candidate.trim().toUpperCase();
18650
- const t = target.trim().toUpperCase();
18651
- if (c === t) return true;
18652
- if (c.startsWith("LESSON") && t.startsWith("LESSON")) return true;
18653
- if ((c === "CODE" || c === "CODE_LAB") && (t === "CODE" || t === "CODE_LAB")) return true;
18654
- if ((c === "EXPOSITION" || c === "KNOWLEDGE_EXPOSITION") && (t === "EXPOSITION" || t === "KNOWLEDGE_EXPOSITION")) return true;
18655
- if ((c === "WKS" || c === "WORKSHEET") && (t === "WKS" || t === "WORKSHEET")) return true;
18656
- if ((c === "EXT" || c === "EXTENSION") && (t === "EXT" || t === "EXTENSION")) return true;
18657
- return false;
18658
- }
18659
18648
  var TEMPLATE_BY_TYPE = {
18660
18649
  LESSON: "LESSON_5E_template.md",
18661
18650
  LESSON_5E: "LESSON_5E_template.md",
@@ -18664,7 +18653,7 @@ var TEMPLATE_BY_TYPE = {
18664
18653
  ACT: "ACT_template.md",
18665
18654
  CODE: "CODE_template.md",
18666
18655
  // JSON-first code lab shares the CODE label set (the serializer renders its
18667
- // own headings; this lookup only feeds the SLC/directive fallback path).
18656
+ // own headings; this lookup only feeds the directive fallback path).
18668
18657
  CODE_LAB: "CODE_template.md",
18669
18658
  QUIZ: "QUIZ_v4.6_template.md",
18670
18659
  GUIDE: "GUIDE_template.md",
@@ -18676,87 +18665,21 @@ var TEMPLATE_BY_TYPE = {
18676
18665
  LEARNER_PROFILE: "LEARNER_PROFILE_template.md",
18677
18666
  PROJECT_BRIEF: "PROJECT_BRIEF_template.md",
18678
18667
  CURRICULUM_FRAMEWORK: "CURRICULUM_FRAMEWORK_template.md",
18679
- CONTENT_STYLE_GUIDE: "CONTENT_STYLE_GUIDE_template.md",
18680
- SECTION_LANGUAGE_CONTRACT: "SECTION_LANGUAGE_CONTRACT_template.md"
18668
+ CONTENT_STYLE_GUIDE: "CONTENT_STYLE_GUIDE_template.md"
18681
18669
  };
18682
- function keepContractEntries(artifactType, mapping) {
18670
+ function extractSectionHeadings(artifactType, opts) {
18683
18671
  const templateFile = TEMPLATE_BY_TYPE[artifactType.trim().toUpperCase()];
18684
- if (!templateFile) return mapping;
18672
+ if (!templateFile) return {};
18685
18673
  const resolved = resolveArtifactTemplate(templateFile);
18686
- if (!resolved) return mapping;
18687
- const contract = new Set(resolved.sections.map(stripHeadingKey));
18688
- const kept = {};
18689
- for (const [k, v] of Object.entries(mapping)) {
18690
- if (contract.has(stripHeadingKey(k))) kept[k] = v;
18691
- }
18692
- return kept;
18674
+ if (!resolved) return {};
18675
+ return Object.fromEntries(resolved.sections.map((s) => [s, s]));
18693
18676
  }
18694
- function extractSectionHeadingsFromSLC(slcInput, artifactType, targetLanguage = "vi") {
18695
- const upperType = artifactType.trim().toUpperCase();
18696
- const getFallback = () => {
18697
- const templateFile = TEMPLATE_BY_TYPE[upperType];
18698
- if (!templateFile) return {};
18699
- const resolved = resolveArtifactTemplate(templateFile);
18700
- if (!resolved) return {};
18701
- return Object.fromEntries(resolved.sections.map((s) => [s, s]));
18702
- };
18703
- if (!slcInput) return getFallback();
18704
- if (typeof slcInput === "object") {
18705
- if (slcInput[upperType] && Object.keys(slcInput[upperType]).length > 0) {
18706
- return keepContractEntries(upperType, slcInput[upperType]);
18707
- }
18708
- for (const [key, mapping] of Object.entries(slcInput)) {
18709
- if (matchesArtifactType(key, upperType) && Object.keys(mapping).length > 0) {
18710
- return keepContractEntries(upperType, mapping);
18711
- }
18712
- }
18713
- return getFallback();
18714
- }
18715
- const slcMarkdown = slcInput;
18716
- const blocks = slcMarkdown.split(/\n(?=#{2,3}\s+[A-Z0-9_]+)/g);
18717
- for (const block of blocks) {
18718
- const headerMatch = block.match(/^#{2,3}\s+([A-Z0-9_]+)/);
18719
- if (!headerMatch) continue;
18720
- const blockType = headerMatch[1].trim().toUpperCase();
18721
- if (matchesArtifactType(blockType, upperType)) {
18722
- const mapping = {};
18723
- const lines = block.split("\n");
18724
- for (const line of lines) {
18725
- const trimmed = line.trim();
18726
- if (trimmed.startsWith("|") && !trimmed.includes("---")) {
18727
- const cells = trimmed.split("|").map((c) => c.trim()).filter((_, idx, arr) => idx > 0 && idx < arr.length - 1);
18728
- if (cells.length >= 2 && !cells[0].toLowerCase().includes("canonical") && !cells[1].toLowerCase().includes("localized")) {
18729
- mapping[cells[0]] = cells[1];
18730
- }
18731
- } else {
18732
- const bullet = line.match(/^[-*]\s+([^:]+):\s+(.+)$/);
18733
- if (bullet) {
18734
- mapping[bullet[1].trim()] = bullet[2].trim();
18735
- }
18736
- }
18737
- }
18738
- if (Object.keys(mapping).length > 0) return keepContractEntries(upperType, mapping);
18739
- }
18740
- }
18741
- return getFallback();
18742
- }
18743
- function buildHeadingDirective(artifactType, slcMarkdown, targetLanguage = "vi", opts) {
18744
- const upperType = artifactType.trim().toUpperCase();
18745
- const templateFile = TEMPLATE_BY_TYPE[upperType];
18746
- const resolved = templateFile ? resolveArtifactTemplate(templateFile) : null;
18747
- const baked = !!resolved && resolved.declaredLang !== "en";
18748
- const headings = resolved ? Object.fromEntries(
18749
- resolved.sections.map((s) => [
18750
- s,
18751
- baked ? s : extractSectionHeadingsFromSLC(slcMarkdown, upperType, targetLanguage)[s] || s
18752
- ])
18753
- ) : extractSectionHeadingsFromSLC(baked ? null : slcMarkdown, upperType, targetLanguage);
18677
+ function buildHeadingDirective(artifactType, opts) {
18678
+ const headings = extractSectionHeadings(artifactType);
18754
18679
  if (Object.keys(headings).length === 0) {
18755
18680
  return "";
18756
18681
  }
18757
- const lines = Object.entries(headings).map(
18758
- ([heading, display]) => heading === display ? ` - "${display}"` : ` - "${heading}" -> Use Display Heading: "${display}"`
18759
- );
18682
+ const lines = Object.keys(headings).map((heading) => ` - "${heading}"`);
18760
18683
  return `MANDATORY SECTION HEADINGS (SOURCE: RESOLVED ARTIFACT TEMPLATE):
18761
18684
  - Copy the template's YAML frontmatter \`template_required_sections\` list VERBATIM into the artifact frontmatter \u2014 never translate, reorder, or invent entries.
18762
18685
  - In the markdown body, section headers MUST be exactly the Display Headings below (do NOT translate, paraphrase, or re-marker them):
@@ -19075,9 +18998,8 @@ function buildSectionAwareExcerpt(markdown, opts = {}) {
19075
18998
  };
19076
18999
  }
19077
19000
  const minContentChars = opts.minContentChars !== void 0 ? opts.minContentChars : Math.min(400, source.length);
19078
- const slcMap = normalizeSlcContract(opts.sectionLanguageContract);
19079
19001
  const effectiveArtifactType = opts.artifactType || deriveArtifactTypeFromFileName(opts.fileName);
19080
- const sections = parseMarkdownSections(source, slcMap, effectiveArtifactType);
19002
+ const sections = parseMarkdownSections(source);
19081
19003
  const metaBlock = buildMetaBlock(source, effectiveArtifactType);
19082
19004
  if (sections.length === 0) {
19083
19005
  issues.push("parse:no-sections");
@@ -19200,48 +19122,16 @@ function buildLessonExcerpt(markdown, opts = {}) {
19200
19122
  priorities: DEFAULT_LESSON_PRIORITIES
19201
19123
  });
19202
19124
  }
19203
- function normalizeSlcContract(slc) {
19204
- if (!slc) return void 0;
19205
- if (typeof slc !== "string") return slc;
19206
- const out = {};
19207
- const blocks = slc.split(/\n(?=#{2,3}\s+[A-Z0-9_]+)/g);
19208
- for (const block of blocks) {
19209
- const header = block.match(/^#{2,3}\s+([A-Z0-9_]+)/);
19210
- if (!header?.[1]) continue;
19211
- const mapping = {};
19212
- for (const line of block.split("\n")) {
19213
- const t = line.trim();
19214
- if (!t.startsWith("|") || t.includes("---")) continue;
19215
- const cells = t.split("|").map((c) => c.trim()).filter((_, i, a) => i > 0 && i < a.length - 1);
19216
- const [c0, c1] = cells;
19217
- if (c0 && c1 && !c0.toLowerCase().includes("canonical") && !c1.toLowerCase().includes("localized")) {
19218
- mapping[c0] = c1;
19219
- }
19220
- }
19221
- if (Object.keys(mapping).length > 0) out[header[1]] = mapping;
19222
- }
19223
- return Object.keys(out).length > 0 ? out : void 0;
19224
- }
19225
- function parseMarkdownSections(markdown, slcMap, artifactType) {
19125
+ function parseMarkdownSections(markdown) {
19226
19126
  const sections = [];
19227
19127
  const lines = markdown.split("\n");
19228
19128
  let currentHeading = "";
19229
19129
  let currentBody = [];
19230
- const reverseMap = /* @__PURE__ */ new Map();
19231
- if (slcMap) {
19232
- const maps = artifactType && slcMap[artifactType] ? [slcMap[artifactType]] : Object.values(slcMap);
19233
- for (const m of maps) {
19234
- for (const [canonical, localized] of Object.entries(m)) {
19235
- reverseMap.set(normalizeHeading(localized), canonical);
19236
- reverseMap.set(normalizeHeading(canonical), canonical);
19237
- }
19238
- }
19239
- }
19240
19130
  const flush = () => {
19241
19131
  if (!currentHeading) return;
19242
19132
  const cleanTitle = currentHeading.replace(/^#{1,4}\s+/, "").trim();
19243
19133
  const norm = normalizeHeading(cleanTitle);
19244
- const canonicalKey = reverseMap.get(norm) || findCanonicalFuzzy(norm);
19134
+ const canonicalKey = findCanonicalFuzzy(norm);
19245
19135
  sections.push({
19246
19136
  rawHeading: currentHeading,
19247
19137
  cleanTitle,
@@ -19340,7 +19230,7 @@ function buildMetaBlock(source, artifactType) {
19340
19230
  function deriveArtifactTypeFromFileName(fileName) {
19341
19231
  if (!fileName) return void 0;
19342
19232
  const base = fileName.replace(/\.md$/i, "");
19343
- const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|SECTION_LANGUAGE_CONTRACT|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
19233
+ const multiWord = base.match(/^(KNOWLEDGE_EXPOSITION|CONTENT_STYLE_GUIDE|CURRICULUM_FRAMEWORK|LEARNER_PROFILE|PROJECT_BRIEF|REFERENCE_PACK|CURRICULUM_PLAN)/i);
19344
19234
  if (multiWord) return multiWord[1].toUpperCase();
19345
19235
  const token = base.match(/^([A-Z][A-Z0-9_]*?)(?=_|$)/);
19346
19236
  return token ? token[1] : void 0;
@@ -19577,11 +19467,7 @@ async function generateSingleArtifact(req) {
19577
19467
  language.toLowerCase().includes("bilingual") || language.toLowerCase().includes("song");
19578
19468
  const targetLang = resolveTargetLanguageCode(language);
19579
19469
  const langDirective = buildLanguageDirective(language);
19580
- const headingDirective = buildHeadingDirective(
19581
- artifactType.toUpperCase(),
19582
- req.sectionLanguageContract,
19583
- targetLang
19584
- );
19470
+ const headingDirective = buildHeadingDirective(artifactType.toUpperCase());
19585
19471
  const availableSources = {
19586
19472
  KNOWLEDGE_EXPOSITION: contextSot.exposition || researchContext,
19587
19473
  CANONICAL_LESSON: contextSot.lessonPlan,
@@ -19648,11 +19534,10 @@ ${symbolLedgerPrompt}
19648
19534
 
19649
19535
  IMAGE PLANNING (media ledger) \u2014 QUOTA GEN: t\u1ED1i \u0111a ${mediaPolicy.maxGenImagesPerArtifact} \u1EA3nh AI cho artifact n\xE0y (\u1EA3nh search kho kh\xF4ng gi\u1EDBi h\u1EA1n).
19650
19536
  Khi n\u1ED9i dung c\u1EA7n minh h\u1ECDa (diagram quy tr\xECnh, s\u01A1 \u0111\u1ED3 kh\xE1i ni\u1EC7m, step-by-step visual), ch\xE8n placeholder \u0111\xFAng format [IMAGE: slug] (slug ch\u1EEF th\u01B0\u1EDDng-g\u1EA1ch ngang, unique trong b\xE0i, vd img-for-loop-diagram) T\u1EA0I \u0110\xDANG CH\u1ED6 c\u1EA7n \u1EA3nh, tr\xEAn d\xF2ng ri\xEAng. KH\xD4NG t\u1EF1 sinh \u1EA3nh, KH\xD4NG d\xF9ng markdown image \u2014 placeholder s\u1EBD \u0111\u01B0\u1EE3c thay b\u1EB1ng \u1EA3nh th\u1EADt sau khi Media Curator duy\u1EC7t. Ch\u1EC9 \u0111\u1EB7t cho \u1EA3nh TH\u1EF0C S\u1EF0 c\u1EA7n thi\u1EBFt.` : ""}`;
19651
- const slcContract = req.sectionLanguageContract;
19652
- const frameworkExcerpt = contextSot.framework ? buildSectionAwareExcerpt(contextSot.framework, { budget: 2500, sectionLanguageContract: slcContract }).excerpt : "";
19653
- const lessonPlanExcerpt = contextSot.lessonPlan ? buildLessonExcerpt(contextSot.lessonPlan, { budget: 8e3, sectionLanguageContract: slcContract, artifactType: "LESSON" }).excerpt : "";
19654
- const handoutExcerpt = contextSot.handout ? buildSectionAwareExcerpt(contextSot.handout, { budget: 2e3, sectionLanguageContract: slcContract }).excerpt : "";
19655
- const expositionExcerpt = contextSot.exposition ? buildExpositionExcerpt(contextSot.exposition, { budget: 6e3, sectionLanguageContract: slcContract }).excerpt : "";
19537
+ const frameworkExcerpt = contextSot.framework ? buildSectionAwareExcerpt(contextSot.framework, { budget: 2500 }).excerpt : "";
19538
+ const lessonPlanExcerpt = contextSot.lessonPlan ? buildLessonExcerpt(contextSot.lessonPlan, { budget: 8e3, artifactType: "LESSON" }).excerpt : "";
19539
+ const handoutExcerpt = contextSot.handout ? buildSectionAwareExcerpt(contextSot.handout, { budget: 2e3 }).excerpt : "";
19540
+ const expositionExcerpt = contextSot.exposition ? buildExpositionExcerpt(contextSot.exposition, { budget: 6e3 }).excerpt : "";
19656
19541
  const userPrompt = `### CONTEXT GROUND TRUTH:
19657
19542
  - Topic / Concept Domain: "${topic}"
19658
19543
  - Lesson ID: "${lessonId || "ON_DEMAND"}"